1 /**
  2  * Olives http://flams.github.com/olives
  3  * The MIT License (MIT)
  4  * Copyright (c) 2012-2014 Olivier Scherrer <pode.fr@gmail.com> - Olivier Wietrich <olivier.wietrich@gmail.com>
  5  */
  6 "use strict";
  7 
  8 var Tools = require("emily").Tools,
  9     DomUtils = require("./DomUtils");
 10 
 11 /**
 12  * @class
 13  * Plugins is the link between the UI and your plugins.
 14  * You can design your own plugin, declare them in your UI, and call them
 15  * from the template, like :
 16  * <tag data-yourPlugin="method: param"></tag>
 17  * @see Model-Plugin for instance
 18  * @requires Tools
 19  */
 20 module.exports = function PluginsConstructor($plugins) {
 21 
 22     /**
 23      * The list of plugins
 24      * @private
 25      */
 26     var _plugins = {},
 27 
 28     /**
 29      * Just a "functionalification" of trim
 30      * for code readability
 31      * @private
 32      */
 33     trim = function trim(string) {
 34         return string.trim();
 35     },
 36 
 37     /**
 38      * Call the plugins methods, passing them the dom node
 39      * A phrase can be :
 40      * <tag data-plugin='method: param, param; method:param...'/>
 41      * the function has to call every method of the plugin
 42      * passing it the node, and the given params
 43      * @private
 44      */
 45     applyPlugin = function applyPlugin(node, phrase, plugin) {
 46         // Split the methods
 47         phrase.split(";")
 48         .forEach(function (couple) {
 49             // Split the result between method and params
 50             var split = couple.split(":"),
 51             // Trim the name
 52             method = split[0].trim(),
 53             // And the params, if any
 54             params = split[1] ? split[1].split(",").map(trim) : [];
 55 
 56             // The first param must be the dom node
 57             params.unshift(node);
 58 
 59             if (_plugins[plugin] && _plugins[plugin][method]) {
 60                 // Call the method with the following params for instance :
 61                 // [node, "param1", "param2" .. ]
 62                 _plugins[plugin][method].apply(_plugins[plugin], params);
 63             }
 64 
 65         });
 66     };
 67 
 68     /**
 69      * Add a plugin
 70      *
 71      * Note that once added, the function adds a "plugins" property to the plugin.
 72      * It's an object that holds a name property, with the registered name of the plugin
 73      * and an apply function, to use on new nodes that the plugin would generate
 74      *
 75      * @param {String} name the name of the data that the plugin should look for
 76      * @param {Object} plugin the plugin that has the functions to execute
 77      * @returns true if plugin successfully added.
 78      */
 79     this.add = function add(name, plugin) {
 80         var that = this,
 81             propertyName = "plugins";
 82 
 83         if (typeof name == "string" && typeof plugin == "object" && plugin) {
 84             _plugins[name] = plugin;
 85 
 86             plugin[propertyName] = {
 87                     name: name,
 88                     apply: function apply() {
 89                         return that.apply.apply(that, arguments);
 90                     }
 91             };
 92             return true;
 93         } else {
 94             return false;
 95         }
 96     };
 97 
 98     /**
 99      * Add multiple plugins at once
100      * @param {Object} list key is the plugin name and value is the plugin
101      * @returns true if correct param
102      */
103     this.addAll = function addAll(list) {
104         return Tools.loop(list, function (plugin, name) {
105             this.add(name, plugin);
106         }, this);
107     };
108 
109     /**
110      * Get a previously added plugin
111      * @param {String} name the name of the plugin
112      * @returns {Object} the plugin
113      */
114     this.get = function get(name) {
115         return _plugins[name];
116     };
117 
118     /**
119      * Delete a plugin from the list
120      * @param {String} name the name of the plugin
121      * @returns {Boolean} true if success
122      */
123     this.del = function del(name) {
124         return delete _plugins[name];
125     };
126 
127     /**
128      * Apply the plugins to a NodeList
129      * @param {HTMLElement|SVGElement} dom the dom nodes on which to apply the plugins
130      * @returns {Boolean} true if the param is a dom node
131      */
132     this.apply = function apply(dom) {
133 
134         var nodes;
135 
136         if (DomUtils.isAcceptedType(dom)) {
137 
138             nodes = DomUtils.getNodes(dom);
139             Tools.loop(Tools.toArray(nodes), function (node) {
140                 Tools.loop(DomUtils.getDataset(node), function (phrase, plugin) {
141                     applyPlugin(node, phrase, plugin);
142                 });
143             });
144 
145             return dom;
146 
147         } else {
148             return false;
149         }
150     };
151 
152     this.addAll($plugins);
153 
154 };