      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 }