From 867aa3b3e9ff0fe09f431ce610a7fc9d2075a121 Mon Sep 17 00:00:00 2001 From: Hannes Widmoser Date: Thu, 3 Dec 2015 14:36:53 +0100 Subject: [PATCH 01/12] style: added consistent formatting and some explanatory comments --- src/ui-layout.js | 110 ++++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 53 deletions(-) diff --git a/src/ui-layout.js b/src/ui-layout.js index 0a2a5a9..cc0a995 100644 --- a/src/ui-layout.js +++ b/src/ui-layout.js @@ -4,8 +4,7 @@ * UI.Layout */ angular.module('ui.layout', []) - .controller('uiLayoutCtrl', ['$scope', '$attrs', '$element', '$timeout', '$window', 'LayoutContainer', 'Layout', - function uiLayoutCtrl($scope, $attrs, $element, $timeout, $window, LayoutContainer, Layout) { + .controller('uiLayoutCtrl', ['$scope', '$attrs', '$element', '$timeout', '$window', 'LayoutContainer', 'Layout', function uiLayoutCtrl($scope, $attrs, $element, $timeout, $window, LayoutContainer, Layout) { var ctrl = this; var opts = angular.extend({}, $scope.$eval($attrs.uiLayout), $scope.$eval($attrs.options)); @@ -24,32 +23,36 @@ angular.module('ui.layout', []) ctrl.bounds = $element[0].getBoundingClientRect(); ctrl.isUsingColumnFlow = opts.flow === 'column'; ctrl.sizeProperties = !ctrl.isUsingColumnFlow ? - { sizeProperty: 'height', + { + sizeProperty: 'height', offsetSize: 'offsetHeight', offsetPos: 'top', flowProperty: 'top', oppositeFlowProperty: 'bottom', mouseProperty: 'clientY', - flowPropertyPosition: 'y' } : - { sizeProperty: 'width', + flowPropertyPosition: 'y' + } : + { + sizeProperty: 'width', offsetSize: 'offsetWidth', offsetPos: 'left', flowProperty: 'left', oppositeFlowProperty: 'right', mouseProperty: 'clientX', - flowPropertyPosition: 'x' }; + flowPropertyPosition: 'x' + }; $element - // Force the layout to fill the parent space - // fix no height layout... + // Force the layout to fill the parent space + // fix no height layout... .addClass('stretch') // set the layout css class .addClass('ui-layout-' + (opts.flow || 'row')); - if (opts.disableToggle) { + if(opts.disableToggle) { $element.addClass('no-toggle'); } - if (opts.disableMobileToggle) { + if(opts.disableMobileToggle) { $element.addClass('no-mobile-toggle'); } @@ -66,8 +69,9 @@ angular.module('ui.layout', []) }; var debounceEvent; + function draw() { - var position = ctrl.sizeProperties.flowProperty; + var position = ctrl.sizeProperties.flowProperty; // left/top var dividerSize = parseInt(opts.dividerSize); var elementSize = $element[0][ctrl.sizeProperties.offsetSize]; @@ -83,10 +87,10 @@ angular.module('ui.layout', []) if(!beforeContainer.collapsed && !afterContainer.collapsed) { // calculate container positons var difference = ctrl.movingSplitbar[position] - lastPos; - var newPosition = ctrl.movingSplitbar[position] - difference; + var newPosition = ctrl.movingSplitbar[position] - difference; // TODO: this computation is unnecessary, newPosition === lastPos // Keep the bar in the window (no left/top 100%) - newPosition = Math.min(elementSize-dividerSize, newPosition); + newPosition = Math.min(elementSize - dividerSize, newPosition); // Keep the bar from going past the previous element min/max values if(angular.isNumber(beforeContainer.beforeMinValue) && newPosition < beforeContainer.beforeMinValue) @@ -174,7 +178,7 @@ angular.module('ui.layout', []) ctrl.mouseMoveHandler = function(mouseEvent) { var mousePos = mouseEvent[ctrl.sizeProperties.mouseProperty] || (mouseEvent.originalEvent && mouseEvent.originalEvent[ctrl.sizeProperties.mouseProperty]) || - // jQuery does touches weird, see #82 + // jQuery does touches weird, see #82 ($window.jQuery ? (mouseEvent.originalEvent ? mouseEvent.originalEvent.targetTouches[0][ctrl.sizeProperties.mouseProperty] : 0) : (mouseEvent.targetTouches ? mouseEvent.targetTouches[0][ctrl.sizeProperties.mouseProperty] : 0)); @@ -201,7 +205,7 @@ angular.module('ui.layout', []) var index = ctrl.containers.indexOf(container); var setValues = function(container) { - var start = container[ctrl.sizeProperties.flowProperty]; + var start = container[ctrl.sizeProperties.flowProperty]; // top or left var end = container[ctrl.sizeProperties.flowProperty] + container.size; container.beforeMinValue = angular.isNumber(container.minSize) ? start + container.minSize : start; @@ -213,8 +217,8 @@ angular.module('ui.layout', []) //verify the container was found in the list if(index > -1) { - var beforeContainer = (index > 0) ? ctrl.containers[index-1] : null; - var afterContainer = ((index+1) <= ctrl.containers.length) ? ctrl.containers[index+1] : null; + var beforeContainer = (index > 0) ? ctrl.containers[index - 1] : null; + var afterContainer = ((index + 1) <= ctrl.containers.length) ? ctrl.containers[index + 1] : null; if(beforeContainer !== null) setValues(beforeContainer); if(afterContainer !== null) setValues(afterContainer); @@ -248,12 +252,12 @@ angular.module('ui.layout', []) }; /** - * Sets the default size for each container. + * Sets the default size and position (left, top) for each container. */ ctrl.calculate = function() { var c, i; var dividerSize = parseInt(opts.dividerSize); - var elementSize = $element[0].getBoundingClientRect()[ctrl.sizeProperties.sizeProperty]; + var elementSize = $element[0].getBoundingClientRect()[ctrl.sizeProperties.sizeProperty]; // width/height var availableSize = elementSize - (dividerSize * numOfSplitbars); var originalSize = availableSize; var usedSpace = 0; @@ -261,7 +265,7 @@ angular.module('ui.layout', []) if(ctrl.containers.length > 0 && $element.children().length > 0) { // calculate sizing for ctrl.containers - for(i=0; i < ctrl.containers.length; i++) { + for(i = 0; i < ctrl.containers.length; i++) { if(!LayoutContainer.isSplitbar(ctrl.containers[i])) { c = ctrl.containers[i]; @@ -315,9 +319,9 @@ angular.module('ui.layout', []) */ var autoSize = Math.floor(availableSize / numOfAutoContainers), remainder = availableSize - autoSize * numOfAutoContainers; - for(i=0; i < ctrl.containers.length; i++) { + for(i = 0; i < ctrl.containers.length; i++) { c = ctrl.containers[i]; - c[ctrl.sizeProperties.flowProperty] = usedSpace; + c[ctrl.sizeProperties.flowProperty] = usedSpace; // left/top c.maxSize = opts.maxSizes[i]; c.minSize = opts.minSizes[i]; @@ -328,7 +332,7 @@ angular.module('ui.layout', []) if(opts.sizes[i] === 'auto') { newSize = autoSize; // add the rounding down remainder to the last auto-sized container in the layout - if (remainder > 0 && i === ctrl.containers.length - 1) { + if(remainder > 0 && i === ctrl.containers.length - 1) { newSize += remainder; } } else { @@ -379,10 +383,10 @@ angular.module('ui.layout', []) // We need to remove this container and the sidebar next to it if(index == ctrl.containers.length - 1) { // We're removing the last element, the side bar is on the left - ctrl.containers[index-1].element.remove(); + ctrl.containers[index - 1].element.remove(); } else { // The side bar is on the right - ctrl.containers[index+1].element.remove(); + ctrl.containers[index + 1].element.remove(); } } } else { @@ -415,14 +419,14 @@ angular.module('ui.layout', []) var splitter = ctrl.containers[index + 1], el; - if (splitter) { + if(splitter) { el = splitter.element[0].children[0]; } else { splitter = ctrl.containers[index - 1]; el = splitter.element[0].children[1]; } - $timeout(function(){ + $timeout(function() { angular.element(el).triggerHandler('click'); }); }; @@ -438,12 +442,12 @@ angular.module('ui.layout', []) var c = ctrl.containers[index]; c.collapsed = !ctrl.containers[index].collapsed; - var nextSplitbar = ctrl.containers[index+1]; - var nextContainer = ctrl.containers[index+2]; + var nextSplitbar = ctrl.containers[index + 1]; + var nextContainer = ctrl.containers[index + 2]; // uncollapsedSize is undefined in case of 'auto' sized containers. // Perhaps there's a place where we could set... could find it though. @see also toggleBefore - if (c.uncollapsedSize === undefined) { + if(c.uncollapsedSize === undefined) { c.uncollapsedSize = c.size; } else { c.uncollapsedSize = parseInt(c.uncollapsedSize); @@ -486,8 +490,8 @@ angular.module('ui.layout', []) ctrl.toggleAfter = function(splitbar) { var index = ctrl.containers.indexOf(splitbar) + 1; var c = ctrl.containers[index]; - var prevSplitbar = ctrl.containers[index-1]; - var prevContainer = ctrl.containers[index-2]; + var prevSplitbar = ctrl.containers[index - 1]; + var prevContainer = ctrl.containers[index - 2]; var isLastContainer = index === (ctrl.containers.length - 1); var endDiff; var flowProperty = ctrl.sizeProperties.flowProperty; @@ -499,7 +503,7 @@ angular.module('ui.layout', []) // uncollapsedSize is undefined in case of 'auto' sized containers. // Perhaps there's a place where we could set... could find it though. @see also toggleBefore - if (c.uncollapsedSize === undefined) { + if(c.uncollapsedSize === undefined) { c.uncollapsedSize = c.size; } else { c.uncollapsedSize = parseInt(c.uncollapsedSize); @@ -583,7 +587,7 @@ angular.module('ui.layout', []) ctrl.hasSplitbarBefore = function(container) { var index = ctrl.containers.indexOf(container); if(1 <= index) { - return LayoutContainer.isSplitbar(ctrl.containers[index-1]); + return LayoutContainer.isSplitbar(ctrl.containers[index - 1]); } return false; @@ -597,7 +601,7 @@ angular.module('ui.layout', []) ctrl.hasSplitbarAfter = function(container) { var index = ctrl.containers.indexOf(container); if(index < ctrl.containers.length - 1) { - return LayoutContainer.isSplitbar(ctrl.containers[index+1]); + return LayoutContainer.isSplitbar(ctrl.containers[index + 1]); } return false; @@ -643,7 +647,7 @@ angular.module('ui.layout', []) restrict: 'AE', controller: 'uiLayoutCtrl', link: function(scope, element, attrs, ctrl) { - scope.$watch(function () { + scope.$watch(function() { return element[0][ctrl.sizeProperties.offsetSize]; }, function() { ctrl.calculate(); @@ -890,7 +894,7 @@ angular.module('ui.layout', []) scope.container.layoutId = ctrl.id; scope.container.isCentral = attrs.uiLayoutContainer === 'central'; - if (scope.collapsed === true) { + if(scope.collapsed === true) { scope.collapsed = false; Layout.addCollapsed(scope.container); } @@ -899,7 +903,7 @@ angular.module('ui.layout', []) // scope.container.collapsed = scope.collapsed; //} - if (angular.isDefined(scope.resizable)) { + if(angular.isDefined(scope.resizable)) { scope.container.resizable = scope.resizable; } scope.container.size = scope.size; @@ -920,8 +924,8 @@ angular.module('ui.layout', []) var animationClass = ctrl.isUsingColumnFlow ? 'animate-column' : 'animate-row'; element.addClass(animationClass); - scope.$watch('collapsed', function (val, old) { - if (angular.isDefined(old) && val !== old) { + scope.$watch('collapsed', function(val, old) { + if(angular.isDefined(old) && val !== old) { ctrl.toggleContainer(scope.container.index); } }); @@ -948,7 +952,7 @@ angular.module('ui.layout', []) '' + ''); if(0 < index && !ctrl.hasSplitbarBefore(scope.container)) { - angular.element(children[index-1]).after(splitbar); + angular.element(children[index - 1]).after(splitbar); $compile(splitbar)(scope); } else if(index < children.length - 1) { element.after(splitbar); @@ -974,17 +978,17 @@ angular.module('ui.layout', []) require: '^uiLayout', restrict: 'A', priority: -100, - link: function($scope, el, attrs){ + link: function($scope, el, attrs) { // negation is safe here, because we are expecting non-empty string - if (!attrs['uiLayoutLoaded']) { + if(!attrs['uiLayoutLoaded']) { Layout.toggle().then( - function(){ + function() { $scope.$broadcast('ui.layout.loaded', null); } ); } else { - $scope.$broadcast('ui.layout.loaded', attrs['uiLayoutLoaded']); + $scope.$broadcast('ui.layout.loaded', attrs['uiLayoutLoaded']); } } }; @@ -994,7 +998,7 @@ angular.module('ui.layout', []) var layouts = [], collapsing = [], toBeCollapsed = 0, - toggledDeffered = null; + toggledDeffered = null; function toggleContainer(container) { try { @@ -1006,7 +1010,7 @@ angular.module('ui.layout', []) } return { - addLayout: function (ctrl) { + addLayout: function(ctrl) { ctrl.id = layouts.length; layouts.push(ctrl); }, @@ -1018,29 +1022,29 @@ angular.module('ui.layout', []) }, toggled: function() { // event already dispatched, do nothing - if (toBeCollapsed === 0) { - if (toggledDeffered) { + if(toBeCollapsed === 0) { + if(toggledDeffered) { toggledDeffered.reject(); } else { return false; } } toBeCollapsed--; - if (toBeCollapsed === 0) { + if(toBeCollapsed === 0) { toggledDeffered.resolve(); } }, toggle: function() { toggledDeffered = $q.defer(); toBeCollapsed = collapsing.length; - if (toBeCollapsed === 0) { - $timeout(function(){ + if(toBeCollapsed === 0) { + $timeout(function() { toggledDeffered.resolve(); }); } collapsing.reverse(); var c; - while(c = collapsing.pop()) { + while (c = collapsing.pop()) { toggleContainer(c); } return toggledDeffered.promise; From 06c32bb8710653fbf7023a2b42d2e03a4478908d Mon Sep 17 00:00:00 2001 From: Hannes Widmoser Date: Thu, 3 Dec 2015 14:40:06 +0100 Subject: [PATCH 02/12] feat(persistentState): persisting container sizes in local storage --- src/ui-layout.js | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/ui-layout.js b/src/ui-layout.js index cc0a995..1d593b7 100644 --- a/src/ui-layout.js +++ b/src/ui-layout.js @@ -124,6 +124,12 @@ angular.module('ui.layout', []) afterContainer.uncollapsedSize = afterContainer.size; } + // store the current value in local storage to preserve size also when reloading the window + if($window.localStorage !== undefined) { + $window.localStorage.setItem(beforeContainer.storageId, beforeContainer.uncollapsedSize + 'px'); + $window.localStorage.setItem(afterContainer.storageId, afterContainer.uncollapsedSize + 'px'); + } + // move the splitbar ctrl.movingSplitbar[position] = newPosition; @@ -871,8 +877,8 @@ angular.module('ui.layout', []) }]) .directive('uiLayoutContainer', - ['LayoutContainer', '$compile', '$timeout', 'Layout', - function(LayoutContainer, $compile, $timeout, Layout) { + ['LayoutContainer', '$compile', '$timeout', '$window', 'Layout', + function(LayoutContainer, $compile, $timeout, $window, Layout) { return { restrict: 'AE', require: '^uiLayout', @@ -892,6 +898,7 @@ angular.module('ui.layout', []) scope.container.element = element; scope.container.id = element.attr('id') || null; scope.container.layoutId = ctrl.id; + scope.container.storageId = ctrl.id + ':' + Array.prototype.indexOf.call(element.parent()[0].children, element[0]); scope.container.isCentral = attrs.uiLayoutContainer === 'central'; if(scope.collapsed === true) { @@ -907,7 +914,16 @@ angular.module('ui.layout', []) scope.container.resizable = scope.resizable; } scope.container.size = scope.size; - scope.container.uncollapsedSize = scope.size; + + // load uncollapsedSize from local storage if available: + scope.container.uncollapsedSize = null; + if($window.localStorage !== undefined) { + scope.container.uncollapsedSize = $window.localStorage.getItem(scope.container.storageId); + } + if(scope.container.uncollapsedSize === null) { + scope.container.uncollapsedSize = scope.size; + } + scope.container.minSize = scope.minSize; scope.container.maxSize = scope.maxSize; ctrl.addContainer(scope.container); From deaad261dc5bb081e4aec1924531a9e26b5dff8c Mon Sep 17 00:00:00 2001 From: Hannes Widmoser Date: Thu, 3 Dec 2015 14:57:56 +0100 Subject: [PATCH 03/12] test: added a .bowerrc file to explicitly define the location of bower_components This helps in case the repository is cloned inside a larger project that has a different bower setup (e.g. for angular when the bower_components is inside the app folder) --- .bowerrc | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .bowerrc diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 0000000..baa91a3 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "bower_components" +} \ No newline at end of file From 861ca93272e16edde2f8a2d469214cdeec2fb52a Mon Sep 17 00:00:00 2001 From: Hannes Widmoser Date: Thu, 3 Dec 2015 15:06:21 +0100 Subject: [PATCH 04/12] test(persistentState): fixed existing tests by clearing local storage at the beginning --- test/layout-scenar.spec.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/layout-scenar.spec.js b/test/layout-scenar.spec.js index a545d67..97491fd 100644 --- a/test/layout-scenar.spec.js +++ b/test/layout-scenar.spec.js @@ -8,7 +8,7 @@ splitMoveTests('mouse', 'mousedown', 'mousemove', 'mouseup'); // Wrapper to abstract over using touch events or mouse events. function splitMoveTests(description, startEvent, moveEvent, endEvent) { return describe('Directive: uiLayout with ' + description + ' events', function () { - var element, scope, compile, $timeout, + var element, scope, compile, $timeout, $window, validTemplate = '
', defaultDividerSize = 10; @@ -29,13 +29,19 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { module('ui.layout'); - inject(function ($rootScope, $compile, _$timeout_) { + inject(function ($rootScope, $compile, _$timeout_, _$window_) { scope = $rootScope.$new(); compile = $compile; $timeout = _$timeout_; + $window = _$window_; }); }); + beforeEach(function() { + // clear local storage: + $window.localStorage.clear(); + }); + afterEach(function () { if (element) element.remove(); }); From b1beee2b0cd33f30790943bcbe6cbeb4e1be79b8 Mon Sep 17 00:00:00 2001 From: Hannes Widmoser Date: Thu, 3 Dec 2015 15:31:11 +0100 Subject: [PATCH 05/12] test(persistentState): extended existing tests to check if new positions are stored in local storage --- test/layout-scenar.spec.js | 14 +++++++++----- test/uiLayoutContainer.spec.js | 3 +++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/test/layout-scenar.spec.js b/test/layout-scenar.spec.js index 97491fd..104483c 100644 --- a/test/layout-scenar.spec.js +++ b/test/layout-scenar.spec.js @@ -68,12 +68,13 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { describe('the slider', function () { - var element_bb, $splitbar, splitbar_bb, splitbarLeftPos; + var element_bb, leftContainer, $splitbar, splitbar_bb, splitbarLeftPos; beforeEach(function () { element = createDirective(); element_bb = element[0].getBoundingClientRect(); + leftContainer = angular.element(_jQuery(element[0]).find('header')[0]).isolateScope(); $splitbar = _jQuery(element[0]).find('.ui-splitbar'); splitbar_bb = $splitbar[0].getBoundingClientRect(); @@ -89,7 +90,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { expect(window.requestAnimationFrame).not.toHaveBeenCalled(); expect(Math.ceil(splitbar_bb.left)).toEqual(splitbarLeftPos); - + expect($window.localStorage.getItem(leftContainer.container.storageId)).toBeNull(); }); it('should do nothing when moving around it', function () { @@ -101,7 +102,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { expect(window.requestAnimationFrame).not.toHaveBeenCalled(); expect(Math.ceil(splitbar_bb.left)).toEqual(splitbarLeftPos); - + expect($window.localStorage.getItem(leftContainer.container.storageId)).toBeNull(); }); it('should follow the ' + description, function () { @@ -109,8 +110,9 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { browserTrigger($splitbar, moveEvent, { y: element_bb.height / 4}); expect(window.requestAnimationFrame).toHaveBeenCalled(); - var expextedPos = Math.floor(element_bb.height / 4); - expect(Math.ceil(parseFloat($splitbar[0].style.top))).toEqual(expextedPos); + var expectedPos = Math.floor(element_bb.height / 4); + expect(Math.ceil(parseFloat($splitbar[0].style.top))).toEqual(expectedPos); + expect($window.localStorage.getItem(leftContainer.container.storageId)).toEqual(expectedPos + 'px'); browserTrigger(document.body, endEvent); }); @@ -125,6 +127,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { expect(window.requestAnimationFrame).not.toHaveBeenCalled(); expect(Math.ceil(parseFloat($splitbar[0].style.top))).toEqual(expectedPos); + expect($window.localStorage.getItem(leftContainer.container.storageId)).toBeNull(); }); it('should not follow the ' + description + ' after ' + startEvent, function () { @@ -140,6 +143,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { var expectedPos = Math.floor(element_bb.height / 4); expect(window.requestAnimationFrame.calls.count()).toEqual(1); expect(Math.ceil(parseFloat($splitbar[0].style.top))).toEqual(expectedPos); + expect($window.localStorage.getItem(leftContainer.container.storageId)).toEqual(expectedPos + 'px'); }); describe('collapse buttons', function() { diff --git a/test/uiLayoutContainer.spec.js b/test/uiLayoutContainer.spec.js index ade2406..5953bd0 100644 --- a/test/uiLayoutContainer.spec.js +++ b/test/uiLayoutContainer.spec.js @@ -59,6 +59,9 @@ describe('Directive: uiLayoutContainer', function () { expect(acScope.container.minSize).toBeNull(); expect(acScope.container.maxSize).toBeNull(); + // every container has a storageId: + expect(acScope.container.storageId).not.toBeNull(); + }); }); \ No newline at end of file From 7d74e0f1ccccc84388af0e853f7fa78425ea837b Mon Sep 17 00:00:00 2001 From: Hannes Widmoser Date: Thu, 3 Dec 2015 17:55:24 +0100 Subject: [PATCH 06/12] test(persistentState): added a test to check if state is persisted --- test/layout-scenar.spec.js | 92 +++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 25 deletions(-) diff --git a/test/layout-scenar.spec.js b/test/layout-scenar.spec.js index 104483c..15adced 100644 --- a/test/layout-scenar.spec.js +++ b/test/layout-scenar.spec.js @@ -7,7 +7,7 @@ splitMoveTests('mouse', 'mousedown', 'mousemove', 'mouseup'); // Wrapper to abstract over using touch events or mouse events. function splitMoveTests(description, startEvent, moveEvent, endEvent) { - return describe('Directive: uiLayout with ' + description + ' events', function () { + return describe('Directive: uiLayout with ' + description + ' events', function() { var element, scope, compile, $timeout, $window, validTemplate = '
', defaultDividerSize = 10; @@ -25,11 +25,11 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { return elm; } - beforeEach(function () { + beforeEach(function() { module('ui.layout'); - inject(function ($rootScope, $compile, _$timeout_, _$window_) { + inject(function($rootScope, $compile, _$timeout_, _$window_) { scope = $rootScope.$new(); compile = $compile; $timeout = _$timeout_; @@ -39,38 +39,40 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { beforeEach(function() { // clear local storage: - $window.localStorage.clear(); + if($window.localStorage !== undefined) { + $window.localStorage.clear(); + } }); - afterEach(function () { - if (element) element.remove(); + afterEach(function() { + if(element) element.remove(); }); - describe('require', function () { - it('requestAnimationFrame', function () { + describe('require', function() { + it('requestAnimationFrame', function() { expect(window.requestAnimationFrame).toBeDefined(); }); - it('cancelAnimationFrame', function () { + it('cancelAnimationFrame', function() { expect(window.cancelAnimationFrame).toBeDefined(); }); }); // Spy on the requestAnimationFrame to directly trigger it - beforeEach(function () { - spyOn(window, 'requestAnimationFrame').and.callFake(function (fct) { + beforeEach(function() { + spyOn(window, 'requestAnimationFrame').and.callFake(function(fct) { fct(); }); }); - afterEach(function () { - if (element) element.remove(); + afterEach(function() { + if(element) element.remove(); }); - describe('the slider', function () { + describe('the slider', function() { var element_bb, leftContainer, $splitbar, splitbar_bb, splitbarLeftPos; - beforeEach(function () { + beforeEach(function() { element = createDirective(); element_bb = element[0].getBoundingClientRect(); @@ -81,7 +83,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { splitbarLeftPos = Math.ceil(splitbar_bb.left); }); - it('should do nothing when clicking on it', function () { + it('should do nothing when clicking on it', function() { // Click on the splitbar left browserTrigger($splitbar, startEvent, { x: splitbarLeftPos }); @@ -93,7 +95,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { expect($window.localStorage.getItem(leftContainer.container.storageId)).toBeNull(); }); - it('should do nothing when moving around it', function () { + it('should do nothing when moving around it', function() { // Click on the splitbar left browserTrigger($splitbar, moveEvent, { x: splitbarLeftPos }); @@ -105,9 +107,9 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { expect($window.localStorage.getItem(leftContainer.container.storageId)).toBeNull(); }); - it('should follow the ' + description, function () { + it('should follow the ' + description, function() { browserTrigger($splitbar, startEvent, { y: splitbarLeftPos }); - browserTrigger($splitbar, moveEvent, { y: element_bb.height / 4}); + browserTrigger($splitbar, moveEvent, { y: element_bb.height / 4 }); expect(window.requestAnimationFrame).toHaveBeenCalled(); var expectedPos = Math.floor(element_bb.height / 4); @@ -117,7 +119,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { browserTrigger(document.body, endEvent); }); - it('should not follow the ' + description + ' before ' + startEvent, function () { + it('should not follow the ' + description + ' before ' + startEvent, function() { var expectedPos = Math.floor((element_bb.height - defaultDividerSize) / 2); expect(Math.ceil(parseFloat($splitbar[0].style.top))).toEqual(expectedPos); @@ -130,9 +132,9 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { expect($window.localStorage.getItem(leftContainer.container.storageId)).toBeNull(); }); - it('should not follow the ' + description + ' after ' + startEvent, function () { + it('should not follow the ' + description + ' after ' + startEvent, function() { browserTrigger($splitbar, startEvent, { y: splitbarLeftPos }); - browserTrigger($splitbar, moveEvent, { y: element_bb.height / 4}); + browserTrigger($splitbar, moveEvent, { y: element_bb.height / 4 }); browserTrigger($splitbar, endEvent); expect(window.requestAnimationFrame).toHaveBeenCalled(); @@ -146,6 +148,45 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { expect($window.localStorage.getItem(leftContainer.container.storageId)).toEqual(expectedPos + 'px'); }); + describe('persistent state', function() { + + var leftContainerElement, rightContainerElement, $splitbar, splitbar_bb, splitbarLeftPos; + + beforeEach(function() { + leftContainerElement = _jQuery(element[0]).find('header')[0]; + rightContainerElement = _jQuery(element[0]).find('footer')[0]; + $splitbar = _jQuery(element[0]).find('.ui-splitbar'); + splitbar_bb = $splitbar[0].getBoundingClientRect(); + + splitbarLeftPos = Math.ceil(splitbar_bb.left); + }); + + it('should initially respect size from attributes', function() { + expect(leftContainerElement.style.width).toEqual(''); + expect(rightContainerElement.style.width).toEqual(''); + }); + + it('should save the saved splitbar position', function() { + browserTrigger($splitbar, 'mousedown', { y: splitbarLeftPos }); + browserTrigger($splitbar, 'mousemove', { y: 150 }); + expect(window.requestAnimationFrame).toHaveBeenCalled(); + + var expectedPos = Math.floor(150); + expect(Math.ceil(parseFloat($splitbar[0].style.top))).toEqual(expectedPos); + expect($window.localStorage.getItem(leftContainer.container.storageId)).toEqual(expectedPos + 'px'); + + browserTrigger(document.body, 'mouseup'); + + if(element) element.remove(); + element = createDirective(); + + splitbar_bb = $splitbar[0].getBoundingClientRect(); + splitbarLeftPos = Math.ceil(splitbar_bb.left); + expect(Math.ceil(parseFloat($splitbar[0].style.top))).toEqual(expectedPos); + }); + + }); + describe('collapse buttons', function() { var toggleBeforeButton, toggleAfterButton; @@ -187,7 +228,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { expectedLastAutosized = roundedHalf; // add remainder to the last element when parent size is odd - if (element_bb.height % 2 === 1) { + if(element_bb.height % 2 === 1) { expectedLastAutosized += 1; } var $footer = element.children().eq(2)[0]; @@ -205,6 +246,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { expect(toggleBeforeButton.style.display).toBe('inline'); }); }); + }); }); @@ -212,11 +254,11 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { describe('toggle programmatically', function() { var scope, $controller, $compile, $timeout; - beforeEach(function () { + beforeEach(function() { module('ui.layout'); - inject(function ($rootScope, _$controller_, _$compile_, _$timeout_) { + inject(function($rootScope, _$controller_, _$compile_, _$timeout_) { scope = $rootScope.$new(); $controller = _$controller_; $compile = _$compile_; From 0880294f5049cf660a3db42eaabab1afb82fafa7 Mon Sep 17 00:00:00 2001 From: Hannes Widmoser Date: Fri, 4 Dec 2015 13:56:53 +0100 Subject: [PATCH 07/12] feat(persistentState): improved storage id robustness This is achieved by adding an optional attribute layout-id in the markup to uniquely identify a ui-layout. The children are identified by their indices which are now correctly updated whenever they change. --- src/ui-layout.js | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/ui-layout.js b/src/ui-layout.js index 1d593b7..955a208 100644 --- a/src/ui-layout.js +++ b/src/ui-layout.js @@ -17,6 +17,9 @@ angular.module('ui.layout', []) var sizePattern = /\d+\s*(px|%)\s*$/i; Layout.addLayout(ctrl); + if ($attrs.layoutId) { + ctrl.id = $attrs.layoutId; + } ctrl.containers = []; ctrl.movingSplitbar = null; @@ -171,6 +174,27 @@ angular.module('ui.layout', []) } } + function loadContainerState(container) { + // load uncollapsedSize from local storage if available: + container.uncollapsedSize = null; + if($window.localStorage !== undefined) { + container.uncollapsedSize = $window.localStorage.getItem(container.storageId); + } + if(container.uncollapsedSize === null) { + container.uncollapsedSize = container.size; + } + } + + /** + * Updates the storage ids of all containers according to the id of this controller and the index of the container. + */ + function updateContainerStorageIds() { + for (var i = 0; i < ctrl.containers.length; ++i) { + var c = ctrl.containers[i]; + c.storageId = ctrl.id + ':' + i; + } + }; + //================================================================================ // Public Controller Functions //================================================================================ @@ -373,6 +397,9 @@ angular.module('ui.layout', []) container.index = index; ctrl.containers.splice(index, 0, container); + updateContainerStorageIds(); + loadContainerState(container); + ctrl.calculate(); }; @@ -406,6 +433,7 @@ angular.module('ui.layout', []) if(newIndex >= 0) { ctrl.containers.splice(newIndex, 1); } + updateContainerStorageIds(); ctrl.calculate(); } else { console.error("removeContainer for container that did not exist!"); @@ -898,7 +926,6 @@ angular.module('ui.layout', []) scope.container.element = element; scope.container.id = element.attr('id') || null; scope.container.layoutId = ctrl.id; - scope.container.storageId = ctrl.id + ':' + Array.prototype.indexOf.call(element.parent()[0].children, element[0]); scope.container.isCentral = attrs.uiLayoutContainer === 'central'; if(scope.collapsed === true) { @@ -915,17 +942,9 @@ angular.module('ui.layout', []) } scope.container.size = scope.size; - // load uncollapsedSize from local storage if available: - scope.container.uncollapsedSize = null; - if($window.localStorage !== undefined) { - scope.container.uncollapsedSize = $window.localStorage.getItem(scope.container.storageId); - } - if(scope.container.uncollapsedSize === null) { - scope.container.uncollapsedSize = scope.size; - } - scope.container.minSize = scope.minSize; scope.container.maxSize = scope.maxSize; + ctrl.addContainer(scope.container); element.on('$destroy', function() { From 220cbb76b145bdc5407ab1f8d14e48e9c194e594 Mon Sep 17 00:00:00 2001 From: Hannes Widmoser Date: Fri, 4 Dec 2015 14:21:53 +0100 Subject: [PATCH 08/12] style(persistentState): fixed jshint problems --- src/ui-layout.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ui-layout.js b/src/ui-layout.js index 955a208..90c6401 100644 --- a/src/ui-layout.js +++ b/src/ui-layout.js @@ -4,7 +4,8 @@ * UI.Layout */ angular.module('ui.layout', []) - .controller('uiLayoutCtrl', ['$scope', '$attrs', '$element', '$timeout', '$window', 'LayoutContainer', 'Layout', function uiLayoutCtrl($scope, $attrs, $element, $timeout, $window, LayoutContainer, Layout) { + .controller('uiLayoutCtrl', ['$scope', '$attrs', '$element', '$timeout', '$window', 'LayoutContainer', 'Layout', + function uiLayoutCtrl($scope, $attrs, $element, $timeout, $window, LayoutContainer, Layout) { var ctrl = this; var opts = angular.extend({}, $scope.$eval($attrs.uiLayout), $scope.$eval($attrs.options)); @@ -193,7 +194,7 @@ angular.module('ui.layout', []) var c = ctrl.containers[i]; c.storageId = ctrl.id + ':' + i; } - }; + } //================================================================================ // Public Controller Functions From 2e0b7dbe9ab548728d951227d4c22e3284177bc0 Mon Sep 17 00:00:00 2001 From: Hannes Widmoser Date: Wed, 9 Dec 2015 10:48:13 +0100 Subject: [PATCH 09/12] style: reset formatting changes to clean up diff --- src/ui-layout.js | 103 +++++++++++++++++-------------------- test/layout-scenar.spec.js | 37 +++++++------ 2 files changed, 66 insertions(+), 74 deletions(-) diff --git a/src/ui-layout.js b/src/ui-layout.js index 90c6401..c3bbe64 100644 --- a/src/ui-layout.js +++ b/src/ui-layout.js @@ -5,7 +5,7 @@ */ angular.module('ui.layout', []) .controller('uiLayoutCtrl', ['$scope', '$attrs', '$element', '$timeout', '$window', 'LayoutContainer', 'Layout', - function uiLayoutCtrl($scope, $attrs, $element, $timeout, $window, LayoutContainer, Layout) { + function uiLayoutCtrl($scope, $attrs, $element, $timeout, $window, LayoutContainer, Layout) { var ctrl = this; var opts = angular.extend({}, $scope.$eval($attrs.uiLayout), $scope.$eval($attrs.options)); @@ -27,36 +27,32 @@ angular.module('ui.layout', []) ctrl.bounds = $element[0].getBoundingClientRect(); ctrl.isUsingColumnFlow = opts.flow === 'column'; ctrl.sizeProperties = !ctrl.isUsingColumnFlow ? - { - sizeProperty: 'height', + { sizeProperty: 'height', offsetSize: 'offsetHeight', offsetPos: 'top', flowProperty: 'top', oppositeFlowProperty: 'bottom', mouseProperty: 'clientY', - flowPropertyPosition: 'y' - } : - { - sizeProperty: 'width', + flowPropertyPosition: 'y' } : + { sizeProperty: 'width', offsetSize: 'offsetWidth', offsetPos: 'left', flowProperty: 'left', oppositeFlowProperty: 'right', mouseProperty: 'clientX', - flowPropertyPosition: 'x' - }; + flowPropertyPosition: 'x' }; $element - // Force the layout to fill the parent space - // fix no height layout... + // Force the layout to fill the parent space + // fix no height layout... .addClass('stretch') // set the layout css class .addClass('ui-layout-' + (opts.flow || 'row')); - if(opts.disableToggle) { + if (opts.disableToggle) { $element.addClass('no-toggle'); } - if(opts.disableMobileToggle) { + if (opts.disableMobileToggle) { $element.addClass('no-mobile-toggle'); } @@ -73,9 +69,8 @@ angular.module('ui.layout', []) }; var debounceEvent; - function draw() { - var position = ctrl.sizeProperties.flowProperty; // left/top + var position = ctrl.sizeProperties.flowProperty; var dividerSize = parseInt(opts.dividerSize); var elementSize = $element[0][ctrl.sizeProperties.offsetSize]; @@ -94,7 +89,7 @@ angular.module('ui.layout', []) var newPosition = ctrl.movingSplitbar[position] - difference; // TODO: this computation is unnecessary, newPosition === lastPos // Keep the bar in the window (no left/top 100%) - newPosition = Math.min(elementSize - dividerSize, newPosition); + newPosition = Math.min(elementSize-dividerSize, newPosition); // Keep the bar from going past the previous element min/max values if(angular.isNumber(beforeContainer.beforeMinValue) && newPosition < beforeContainer.beforeMinValue) @@ -209,7 +204,7 @@ angular.module('ui.layout', []) ctrl.mouseMoveHandler = function(mouseEvent) { var mousePos = mouseEvent[ctrl.sizeProperties.mouseProperty] || (mouseEvent.originalEvent && mouseEvent.originalEvent[ctrl.sizeProperties.mouseProperty]) || - // jQuery does touches weird, see #82 + // jQuery does touches weird, see #82 ($window.jQuery ? (mouseEvent.originalEvent ? mouseEvent.originalEvent.targetTouches[0][ctrl.sizeProperties.mouseProperty] : 0) : (mouseEvent.targetTouches ? mouseEvent.targetTouches[0][ctrl.sizeProperties.mouseProperty] : 0)); @@ -236,7 +231,7 @@ angular.module('ui.layout', []) var index = ctrl.containers.indexOf(container); var setValues = function(container) { - var start = container[ctrl.sizeProperties.flowProperty]; // top or left + var start = container[ctrl.sizeProperties.flowProperty]; var end = container[ctrl.sizeProperties.flowProperty] + container.size; container.beforeMinValue = angular.isNumber(container.minSize) ? start + container.minSize : start; @@ -249,7 +244,7 @@ angular.module('ui.layout', []) //verify the container was found in the list if(index > -1) { var beforeContainer = (index > 0) ? ctrl.containers[index - 1] : null; - var afterContainer = ((index + 1) <= ctrl.containers.length) ? ctrl.containers[index + 1] : null; + var afterContainer = ((index+1) <= ctrl.containers.length) ? ctrl.containers[index + 1] : null; if(beforeContainer !== null) setValues(beforeContainer); if(afterContainer !== null) setValues(afterContainer); @@ -296,7 +291,7 @@ angular.module('ui.layout', []) if(ctrl.containers.length > 0 && $element.children().length > 0) { // calculate sizing for ctrl.containers - for(i = 0; i < ctrl.containers.length; i++) { + for(i=0; i < ctrl.containers.length; i++) { if(!LayoutContainer.isSplitbar(ctrl.containers[i])) { c = ctrl.containers[i]; @@ -350,7 +345,7 @@ angular.module('ui.layout', []) */ var autoSize = Math.floor(availableSize / numOfAutoContainers), remainder = availableSize - autoSize * numOfAutoContainers; - for(i = 0; i < ctrl.containers.length; i++) { + for(i=0; i < ctrl.containers.length; i++) { c = ctrl.containers[i]; c[ctrl.sizeProperties.flowProperty] = usedSpace; // left/top c.maxSize = opts.maxSizes[i]; @@ -363,7 +358,7 @@ angular.module('ui.layout', []) if(opts.sizes[i] === 'auto') { newSize = autoSize; // add the rounding down remainder to the last auto-sized container in the layout - if(remainder > 0 && i === ctrl.containers.length - 1) { + if (remainder > 0 && i === ctrl.containers.length - 1) { newSize += remainder; } } else { @@ -417,10 +412,10 @@ angular.module('ui.layout', []) // We need to remove this container and the sidebar next to it if(index == ctrl.containers.length - 1) { // We're removing the last element, the side bar is on the left - ctrl.containers[index - 1].element.remove(); + ctrl.containers[index-1].element.remove(); } else { // The side bar is on the right - ctrl.containers[index + 1].element.remove(); + ctrl.containers[index+1].element.remove(); } } } else { @@ -454,14 +449,14 @@ angular.module('ui.layout', []) var splitter = ctrl.containers[index + 1], el; - if(splitter) { + if (splitter) { el = splitter.element[0].children[0]; } else { splitter = ctrl.containers[index - 1]; el = splitter.element[0].children[1]; } - $timeout(function() { + $timeout(function(){ angular.element(el).triggerHandler('click'); }); }; @@ -477,12 +472,12 @@ angular.module('ui.layout', []) var c = ctrl.containers[index]; c.collapsed = !ctrl.containers[index].collapsed; - var nextSplitbar = ctrl.containers[index + 1]; - var nextContainer = ctrl.containers[index + 2]; + var nextSplitbar = ctrl.containers[index+1]; + var nextContainer = ctrl.containers[index+2]; // uncollapsedSize is undefined in case of 'auto' sized containers. // Perhaps there's a place where we could set... could find it though. @see also toggleBefore - if(c.uncollapsedSize === undefined) { + if (c.uncollapsedSize === undefined) { c.uncollapsedSize = c.size; } else { c.uncollapsedSize = parseInt(c.uncollapsedSize); @@ -525,8 +520,8 @@ angular.module('ui.layout', []) ctrl.toggleAfter = function(splitbar) { var index = ctrl.containers.indexOf(splitbar) + 1; var c = ctrl.containers[index]; - var prevSplitbar = ctrl.containers[index - 1]; - var prevContainer = ctrl.containers[index - 2]; + var prevSplitbar = ctrl.containers[index-1]; + var prevContainer = ctrl.containers[index-2]; var isLastContainer = index === (ctrl.containers.length - 1); var endDiff; var flowProperty = ctrl.sizeProperties.flowProperty; @@ -538,7 +533,7 @@ angular.module('ui.layout', []) // uncollapsedSize is undefined in case of 'auto' sized containers. // Perhaps there's a place where we could set... could find it though. @see also toggleBefore - if(c.uncollapsedSize === undefined) { + if (c.uncollapsedSize === undefined) { c.uncollapsedSize = c.size; } else { c.uncollapsedSize = parseInt(c.uncollapsedSize); @@ -622,7 +617,7 @@ angular.module('ui.layout', []) ctrl.hasSplitbarBefore = function(container) { var index = ctrl.containers.indexOf(container); if(1 <= index) { - return LayoutContainer.isSplitbar(ctrl.containers[index - 1]); + return LayoutContainer.isSplitbar(ctrl.containers[index-1]); } return false; @@ -636,7 +631,7 @@ angular.module('ui.layout', []) ctrl.hasSplitbarAfter = function(container) { var index = ctrl.containers.indexOf(container); if(index < ctrl.containers.length - 1) { - return LayoutContainer.isSplitbar(ctrl.containers[index + 1]); + return LayoutContainer.isSplitbar(ctrl.containers[index+1]); } return false; @@ -682,7 +677,7 @@ angular.module('ui.layout', []) restrict: 'AE', controller: 'uiLayoutCtrl', link: function(scope, element, attrs, ctrl) { - scope.$watch(function() { + scope.$watch(function () { return element[0][ctrl.sizeProperties.offsetSize]; }, function() { ctrl.calculate(); @@ -906,8 +901,8 @@ angular.module('ui.layout', []) }]) .directive('uiLayoutContainer', - ['LayoutContainer', '$compile', '$timeout', '$window', 'Layout', - function(LayoutContainer, $compile, $timeout, $window, Layout) { + ['LayoutContainer', '$compile', '$timeout', 'Layout', + function(LayoutContainer, $compile, $timeout, Layout) { return { restrict: 'AE', require: '^uiLayout', @@ -929,7 +924,7 @@ angular.module('ui.layout', []) scope.container.layoutId = ctrl.id; scope.container.isCentral = attrs.uiLayoutContainer === 'central'; - if(scope.collapsed === true) { + if (scope.collapsed === true) { scope.collapsed = false; Layout.addCollapsed(scope.container); } @@ -938,14 +933,12 @@ angular.module('ui.layout', []) // scope.container.collapsed = scope.collapsed; //} - if(angular.isDefined(scope.resizable)) { + if (angular.isDefined(scope.resizable)) { scope.container.resizable = scope.resizable; } scope.container.size = scope.size; - scope.container.minSize = scope.minSize; scope.container.maxSize = scope.maxSize; - ctrl.addContainer(scope.container); element.on('$destroy', function() { @@ -960,7 +953,7 @@ angular.module('ui.layout', []) var animationClass = ctrl.isUsingColumnFlow ? 'animate-column' : 'animate-row'; element.addClass(animationClass); - scope.$watch('collapsed', function(val, old) { + scope.$watch('collapsed', function (val, old) { if(angular.isDefined(old) && val !== old) { ctrl.toggleContainer(scope.container.index); } @@ -988,7 +981,7 @@ angular.module('ui.layout', []) '' + ''); if(0 < index && !ctrl.hasSplitbarBefore(scope.container)) { - angular.element(children[index - 1]).after(splitbar); + angular.element(children[index-1]).after(splitbar); $compile(splitbar)(scope); } else if(index < children.length - 1) { element.after(splitbar); @@ -1014,17 +1007,17 @@ angular.module('ui.layout', []) require: '^uiLayout', restrict: 'A', priority: -100, - link: function($scope, el, attrs) { + link: function($scope, el, attrs){ // negation is safe here, because we are expecting non-empty string - if(!attrs['uiLayoutLoaded']) { + if (!attrs['uiLayoutLoaded']) { Layout.toggle().then( - function() { + function(){ $scope.$broadcast('ui.layout.loaded', null); } ); } else { - $scope.$broadcast('ui.layout.loaded', attrs['uiLayoutLoaded']); + $scope.$broadcast('ui.layout.loaded', attrs['uiLayoutLoaded']); } } }; @@ -1034,7 +1027,7 @@ angular.module('ui.layout', []) var layouts = [], collapsing = [], toBeCollapsed = 0, - toggledDeffered = null; + toggledDeffered = null; function toggleContainer(container) { try { @@ -1046,7 +1039,7 @@ angular.module('ui.layout', []) } return { - addLayout: function(ctrl) { + addLayout: function (ctrl) { ctrl.id = layouts.length; layouts.push(ctrl); }, @@ -1058,29 +1051,29 @@ angular.module('ui.layout', []) }, toggled: function() { // event already dispatched, do nothing - if(toBeCollapsed === 0) { - if(toggledDeffered) { + if (toBeCollapsed === 0) { + if (toggledDeffered) { toggledDeffered.reject(); } else { return false; } } toBeCollapsed--; - if(toBeCollapsed === 0) { + if (toBeCollapsed === 0) { toggledDeffered.resolve(); } }, toggle: function() { toggledDeffered = $q.defer(); toBeCollapsed = collapsing.length; - if(toBeCollapsed === 0) { - $timeout(function() { + if (toBeCollapsed === 0) { + $timeout(function(){ toggledDeffered.resolve(); }); } collapsing.reverse(); var c; - while (c = collapsing.pop()) { + while(c = collapsing.pop()) { toggleContainer(c); } return toggledDeffered.promise; diff --git a/test/layout-scenar.spec.js b/test/layout-scenar.spec.js index 15adced..ce1adcf 100644 --- a/test/layout-scenar.spec.js +++ b/test/layout-scenar.spec.js @@ -25,7 +25,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { return elm; } - beforeEach(function() { + beforeEach(function () { module('ui.layout'); @@ -48,31 +48,31 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { if(element) element.remove(); }); - describe('require', function() { - it('requestAnimationFrame', function() { + describe('require', function () { + it('requestAnimationFrame', function () { expect(window.requestAnimationFrame).toBeDefined(); }); - it('cancelAnimationFrame', function() { + it('cancelAnimationFrame', function () { expect(window.cancelAnimationFrame).toBeDefined(); }); }); // Spy on the requestAnimationFrame to directly trigger it - beforeEach(function() { + beforeEach(function () { spyOn(window, 'requestAnimationFrame').and.callFake(function(fct) { fct(); }); }); - afterEach(function() { + afterEach(function () { if(element) element.remove(); }); - describe('the slider', function() { + describe('the slider', function () { var element_bb, leftContainer, $splitbar, splitbar_bb, splitbarLeftPos; - beforeEach(function() { + beforeEach(function () { element = createDirective(); element_bb = element[0].getBoundingClientRect(); @@ -83,7 +83,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { splitbarLeftPos = Math.ceil(splitbar_bb.left); }); - it('should do nothing when clicking on it', function() { + it('should do nothing when clicking on it', function () { // Click on the splitbar left browserTrigger($splitbar, startEvent, { x: splitbarLeftPos }); @@ -95,7 +95,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { expect($window.localStorage.getItem(leftContainer.container.storageId)).toBeNull(); }); - it('should do nothing when moving around it', function() { + it('should do nothing when moving around it', function () { // Click on the splitbar left browserTrigger($splitbar, moveEvent, { x: splitbarLeftPos }); @@ -107,9 +107,9 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { expect($window.localStorage.getItem(leftContainer.container.storageId)).toBeNull(); }); - it('should follow the ' + description, function() { + it('should follow the ' + description, function () { browserTrigger($splitbar, startEvent, { y: splitbarLeftPos }); - browserTrigger($splitbar, moveEvent, { y: element_bb.height / 4 }); + browserTrigger($splitbar, moveEvent, { y: element_bb.height / 4}); expect(window.requestAnimationFrame).toHaveBeenCalled(); var expectedPos = Math.floor(element_bb.height / 4); @@ -119,7 +119,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { browserTrigger(document.body, endEvent); }); - it('should not follow the ' + description + ' before ' + startEvent, function() { + it('should not follow the ' + description + ' before ' + startEvent, function () { var expectedPos = Math.floor((element_bb.height - defaultDividerSize) / 2); expect(Math.ceil(parseFloat($splitbar[0].style.top))).toEqual(expectedPos); @@ -132,9 +132,9 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { expect($window.localStorage.getItem(leftContainer.container.storageId)).toBeNull(); }); - it('should not follow the ' + description + ' after ' + startEvent, function() { + it('should not follow the ' + description + ' after ' + startEvent, function () { browserTrigger($splitbar, startEvent, { y: splitbarLeftPos }); - browserTrigger($splitbar, moveEvent, { y: element_bb.height / 4 }); + browserTrigger($splitbar, moveEvent, { y: element_bb.height / 4}); browserTrigger($splitbar, endEvent); expect(window.requestAnimationFrame).toHaveBeenCalled(); @@ -228,7 +228,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { expectedLastAutosized = roundedHalf; // add remainder to the last element when parent size is odd - if(element_bb.height % 2 === 1) { + if (element_bb.height % 2 === 1) { expectedLastAutosized += 1; } var $footer = element.children().eq(2)[0]; @@ -246,7 +246,6 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { expect(toggleBeforeButton.style.display).toBe('inline'); }); }); - }); }); @@ -254,11 +253,11 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { describe('toggle programmatically', function() { var scope, $controller, $compile, $timeout; - beforeEach(function() { + beforeEach(function () { module('ui.layout'); - inject(function($rootScope, _$controller_, _$compile_, _$timeout_) { + inject(function ($rootScope, _$controller_, _$compile_, _$timeout_) { scope = $rootScope.$new(); $controller = _$controller_; $compile = _$compile_; From 6bcba31c09f92d70d5e9ca6ef9f17424c6965ec7 Mon Sep 17 00:00:00 2001 From: Hannes Widmoser Date: Wed, 9 Dec 2015 10:49:24 +0100 Subject: [PATCH 10/12] refactor: removed .bowerrc file because this change is out of scope for this feature/PR --- .bowerrc | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .bowerrc diff --git a/.bowerrc b/.bowerrc deleted file mode 100644 index baa91a3..0000000 --- a/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory": "bower_components" -} \ No newline at end of file From 4bc969ee9635b58f00b3bc632f65947e12e5fa1a Mon Sep 17 00:00:00 2001 From: Hannes Widmoser Date: Wed, 9 Dec 2015 10:52:31 +0100 Subject: [PATCH 11/12] style: some more formatting fixes to clean up diff --- src/ui-layout.js | 10 +++++----- test/layout-scenar.spec.js | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ui-layout.js b/src/ui-layout.js index c3bbe64..dc6c6f0 100644 --- a/src/ui-layout.js +++ b/src/ui-layout.js @@ -243,8 +243,8 @@ angular.module('ui.layout', []) //verify the container was found in the list if(index > -1) { - var beforeContainer = (index > 0) ? ctrl.containers[index - 1] : null; - var afterContainer = ((index+1) <= ctrl.containers.length) ? ctrl.containers[index + 1] : null; + var beforeContainer = (index > 0) ? ctrl.containers[index-1] : null; + var afterContainer = ((index+1) <= ctrl.containers.length) ? ctrl.containers[index+1] : null; if(beforeContainer !== null) setValues(beforeContainer); if(afterContainer !== null) setValues(afterContainer); @@ -283,7 +283,7 @@ angular.module('ui.layout', []) ctrl.calculate = function() { var c, i; var dividerSize = parseInt(opts.dividerSize); - var elementSize = $element[0].getBoundingClientRect()[ctrl.sizeProperties.sizeProperty]; // width/height + var elementSize = $element[0].getBoundingClientRect()[ctrl.sizeProperties.sizeProperty]; var availableSize = elementSize - (dividerSize * numOfSplitbars); var originalSize = availableSize; var usedSpace = 0; @@ -347,7 +347,7 @@ angular.module('ui.layout', []) remainder = availableSize - autoSize * numOfAutoContainers; for(i=0; i < ctrl.containers.length; i++) { c = ctrl.containers[i]; - c[ctrl.sizeProperties.flowProperty] = usedSpace; // left/top + c[ctrl.sizeProperties.flowProperty] = usedSpace; c.maxSize = opts.maxSizes[i]; c.minSize = opts.minSizes[i]; @@ -954,7 +954,7 @@ angular.module('ui.layout', []) element.addClass(animationClass); scope.$watch('collapsed', function (val, old) { - if(angular.isDefined(old) && val !== old) { + if (angular.isDefined(old) && val !== old) { ctrl.toggleContainer(scope.container.index); } }); diff --git a/test/layout-scenar.spec.js b/test/layout-scenar.spec.js index ce1adcf..8f33906 100644 --- a/test/layout-scenar.spec.js +++ b/test/layout-scenar.spec.js @@ -44,7 +44,7 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { } }); - afterEach(function() { + afterEach(function () { if(element) element.remove(); }); @@ -59,13 +59,13 @@ function splitMoveTests(description, startEvent, moveEvent, endEvent) { // Spy on the requestAnimationFrame to directly trigger it beforeEach(function () { - spyOn(window, 'requestAnimationFrame').and.callFake(function(fct) { + spyOn(window, 'requestAnimationFrame').and.callFake(function (fct) { fct(); }); }); afterEach(function () { - if(element) element.remove(); + if (element) element.remove(); }); describe('the slider', function () { From 35651cbc4c4195259cb0a9543767adc9309b40d2 Mon Sep 17 00:00:00 2001 From: Hannes Widmoser Date: Fri, 19 Feb 2016 07:44:22 +0100 Subject: [PATCH 12/12] style: removed TODO and using forEach instead of for loop --- src/ui-layout.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ui-layout.js b/src/ui-layout.js index dc6c6f0..63b913d 100644 --- a/src/ui-layout.js +++ b/src/ui-layout.js @@ -86,7 +86,7 @@ angular.module('ui.layout', []) if(!beforeContainer.collapsed && !afterContainer.collapsed) { // calculate container positons var difference = ctrl.movingSplitbar[position] - lastPos; - var newPosition = ctrl.movingSplitbar[position] - difference; // TODO: this computation is unnecessary, newPosition === lastPos + var newPosition = ctrl.movingSplitbar[position] - difference; // Keep the bar in the window (no left/top 100%) newPosition = Math.min(elementSize-dividerSize, newPosition); @@ -184,11 +184,10 @@ angular.module('ui.layout', []) /** * Updates the storage ids of all containers according to the id of this controller and the index of the container. */ - function updateContainerStorageIds() { - for (var i = 0; i < ctrl.containers.length; ++i) { - var c = ctrl.containers[i]; + function updateContainerStorageIds() { + ctrl.containers.forEach(function(c, i) { c.storageId = ctrl.id + ':' + i; - } + }); } //================================================================================