refactoring of feature loading, now meta features are supported...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2014-12-08 17:37:29 +03:00
parent 2c196bc507
commit dfce671fff
3 changed files with 86 additions and 65 deletions

View File

@ -190,40 +190,56 @@ module.FeatureSet = {
// e.g. a -> b but a has a higher priority that b thus // e.g. a -> b but a has a higher priority that b thus
// making it impossible to order the two without // making it impossible to order the two without
// breaking either the dependency or priority ordering. // breaking either the dependency or priority ordering.
buildFeatureList: function(obj, lst){ //
lst = lst == null ? Object.keys(this) : lst //
lst = lst.constructor !== Array ? [lst] : lst // Dependency sorting:
var that = this
// sort dependencies...
// //
// These are order dependencies, i.e. for a dependency to be // These are order dependencies, i.e. for a dependency to be
// resolved it must satisfy ALL of the folowing: // resolved it must satisfy ALL of the folowing:
// - all dependencies must exist in the list. // - all dependencies must exist in the list.
// - all dependencies must be positiond/setup before the // - all dependencies must be positiond/setup before the dependant.
// dependant.
// //
// The general algorithm is as folows: // The general algorithm is as folows:
// 1) place the dependencies befeore the dependant for each // 1) place the dependencies befeore the dependant for each element
// element // 2) remove the duplicate features except fot the first occurance
// 2) remove the duplicate features except fot the first // 3) repeat 1 and 2 for 2 to depth times or until the feature list
// occurance // stabelizes, i.e. no new features are added on the last run.
// 3) repeat 1 and 2 for a second time to cover 2'nd gen
// dependencies...
// //
// NOTE: recursice dependency expansion is not needed here as if // NOTE: if auto_include is true (default) this will add dependencies
// a dependency is not included in the list then it is not // as they are needed...
// needed... // This is useful for "meta-features" that do nothing other than
// NOTE: stage 2 is done later when filtering the list... // depend/include sets of other features, for exmale: 'ui',
// NOTE: if dependency errors/conflicts exist this will break at // 'core', 'browser', ...etc.
// the next step. // NOTE: dependency chains larger than depth will be dropped, this
// NOTE: conflicta that can occur and can not be recovered from: // can be fixed by setting a greater depth (default: 8)...
// NOTE: conflicts that can occur and can not be recovered from:
// - cyclic dependency // - cyclic dependency
// X will be before one of its dependencies... // X will be before one of its dependencies...
// - dependency / priority conflict // - dependency / priority conflict
// X will have higher priority than one of its // X will have higher priority than one of its dependencies...
// dependencies... buildFeatureList: function(obj, lst, auto_include, depth){
lst = lst == null ? Object.keys(this) : lst
lst = lst.constructor !== Array ? [lst] : lst
auto_include = auto_include == null ? true : false
depth = depth || 8
var that = this
// 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] = []
}
if(missing[d].indexOf(feature) < 0){
missing[d].push(feature)
}
}
return missing[d] == null
})
}
var _sortDep = function(lst, missing){ var _sortDep = function(lst, missing){
var res = [] var res = []
lst.forEach(function(n){ lst.forEach(function(n){
@ -233,22 +249,15 @@ module.FeatureSet = {
res.push(n) res.push(n)
} else { } else {
// auto-include dependencies...
if(auto_include){
var deps = e.depends
// skip dependencies that are not in list... // skip dependencies that are not in list...
var deps = e.depends.filter(function(d){ } else {
if(lst.indexOf(d) < 0){ var deps = _skipMissing(n, e.depends, missing)
if(missing[d] == null){
missing[d] = []
} }
if(missing[d].indexOf(n) < 0){
missing[d].push(n)
}
return false
}
return true
})
// place dependencies before the depended... // place dependencies before the depended...
res = res.concat(deps) res = res.concat(deps)
res.push(n) res.push(n)
@ -258,19 +267,21 @@ module.FeatureSet = {
return res return res
} }
// expand and sort dependencies...
// 2+ times untill depth is 0 or length stabelizes...
var missing = {} var missing = {}
// sort twice to cover the dependencies of dependencies... lst = _sortDep(lst, missing).unique()
// ...if this does not work we give up ;) var l
lst = _sortDep(lst, missing) do {
lst = _sortDep(lst, missing) l = lst.length
lst = _sortDep(lst, missing).unique()
depth -= 1
} while(l != lst.length && depth > 0)
// sort features via priority keeping the order as close to // sort features via priority keeping the order as close to
// manual as possible... // manual as possible...
var l = lst.length var l = lst.length
lst = lst lst = lst
// remove duplicates, keeping only the first occurance...
//.filter(function(e, i, l){ return l.indexOf(e) == i })
.unique()
// remove undefined and non-features... // remove undefined and non-features...
.filter(function(e){ return that[e] != null .filter(function(e){ return that[e] != null
&& that[e] instanceof Feature }) && that[e] instanceof Feature })
@ -311,14 +322,17 @@ module.FeatureSet = {
}) })
// skip missing dependencies... // skip missing dependencies...
deps = deps.filter(function(d){ return missing[d] == null }) // 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... // no conflicts...
if(deps.length == 0){ if(deps.length == 0){
return true return true
} }
// can't fix... // dependency exists but in wrong order -- can't fix...
conflicts[n] = deps conflicts[n] = deps
return false return false

View File

@ -217,12 +217,12 @@ $(function(){
'ui-single-image-view', 'ui-single-image-view',
'ui-partial-ribbons', 'ui-partial-ribbons',
'image-marks',
'image-bookmarks',
'fs-loader', 'fs-loader',
'app-control', 'app-control',
// ui elements...
'image-marks',
'image-bookmarks',
// chrome... // chrome...
'ui-animation', 'ui-animation',
@ -258,7 +258,6 @@ $(function(){
//.syncTags() //.syncTags()
a.setEmptyMsg( a.setEmptyMsg(
'Nothing loaded...', 'Nothing loaded...',
'Press \'O\' to load, \'F1\' for help or \'?\' for keyboard mappings.') 'Press \'O\' to load, \'F1\' for help or \'?\' for keyboard mappings.')

View File

@ -2156,7 +2156,7 @@ function makeTagTogglerAction(tag){
} }
// XXX add image updater... // XXX .toggleMarkBlock(..) not done yet...
var ImageMarkActions = actions.Actions({ var ImageMarkActions = actions.Actions({
// a shorthand... // a shorthand...
@ -2217,6 +2217,7 @@ var ImageMarkActions = actions.Actions({
}) })
// NOTE: this is usable without ribbons...
var ImageMarks = var ImageMarks =
module.ImageMarks = features.Feature(ImageGridFeatures, { module.ImageMarks = features.Feature(ImageGridFeatures, {
title: '', title: '',
@ -2229,11 +2230,14 @@ module.ImageMarks = features.Feature(ImageGridFeatures, {
handlers: [ handlers: [
// XXX is this the right way to go??? // XXX is this the right way to go???
['updateImage', function(gid, img){ ['updateImage', function(gid, img){
// update only when ribbons are preset...
if(this.ribbons != null){
if(this.toggleMark(gid, '?') == 'on'){ if(this.toggleMark(gid, '?') == 'on'){
this.ribbons.toggleImageMark(gid, 'selected', 'on') this.ribbons.toggleImageMark(gid, 'selected', 'on')
} else { } else {
this.ribbons.toggleImageMark(gid, 'selected', 'off') this.ribbons.toggleImageMark(gid, 'selected', 'off')
} }
}
}], }],
], ],
}) })
@ -2275,6 +2279,7 @@ var ImageBookmarkActions = actions.Actions({
}) })
// NOTE: this is usable without ribbons...
var ImageBookmarks = var ImageBookmarks =
module.ImageBookmarks = features.Feature(ImageGridFeatures, { module.ImageBookmarks = features.Feature(ImageGridFeatures, {
title: '', title: '',
@ -2287,11 +2292,14 @@ module.ImageBookmarks = features.Feature(ImageGridFeatures, {
handlers: [ handlers: [
// XXX is this the right way to go??? // XXX is this the right way to go???
['updateImage', function(gid, img){ ['updateImage', function(gid, img){
// update only when ribbons are preset...
if(this.ribbons != null){
if(this.toggleBookmark(gid, '?') == 'on'){ if(this.toggleBookmark(gid, '?') == 'on'){
this.ribbons.toggleImageMark(gid, 'bookmark', 'on') this.ribbons.toggleImageMark(gid, 'bookmark', 'on')
} else { } else {
this.ribbons.toggleImageMark(gid, 'bookmark', 'off') this.ribbons.toggleImageMark(gid, 'bookmark', 'off')
} }
}
}], }],
], ],
}) })