2015-02-17 20:58:36 +00:00
|
|
|
/*global define*/
|
|
|
|
define(
|
|
|
|
[],
|
|
|
|
function () {
|
|
|
|
"use strict";
|
|
|
|
|
2015-02-17 21:47:14 +00:00
|
|
|
// Utility functions for reducing truth arrays
|
|
|
|
function and(a, b) { return a && b; }
|
|
|
|
function or(a, b) { return a || b; }
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Provides initial structure and state (as suitable for provision
|
|
|
|
* to the `mct-toolbar` directive) for a view's tool bar, based on
|
|
|
|
* that view's declaration of what belongs in its tool bar and on
|
|
|
|
* the current selection.
|
|
|
|
*
|
|
|
|
* @param structure toolbar structure, as provided by view definition
|
|
|
|
* @param {Array} selection the current selection state
|
|
|
|
* @constructor
|
|
|
|
*/
|
2015-02-17 20:58:36 +00:00
|
|
|
function EditToolbar(structure, selection) {
|
2015-02-17 21:47:14 +00:00
|
|
|
var toolbarStructure = Object.create(structure || {}),
|
|
|
|
toolbarState,
|
|
|
|
properties = [];
|
|
|
|
|
|
|
|
// Generate a new key for an item's property
|
|
|
|
function addKey(property) {
|
|
|
|
properties.push(property);
|
|
|
|
return properties.length - 1; // Return index of property
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update value for this property in all elements of the
|
|
|
|
// selection which have this property.
|
|
|
|
function updateProperties(property, value) {
|
|
|
|
// Update property in a selected element
|
|
|
|
function updateProperty(selected) {
|
|
|
|
// Ignore selected elements which don't have this property
|
|
|
|
if (selected[property] !== undefined) {
|
|
|
|
// Check if this is a setter, or just assignable
|
|
|
|
if (typeof selected[property] === 'function') {
|
|
|
|
selected[property](value);
|
|
|
|
} else {
|
|
|
|
selected[property] = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update property in all selected elements
|
|
|
|
selection.forEach(updateProperty);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Look up the current value associated with a property
|
|
|
|
// in selection i
|
|
|
|
function lookupState(property, selected) {
|
|
|
|
var value = selected[property];
|
|
|
|
return (typeof value === 'function') ? value() : value;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get initial value for a given property
|
|
|
|
function initializeState(property) {
|
|
|
|
var result;
|
|
|
|
// Look through all selections for this property;
|
|
|
|
// values should all match by the time we perform
|
|
|
|
// this lookup anyway.
|
|
|
|
selection.forEach(function (selected) {
|
|
|
|
result = (selected[property] !== undefined) ?
|
|
|
|
lookupState(property, selected) :
|
|
|
|
result;
|
|
|
|
});
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if all elements of the selection which have this
|
|
|
|
// property have the same value for this property.
|
|
|
|
function isConsistent(property) {
|
|
|
|
var consistent = true,
|
|
|
|
observed = false,
|
|
|
|
state;
|
|
|
|
|
|
|
|
// Check if a given element of the selection is consistent
|
|
|
|
// with previously-observed elements for this property.
|
|
|
|
function checkConsistency(selected) {
|
|
|
|
var next;
|
|
|
|
// Ignore selections which don't have this property
|
|
|
|
if (selected[property] !== undefined) {
|
|
|
|
// Look up state of this element in the selection
|
|
|
|
next = lookupState(property, selected);
|
|
|
|
// Detect inconsistency
|
|
|
|
if (observed) {
|
|
|
|
consistent = consistent && (next === state);
|
|
|
|
}
|
|
|
|
// Track state for next iteration
|
|
|
|
state = next;
|
|
|
|
observed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Iterate through selections
|
|
|
|
selection.forEach(checkConsistency);
|
|
|
|
|
|
|
|
return consistent;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used to filter out items which are applicable (or not)
|
|
|
|
// to the current selection.
|
|
|
|
function isApplicable(item) {
|
|
|
|
var property = (item || {}).property,
|
2015-02-18 00:20:02 +00:00
|
|
|
method = (item || {}).method,
|
2015-02-17 21:47:14 +00:00
|
|
|
exclusive = !(item || {}).inclusive;
|
|
|
|
|
|
|
|
// Check if a selected item defines this property
|
|
|
|
function hasProperty(selected) {
|
2015-02-18 00:20:02 +00:00
|
|
|
return (property && (selected[property] !== undefined)) ||
|
|
|
|
(method && (typeof selected[method] === 'function'));
|
2015-02-17 21:47:14 +00:00
|
|
|
}
|
|
|
|
|
2015-02-18 00:20:02 +00:00
|
|
|
return selection.map(hasProperty).reduce(
|
2015-02-17 21:47:14 +00:00
|
|
|
exclusive ? and : or,
|
|
|
|
exclusive
|
|
|
|
) && isConsistent(property);
|
|
|
|
}
|
|
|
|
|
2015-02-18 00:20:02 +00:00
|
|
|
// Invoke all functions in selections with the given name
|
|
|
|
function invoke(method, value) {
|
|
|
|
if (method) {
|
|
|
|
selection.forEach(function (selected) {
|
|
|
|
if (typeof selected[method] === 'function') {
|
|
|
|
selected[method](value);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-17 21:47:14 +00:00
|
|
|
// Prepare a toolbar item based on current selection
|
|
|
|
function convertItem(item) {
|
|
|
|
var converted = Object.create(item || {});
|
2015-02-18 00:20:02 +00:00
|
|
|
if (item.property) {
|
|
|
|
converted.key = addKey(item.property);
|
|
|
|
}
|
|
|
|
if (item.method) {
|
|
|
|
converted.click = function (v) { invoke(item.method, v); };
|
|
|
|
}
|
2015-02-17 21:47:14 +00:00
|
|
|
return converted;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used to filter out sections that have become empty
|
|
|
|
function nonEmpty(section) {
|
|
|
|
return section && section.items && section.items.length > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prepare a toolbar section based on current selection
|
|
|
|
function convertSection(section) {
|
|
|
|
var converted = Object.create(section || {});
|
|
|
|
converted.items =
|
|
|
|
((section || {}).items || [])
|
|
|
|
.map(convertItem)
|
|
|
|
.filter(isApplicable);
|
|
|
|
return converted;
|
|
|
|
}
|
|
|
|
|
|
|
|
toolbarStructure.sections =
|
|
|
|
((structure || {}).sections || [])
|
|
|
|
.map(convertSection)
|
|
|
|
.filter(nonEmpty);
|
|
|
|
|
|
|
|
toolbarState = properties.map(initializeState);
|
2015-02-17 20:58:36 +00:00
|
|
|
|
|
|
|
return {
|
2015-02-17 21:47:14 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
2015-02-17 20:58:36 +00:00
|
|
|
getStructure: function () {
|
2015-02-17 21:47:14 +00:00
|
|
|
return toolbarStructure;
|
2015-02-17 20:58:36 +00:00
|
|
|
},
|
|
|
|
getState: function () {
|
2015-02-17 21:47:14 +00:00
|
|
|
return toolbarState;
|
2015-02-17 20:58:36 +00:00
|
|
|
},
|
2015-02-17 21:47:14 +00:00
|
|
|
updateState: function (key, value) {
|
|
|
|
updateProperties(properties[key], value);
|
2015-02-17 20:58:36 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return EditToolbar;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|