diff --git a/ui (gen4)/features/base.js b/ui (gen4)/features/base.js index 5ed463e5..5761fd9e 100755 --- a/ui (gen4)/features/base.js +++ b/ui (gen4)/features/base.js @@ -1,6 +1,19 @@ /********************************************************************** * -* All the base features... +* Base features... +* +* Features: +* - base +* map to data and images +* - crop +* - tags +* - groups +* XXX experimental... +* +* Meta Features: +* - base-full +* combines the above features into one +* * * **********************************************************************/ @@ -20,35 +33,6 @@ var core = require('features/core') /*********************************************************************/ -// Helpers and meta stuff... - -// mode can be: -// "ribbon" - next marked in current ribbon (default) -// "all" - next marked in sequence -// -// XXX add support for tag lists... -var makeTagWalker = -module.makeTagWalker = -function(direction, dfl_tag){ - var meth = direction == 'next' ? 'nextImage' : 'prevImage' - - return function(tag, mode){ - mode = mode == null ? 'all' : mode - tag = tag || dfl_tag - - // account for no tags or no images tagged... - var lst = this.data.tags != null ? this.data.tags[tag] : [] - lst = lst || [] - - if(mode == 'ribbon'){ - this[meth](this.data.getImages(lst, 'current')) - - } else { - this[meth](lst) - } - } -} - // Generate an undo function for shift operations... // @@ -67,8 +51,7 @@ var undoShift = function(undo){ this[undo](a.args.length == 0 ? a.current : a.args[0]) }} - -/*********************************************************************/ +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // XXX split this into read and write actions... var BaseActions = @@ -759,6 +742,36 @@ module.Base = core.ImageGridFeatures.Feature({ //--------------------------------------------------------------------- // Tags... +// mode can be: +// "ribbon" - next marked in current ribbon (default) +// "all" - next marked in sequence +// +// XXX add support for tag lists... +var makeTagWalker = +module.makeTagWalker = +function(direction, dfl_tag){ + var meth = direction == 'next' ? 'nextImage' : 'prevImage' + + return function(tag, mode){ + mode = mode == null ? 'all' : mode + tag = tag || dfl_tag + + // account for no tags or no images tagged... + var lst = this.data.tags != null ? this.data.tags[tag] : [] + lst = lst || [] + + if(mode == 'ribbon'){ + this[meth](this.data.getImages(lst, 'current')) + + } else { + this[meth](lst) + } + } +} + + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + var TagsActions = module.TagsActions = actions.Actions({ // tags... @@ -1186,185 +1199,5 @@ core.ImageGridFeatures.Feature('base-full', [ -//--------------------------------------------------------------------- -// Journal... - -// XXX is this the right level for this??? -// ...data seems to be a better candidate... -// XXX would be great to add a mechanism define how to reverse actions... -// ...one way to do this at this point is to revert to last state -// and re-run the journal until the desired event... -// XXX need to define a clear journaling strategy in the lines of: -// - save state clears journal and adds a state load action -// - .load(..) clears journal -// XXX needs careful testing... -var Journal = -module.Journal = core.ImageGridFeatures.Feature({ - title: 'Action Journal', - - tag: 'system-journal', - - depends: [ - 'base' - ], - - actions: actions.Actions({ - - journal: null, - rjournal: null, - - journalable: null, - - updateJournalableActions: ['System/Update list of journalable actions', - function(){ - var that = this - - var handler = function(action){ - return function(){ - var cur = this.current - var args = args2array(arguments) - - return function(){ - this.journalPush({ - type: 'basic', - - action: action, - args: args, - // the current image before the action... - current: cur, - // the target (current) image after action... - target: this.current, - }) - } - } - } - - this.journalable = this.actions - .filter(function(action){ - return !!that.getAttr(action, 'undo') - || !!that.getAttr(action, 'journal') - }) - // reset the handler - .map(function(action){ - that - .off(action+'.pre', 'journal-handler') - .on(action+'.pre', 'journal-handler', handler(action)) - return action - }) - }], - - clone: [function(full){ - return function(res){ - res.rjournal = null - res.journal = null - if(full && this.hasOwnProperty('journal') && this.journal){ - res.journal = JSON.parse(JSON.stringify(this.journal)) - } - } - }], - - // XXX might be good to add some kind of metadata to journal... - journalPush: ['- System/Journal/Add an item to journal', - function(data){ - this.journal = (this.hasOwnProperty('journal') - || this.journal) ? - this.journal || [] - : [] - this.journal.push(data) - }], - clearJournal: ['System/Journal/Clear the action journal', - function(){ - if(this.journal){ - // NOTE: overwriting here is better as it will keep - // shadowing the parent's .journal in case we - // are cloned. - // NOTE: either way this will have no effect as we - // only use the local .journal but the user may - // get confused... - //delete this.journal - this.journal = null - } - }], - runJournal: ['- System/Journal/Run journal', - //{journal: true}, - function(journal){ - var that = this - journal.forEach(function(e){ - // load state... - that - .focusImage(e.current) - // run action... - [e.action].apply(that, e.args) - }) - }], - - // XXX need to clear the rjournal as soon as we do something... - // ...at this point it is really easy to mess things up by - // undoing something, and after some actions doing a - // .redoLast(..) - // XXX this is not ready for production... - undo: ['Edit/Undo', - {browseMode: function(){ - return (this.journal && this.journal.length > 0) || 'disabled' }}, - function(){ - var journal = this.journal - this.rjournal = (this.hasOwnProperty('rjournal') - || this.rjournal) ? - this.rjournal - : [] - - for(var i = journal.length-1; i >= 0; i--){ - var a = journal[i] - - // see if the actions has an explicit undo attr... - var undo = this.getAttr(a.action, 'undo') - - // general undo... - if(undo){ - this.focusImage(a.current) - - var undo = undo instanceof Function ? - // pass the action name... - undo.call(this, a) - : typeof(undo) == typeof('str') ? - // pass journal structure as-is... - this[undo].apply(this, a) - : null - - // pop the undo command... - this.journal.pop() - this.rjournal.push(journal.splice(i, 1)[0]) - break - } - } - }], - // XXX this is not final -- needs careful revision... - redo: ['Edit/Redo', - {browseMode: function(){ - return (this.rjournal && this.rjournal.length > 0) || 'disabled' }}, - function(){ - if(!this.rjournal || this.rjournal.length == 0){ - return - } - - this.runJournal([this.rjournal.pop()]) - }], - }), - - // XXX need to drop journal on save... - // XXX rotate/truncate journal??? - // XXX need to check that all the listed actions are clean -- i.e. - // running the journal will produce the same results as user - // actions that generated the journal. - handlers: [ - // log state, action and its args... - ['start', - function(){ this.updateJournalableActions() }], - ], -}) - - - - /********************************************************************** * vim:set ts=4 sw=4 : */ return module }) diff --git a/ui (gen4)/features/core.js b/ui (gen4)/features/core.js index b6ebc704..6b62f9b0 100755 --- a/ui (gen4)/features/core.js +++ b/ui (gen4)/features/core.js @@ -1,7 +1,31 @@ /********************************************************************** * -* Core features that setup the life-cycle and the base interfaces for -* features to use... +* Core features... +* Setup the life-cycle and the base interfaces for features to use... +* +* Defined here: +* - protocol action constructor +* - config value toggler constructor +* - meta actions +* - .isToggler(..) predicate +* - .preActionHandler(..) used to toggler special args +* - ImageGrid root object/constructor +* - ImageGridFeatures object +* +* +* Features: +* - lifecycle +* base life-cycle events (start/stop/..) +* - util +* - introspection +* - journal +* action journaling and undo/redo functionality +* XXX needs revision... +* - workspace +* XXX needs revision... +* - tasks +* XXX not yet used +* * * **********************************************************************/ @@ -333,6 +357,8 @@ module.notUserCallable = function(func){ } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + var IntrospectionActions = actions.Actions({ // user-callable actions... get useractions(){ @@ -356,6 +382,198 @@ module.Introspection = ImageGridFeatures.Feature({ +//--------------------------------------------------------------------- +// Journal... + +// XXX would be great to add a mechanism define how to reverse actions... +// ...one way to do this at this point is to revert to last state +// and re-run the journal until the desired event... +// XXX need to define a clear journaling strategy in the lines of: +// - save state clears journal and adds a state load action +// - .load(..) clears journal +// XXX needs careful testing... +var JournalActions = actions.Actions({ + + clone: [function(full){ + return function(res){ + res.rjournal = null + res.journal = null + if(full && this.hasOwnProperty('journal') && this.journal){ + res.journal = JSON.parse(JSON.stringify(this.journal)) + } + } + }], + + journal: null, + rjournal: null, + + journalable: null, + + updateJournalableActions: ['System/Update list of journalable actions', + function(){ + var that = this + + var handler = function(action){ + return function(){ + var cur = this.current + var args = args2array(arguments) + + return function(){ + this.journalPush({ + type: 'basic', + + action: action, + args: args, + // the current image before the action... + current: cur, + // the target (current) image after action... + target: this.current, + }) + } + } + } + + this.journalable = this.actions + .filter(function(action){ + return !!that.getAttr(action, 'undo') + || !!that.getAttr(action, 'journal') + }) + // reset the handler + .map(function(action){ + that + .off(action+'.pre', 'journal-handler') + .on(action+'.pre', 'journal-handler', handler(action)) + return action + }) + }], + + journalPush: ['- System/Journal/Add an item to journal', + function(data){ + // clear the reverse journal... + this.rjournal + && (this.rjournal = null) + + this.journal = (this.hasOwnProperty('journal') || this.journal) ? + this.journal || [] + : [] + this.journal.push(data) + }], + clearJournal: ['System/Journal/Clear the action journal', + function(){ + // NOTE: overwriting here is better as it will keep + // shadowing the parent's .journal in case we + // are cloned. + // NOTE: either way this will have no effect as we + // only use the local .journal but the user may + // get confused... + //delete this.journal + this.journal + && (this.journal = null) + this.rjournal + && (this.rjournal = null) + }], + runJournal: ['- System/Journal/Run journal', + //{journal: true}, + function(journal){ + var that = this + journal.forEach(function(e){ + // load state... + that + .focusImage(e.current) + // run action... + [e.action].apply(that, e.args) + }) + }], + + // XXX needs very careful revision... + // - should this be thread safe??? (likely not) + // - should the undo action have side-effects on the + // journal/rjournal or should we clean them out??? + // (currently cleaned) + undo: ['Edit/Undo', + {browseMode: function(){ + return (this.journal && this.journal.length > 0) || 'disabled' }}, + function(){ + var journal = this.journal.slice() || [] + + var rjournal = this.rjournal = + (this.hasOwnProperty('rjournal') || this.rjournal) ? + this.rjournal || [] + : [] + + for(var i = journal.length-1; i >= 0; i--){ + var a = journal[i] + + // see if the action has an explicit undo attr... + var undo = this.getAttr(a.action, 'undo') + + // general undo... + if(undo){ + // restore focus to where it was when the action + // was called... + this.focusImage(a.current) + + // call the undo method/action... + // NOTE: this is likely to have side-effect on the + // journal and maybe even rjournal... + // NOTE: these side-effects are cleaned out later. + var undo = undo instanceof Function ? + // pass the action name... + undo.call(this, a) + : typeof(undo) == typeof('str') ? + // pass journal structure as-is... + this[undo].apply(this, a) + : null + + // push the undone command to the reverse journal... + rjournal.push(journal.splice(i, 1)[0]) + + // restore journal state... + // NOTE: calling the undo action would have cleared + // the rjournal and added stuff to the journal + // so we will need to restore things... + this.journal = journal + this.rjournal = rjournal + + break + } + } + }], + redo: ['Edit/Redo', + {browseMode: function(){ + return (this.rjournal && this.rjournal.length > 0) || 'disabled' }}, + function(){ + if(!this.rjournal || this.rjournal.length == 0){ + return + } + + this.runJournal([this.rjournal.pop()]) + }], +}) + + +var Journal = +module.Journal = ImageGridFeatures.Feature({ + title: 'Action Journal', + + tag: 'journal', + + actions: JournalActions, + + // XXX need to drop journal on save... + // XXX rotate/truncate journal??? + // XXX need to check that all the listed actions are clean -- i.e. + // running the journal will produce the same results as user + // actions that generated the journal. + handlers: [ + // log state, action and its args... + ['start', + function(){ this.updateJournalableActions() }], + ], +}) + + + //--------------------------------------------------------------------- // Workspace... // @@ -421,7 +639,6 @@ module.makeWorkspaceConfigLoader = function(keys, callback){ } - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // XXX need a way to handle defaults... diff --git a/ui (gen4)/features/filesystem.js b/ui (gen4)/features/filesystem.js index ef2b6d4c..850db8e2 100755 --- a/ui (gen4)/features/filesystem.js +++ b/ui (gen4)/features/filesystem.js @@ -1034,11 +1034,9 @@ var CommentsActions = actions.Actions({ __comments: null, get comments(){ - return this.__comments - }, + return this.__comments }, set comments(value){ - this.__comments = value - }, + this.__comments = value }, }) var Comments = diff --git a/ui (gen4)/features/history.js b/ui (gen4)/features/history.js index ae05ba6f..9eac59d5 100755 --- a/ui (gen4)/features/history.js +++ b/ui (gen4)/features/history.js @@ -48,11 +48,9 @@ var URLHistoryActions = actions.Actions({ // NOTE: though functions are supported they are not recommended as // we can not stringify them to JSON... get url_history(){ - return this.hasOwnProperty('__url_history') ? this.__url_history : undefined - }, + return this.hasOwnProperty('__url_history') ? this.__url_history : undefined }, set url_history(value){ - this.__url_history = value - }, + this.__url_history = value }, clone: [function(full){ @@ -495,7 +493,7 @@ var URLHistoryUIActions = actions.Actions({ l++ }) - // empty history... + // history is empty... if(l == 0){ make('No history...', null, true) .find('.button').remove() diff --git a/ui (gen4)/features/meta.js b/ui (gen4)/features/meta.js index edf37864..ef59b9e4 100755 --- a/ui (gen4)/features/meta.js +++ b/ui (gen4)/features/meta.js @@ -52,7 +52,7 @@ core.ImageGridFeatures.Feature('viewer-testing', [ 'ui', 'keyboard', - 'ui-ribbons-placement', + //'ui-ribbons-placement', // features... 'ui-ribbon-auto-align', @@ -121,7 +121,7 @@ core.ImageGridFeatures.Feature('viewer-testing', [ 'ui-app-control', // XXX not yet fully tested... - 'system-journal', + 'journal', 'fail-safe-devtools', diff --git a/ui (gen4)/features/ui.js b/ui (gen4)/features/ui.js index 9044b450..2be7138e 100755 --- a/ui (gen4)/features/ui.js +++ b/ui (gen4)/features/ui.js @@ -1,5 +1,41 @@ /********************************************************************** * +* User Interface Features... +* +* Features: +* - ui +* maps ribbons to base (data + images) +* - config-local-storage +* maintain configuration state in local storage +* - ui-url-hash +* handle .location.hash +* - ui-ribbon-auto-align +* handle ribbon alignment... +* - ui-ribbon-align-to-order +* - ui-ribbon-align-to-first +* - ui-ribbon-manual-align +* - ui-animation +* manage UI non-css animations... +* - ui-autohide-cursor +* - ui-control +* control mechanics (touch/mouse) +* +* Dev Features: +* - fail-safe-devtools +* starts devtools if for some reason the main ui fails to start. +* +* Experimental Features: +* - ui-ribbons-placement +* manage different low level ribbon placement mechanics +* XXX experimental... +* - auto-single-image +* - auto-ribbon +* +* Legacy: +* - ui-clickable +* - ui-direct-control-hammer +* - ui-indirect-control +* * * **********************************************************************/ @@ -22,7 +58,6 @@ var base = require('features/base') /*********************************************************************/ - var reloadAfter = module.reloadAfter = function(force, callback){ @@ -2058,6 +2093,7 @@ var ControlActions = actions.Actions({ } })], + // XXX revise name... makeRibbonVisible: ['- Interface/Make ribbon visible if it is off screen', function(target, center_off_screen){ var r = this.ribbons.getRibbon(target)