From c66eb2e354d16cbe5278da9661256f011eeb45ba Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Thu, 5 Nov 2015 02:27:26 +0300 Subject: [PATCH] some refactoring and rework of feature logic... Signed-off-by: Alex A. Naanou --- ui (gen4)/lib/features.js | 132 +++++++++++++++++++++++++++++--------- ui (gen4)/viewer.js | 62 +++++++++--------- 2 files changed, 131 insertions(+), 63 deletions(-) diff --git a/ui (gen4)/lib/features.js b/ui (gen4)/lib/features.js index 856bb834..4338cfbe 100755 --- a/ui (gen4)/lib/features.js +++ b/ui (gen4)/lib/features.js @@ -230,6 +230,8 @@ Feature.prototype.constructor = Feature var FeatureSet = module.FeatureSet = { + __feature__: Feature, + // Build feature list... // // Build a list of all registered features @@ -283,6 +285,15 @@ module.FeatureSet = { // 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... buildFeatureList: function(obj, lst, auto_include, depth){ lst = lst == null ? Object.keys(this) : lst lst = lst.constructor !== Array ? [lst] : lst @@ -291,14 +302,14 @@ module.FeatureSet = { var that = this + 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){ - if(missing[d] == null){ - missing[d] = [] - } + missing[d] = missing[d] != null ? missing[d] : [] if(missing[d].indexOf(feature) < 0){ missing[d].push(feature) } @@ -306,39 +317,82 @@ module.FeatureSet = { return missing[d] == null }) } - var _sortDep = function(lst, missing){ - var res = [] - lst.forEach(function(n){ - var e = that[n] - // no dependencies... - if(e.depends == null || e.depends.length == 0){ - res.push(n) + var _sortDep = function(lst, missing, depth){ - } else { - // auto-include dependencies... - if(auto_include){ - var deps = e.depends + do { + var res = [] + var l = lst.length + + lst.forEach(function(n){ + var e = that[n] + + // no dependencies... + if(e.depends == null || e.depends.length == 0){ + res.push(n) - // skip dependencies that are not in list... } else { - var deps = _skipMissing(n, e.depends, missing) + // 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) } - // place dependencies before the depended... - res = res.concat(deps) - res.push(n) - } + }) + lst = res + depth -= 1 + } while(lst.length != l && depth > 0) - }) - return res + 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(e.suggested) + res = res.concat(_getSuggested(that, e, res, missing)) } res.push(n) }) @@ -346,14 +400,7 @@ module.FeatureSet = { // expand and sort dependencies... // 2+ times untill depth is 0 or length stabelizes... - var missing = {} - lst = _sortDep(lst, missing).unique() - var l - do { - l = lst.length - lst = _sortDep(lst, missing).unique() - depth -= 1 - } while(l != lst.length && depth > 0) + lst = _sortDep(lst, missing, depth).unique() // sort features via priority keeping the order as close to // manual as possible... @@ -369,9 +416,14 @@ module.FeatureSet = { // 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 -- drom the table... + // 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() + // clasify features... var unapplicable = [] var conflicts = {} @@ -392,6 +444,16 @@ module.FeatureSet = { return true } + // mark feature unapplicable if it depends on an unapplicable... + // 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 + }).length > 0){ + unapplicable.push(n) + return false + } + // keep only conflicting... var deps = e.depends.filter(function(dep){ dep = lst.indexOf(dep) @@ -512,6 +574,12 @@ module.FeatureSet = { } }) }, + + // shorthand for: Feature(, ...) + // XXX should this return this? + Feature: function(){ + return this.__feature__.apply(null, [this].concat(args2array(arguments))) + }, } diff --git a/ui (gen4)/viewer.js b/ui (gen4)/viewer.js index 5f723fa7..b0b5ffb8 100755 --- a/ui (gen4)/viewer.js +++ b/ui (gen4)/viewer.js @@ -1293,13 +1293,11 @@ actions.Actions({ }) var Viewer = -module.Viewer = features.Feature(ImageGridFeatures, { +module.Viewer = ImageGridFeatures.Feature({ title: 'Graphical User Interface', tag: 'ui', - priority: 'high', - config: { // The maximum screen width allowed when zooming... 'max-screen-images': 30, @@ -1316,6 +1314,13 @@ module.Viewer = features.Feature(ImageGridFeatures, { }, actions: ViewerActions, + + // check if we are running in a UI context... + // NOTE: this will prevent loading of any features dependant on the + // UI in a non UI context... + isApplicable: function(){ + return typeof(window) == typeof({}) + }, }) @@ -1332,7 +1337,7 @@ module.Viewer = features.Feature(ImageGridFeatures, { // - .load(..) clears journal // XXX needs careful testing... var Journal = -module.Journal = features.Feature(ImageGridFeatures, { +module.Journal = ImageGridFeatures.Feature({ title: 'Action Journal', tag: 'system-journal', @@ -1558,7 +1563,7 @@ var PartialRibbonsActions = actions.Actions({ // - shift image up // XXX The two should be completely independent.... (???) var PartialRibbons = -module.PartialRibbons = features.Feature(ImageGridFeatures, { +module.PartialRibbons = ImageGridFeatures.Feature({ title: 'Partial Ribbons', doc: 'Maintains partially loaded ribbons, this enables very lage ' +'image sets to be hadled eficiently.', @@ -1704,7 +1709,7 @@ function updateImageProportions(){ // // var SingleImageView = -module.SingleImageView = features.Feature(ImageGridFeatures, { +module.SingleImageView = ImageGridFeatures.Feature({ title: '', doc: '', @@ -1763,7 +1768,7 @@ module.SingleImageView = features.Feature(ImageGridFeatures, { // XXX should .alignByOrder(..) be a feature-specific action or global // as it is now??? var AlignRibbonsToImageOrder = -module.AlignRibbonsToImageOrder = features.Feature(ImageGridFeatures, { +module.AlignRibbonsToImageOrder = ImageGridFeatures.Feature({ title: '', doc: '', @@ -1778,7 +1783,7 @@ module.AlignRibbonsToImageOrder = features.Feature(ImageGridFeatures, { var AlignRibbonsToFirstImage = -module.AlignRibbonsToFirstImage = features.Feature(ImageGridFeatures, { +module.AlignRibbonsToFirstImage = ImageGridFeatures.Feature({ title: '', doc: '', @@ -1797,7 +1802,7 @@ module.AlignRibbonsToFirstImage = features.Feature(ImageGridFeatures, { // XXX at this point this does not support target lists... var ShiftAnimation = -module.ShiftAnimation = features.Feature(ImageGridFeatures, { +module.ShiftAnimation = ImageGridFeatures.Feature({ title: '', doc: '', @@ -1883,7 +1888,7 @@ function didAdvance(indicator){ } var BoundsIndicators = -module.BoundsIndicators = features.Feature(ImageGridFeatures, { +module.BoundsIndicators = ImageGridFeatures.Feature({ title: '', doc: '', @@ -2042,7 +2047,7 @@ var CurrentImageIndicatorActions = actions.Actions({ }) var CurrentImageIndicator = -module.CurrentImageIndicator = features.Feature(ImageGridFeatures, { +module.CurrentImageIndicator = ImageGridFeatures.Feature({ title: '', doc: '', @@ -2143,7 +2148,7 @@ module.CurrentImageIndicator = features.Feature(ImageGridFeatures, { var CurrentImageIndicatorHideOnFastScreenNav = -module.CurrentImageIndicatorHideOnFastScreenNav = features.Feature(ImageGridFeatures, { +module.CurrentImageIndicatorHideOnFastScreenNav = ImageGridFeatures.Feature({ title: '', doc: '', @@ -2208,7 +2213,7 @@ module.CurrentImageIndicatorHideOnFastScreenNav = features.Feature(ImageGridFeat }) var CurrentImageIndicatorHideOnScreenNav = -module.CurrentImageIndicatorHideOnScreenNav = features.Feature(ImageGridFeatures, { +module.CurrentImageIndicatorHideOnScreenNav = ImageGridFeatures.Feature({ title: '', doc: '', @@ -2249,7 +2254,7 @@ module.CurrentImageIndicatorHideOnScreenNav = features.Feature(ImageGridFeatures // XXX var ImageStateIndicator = -module.ImageStateIndicator = features.Feature(ImageGridFeatures, { +module.ImageStateIndicator = ImageGridFeatures.Feature({ title: '', doc: '', @@ -2263,7 +2268,7 @@ module.ImageStateIndicator = features.Feature(ImageGridFeatures, { // XXX var GlobalStateIndicator = -module.GlobalStateIndicator = features.Feature(ImageGridFeatures, { +module.GlobalStateIndicator = ImageGridFeatures.Feature({ title: '', doc: '', @@ -2463,7 +2468,7 @@ var ActionTreeActions = actions.Actions({ }) var ActionTree = -module.ActionTree = features.Feature(ImageGridFeatures, { +module.ActionTree = ImageGridFeatures.Feature({ title: '', doc: '', @@ -2496,7 +2501,7 @@ module.ActionTree = features.Feature(ImageGridFeatures, { // XXX need to get the minimal size and not the width as results will // depend on viewer format... var AutoSingleImage = -module.AutoSingleImage = features.Feature(ImageGridFeatures, { +module.AutoSingleImage = ImageGridFeatures.Feature({ title: '', doc: '', @@ -2655,7 +2660,7 @@ var ImageMarkActions = actions.Actions({ // NOTE: this is usable without ribbons... var ImageMarks = -module.ImageMarks = features.Feature(ImageGridFeatures, { +module.ImageMarks = ImageGridFeatures.Feature({ title: '', doc: '', @@ -2717,7 +2722,7 @@ var ImageBookmarkActions = actions.Actions({ // NOTE: this is usable without ribbons... var ImageBookmarks = -module.ImageBookmarks = features.Feature(ImageGridFeatures, { +module.ImageBookmarks = ImageGridFeatures.Feature({ title: '', doc: '', @@ -2767,7 +2772,7 @@ var AppControlActions = actions.Actions({ // XXX this needs a better .isApplicable(..) var AppControl = -module.AppControl = features.Feature(ImageGridFeatures, { +module.AppControl = ImageGridFeatures.Feature({ title: '', doc: '', @@ -2789,7 +2794,7 @@ module.AppControl = features.Feature(ImageGridFeatures, { //--------------------------------------------------------------------- // XXX at this point this is a stub... var FileSystemLoader = -module.FileSystemLoader = features.Feature(ImageGridFeatures, { +module.FileSystemLoader = ImageGridFeatures.Feature({ title: '', doc: '', @@ -2812,7 +2817,7 @@ module.FileSystemLoader = features.Feature(ImageGridFeatures, { // - editor - editing capability // -features.Feature(ImageGridFeatures, 'viewer-testing', [ +ImageGridFeatures.Feature('viewer-testing', [ 'ui', // features... @@ -2844,12 +2849,7 @@ features.Feature(ImageGridFeatures, 'viewer-testing', [ 'system-journal', ]) -features.Feature(ImageGridFeatures, 'commandline', [ - 'image-marks', - 'image-bookmarks', -]) - -features.Feature(ImageGridFeatures, 'viewer-minimal', [ +ImageGridFeatures.Feature('viewer-minimal', [ 'ui', 'ui-ribbon-align-to-order', 'ui-animation', @@ -2860,11 +2860,11 @@ features.Feature(ImageGridFeatures, 'viewer-minimal', [ 'ui-action-tree', ]) -features.Feature(ImageGridFeatures, 'viewer', [ +ImageGridFeatures.Feature('viewer', [ 'viewer-minimal', ]) -features.Feature(ImageGridFeatures, 'viewer-partial', [ +ImageGridFeatures.Feature('viewer-partial', [ 'viewer', 'ui-partial-ribbons', ]) @@ -2883,7 +2883,7 @@ var ExperimentActions = actions.Actions({ }) var ExperimentFeature = -module.ExperimentFeature = features.Feature(ImageGridFeatures, { +module.ExperimentFeature = ImageGridFeatures.Feature({ title: '', doc: '',