Browse Source

[assist] Add knockout binding for resizing of an arbitrary amount of inner assist panels

Johan Ahlen 10 years ago
parent
commit
cec2c4a
1 changed files with 167 additions and 28 deletions
  1. 167 28
      desktop/core/src/desktop/static/desktop/js/ko.hue-bindings.js

+ 167 - 28
desktop/core/src/desktop/static/desktop/js/ko.hue-bindings.js

@@ -873,45 +873,184 @@
 
   ko.bindingHandlers.assistVerticalResizer = {
     init: function (element, valueAccessor) {
+      var $container = $(element);
       var options = ko.unwrap(valueAccessor());
+      var panelDefinitions = options.panels;
 
+      var timeout = -1;
+      var checkForElements = function () {
+        var $allPanels = $container.children('.assist-inner-panel');
+        if (panelDefinitions().length == $allPanels.length) {
+          ko.bindingHandlers.assistVerticalResizer.updateWhenRendered(element, valueAccessor);
+        } else {
+          timeout = window.setTimeout(checkForElements, 10);
+        }
+      };
+
+      checkForElements();
+      panelDefinitions.subscribe(function () {
+        timeout = window.setTimeout(checkForElements, 10);
+      })
+    },
+
+    updateWhenRendered: function (element, valueAccessor) {
+      var self = this;
+      var options = ko.unwrap(valueAccessor());
       var assistHelper = options.assistHelper;
+      var panelDefinitions = options.panels;
 
-      var $resizer = $(element);
-      var $above = $resizer.prev();
-      var $below = $resizer.next();
+      var $container = $(element);
+      var $allPanels = $container.children('.assist-inner-panel');
+      var $allResizers = $container.children(".assist-resizer");
+      var $allExtras = $container.children('.assist-fixed-height');
 
-      $resizer.parent().height();
+      var allExtrasHeight = 0;
+      $allExtras.each(function (idx, extra) {
+        allExtrasHeight += $(extra).outerHeight(true);
+      });
 
-      var aboveRatio = assistHelper.getFromTotalStorage('assist', 'twoPanelAboveRatio', 0.5);
+      var panelRatios = {};
+      if (panelDefinitions().length === 0) {
+        $allExtras.show();
+      }
+      if (panelDefinitions().length === 1) {
+        $allPanels.height($container.innerHeight() - allExtrasHeight);
+        $allExtras.show();
+        $allPanels.show();
+        return;
+      }
 
-      var aboveInitialHeight = ($resizer.parent().height() - $resizer.height()) * aboveRatio;
-      var belowInitialHeight = aboveInitialHeight;
 
-      $above.css("height", aboveInitialHeight + 'px');
-      $below.css("height", belowInitialHeight + 'px');
+      $allPanels.each(function (idx, panel) {
+        panelRatios[idx] = 1 / ($allPanels.length);
+        $(panel).data('minHeight', panels()[idx].minHeight);
+      });
 
-      $resizer.draggable({
-        axis: "y",
-        drag: function (event, ui) {
-          var currentHeight = ui.offset.top - 81;
-          aboveRatio = currentHeight / ($resizer.parent().height() - $resizer.height());
-          $above.css("height", currentHeight + 'px');
-          $below.css("height", ($resizer.parent().height() - currentHeight - $resizer.height() - 30));
-          ui.offset.top = 0;
-          ui.position.top = 0;
-        },
-        stop: function (event, ui) {
-          ui.offset.top = 0;
-          ui.position.top = 0;
-          assistHelper.setInTotalStorage('assist', 'twoPanelAboveRatio', aboveRatio);
+      var totalHeight = -1;
+      var containerTop = $container.offset().top;
+
+      // Resizes all containers according to the set ratios
+      var resizeByRatio = function () {
+        if (totalHeight == $container.innerHeight()) {
+          return;
         }
-      });
+        totalHeight = $container.innerHeight();
+        containerTop = $container.offset().top;
+
+        var availableForPanels = totalHeight - allExtrasHeight;
+        var leftoverSpace = 0;
+        $allPanels.each(function (idx, panel) {
+          var $panel = $(panel);
+          var desiredHeight = availableForPanels * panelRatios[idx];
+          var newHeight = Math.max($panel.data('minHeight'), desiredHeight);
+          $panel.height(newHeight);
+          leftoverSpace += newHeight - desiredHeight;
+        });
+        // The minheight is greater than the ratio so we shrink where possible
+        if (leftoverSpace > 0) {
+          $allPanels.each(function (idx, panel) {
+            if (leftoverSpace === 0) {
+              return false;
+            }
+            var $panel = $(panel);
+            var currentHeight = $panel.height();
+            var possibleContribution = Math.min(currentHeight - $panel.data('minHeight'), leftoverSpace);
+            if (possibleContribution > 0) {
+              $panel.height(currentHeight - possibleContribution);
+              leftoverSpace -= possibleContribution;
+            }
+          });
+        }
+      };
+
+      resizeByRatio();
+      $(window).resize(resizeByRatio);
+
+      $allExtras.show();
+      $allPanels.show();
+
+      var fitPanelHeights = function ($panelsToResize, desiredTotalHeight) {
+        var currentHeightForPanels = 0;
+
+        var noMoreSpace = true;
+        $panelsToResize.each(function (idx, panel) {
+          var $panel = $(panel);
+          var panelHeight = $panel.outerHeight(true);
+          noMoreSpace = noMoreSpace && panelHeight <= $panel.data('minHeight');
+          currentHeightForPanels += panelHeight;
+        });
+
+        var distanceToGo = desiredTotalHeight - currentHeightForPanels;
+        if (noMoreSpace && distanceToGo < 0) {
+          return;
+        }
+
+        // Add all to the first panel if expanding (distanceToGo is positive
+        if (distanceToGo >= 0) {
+          $panelsToResize.first().height($panelsToResize.first().height() + distanceToGo + 'px');
+          return;
+        }
+
+        // Remove as much as possible on each panel if shrinking (distanceToGo is negative)
+        $panelsToResize.each(function (idx, panel) {
+          var $panel = $(panel);
+          var initialHeight = $panel.height();
+          var newHeight = Math.max($panel.data('minHeight'), initialHeight + distanceToGo);
+          if (initialHeight == newHeight) {
+            return true;
+          }
+          $panel.height(newHeight);
+          distanceToGo += initialHeight - newHeight;
+          if (distanceToGo >= 0) {
+            return false;
+          }
+        });
+      };
+
+      $allResizers.each(function (idx, resizer) {
+        var $resizer = $(resizer);
+        var extrasBeforeHeight = 0;
+        $resizer.prevAll('.assist-fixed-height').each(function (idx, extra) {
+          extrasBeforeHeight += $(extra).outerHeight(true);
+        });
+        var $panelsBefore = $resizer.prevAll('.assist-inner-panel');
+        var limitBefore = extrasBeforeHeight;
+        $panelsBefore.each(function (idx, panel) {
+          limitBefore += $(panel).data('minHeight');
+        });
+
+        var extrasAfterHeight = allExtrasHeight - extrasBeforeHeight;
+        var $panelsAfter = $resizer.nextAll('.assist-inner-panel');
+        var limitAfter = totalHeight - extrasAfterHeight;
+        $panelsAfter.each(function (idx, panel) {
+          limitAfter -= $(panel).data('minHeight');
+        });
 
-      $(window).resize(function () {
-        var aboveHeight = ($resizer.parent().height() - $resizer.height()) * aboveRatio;
-        $above.css("height", aboveHeight + 'px');
-        $below.css("height", ($resizer.parent().height() - aboveHeight - $resizer.height() - 30));
+        $resizer.draggable({
+          axis: "y",
+          drag: function (event, ui) {
+            var position = ui.offset.top - containerTop;
+            if (position > limitBefore && position < limitAfter) {
+              fitPanelHeights($panelsBefore, position - extrasBeforeHeight);
+              fitPanelHeights($panelsAfter, totalHeight - extrasAfterHeight - position);
+            }
+
+            ui.offset.top = 0;
+            ui.position.top = 0;
+          },
+          stop: function (event, ui) {
+            ui.offset.top = 0;
+            ui.position.top = 0;
+            var totalHeightForPanels = 0;
+            $allPanels.each(function (idx, panel) {
+              totalHeightForPanels += $(panel).outerHeight(true);
+            });
+            panelRatios = {};
+            $allPanels.each(function (idx, panel) {
+              panelRatios[idx] = $(panel).outerHeight(true) / totalHeightForPanels;
+            });
+          }
+        });
       });
     }
   };