diff --git a/ui (gen4)/lib/features.js b/ui (gen4)/lib/features.js index 23b43d89..df99833f 100755 --- a/ui (gen4)/lib/features.js +++ b/ui (gen4)/lib/features.js @@ -248,330 +248,6 @@ var FeatureSetProto = { && that[e] instanceof Feature }) }, - - /* - // Build feature list... - // - // Build a list of all registered features - // .buildFeatureList() - // .buildFeatureList(actions) - // -> list - // - // Build a list of given features - // .buildFeatureList(null, list) - // .buildFeatureList(actions, list) - // -> list - // - // - // NOTE: some feature .isApplicable(..) may expect the action set thus - // making it required for building a feature list. - // NOTE: this will try and keep the order as close as possible to the - // original as possible, this if the list is correctly ordered - // it will not be affected... - // NOTE: this will fix most dependency ordering errors except for two: - // - cyclic dependencies - // e.g. a -> b and b -> a, here there is no way to reorder - // a and b to resolve this. - // - dependency / priority conflict - // e.g. a -> b but a has a higher priority that b thus - // making it impossible to order the two without - // breaking either the dependency or priority ordering. - // - // - // Forcing a feature disabled: - // - // If a feature is indicated with a leading '-' then it is forced - // disabled and will not load. - // Disabled features are treated in the same way as inaplicable - // features. - // - // - // Dependency sorting: - // - // These are order dependencies, i.e. for a dependency to be - // resolved it must satisfy ALL of the folowing: - // - all dependencies must exist in the list. - // - all dependencies must be positiond/setup before the dependant. - // - // The general algorithm is as folows: - // 1) place the dependencies befeore the dependant for each element - // 2) remove the duplicate features except fot the first occurance - // 3) repeat 1 and 2 for 2 to depth times or until the feature list - // stabelizes, i.e. no new features are added on the last run. - // - // NOTE: if auto_include is true (default) this will add dependencies - // as they are needed... - // This is useful for "meta-features" that do nothing other than - // depend/include sets of other features, for exmale: 'ui', - // 'core', 'browser', ...etc. - // NOTE: dependency chains larger than depth will be dropped, this - // can be fixed by setting a greater depth (default: 8)... - // NOTE: conflicts that can occur and can not be recovered from: - // - cyclic dependency - // X will be before one of its dependencies... - // - dependency / priority conflict - // X will have higher priority than one of its dependencies... - // NOTE: feature that depend in unapplicable features are considered - // unapplicable. - // XXX not sure if this is 100% correct... - // NOTE: child high priority features will push their dependencies up - // to precede them. - // ...this will not resolve all the possible conflicts so be - // careful. - // - // XXX make suggested feature expansion recursive... - // XXX this appears to be very slow if lst not passed... - // XXX add ability to remove features by prefixing a '-' to its name - // ...if one - is present, remove all instances of - // - // XXX .buildFeatureList() is slow and can be a bottleneck for large - // numbers of features... might be a good idea to take a look at - // this sometime... - _buildFeatureList: function(obj, lst, auto_include, depth){ - var that = this - obj = obj || {} - - lst = lst == null ? this.features : lst - lst = lst.constructor !== Array ? [lst] : lst - - auto_include = auto_include == null ? true : false - depth = depth || 8 - - - var missing = {} - - // helpers... - // NOTE: _skipMissing(..) will add missing dependencies to missing... - var _skipMissing = function(feature, deps, missing){ - return deps.filter(function(d){ - if(lst.indexOf(d) < 0){ - missing[d] = missing[d] != null ? missing[d] : [] - if(missing[d].indexOf(feature) < 0){ - missing[d].push(feature) - } - } - return missing[d] == null - }) - } - var _sortDep = function(lst, missing, depth){ - - do { - var res = [] - var l = lst.length - - lst.forEach(function(n){ - var e = that[n] - - if(!e){ - //console.warn('%s: feature is not loaded.', n) - // XXX should we break here??? - throw (n + ': feature is not loaded.') - - // no dependencies... - } else if(e.depends == null || e.depends.length == 0){ - res.push(n) - - } else { - // auto-include dependencies... - if(auto_include){ - var deps = e.depends - - // skip dependencies that are not in list... - } else { - var deps = _skipMissing(n, e.depends, missing) - } - - // place dependencies before the depended... - res = res.concat(deps) - res.push(n) - } - }) - lst = res - depth -= 1 - } while(lst.length != l && depth > 0) - - return lst - } - var _getSuggested = function(featureset, feature, suggested, missing){ - suggested = suggested || [] - - var s = (feature.suggested || []) - - s - // remove the already visited suggenstions... - .filter(function(e){ return suggested.indexOf(e) < 0 }) - // add unloaded features to missing... - .filter(function(e){ - if(featureset[e] == null){ - missing[e] = missing[e] != null ? missing[e] : [] - if(missing[e].indexOf(feature.tag) < 0){ - missing[e].push(feature.tag) - } - return false - } - return true - }) - // load new suggenstions... - .forEach(function(n){ - var e = featureset[n] - if(e != null && e.suggested != null){ - suggested = suggested - .concat(_getSuggested(featureset, e, suggested, missing)) - .unique() - } - suggested.push(n) - }) - - return suggested - } - - // expand optional "suggested" features... - // XXX make this recursive... - var res = [] - lst.forEach(function(n){ - var e = that[n] - if(e != null && e.suggested != null){ - //res = res.concat(e.suggested) - res = res.concat(_getSuggested(that, e, res, missing)) - } - res.push(n) - }) - lst = res - - // expand and sort dependencies... - // 2+ times untill depth is 0 or length stabelizes... - lst = _sortDep(lst, missing, depth).unique() - - // sort features via priority keeping the order as close to - // manual as possible... - var l = lst.length - lst = lst - // remove undefined and non-features... - .filter(function(e){ - return that[e] != null && that[e] instanceof Feature }) - // build the sort table: [ , , ] - // NOTE: is element number from the tail... - .map(function(e, i){ return [ -that[e].getPriority(), i, e ] }) - // do the sort... - // NOTE: for some reason JS compares lists as strings so we - // have to comare the list manually... - .sort(function(a, b){ return a[0] - b[0] || a[1] - b[1] }) - // cleanup -- drop the table... - .map(function(e){ return e[2] }) - - // sort dependencies again... - // NOTE: this bubles the "priority" up the dependency tree... - // NOTE: this will not resolve all the conflicts... - lst = _sortDep(lst, missing, depth).unique() - - // get disabled features... - var disabled = [] - Object.keys(missing).forEach(function(n){ - if(n[0] == '-'){ - delete missing[n] - disabled.push(n.slice(1)) - } - }) - - // clasify features... - var unapplicable = [] - var conflicts = {} - var that = this - lst = lst.filter(function(n, i){ - var e = that[n] - if(e == null){ - return true - } - - // disabled... - if(disabled.indexOf(n) >= 0){ - return false - } - - // check applicability... - if(e.isApplicable && !e.isApplicable.call(that, obj)){ - unapplicable.push(n) - return false - } - - // no dependencies... - if(e.depends == null || e.depends.length == 0){ - return true - } - - // mark feature unapplicable if it depends on an unapplicable - // or a disabled... - // NOTE: we need to do this once as features at this point - // are sorted by dependencies... - if(e.depends.filter(function(dep){ - return unapplicable.indexOf(dep) > -1 - || disabled.indexOf(dep) > -1 - }).length > 0){ - unapplicable.push(n) - return false - } - - // keep only conflicting... - var deps = e.depends.filter(function(dep){ - dep = lst.indexOf(dep) - return dep == -1 || dep > i - }) - - // skip missing dependencies... - // NOTE: we need to check for missing again as a feature - // could have been removed due to inapplicability or - // being undefined... - deps = _skipMissing(n, deps, missing) - - // no conflicts... - if(deps.length == 0){ - return true - } - - // dependency exists but in wrong order -- can't fix... - conflicts[n] = deps - - return false - }) - - // skip duplicate exclusive features... - var exclusive = [] - var excluded = [] - lst = lst.filter(function(n){ - var e = that[n] - if(e == null || e.exclusive == null ){ - return true - } - // count the number of exclusive features already present... - var res = e.exclusive - .filter(function(n){ - if(exclusive.indexOf(n) < 0){ - exclusive.push(n) - return false - } - return true - }) - .length == 0 - - if(!res){ - excluded.push(n) - } - - return res - }) - - return { - features: lst, - disabled: disabled, - excluded: excluded, - missing: missing, - conflicts: conflicts, - unapplicable: unapplicable, - } - }, - //*/ - - // Build list of features... // // Build list of all features for an empty object...