1 // The Antville Project
  2 // http://code.google.com/p/antville
  3 //
  4 // Copyright 2007-2011 by Tobi Schäfer.
  5 //
  6 // Copyright 2001–2007 Robert Gaggl, Hannes Wallnöfer, Tobi Schäfer,
  7 // Matthias & Michael Platzer, Christoph Lincke.
  8 //
  9 // Licensed under the Apache License, Version 2.0 (the ``License'');
 10 // you may not use this file except in compliance with the License.
 11 // You may obtain a copy of the License at
 12 //
 13 //    http://www.apache.org/licenses/LICENSE-2.0
 14 //
 15 // Unless required by applicable law or agreed to in writing, software
 16 // distributed under the License is distributed on an ``AS IS'' BASIS,
 17 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 18 // See the License for the specific language governing permissions and
 19 // limitations under the License.
 20 //
 21 // $Revision$
 22 // $Author$
 23 // $Date$
 24 // $URL$
 25 
 26 /**
 27  * @fileoverview Defines the Feature prototype.
 28  * Another trial to implement modular features.
 29  */
 30 
 31 /**
 32  * Renders the main() method of a feature, if available.
 33  * @param {Object} param The default Helma macro parameter object
 34  * @param {String} id The identifier of the desired feature.
 35  */
 36 global.feature_macro = function(param, id) {
 37    var func, feature = Feature.get(id);
 38    if (feature && (func = feature.main)) {
 39       func.constructor === Function && func(param);
 40    }
 41    return;
 42 }
 43 
 44 /**
 45  * @constructor
 46  * @property {String} id The feature’s unique identifier.
 47  * @param {String} id A unique identifier for the feature.
 48  * @param {String} url The URL of the website providing further information about the feature.
 49  * @param {Object} feature The initial properties of the feature.
 50  */
 51 var Feature = function(id, url, feature) {
 52    var self = this;
 53 
 54    this.__defineGetter__("id", function() {return id});
 55 
 56    for (let i in feature) {
 57       this[i] = feature[i];
 58    }
 59 
 60    this.toString = function() {
 61       return "[Feature: " + html.linkAsString({href: url}, id) + "]";
 62    }
 63 
 64    return this;
 65 }
 66 
 67 /**
 68  * Adds a feature to the registry.
 69  * @see Feature
 70  * @returns {Feature}
 71  */
 72 Feature.add = function(id, url, feature) {
 73    if (!id || !url) {
 74       throw Error("Insufficient arguments");
 75    }
 76 
 77    var existingFeature = Feature.get(id);
 78    if (existingFeature) {
 79       app.log("Warning! Overwriting already present feature with ID " + id);
 80       Feature.remove(existingFeature);
 81    }
 82 
 83    Feature.list().push(new Feature(id, url, feature));
 84    return this;
 85 }
 86 
 87 /**
 88  * Removes a feature from the registry.
 89  * @param {Feature} feature The feature object to be removed.
 90  * @returns {Number} The resulting number of features still in the registry.
 91  */
 92 Feature.remove = function(feature) {
 93    var features = Feature.list();
 94    if (feature === "*") {
 95       features.length = 0;
 96    } else if (feature) {
 97       var index = features.indexOf(feature);
 98       (index > -1) && features.splice(index, 1);
 99    }
100    return features.length;
101 }
102 
103 /**
104  * Lists all available features in the registry.
105  * @returns {Feature[]}
106  */
107 Feature.list = function() {
108    return app.data.features;
109 }
110 
111 /**
112  * Retrieves a feature from the registry.
113  * @param {String} id The identifier of the desired feature.
114  * @returns {Feature}
115  */
116 Feature.get = function(id) {
117    for each (let feature in Feature.list()) {
118       if (feature.id === id) {
119          return feature;
120       }
121    }
122    return;
123 }
124 
125 /**
126  * Invokes a (callback) function for a feauture.
127  * @param {String} id The identifier of the desired feature. '*' can be used to address all available features.
128  * @param {Function|String} callback The callback function or the name of method of the feature.
129  * @returns {Object}
130  */
131 Feature.invoke = function(id, callback) {
132    id || (id = "*");
133    if (callback) {
134       var feature, method, result;
135       var args = Array.prototype.slice.call(arguments, 2);
136       if (id === "*") {
137          for each (feature in Feature.list()) {
138             method = feature[String(callback)];
139             if (method && method.constructor === Function) {
140                result = method.apply(feature, args);
141             }
142          }
143       } else {
144          feature = Feature.get(id);
145          if (feature) {
146             if (callback.constructor === Function) {
147                result = callback.apply(feature, args);
148             } else {
149                method = feature[callback];
150                if (method && method.constructor === Function) {
151                   result = method.apply(feature, args);
152                }
153             }
154          }
155       }
156    }
157    return result;
158 }
159 
160 /**
161  * Wrapper for the Feature._getPermission method. All registered features will be evaluated.
162  * @param {String} action The desired action to be invoked.
163  * @returns {Boolean}
164  */
165 Feature.getPermission = function(action) {
166    for each (let feature in Feature.list()) {
167       let method = feature._getPermission;
168       if (method && method.constructor === Function && method.call(this, action)) {
169          return true;
170       }
171    }
172    return false;
173 }