1
/* Copyright (c) 2009, Canonical Ltd. All rights reserved. */
3
YUI.add('lazr.actions', function(Y) {
5
Y.namespace('lazr.actions');
8
ACTIONCLASS = "Action",
10
ACTIONS_HELPER = "ActionsHelper",
11
ACTIONS_ID = "actionsId",
13
ITEMCLASSNAME = "itemClassName",
15
LAZR_ACTION_DISABLED = 'lazr-action-disabled',
17
LINKCLASSNAME = "linkClassName",
18
PERMISSION = "permission",
23
* The Actions and ActionsHelper widgets allow for creating arbitrary collections of behavioral
24
* links and situating them in DOM elements on the page. In the absence of a label attribute,
25
* they can be presented with CSS sprites for graphical representation. When actions are running,
26
* they have their primary linkClassName CSS class replaced with lazr-waiting, which can be
27
* styled as needed (spinner, hidden, greyed-out, &c). Each action can be governed by a
28
* permission, which will fire at the time of rendering and, if failing, decorate the action with
29
* the lazr-action-disabled class, which can be styled as needed (hidden, greyed-out, &c).
33
* The ActionsHelper widget collects and delegates Action
34
* widgets associated with a common Node
36
* @class ActionsHelper
38
var ActionsHelper = function(config) {
39
ActionsHelper.superclass.constructor.apply(this, arguments);
42
ActionsHelper.NAME = ACTIONS_HELPER;
44
ActionsHelper.ATTRS = {
45
actions: { valueFn: function() { return []; }},
46
actionsId: { valueFn: function() { return Y.guid(); }},
49
Y.extend(ActionsHelper, Y.Base, {
53
* This method is called to render each of its Actions in turn, in the specified node.
57
* @param node {Node} The node that should contain the ActionsHelper
59
render: function(node) {
60
var doc = Y.config.doc;
61
var actions = this.get(ACTIONS);
62
var actionsId = this.get(ACTIONS_ID);
64
// Check if we already have an instance of the
65
// container in the DOM.
66
var actionsContainer = Y.one("#" + actionsId);
68
if (actionsContainer) {
69
// If the container already exists in the DOM,
70
// unattach it so that it can be moved to a
72
actionsContainer.remove()
74
actionsContainer = new Y.Node.create(
75
"<ul id='" + actionsId + "' />");
77
// If there are no icons to be displayed, don't bother
78
// creating the container.
80
// Render each action as a separate item inside
82
for (var i=0; i<actions.length; i++){
83
var action = actions[i];
84
action.render(actionsContainer);
88
// Finally, if a container was created or an existing
89
// one was found, append it to the Document Fragment
90
// for later attachment to the new destination node.
91
if (actionsContainer !== null) {
92
node.appendChild(Y.Node.getDOMNode(actionsContainer));
97
Y.lazr.actions.ActionsHelper = ActionsHelper;
100
* This class provides a self-protecting action, governed by permissions, attached
101
* to a link that can have its style updated when running.
106
var Action = function(config) {
107
Action.superclass.constructor.apply(this, arguments);
111
* Dictionary of selectors to define subparts of the widget that we care about.
112
* YUI calls ATTRS.set(foo) for each foo defined here
114
* @property Action.NAME
118
Action.NAME = ACTIONCLASS;
122
* A function representing the underlying behavior of this action.
132
* A function which runs at render time, evaluating to true or fase, determining
133
* whether or not the action should be disabled.
135
* @attribute permission
143
* Optional text label for the Action. If present, it will be the text of the
154
* Title attribute of the inner anchor tag
164
* A special CSS class name for the list element of the Action
166
* @attribute itemClassName
174
* A special CSS class name for the inner anchor element of the Action, will get
175
* swapped out with Y.lazr.ui.CSS_WAITING when the action is running.
177
* @attribute linkClassName
185
* A flag determining whether the current Action is engaged in its action
192
setter: function(v) { return this._updateRunState(v); },
193
getter: function(v) { return v; }
197
* A list element, decorated with our CSS class and with our link attached.
203
valueFn: function() { return this._createItem(); }
207
* An anchor element, decorated with our CSS class and with our behavior attached.
213
valueFn: function() { return this._createLink(); }
218
Y.extend(Action, Y.Base, {
221
* Helper method to toggle the CSS_WAITING class on the link element
226
_updateRunState: function(isRunning) {
227
// when we get set to true:
228
// - turn our icon to a spinner, if appropriate
229
if (this.get(LINKCLASSNAME) !== null) {
231
this.get(LINK).replaceClass(
232
this.get(LINKCLASSNAME),
233
Y.lazr.ui.CSS_WAITING);
235
this.get(LINK).replaceClass(
236
Y.lazr.ui.CSS_WAITING,
237
this.get(LINKCLASSNAME));
244
* Helper method to create the link element, and perform initial decoration
249
_createLink: function() {
250
var label = this.get(LABEL);
251
var title = this.get(TITLE);
252
var linkClassName = this.get(LINKCLASSNAME);
253
var link = Y.Node.create(
254
"<a href='#' alt='" + title +
255
"' title='" + title + "'></a>");
256
link.on("click", this.actionRunner, this);
258
if (label !== null) {
259
link.append(Y.Node.create(label));
262
if (linkClassName !== null) {
263
link.addClass(linkClassName);
270
* Helper method to create the list item element, and perform initial decoration
275
_createItem: function() {
276
var itemClassName = this.get(ITEMCLASSNAME);
277
var link = this.get(LINK);
278
var item = Y.Node.create('<li/>');
280
if (itemClassName !== null) {
281
item.addClass(itemClassName);
290
* Render the action and attach it to a node
294
render: function(node) {
295
// Build the link, labeling it if necessary
296
// Compose the item, decorating it if necessary
297
var item = this.get(ITEM);
298
var permission = this.get(PERMISSION);
300
if (permission && !permission()) {
301
item.addClass(LAZR_ACTION_DISABLED);
303
item.removeClass(LAZR_ACTION_DISABLED);
311
* Wrap the actual function so that it short-circuits if the action is currently
314
* @method actionRunner
316
actionRunner: function() {
317
if (!this.get(RUNNING)) {
318
// Not running, fire.
324
Y.lazr.actions.Action = Action;
326
}, "0.1.", {"requires": ["oop", "base", "node", "lazr.base"]});