/*global define,Promise*/ /** * Module defining ActionProvider. Created by vwoeltje on 11/7/14. */ define( [], function () { "use strict"; /** * An ActionProvider (implementing ActionService) provides actions * that are applicable in specific contexts, chosen from a set * of actions exposed via extension (specifically, the "actions" * category of extension.) * * @constructor */ function ActionProvider(actions) { var actionsByKey = {}, actionsByCategory = {}; // Instantiate an action; invokes the constructor and // additionally fills in the action's getMetadata method // with the extension definition (if no getMetadata // method was supplied.) function instantiateAction(Action, context) { var action = new Action(context), metadata; // Provide a getMetadata method that echos // declarative bindings, as well as context, // unless the action has defined its own. if (!action.getMetadata) { metadata = Object.create(Action.definition || {}); metadata.context = context; action.getMetadata = function () { return metadata; }; } return action; } // Filter the array of actions down to those which are // applicable in a given context, according to the static // appliesTo method of given actions (if defined), and // instantiate those applicable actions. function createIfApplicable(actions, context) { return (actions || []).filter(function (Action) { return Action.appliesTo ? Action.appliesTo(context) : true; }).map(function (Action) { return instantiateAction(Action, context); }); } // Get an array of actions that are valid in the supplied context. function getActions(actionContext) { var context = (actionContext || {}), category = context.category, key = context.key, candidates; // Match actions to the provided context by comparing "key" // and/or "category" parameters, if specified. candidates = actions; if (key) { candidates = actionsByKey[key]; if (category) { candidates = candidates.filter(function (Action) { return Action.category === category; }); } } else if (category) { candidates = actionsByCategory[category]; } // Instantiate those remaining actions, with additional // filtering per any appliesTo methods defined on those // actions. return createIfApplicable(candidates, context); } // Build up look-up tables actions.forEach(function (Action) { if (Action.category) { actionsByCategory[Action.category] = actionsByCategory[Action.category] || []; actionsByCategory[Action.category].push(Action); } if (Action.key) { actionsByKey[Action.key] = actionsByKey[Action.key] || []; actionsByKey[Action.key].push(Action); } }); return { /** * Get a list of actions which are valid in a given * context. * * @param {ActionContext} the context in which * the action will occur; this is a * JavaScript object containing key-value * pairs. Typically, this will contain a * field "domainObject" which refers to * the domain object that will be acted * upon, but may contain arbitrary information * recognized by specific providers. * @return {Action[]} an array of actions which * may be performed in the provided context. * * @method * @memberof ActionProvider */ getActions: getActions }; } return ActionProvider; } );