diff --git a/.gitignore b/.gitignore index b8eea4a5be..3d231f100b 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,5 @@ protractor/logs # npm-debug log npm-debug.log + +package-lock.json diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html index b6d4dd0b92..0855ebcf59 100644 --- a/platform/commonUI/browse/res/templates/browse.html +++ b/platform/commonUI/browse/res/templates/browse.html @@ -26,7 +26,7 @@ ng-controller="PaneController as modelPaneTree" ng-class="modelPaneTree.visible() ? 'pane-tree-showing' : 'pane-tree-hidden'"> + anchor='left' alias="leftSide">
- +
- diff --git a/platform/commonUI/general/bundle.js b/platform/commonUI/general/bundle.js index 78e0e551ba..75f240d8c2 100644 --- a/platform/commonUI/general/bundle.js +++ b/platform/commonUI/general/bundle.js @@ -374,7 +374,8 @@ define([ "depends": [ "$parse", "$log", - "$interval" + "$interval", + "$window" ] }, { diff --git a/platform/commonUI/general/src/directives/MCTSplitPane.js b/platform/commonUI/general/src/directives/MCTSplitPane.js index 35625da413..f52876335c 100644 --- a/platform/commonUI/general/src/directives/MCTSplitPane.js +++ b/platform/commonUI/general/src/directives/MCTSplitPane.js @@ -93,13 +93,21 @@ define( * @memberof platform/commonUI/general * @constructor */ - function MCTSplitPane($parse, $log, $interval) { + function MCTSplitPane($parse, $log, $interval, $window) { function controller($scope, $element, $attrs) { var anchorKey = $attrs.anchor || DEFAULT_ANCHOR, + positionParsed = $parse($attrs.position), anchor, activeInterval, - positionParsed = $parse($attrs.position), - position; // Start undefined, until explicitly set + position, + splitterSize, + + alias = $attrs.alias !== undefined ? + "mctSplitPane-" + $attrs.alias : undefined, + + //convert string to number from localStorage + userWidthPreference = $window.localStorage.getItem(alias) === null ? + undefined : Number($window.localStorage.getItem(alias)); // Get relevant size (height or width) of DOM element function getSize(domElement) { @@ -114,11 +122,11 @@ define( var first = children.eq(anchor.reversed ? 2 : 0), splitter = children.eq(1), last = children.eq(anchor.reversed ? 0 : 2), - splitterSize = getSize(splitter[0]), firstSize; + splitterSize = getSize(splitter[0]); first.css(anchor.edge, "0px"); - first.css(anchor.dimension, (position - splitterSize) + 'px'); + first.css(anchor.dimension, (userWidthPreference || position) + 'px'); // Get actual size (to obey min-width etc.) firstSize = getSize(first[0]); @@ -126,9 +134,8 @@ define( splitter.css(anchor.edge, firstSize + 'px'); splitter.css(anchor.opposite, "auto"); - last.css(anchor.edge, (firstSize + splitterSize) + 'px'); + last.css(anchor.edge, firstSize + splitterSize + 'px'); last.css(anchor.opposite, "0px"); - position = firstSize + splitterSize; } @@ -169,6 +176,17 @@ define( return position; } + function setUserWidthPreference(value) { + userWidthPreference = value - splitterSize; + } + + function persistToLocalStorage(value) { + if (alias) { + userWidthPreference = value - splitterSize; + $window.localStorage.setItem(alias, userWidthPreference); + } + } + // Dynamically apply a CSS class to elements when the user // is actively resizing function toggleClass(classToToggle) { @@ -196,18 +214,31 @@ define( activeInterval = $interval(function () { getSetPosition(getSetPosition()); }, POLLING_INTERVAL, 0, false); - // ...and stop polling when we're destroyed. $scope.$on('$destroy', function () { $interval.cancel(activeInterval); }); + // Interface exposed by controller, for mct-splitter to user return { - position: getSetPosition, - toggleClass: toggleClass, anchor: function () { return anchor; + }, + position: function (value) { + if (arguments.length > 0) { + setUserWidthPreference(value); + return getSetPosition(value); + } else { + return getSetPosition(); + } + }, + startResizing: function () { + toggleClass('resizing'); + }, + endResizing: function (finalPosition) { + persistToLocalStorage(finalPosition); + toggleClass('resizing'); } }; } @@ -219,9 +250,7 @@ define( controller: ['$scope', '$element', '$attrs', controller] }; } - return MCTSplitPane; } ); - diff --git a/platform/commonUI/general/src/directives/MCTSplitter.js b/platform/commonUI/general/src/directives/MCTSplitter.js index 63acb90824..69db2f0a02 100644 --- a/platform/commonUI/general/src/directives/MCTSplitter.js +++ b/platform/commonUI/general/src/directives/MCTSplitter.js @@ -37,15 +37,16 @@ define( */ function MCTSplitter() { function link(scope, element, attrs, mctSplitPane) { - var initialPosition; + var initialPosition, + newPosition; element.addClass("splitter"); scope.splitter = { // Begin moving this splitter startMove: function () { + mctSplitPane.startResizing(); initialPosition = mctSplitPane.position(); - mctSplitPane.toggleClass('resizing'); }, // Handle user changes to splitter position move: function (delta) { @@ -55,12 +56,13 @@ define( (anchor.reversed ? -1 : 1); // Update the position of this splitter - mctSplitPane.position(initialPosition + pixelDelta); + newPosition = initialPosition + pixelDelta; + mctSplitPane.position(newPosition); }, // Grab the event when the user is done moving // the splitter and pass it on endMove: function () { - mctSplitPane.toggleClass('resizing'); + mctSplitPane.endResizing(newPosition); } }; } @@ -83,4 +85,3 @@ define( } ); - diff --git a/platform/commonUI/general/test/directives/MCTSplitPaneSpec.js b/platform/commonUI/general/test/directives/MCTSplitPaneSpec.js index fb36eba68c..abd0935021 100644 --- a/platform/commonUI/general/test/directives/MCTSplitPaneSpec.js +++ b/platform/commonUI/general/test/directives/MCTSplitPaneSpec.js @@ -38,7 +38,8 @@ define( mockLog, mockInterval, mockParsed, - mctSplitPane; + mctSplitPane, + mockWindow = {}; beforeEach(function () { mockParse = jasmine.createSpy('$parse'); @@ -48,13 +49,23 @@ define( mockInterval.cancel = jasmine.createSpy('mockCancel'); mockParsed = jasmine.createSpy('parsed'); mockParsed.assign = jasmine.createSpy('assign'); - mockParse.andReturn(mockParsed); + mockWindow.localStorage = { + store: {}, + setItem: function (key, value) { + this.store[key] = value; + }, + getItem: function (key) { + return this.store[key]; + } + }; + mctSplitPane = new MCTSplitPane( mockParse, mockLog, - mockInterval + mockInterval, + mockWindow ); }); @@ -85,7 +96,7 @@ define( jasmine.createSpyObj('$scope', ['$apply', '$watch', '$on']); mockElement = jasmine.createSpyObj('element', JQLITE_METHODS); - testAttrs = {}; + testAttrs = {alias: 'rightSide'}; mockChildren = jasmine.createSpyObj('children', JQLITE_METHODS); mockFirstPane = @@ -142,10 +153,14 @@ define( }); }); - it("allows classes to be toggled on contained elements", function () { - controller.toggleClass('resizing'); - expect(mockChildren.toggleClass) - .toHaveBeenCalledWith('resizing'); + it("applies resizing class to children when resizing", function () { + controller.startResizing(); + expect(mockChildren.toggleClass).toHaveBeenCalledWith('resizing'); + }); + + it("removes resizing class from children when resizing action ends", function () { + controller.endResizing(0); + expect(mockChildren.toggleClass).toHaveBeenCalledWith('resizing'); }); it("allows positions to be set", function () { @@ -198,6 +213,12 @@ define( fireOn('$destroy'); expect(mockInterval.cancel).toHaveBeenCalled(); }); + + it("saves user preference to localStorage when user is done resizing", function () { + controller.endResizing(100); + expect(Number(mockWindow.localStorage.getItem('mctSplitPane-rightSide'))).toEqual(100 - mockSplitter[0].offsetWidth); + }); + }); }); diff --git a/platform/commonUI/general/test/directives/MCTSplitterSpec.js b/platform/commonUI/general/test/directives/MCTSplitterSpec.js index df6ee256e6..caf0fd468d 100644 --- a/platform/commonUI/general/test/directives/MCTSplitterSpec.js +++ b/platform/commonUI/general/test/directives/MCTSplitterSpec.js @@ -57,7 +57,7 @@ define( testAttrs = {}; mockSplitPane = jasmine.createSpyObj( 'mctSplitPane', - ['position', 'toggleClass', 'anchor'] + ['position', 'startResizing', 'endResizing', 'anchor'] ); mctSplitter.link( @@ -86,9 +86,9 @@ define( mockScope.splitter.startMove(); }); - it("adds a 'resizing' class", function () { - expect(mockSplitPane.toggleClass) - .toHaveBeenCalledWith('resizing'); + it("tell's the splitter when it is resizing", function () { + expect(mockSplitPane.startResizing) + .toHaveBeenCalled(); }); it("repositions during drag", function () { @@ -97,11 +97,10 @@ define( .toHaveBeenCalledWith(testPosition + 10); }); - it("removes the 'resizing' class when finished", function () { - mockSplitPane.toggleClass.reset(); + it("tell's the splitter when it is done resizing", function () { + mockScope.splitter.move([10,0]); mockScope.splitter.endMove(); - expect(mockSplitPane.toggleClass) - .toHaveBeenCalledWith('resizing'); + expect(mockSplitPane.endResizing).toHaveBeenCalledWith(testPosition + 10); }); });