resizeHandle.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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. if (!leftColTemplate) {
  69. leftColTemplate = '1fr';
  70. }
  71. const gridTemplateColumns = `${leftColTemplate} ${PAD}px ${parent.children[1].style.flexGrow}fr`;
  72. parent.style.gridTemplateColumns = gridTemplateColumns;
  73. parent.style.originalGridTemplateColumns = gridTemplateColumns;
  74. const resizeHandle = document.createElement('div');
  75. resizeHandle.classList.add('resize-handle');
  76. parent.insertBefore(resizeHandle, rightCol);
  77. parent.resizeHandle = resizeHandle;
  78. ['mousedown', 'touchstart'].forEach((eventType) => {
  79. resizeHandle.addEventListener(eventType, (evt) => {
  80. if (eventType.startsWith('mouse')) {
  81. if (evt.button !== 0) return;
  82. } else {
  83. if (evt.changedTouches.length !== 1) return;
  84. const currentTime = new Date().getTime();
  85. if (R.lastTapTime && currentTime - R.lastTapTime <= DOUBLE_TAP_DELAY) {
  86. onDoubleClick(evt);
  87. return;
  88. }
  89. R.lastTapTime = currentTime;
  90. }
  91. evt.preventDefault();
  92. evt.stopPropagation();
  93. document.body.classList.add('resizing');
  94. R.tracking = true;
  95. R.parent = parent;
  96. R.parentWidth = parent.offsetWidth;
  97. R.leftCol = leftCol;
  98. R.leftColStartWidth = leftCol.offsetWidth;
  99. if (eventType.startsWith('mouse')) {
  100. R.screenX = evt.screenX;
  101. } else {
  102. R.screenX = evt.changedTouches[0].screenX;
  103. }
  104. }, {passive: false});
  105. });
  106. resizeHandle.addEventListener('dblclick', onDoubleClick);
  107. afterResize(parent);
  108. }
  109. ['mousemove', 'touchmove'].forEach((eventType) => {
  110. window.addEventListener(eventType, (evt) => {
  111. if (eventType.startsWith('mouse')) {
  112. if (evt.button !== 0) return;
  113. } else {
  114. if (evt.changedTouches.length !== 1) return;
  115. }
  116. if (R.tracking) {
  117. if (eventType.startsWith('mouse')) {
  118. evt.preventDefault();
  119. }
  120. evt.stopPropagation();
  121. let delta = 0;
  122. if (eventType.startsWith('mouse')) {
  123. delta = R.screenX - evt.screenX;
  124. } else {
  125. delta = R.screenX - evt.changedTouches[0].screenX;
  126. }
  127. const leftColWidth = Math.max(Math.min(R.leftColStartWidth - delta, R.parent.offsetWidth - R.parent.minRightColWidth - PAD), R.parent.minLeftColWidth);
  128. setLeftColGridTemplate(R.parent, leftColWidth);
  129. }
  130. });
  131. });
  132. ['mouseup', 'touchend'].forEach((eventType) => {
  133. window.addEventListener(eventType, (evt) => {
  134. if (eventType.startsWith('mouse')) {
  135. if (evt.button !== 0) return;
  136. } else {
  137. if (evt.changedTouches.length !== 1) return;
  138. }
  139. if (R.tracking) {
  140. evt.preventDefault();
  141. evt.stopPropagation();
  142. R.tracking = false;
  143. document.body.classList.remove('resizing');
  144. }
  145. });
  146. });
  147. window.addEventListener('resize', () => {
  148. clearTimeout(resizeTimer);
  149. resizeTimer = setTimeout(function() {
  150. for (const parent of parents) {
  151. afterResize(parent);
  152. }
  153. }, DEBOUNCE_TIME);
  154. });
  155. setupResizeHandle = setup;
  156. })();
  157. function setupAllResizeHandles() {
  158. for (var elem of gradioApp().querySelectorAll('.resize-handle-row')) {
  159. if (!elem.querySelector('.resize-handle') && !elem.children[0].classList.contains("hidden")) {
  160. setupResizeHandle(elem);
  161. }
  162. }
  163. }
  164. onUiLoaded(setupAllResizeHandles);