Merge remote-tracking branch 'origin/open929' into open-master

This commit is contained in:
bwyu
2015-03-13 16:21:08 -07:00
10 changed files with 119 additions and 200 deletions

View File

@@ -1,8 +1,8 @@
/*global define*/
define(
['./EditToolbar'],
function (EditToolbar) {
['./EditToolbar', './EditToolbarSelection'],
function (EditToolbar, EditToolbarSelection) {
"use strict";
// No operation
@@ -81,8 +81,8 @@ define(
var definition = (representation || {}).toolbar || {};
// Expose the toolbar object to the parent scope
initialize(definition);
// Clear any existing selection
scope.selection = [];
// Create a selection scope
scope.selection = new EditToolbarSelection();
// Initialize toolbar to an empty selection
updateSelection([]);
}
@@ -101,7 +101,7 @@ define(
// Detect and handle changes to state from the toolbar
scope.$watchCollection(getState, updateState);
// Watch for changes in the current selection state
scope.$watchCollection("selection", updateSelection);
scope.$watchCollection("selection.all()", updateSelection);
// Expose toolbar state under that name
scope.$parent[attrs.toolbar] = toolbarObject;
}

View File

@@ -0,0 +1,125 @@
/*global define*/
define(
[],
function () {
"use strict";
/**
* Tracks selection state for editable views. Selection is
* implemented such that (from the toolbar's perspective)
* up to two objects can be "selected" at any given time:
*
* * The view proxy (see the `proxy` method), which provides
* an interface for interacting with the view itself (e.g.
* for buttons like "Add")
* * The selection, for single selected elements within the
* view.
*
* @constructor
*/
function EditToolbarSelection() {
var selection = [ {} ],
selecting = false,
selected;
// Remove the currently-selected object
function deselect() {
// Nothing to do if we don't have a selected object
if (selecting) {
// Clear state tracking
selecting = false;
selected = undefined;
// Remove the selection
selection.pop();
return true;
}
return false;
}
// Select an object
function select(obj) {
// Proxy is always selected
if (obj === selection[0]) {
return false;
}
// Clear any existing selection
deselect();
// Note the current selection state
selected = obj;
selecting = true;
// Add the selection
selection.push(obj);
}
// Check if an object is selected
function isSelected(obj) {
return (obj === selected) || (obj === selection[0]);
}
// Getter for current selection
function get() {
return selected;
}
// Getter/setter for view proxy
function proxy(p) {
if (arguments.length > 0) {
selection[0] = p;
}
return selection[0];
}
// Getter for the full array of selected objects (incl. view proxy)
function all() {
return selection;
}
return {
/**
* Check if an object is currently selected.
* @returns true if selected, otherwise false
*/
selected: isSelected,
/**
* Select an object.
* @param obj the object to select
* @returns {boolean} true if selection changed
*/
select: select,
/**
* Clear the current selection.
* @returns {boolean} true if selection changed
*/
deselect: deselect,
/**
* Get the currently-selected object.
* @returns the currently selected object
*/
get: get,
/**
* Get/set the view proxy (for toolbar actions taken upon
* the view itself.)
* @param [proxy] the view proxy (if setting)
* @returns the current view proxy
*/
proxy: proxy,
/**
* Get an array containing all selections, including the
* selection proxy. It is generally not advisable to
* mutate this array directly.
* @returns {Array} all selections
*/
all: all
};
}
return EditToolbarSelection;
}
);

View File

@@ -77,9 +77,9 @@ define(
});
// Update the selection
mockScope.selection.push(testObject);
mockScope.selection.select(testObject);
expect(mockScope.$watchCollection.mostRecentCall.args[0])
.toEqual('selection'); // Make sure we're using right watch
.toEqual('selection.all()'); // Make sure we're using right watch
mockScope.$watchCollection.mostRecentCall.args[1]([testObject]);
// Update the state
@@ -105,9 +105,9 @@ define(
});
// Update the selection
mockScope.selection.push(testObject);
mockScope.selection.select(testObject);
expect(mockScope.$watchCollection.mostRecentCall.args[0])
.toEqual('selection'); // Make sure we're using right watch
.toEqual('selection.all()'); // Make sure we're using right watch
mockScope.$watchCollection.mostRecentCall.args[1]([testObject]);
// Invoke the first watch (assumed to be for toolbar state)

View File

@@ -0,0 +1,77 @@
/*global define,describe,it,expect,beforeEach,jasmine,xit*/
define(
['../../src/representers/EditToolbarSelection'],
function (EditToolbarSelection) {
"use strict";
describe("The Edit mode selection manager", function () {
var testProxy,
testElement,
otherElement,
selection;
beforeEach(function () {
testProxy = { someKey: "some value" };
testElement = { someOtherKey: "some other value" };
otherElement = { yetAnotherKey: 42 };
selection = new EditToolbarSelection();
selection.proxy(testProxy);
});
it("adds the proxy to the selection array", function () {
expect(selection.all()).toEqual([testProxy]);
});
it("exposes view proxy", function () {
expect(selection.proxy()).toBe(testProxy);
});
it("includes selected objects alongside the proxy", function () {
selection.select(testElement);
expect(selection.all()).toEqual([testProxy, testElement]);
});
it("allows elements to be deselected", function () {
selection.select(testElement);
selection.deselect();
expect(selection.all()).toEqual([testProxy]);
});
it("replaces old selections with new ones", function () {
selection.select(testElement);
selection.select(otherElement);
expect(selection.all()).toEqual([testProxy, otherElement]);
});
it("allows retrieval of the current selection", function () {
selection.select(testElement);
expect(selection.get()).toBe(testElement);
selection.select(otherElement);
expect(selection.get()).toBe(otherElement);
});
it("can check if an element is selected", function () {
selection.select(testElement);
expect(selection.selected(testElement)).toBeTruthy();
expect(selection.selected(otherElement)).toBeFalsy();
selection.select(otherElement);
expect(selection.selected(testElement)).toBeFalsy();
expect(selection.selected(otherElement)).toBeTruthy();
});
it("considers the proxy to be selected", function () {
expect(selection.selected(testProxy)).toBeTruthy();
selection.select(testElement);
// Even when something else is selected...
expect(selection.selected(testProxy)).toBeTruthy();
});
it("treats selection of the proxy as a no-op", function () {
selection.select(testProxy);
expect(selection.all()).toEqual([testProxy]);
});
});
}
);

View File

@@ -18,5 +18,6 @@
"objects/EditableModelCache",
"representers/EditRepresenter",
"representers/EditToolbar",
"representers/EditToolbarRepresenter"
"representers/EditToolbarRepresenter",
"representers/EditToolbarSelection"
]