resizeHandle.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. (function() {
  2. const GRADIO_MIN_WIDTH = 320;
  3. const PAD = 16;
  4. const DEBOUNCE_TIME = 100;
  5. const DOUBLE_TAP_DELAY = 200; //ms
  6. const R = {
  7. tracking: false,
  8. parent: null,
  9. parentWidth: null,
  10. leftCol: null,
  11. leftColStartWidth: null,
  12. screenX: null,
  13. lastTapTime: null,
  14. };
  15. let resizeTimer;
  16. let parents = [];
  17. function setLeftColGridTemplate(el, width) {
  18. el.style.gridTemplateColumns = `${width}px 16px 1fr`;
  19. }
  20. function displayResizeHandle(parent) {
  21. if (!parent.needHideOnMoblie) {
  22. return true;
  23. }
  24. if (window.innerWidth < GRADIO_MIN_WIDTH * 2 + PAD * 4) {
  25. parent.style.display = 'flex';
  26. parent.resizeHandle.style.display = "none";
  27. return false;
  28. } else {
  29. parent.style.display = 'grid';
  30. parent.resizeHandle.style.display = "block";
  31. return true;
  32. }
  33. }
  34. function afterResize(parent) {
  35. if (displayResizeHandle(parent) && parent.style.gridTemplateColumns != parent.style.originalGridTemplateColumns) {
  36. const oldParentWidth = R.parentWidth;
  37. const newParentWidth = parent.offsetWidth;
  38. const widthL = parseInt(parent.style.gridTemplateColumns.split(' ')[0]);
  39. const ratio = newParentWidth / oldParentWidth;
  40. const newWidthL = Math.max(Math.floor(ratio * widthL), parent.minLeftColWidth);
  41. setLeftColGridTemplate(parent, newWidthL);
  42. R.parentWidth = newParentWidth;
  43. }
  44. }
  45. function setup(parent) {
  46. function onDoubleClick(evt) {
  47. evt.preventDefault();
  48. evt.stopPropagation();
  49. parent.style.gridTemplateColumns = parent.style.originalGridTemplateColumns;
  50. }
  51. const leftCol = parent.firstElementChild;
  52. const rightCol = parent.lastElementChild;
  53. parents.push(parent);
  54. parent.style.display = 'grid';
  55. parent.style.gap = '0';
  56. let leftColTemplate = "";
  57. if (parent.children[0].style.flexGrow) {
  58. leftColTemplate = `${parent.children[0].style.flexGrow}fr`;
  59. parent.minLeftColWidth = GRADIO_MIN_WIDTH;
  60. parent.minRightColWidth = GRADIO_MIN_WIDTH;
  61. parent.needHideOnMoblie = true;
  62. } else {
  63. leftColTemplate = parent.children[0].style.flexBasis;
  64. parent.minLeftColWidth = parent.children[0].style.flexBasis.slice(0, -2) / 2;
  65. parent.minRightColWidth = 0;
  66. parent.needHideOnMoblie = false;
  67. }
  68. const gridTemplateColumns = `${leftColTemplate} ${PAD}px ${parent.children[1].style.flexGrow}fr`;
  69. parent.style.gridTemplateColumns = gridTemplateColumns;
  70. parent.style.originalGridTemplateColumns = gridTemplateColumns;
  71. const resizeHandle = document.createElement('div');
  72. resizeHandle.classList.add('resize-handle');
  73. parent.insertBefore(resizeHandle, rightCol);
  74. parent.resizeHandle = resizeHandle;
  75. ['mousedown', 'touchstart'].forEach((eventType) => {
  76. resizeHandle.addEventListener(eventType, (evt) => {
  77. if (eventType.startsWith('mouse')) {
  78. if (evt.button !== 0) return;
  79. } else {
  80. if (evt.changedTouches.length !== 1) return;
  81. const currentTime = new Date().getTime();
  82. if (R.lastTapTime && currentTime - R.lastTapTime <= DOUBLE_TAP_DELAY) {
  83. onDoubleClick(evt);
  84. return;
  85. }
  86. R.lastTapTime = currentTime;
  87. }
  88. evt.preventDefault();
  89. evt.stopPropagation();
  90. document.body.classList.add('resizing');
  91. R.tracking = true;
  92. R.parent = parent;
  93. R.parentWidth = parent.offsetWidth;
  94. R.leftCol = leftCol;
  95. R.leftColStartWidth = leftCol.offsetWidth;
  96. if (eventType.startsWith('mouse')) {
  97. R.screenX = evt.screenX;
  98. } else {
  99. R.screenX = evt.changedTouches[0].screenX;
  100. }
  101. });
  102. });
  103. resizeHandle.addEventListener('dblclick', onDoubleClick);
  104. afterResize(parent);
  105. }
  106. ['mousemove', 'touchmove'].forEach((eventType) => {
  107. window.addEventListener(eventType, (evt) => {
  108. if (eventType.startsWith('mouse')) {
  109. if (evt.button !== 0) return;
  110. } else {
  111. if (evt.changedTouches.length !== 1) return;
  112. }
  113. if (R.tracking) {
  114. if (eventType.startsWith('mouse')) {
  115. evt.preventDefault();
  116. }
  117. evt.stopPropagation();
  118. let delta = 0;
  119. if (eventType.startsWith('mouse')) {
  120. delta = R.screenX - evt.screenX;
  121. } else {
  122. delta = R.screenX - evt.changedTouches[0].screenX;
  123. }
  124. const leftColWidth = Math.max(Math.min(R.leftColStartWidth - delta, R.parent.offsetWidth - R.parent.minRightColWidth - PAD), R.parent.minLeftColWidth);
  125. setLeftColGridTemplate(R.parent, leftColWidth);
  126. }
  127. });
  128. });
  129. ['mouseup', 'touchend'].forEach((eventType) => {
  130. window.addEventListener(eventType, (evt) => {
  131. if (eventType.startsWith('mouse')) {
  132. if (evt.button !== 0) return;
  133. } else {
  134. if (evt.changedTouches.length !== 1) return;
  135. }
  136. if (R.tracking) {
  137. evt.preventDefault();
  138. evt.stopPropagation();
  139. R.tracking = false;
  140. document.body.classList.remove('resizing');
  141. }
  142. });
  143. });
  144. window.addEventListener('resize', () => {
  145. clearTimeout(resizeTimer);
  146. resizeTimer = setTimeout(function() {
  147. for (const parent of parents) {
  148. afterResize(parent);
  149. }
  150. }, DEBOUNCE_TIME);
  151. });
  152. setupResizeHandle = setup;
  153. })();
  154. function setupAllResizeHandles() {
  155. for (var elem of gradioApp().querySelectorAll('.resize-handle-row')) {
  156. if (!elem.querySelector('.resize-handle') && !elem.children[0].classList.contains("hidden")) {
  157. setupResizeHandle(elem);
  158. }
  159. }
  160. }
  161. onUiLoaded(setupAllResizeHandles);