reworked system caches...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-11-27 23:11:10 +03:00
parent 026ff53ab2
commit d77c01e63e
7 changed files with 304 additions and 203 deletions

View File

@ -1806,9 +1806,19 @@ module.Crop = core.ImageGridFeatures.Feature({
tag: 'crop', tag: 'crop',
depends: [ depends: [
'base', 'base',
//'cache',
], ],
actions: CropActions, actions: CropActions,
handlers: [
[[
'crop',
'uncrop',
'removeFromCrop',
],
'clearCache: "view(-.*)?" "*" -- Clear view cache'],
],
}) })

View File

@ -1779,6 +1779,13 @@ module.Collection = core.ImageGridFeatures.Feature({
// XXX // XXX
}) })
}], }],
// invalidate caches...
[[
'loadCollection',
'uncollect',
],
'clearCache: "view(-.*)?" "*" -- Clear view cache'],
], ],
}) })

View File

@ -1027,9 +1027,21 @@ module.Serialization = ImageGridFeatures.Feature({
// Cache... // Cache...
// XXX should this be in actions.js??? // XXX should this be in actions.js???
// XXX should we invalidate the cache automatically??? // XXX revise: cache group naming...
// XXX the cache can also be saved to localStorage and loaded until either // currently the used groups are:
// the version changes or the feature list... // Session groups -- cleared on .clear() ('cache')
// session-*
// view-*
// View groups -- cleared by crop/collection ('crop', 'collections')
// view-*
// Changes groups -- cleared when specific changes are made ('changes')
// *-data
// *-images
// ...
// This approach seems not flexible enough...
// Ideas:
// - use keywords in group names??
// XXX should we consider persistent caches -- localStorage???
var CacheActions = actions.Actions({ var CacheActions = actions.Actions({
config: { config: {
// Enable/disable caching... // Enable/disable caching...
@ -1062,11 +1074,30 @@ var CacheActions = actions.Actions({
// action is available... // action is available...
'pre-cache-progress': 3000, 'pre-cache-progress': 3000,
// Groups to be cleared at the longest on session change...
//
// These include by default:
// 'session' - will live through the whole session.
// 'view' - cleared when view changes
//
'cache-session-groups': [
'session',
'view',
],
// XXX handler cache.. // XXX handler cache..
}, },
// Cache utility method... // Cache utility method...
// //
// .cache(title, handler)
// -> value
//
// .cache(group, title, handler)
// -> value
//
//
// Example use: // Example use:
// someAction: [ // someAction: [
// function(){ // function(){
@ -1086,18 +1117,106 @@ var CacheActions = actions.Actions({
// return data // return data
// }) }], // }) }],
// //
cache: function(title, lister){ // XXX what should the default group be???
// XXX should this be an action???
__cache: null,
cache: function(title, handler){
var group = 'global'
// caching disabled...
if(!(this.config || {}).cache){ if(!(this.config || {}).cache){
return lister.call(this) return handler.call(this) }
} arguments.length > 2
&& ([group, title, handler] = arguments)
var cache = this.__cache = this.__cache || {} var cache = this.__cache = this.__cache || {}
cache = cache[group] = cache[group] || {}
return (cache[title] = return (cache[title] =
title in cache ? title in cache ?
// pass the cached data for cloning/update to the lister... // pass the cached data for cloning/update to the handler...
lister.call(this, cache[title]) handler.call(this, cache[title])
: lister.call(this)) : handler.call(this)) },
}, clearCache: ['System/Clear cache',
doc`
Clear cache fully...
.clearCache()
Clear title (global group)...
.clearCache(title)
Clear title from group...
.clearCache(group, title)
Clear out the full group...
.clearCache(group, '*')
NOTE: a group can be a string, list or a regexp object.
`,
function(title){
var that = this
// full clear...
if(arguments.length == 0
|| (arguments[0] == '*'
&& arguments[1] == '*')){
delete this.__cache
// partial clear...
} else {
var group = 'global'
// both group and title given...
arguments.length > 1
&& ([group, title] = arguments)
// regexp...
// NOTE: these are only supported in groups...
if(group != '*' && group.includes('*')){
group = new RegExp('^'+ group +'$', 'i')
group = Object.keys(this.__cache || {})
.filter(function(g){
return group.test(g) }) }
// clear title from each group...
if(group == '*' || group instanceof Array || group instanceof RegExp){
;(group instanceof Array ?
group
: group instanceof RegExp ?
Object.keys(this.__cache || {})
.filter(function(g){
return group.test(g) })
: Object.keys(this.__cache || {}))
.forEach(function(group){
that.clearCache(group, title) })
// clear multiple titles...
} else if(title instanceof Array){
title.forEach(function(title){
delete ((that.__cache || {})[group] || {})[title] })
// clear group...
} else if(title == '*'){
delete (this.__cache || {})[group]
// clear title from group...
} else {
delete ((this.__cache || {})[group] || {})[title] } } }],
// special caches...
//
sessionCache: ['- System/',
doc`Add to session cache...
.sessionCache(title, handler)
-> value
This is a shorthand to:
.cache('session', title, handler)
-> value
NOTE: also see .cache(..)
`,
'cache: "session" ...'],
// XXX doc: what are we precaching???
preCache: ['System/Run pre-cache', preCache: ['System/Run pre-cache',
doc`Run pre-cache... doc`Run pre-cache...
@ -1120,8 +1239,7 @@ var CacheActions = actions.Actions({
var done = 0 var done = 0
var attrs = [] var attrs = []
for(var k in this){ for(var k in this){
attrs.push(k) attrs.push(k) }
}
var l = attrs.length var l = attrs.length
var started = Date.now() var started = Date.now()
@ -1131,45 +1249,25 @@ var CacheActions = actions.Actions({
var a = Date.now() var a = Date.now()
var b = a var b = a
if(attrs.length == 0){ if(attrs.length == 0){
return return }
}
while(b - a < c){ while(b - a < c){
this[attrs.pop()] this[attrs.pop()]
b = Date.now() b = Date.now()
done += 1 done += 1
this.showProgress this.showProgress
&& (show === true || (show && b - started > show)) && (show === true || (show && b - started > show))
&& this.showProgress('Caching', done, l) && this.showProgress('Caching', done, l) }
}
t === true ? t === true ?
tick() tick()
: setTimeout(tick, t) : setTimeout(tick, t) }.bind(this)
}.bind(this)
tick() tick() } }],
}
}],
clearCache: ['System/Clear cache',
function(title){
if(title){
delete (this.__cache|| {})[title]
} else {
delete this.__cache
}
}],
// XXX do we need this...
reCache: ['System/Re-cache', reCache: ['System/Re-cache',
function(t){ function(t){
this this
.clearCache() .clearCache()
.preCache(t) }], .preCache(t) }],
toggleHandlerCache: ['System/Action handler cache', toggleHandlerCache: ['System/Action handler cache',
makeConfigToggler('action-handler-cache', makeConfigToggler('action-handler-cache',
['off', 'on']/*, ['off', 'on']/*,
@ -1192,15 +1290,16 @@ module.Cache = ImageGridFeatures.Feature({
actions: CacheActions, actions: CacheActions,
handlers: [ handlers: [
// System...
['start.pre', ['start.pre',
function(){ function(){
this.clearCache()
var t = this.config['pre-cache'] var t = this.config['pre-cache']
t === true ? t === true ?
this.preCache('now') this.preCache('now')
: t >= 0 ? : t >= 0 ?
this.preCache() this.preCache()
: false : false }],
}],
['start', ['start',
function(){ function(){
// XXX this breaks loading... // XXX this breaks loading...
@ -1208,7 +1307,6 @@ module.Cache = ImageGridFeatures.Feature({
// there seems to be no problems... // there seems to be no problems...
//this.toggleHandlerCache(this.config['action-handler-cache'] || 'on') //this.toggleHandlerCache(this.config['action-handler-cache'] || 'on')
}], }],
/*/ XXX clear cache when feature/action topology changes... /*/ XXX clear cache when feature/action topology changes...
[[ [[
'inlineMixin', 'inlineMixin',
@ -1222,6 +1320,16 @@ module.Cache = ImageGridFeatures.Feature({
this.clearCache() this.clearCache()
}], }],
//*/ //*/
// clear session cache...
['clear',
//'clearCache: "(session|view)(-.*)?" "*" -- Clear session cache'],
function(){
this.clearCache(`(${
(this.config['cache-session-groups']
|| ['session', 'view'])
.join('|') })(-.*)?`) }],
], ],
}) })
@ -2148,6 +2256,16 @@ module.Changes = ImageGridFeatures.Feature({
this.changes = JSON.parse(JSON.stringify(data.changes)) this.changes = JSON.parse(JSON.stringify(data.changes))
} }
}], }],
// clear caches relating to stuff we just changed...
['markChanged',
function(_, section){
section = (section instanceof Array ?
section
: [section])
.map(function(section){
return '.*-'+section })
this.clearCache(section, '*') }],
], ],
}) })

View File

@ -25,8 +25,7 @@ var base = require('features/base')
var makeStateIndicator = function(type){ var makeStateIndicator = function(type){
return $('<div>') return $('<div>')
.addClass('state-indicator-container ' + type || '') .addClass('state-indicator-container ' + type || '') }
}
// XXX do we need this??? // XXX do we need this???
var makeStateIndicatorItem = function(container, type, text){ var makeStateIndicatorItem = function(container, type, text){
@ -35,8 +34,7 @@ var makeStateIndicatorItem = function(container, type, text){
.attr('text', text) .attr('text', text)
this.dom.find('.state-indicator-container.'+container) this.dom.find('.state-indicator-container.'+container)
.append(item) .append(item)
return item return item }
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -102,6 +100,13 @@ var StatusBarActions = actions.Actions({
}, },
}, },
get __statusbar_cache(){
return this.cache('view-data', 'statusbar',
function(data){
return data || {}}) },
__statusbar_elements__: { __statusbar_elements__: {
/* item template... /* item template...
item: function(item){ item: function(item){
@ -133,8 +138,7 @@ var StatusBarActions = actions.Actions({
index: function(item, gid, img){ index: function(item, gid, img){
// cleanup... // cleanup...
if(item == null){ if(item == null){
return return }
}
var that = this var that = this
gid = gid || this.current gid = gid || this.current
@ -162,8 +166,7 @@ var StatusBarActions = actions.Actions({
// toggle index state... // toggle index state...
.click(function(){ .click(function(){
that.toggleStatusBarIndexMode() that.toggleStatusBarIndexMode()
that.updateStatusBar() that.updateStatusBar() })
})
// editable... // editable...
: $('<span>') : $('<span>')
.addClass('position editable') .addClass('position editable')
@ -182,40 +185,35 @@ var StatusBarActions = actions.Actions({
//event.stopPropagation() //event.stopPropagation()
(that.config['status-bar-index'] || {})['live-update-on-edit'] (that.config['status-bar-index'] || {})['live-update-on-edit']
&& go(parseInt($(this).text())) && go(parseInt($(this).text())) })
})
.focus(function(){ .focus(function(){
$(this).selectText() $(this).selectText() })
})
.blur(function(){ .blur(function(){
that.updateStatusBar() that.updateStatusBar() }))
}))
.append($('<span>') .append($('<span>')
.addClass('length') .addClass('length')
.attr('info', 'Image count (click to toggle ribbon/global)') .attr('info', 'Image count (click to toggle ribbon/global)')
// toggle index state... // toggle index state...
.click(function(){ .click(function(){
that.toggleStatusBarIndexMode() that.toggleStatusBarIndexMode()
that.updateStatusBar() that.updateStatusBar() }))
}))
} else { } else {
var type = item.attr('type') var type = item.attr('type') }
}
// NOTE: using .toggleStatusBarIndexMode(..) here will fall // NOTE: using .toggleStatusBarIndexMode(..) here will fall
// into an infinite recursion... // into an infinite recursion...
var cls = (that.config['status-bar-index'] || {})['mode'] || 'normal' var cls = (that.config['status-bar-index'] || {})['mode'] || 'normal'
// XXX get the cached length... // get the cached length...
// XXX make this part of the status bar cache... var cache = this.__statusbar_cache.index_total
var cache = this.__statusbar_index_length_cache || [] cache = cache ?
cache = cache[0] == cls ? (cache[0] == cls
cache[1] && cache[1])
: null : null
// empty view... // empty view...
if(this.data){ if(!this.data){
var i = -1 var i = -1
var l = 0 var l = 0
@ -234,11 +232,16 @@ var StatusBarActions = actions.Actions({
// ribbon index... // ribbon index...
} else { } else {
var i = this.data.getImageOrder('ribbon', gid) var i = this.data.getImageOrder('ribbon', gid)
var l = cache = var r = this.current_ribbon
cache || this.data.getImages(gid).len } var l = cache
&& cache instanceof Array
&& cache[0] == r
&& cache[1]
l = l || this.data.getImages(gid).len
cache = [r, l] }
// XXX save cache... // save cache...
this.__statusbar_index_length_cache = [cls, cache] this.__statusbar_cache.index_total = [cls, cache]
// update... // update...
item item
@ -250,13 +253,11 @@ var StatusBarActions = actions.Actions({
.find('.length') .find('.length')
.text(l > 0 ? ('/' + l) : '') .text(l > 0 ? ('/' + l) : '')
return item return item },
},
ribbon: function(item, gid, img){ ribbon: function(item, gid, img){
// cleanup... // cleanup...
if(item == null){ if(item == null){
return return }
}
var that = this var that = this
@ -294,8 +295,7 @@ var StatusBarActions = actions.Actions({
})) }))
.append($('<span>') .append($('<span>')
.addClass('ribbon-count') .addClass('ribbon-count')
.attr('info', 'Ribbon count')) .attr('info', 'Ribbon count')) }
}
item item
.find('.ribbon-number') .find('.ribbon-number')
@ -312,22 +312,18 @@ var StatusBarActions = actions.Actions({
item[0].setAttribute('base', '') item[0].setAttribute('base', '')
} else { } else {
item[0].removeAttribute('base') item[0].removeAttribute('base') }
}
return item return item },
},
changes: function(item, gid, img){ changes: function(item, gid, img){
// cleanup... // cleanup...
if(item == null){ if(item == null){
return return }
}
if(typeof(item) == typeof('str')){ if(typeof(item) == typeof('str')){
item = $('<span>') item = $('<span>')
.addClass('changes') .addClass('changes')
.attr('info', 'Unsaved changes') .attr('info', 'Unsaved changes') }
}
//item.html(this.changes !== false ? //item.html(this.changes !== false ?
// this.config['status-bar-changes-text'] || '*' // this.config['status-bar-changes-text'] || '*'
@ -337,14 +333,12 @@ var StatusBarActions = actions.Actions({
this.config['status-bar-changes-text'] || '*' this.config['status-bar-changes-text'] || '*'
: '') : '')
return item return item },
},
// XXX handle path correctly... // XXX handle path correctly...
gid: function(item, gid, img){ gid: function(item, gid, img){
// cleanup... // cleanup...
if(item == null){ if(item == null){
return return }
}
var that = this var that = this
gid = gid || this.current gid = gid || this.current
@ -363,12 +357,10 @@ var StatusBarActions = actions.Actions({
// select the text... // select the text...
// XXX should this also copy??? // XXX should this also copy???
.click(function(){ .click(function(){
$(this).selectText() $(this).selectText() }))
}))
} else { } else {
var type = item.attr('type') var type = item.attr('type') }
}
// update... // update...
var txt = '' var txt = ''
@ -386,14 +378,14 @@ var StatusBarActions = actions.Actions({
text = (img && img.path && ((img.base_path || '') +'/'+ img.path) || '---') text = (img && img.path && ((img.base_path || '') +'/'+ img.path) || '---')
// remove /./ // remove /./
.replace(/[\\\/]\.[\\\/]/, '/') .replace(/[\\\/]\.[\\\/]/, '/')
txt = img && ((img.name || '') + (img.ext || '')) || text.split(/[\\\/]/).pop() txt = img
} && ((img.name || '') + (img.ext || ''))
|| text.split(/[\\\/]/).pop() }
item.find('.shown').text(txt) item.find('.shown').text(txt)
item.find('.hidden').text(text) item.find('.hidden').text(text)
return item return item },
},
path: 'gid', path: 'gid',
'edit-mode': function(item){ 'edit-mode': function(item){
// cleanup... // cleanup...
@ -401,10 +393,10 @@ var StatusBarActions = actions.Actions({
this.__edit_mode_indicator_update this.__edit_mode_indicator_update
&& this.off('keyPress', this.__edit_mode_indicator_update) && this.off('keyPress', this.__edit_mode_indicator_update)
delete this.__edit_mode_indicator_update delete this.__edit_mode_indicator_update
return return }
}
var update = this.__edit_mode_indicator_update = this.__edit_mode_indicator_update var update = this.__edit_mode_indicator_update =
this.__edit_mode_indicator_update
|| (function(){ || (function(){
var caps = this.keyboard.capslock var caps = this.keyboard.capslock
caps = typeof(event) != 'undefined' && event.getModifierState ? caps = typeof(event) != 'undefined' && event.getModifierState ?
@ -414,8 +406,7 @@ var StatusBarActions = actions.Actions({
.attr('info', 'Edit mode ' .attr('info', 'Edit mode '
+ (caps ? 'on' : 'off') + (caps ? 'on' : 'off')
+ ' (Click to update / Press CapsLock to toggle)') + ' (Click to update / Press CapsLock to toggle)')
[caps ? 'addClass' : 'removeClass']('on') [caps ? 'addClass' : 'removeClass']('on') }).bind(this)
}).bind(this)
// cleanup interval handling... // cleanup interval handling...
this.__edit_mode_indicator_update_interval this.__edit_mode_indicator_update_interval
@ -426,8 +417,7 @@ var StatusBarActions = actions.Actions({
if(item == null){ if(item == null){
this.off('keyPress', update) this.off('keyPress', update)
this.dom.off('focus', update) this.dom.off('focus', update)
return return }
}
// setup... // setup...
if(typeof(item) == typeof('str')){ if(typeof(item) == typeof('str')){
@ -441,8 +431,7 @@ var StatusBarActions = actions.Actions({
.click(update) .click(update)
this.on('keyPress', update) this.on('keyPress', update)
this.dom.focus(update) this.dom.focus(update) }
}
// update timer... // update timer...
// NOTE: this is needed so as to reflect changes to settings... // NOTE: this is needed so as to reflect changes to settings...
@ -454,15 +443,13 @@ var StatusBarActions = actions.Actions({
// update state... // update state...
update() update()
return item return item },
},
// XXX show menu in the appropriate corner... // XXX show menu in the appropriate corner...
// XXX remove the type+ed class... // XXX remove the type+ed class...
mark: function(item, gid, img){ mark: function(item, gid, img){
// cleanup... // cleanup...
if(item == null){ if(item == null){
return return }
}
gid = gid || this.current gid = gid || this.current
var that = this var that = this
@ -484,12 +471,10 @@ var StatusBarActions = actions.Actions({
evt.preventDefault() evt.preventDefault()
evt.stopPropagation() evt.stopPropagation()
that.browseActions('/'+ type.capitalize() +'/') that.browseActions('/'+ type.capitalize() +'/') })
})
} else { } else {
var type = item.attr('type') var type = item.attr('type') }
}
// NOTE: we are not using .toggleMark('?') and friends // NOTE: we are not using .toggleMark('?') and friends
// here to avoid recursion as we might be handling // here to avoid recursion as we might be handling
@ -503,8 +488,7 @@ var StatusBarActions = actions.Actions({
'removeClass' 'removeClass'
: 'addClass']('on') : 'addClass']('on')
return item return item },
},
bookmark: 'mark', bookmark: 'mark',
}, },
@ -520,8 +504,7 @@ var StatusBarActions = actions.Actions({
function(){ function(){
// no viewer yet... // no viewer yet...
if(!this.ribbons || !this.dom){ if(!this.ribbons || !this.dom){
return $() return $() }
}
var bar = this.dom.find('.state-indicator-container.global-info') var bar = this.dom.find('.state-indicator-container.global-info')
if(bar.length == 0){ if(bar.length == 0){
@ -543,17 +526,14 @@ var StatusBarActions = actions.Actions({
.on('mouseout', function(){ .on('mouseout', function(){
bar.find('.info').empty() bar.find('.info').empty()
}) })
.appendTo(this.dom) .appendTo(this.dom) }
} return bar },
return bar
},
function(){ return Object.keys(this.config['status-bars']).concat(['none']) }, function(){ return Object.keys(this.config['status-bars']).concat(['none']) },
// XXX check if we will be getting gid reliably... // XXX check if we will be getting gid reliably...
function(state, bar, gid){ function(state, bar, gid){
// do not do anything unless the status bar exists... // do not do anything unless the status bar exists...
if(bar.length == 0){ if(bar.length == 0){
return return }
}
var that = this var that = this
this.config['status-bar'] = state this.config['status-bar'] = state
@ -564,8 +544,7 @@ var StatusBarActions = actions.Actions({
var handler = elems[key] || base_elems[key] var handler = elems[key] || base_elems[key]
if(handler == null){ if(handler == null){
return return }
}
// handle aliases... // handle aliases...
var seen = [] var seen = []
@ -576,15 +555,13 @@ var StatusBarActions = actions.Actions({
if(seen.indexOf(handler) >= 0){ if(seen.indexOf(handler) >= 0){
console.error('state indicator alias loop detected at:', key) console.error('state indicator alias loop detected at:', key)
handler = null handler = null
break break } }
}
}
return handler return handler }
}
// clear... // clear...
if(state == 'none' || !bar.hasClass(state)){ if(state == 'none' || !bar.hasClass(state)){
this.clearStatusBarCache()
// notify items that they are removed... // notify items that they are removed...
bar.children() bar.children()
.each(function(i, item){ .each(function(i, item){
@ -592,25 +569,21 @@ var StatusBarActions = actions.Actions({
var type = item.attr('type') var type = item.attr('type')
if(type == null){ if(type == null){
return return }
}
var handler = _getHandler(type) var handler = _getHandler(type)
if(handler != null){ if(handler != null){
handler.call(that, null) handler.call(that, null) }
}
}) })
bar.empty() bar.empty() }
}
if(state == 'none'){ if(state == 'none'){
!('none' in this.config['status-bars']) !('none' in this.config['status-bars'])
// XXX this feels like a hack... // XXX this feels like a hack...
&& setTimeout(function(){ this.toggleStatusBar(0) }.bind(this), 0) && setTimeout(function(){ this.toggleStatusBar(0) }.bind(this), 0)
//return Object.keys(this.config['status-bars'])[0] //return Object.keys(this.config['status-bars'])[0]
return return }
}
// build/update... // build/update...
gid = gid || this.current gid = gid || this.current
@ -642,11 +615,9 @@ var StatusBarActions = actions.Actions({
item = (handler ? item = (handler ?
handler.call(that, item, gid, img) handler.call(that, item, gid, img)
: $('<span>')) : $('<span>'))
.attr('type', item) .attr('type', item) }
}
bar.append(item) bar.append(item) })
})
// update... // update...
} else { } else {
@ -656,17 +627,12 @@ var StatusBarActions = actions.Actions({
var type = item.attr('type') var type = item.attr('type')
if(type == null){ if(type == null){
return return }
}
var handler = _getHandler(type) var handler = _getHandler(type)
if(handler != null){ if(handler != null){
handler.call(that, item, gid, img) handler.call(that, item, gid, img) } }) } },
}
})
}
},
null)], null)],
updateStatusBar: ['- Interface/Update satus bar', updateStatusBar: ['- Interface/Update satus bar',
'toggleStatusBar: "!"'], 'toggleStatusBar: "!"'],
@ -675,8 +641,10 @@ var StatusBarActions = actions.Actions({
function(){ function(){
var mode = this.toggleStatusBar('?') var mode = this.toggleStatusBar('?')
this.toggleStatusBar('none') this.toggleStatusBar('none')
this.toggleStatusBar(mode) this.toggleStatusBar(mode) }],
}], clearStatusBarCache: ['- Interface/Clear status bar cache',
'clearCache: "*" "statusbar"'],
// XXX should this blink the on state only??? // XXX should this blink the on state only???
statusItemBlink: ['- Interface/', statusItemBlink: ['- Interface/',
@ -685,8 +653,7 @@ var StatusBarActions = actions.Actions({
NOTE: type is the same as in .__statusbar_elements__`, NOTE: type is the same as in .__statusbar_elements__`,
function(type){ function(type){
if(type == null){ if(type == null){
return return }
}
var gid = this.current var gid = this.current
var item = this.dom.find(`.state-indicator-container.global-info [type=${type}]`) var item = this.dom.find(`.state-indicator-container.global-info [type=${type}]`)
@ -695,42 +662,36 @@ var StatusBarActions = actions.Actions({
item item
.removeClass('blink') .removeClass('blink')
.addClass('blink') .addClass('blink')
.on('animationend', function(){ item.removeClass('blink') }) .on('animationend', function(){ item.removeClass('blink') }) }],
}],
// XXX should these be here??? // XXX should these be here???
// XXX should this show a dialog??? // XXX should this show a dialog???
editStatusBarIndex: ['- Interface/Edit image focus position in statusbar', editStatusBarIndex: ['- Interface/Edit image focus position in statusbar',
function(){ function(){
if((this.config['status-bar-index'] || {} )['editable']){ if((this.config['status-bar-index'] || {} )['editable']){
this.toggleStatusBar('?') == 'none' && this.toggleStatusBar() this.toggleStatusBar('?') == 'none'
&& this.toggleStatusBar()
// XXX do this better... // XXX do this better...
this.dom.find('.global-info .index .position').focus().click() this.dom.find('.global-info .index .position').focus().click() } }],
}
}],
editStatusBarRibbon: ['- Interface/Edit ribbon focus position in statusbar', editStatusBarRibbon: ['- Interface/Edit ribbon focus position in statusbar',
function(){ function(){
this.toggleStatusBar('?') == 'none' && this.toggleStatusBar() this.toggleStatusBar('?') == 'none'
&& this.toggleStatusBar()
// XXX do this better... // XXX do this better...
this.dom.find('.global-info .ribbon-number').focus().click() this.dom.find('.global-info .ribbon-number').focus().click() }],
}],
toggleStatusBarIndexMode: ['Interface/Status bar index mode', toggleStatusBarIndexMode: ['Interface/Status bar index mode',
toggler.CSSClassToggler( toggler.CSSClassToggler(
function(){ function(){
return this.dom.find('.global-info .index') }, return this.dom.find('.global-info .index') },
['normal', 'loaded', 'global'], ['normal', 'loaded', 'global'],
function(state){ function(state){
this.toggleStatusBar('?') == 'none' && this.toggleStatusBar() this.toggleStatusBar('?') == 'none'
&& this.toggleStatusBar()
// prepare for saving the config... // prepare for saving the config...
this.config['status-bar-index'] = this.config['status-bar-index'] =
JSON.parse(JSON.stringify(this.config['status-bar-index'])) JSON.parse(JSON.stringify(this.config['status-bar-index']))
this.config['status-bar-index']['mode'] = state this.config['status-bar-index']['mode'] = state
this.updateStatusBar() })],
this.updateStatusBar()
})],
// XXX revise... // XXX revise...
showStatusBarInfo: ['- Interface/', showStatusBarInfo: ['- Interface/',
@ -807,12 +768,10 @@ module.StatusBar = core.ImageGridFeatures.Feature({
handlers: [ handlers: [
['start', ['start',
function(){ function(){
this.toggleStatusBar(this.config['status-bar']) this.toggleStatusBar(this.config['status-bar']) }],
}],
['focusImage clear markChanged refresh', ['focusImage clear markChanged refresh',
function(){ function(){
this.updateStatusBar() this.updateStatusBar() }],
}],
[[ [[
'tag', 'tag',
'untag', 'untag',
@ -823,14 +782,12 @@ module.StatusBar = core.ImageGridFeatures.Feature({
&& (gids.indexOf('current') >= 0 && (gids.indexOf('current') >= 0
|| gids.indexOf(this.current) >= 0) || gids.indexOf(this.current) >= 0)
|| this.data.getImage(gids) == this.current){ || this.data.getImage(gids) == this.current){
this.updateStatusBar() this.updateStatusBar() } }],
}
}],
['ribbonPanning.post', ['ribbonPanning.post',
function(_, gid){ function(_, gid){
gid == this.data.getRibbon() && this.updateStatusBar() gid == this.data.getRibbon()
}], && this.updateStatusBar() }],
// blink status mark indicators on toggle... // blink status mark indicators on toggle...
['toggleMark', ['toggleMark',
@ -853,13 +810,11 @@ module.StatusBar = core.ImageGridFeatures.Feature({
], ],
function(workspace){ function(workspace){
if(!workspace || workspace in this.workspaces){ if(!workspace || workspace in this.workspaces){
return return }
}
this.config['status-bar'] = this.config['status-bar'] =
(this.config['status-bar-workspace-defaults'][workspace] (this.config['status-bar-workspace-defaults'][workspace]
|| this.config['status-bar']) || this.config['status-bar']) }],
}],
['loadWorkspace', ['loadWorkspace',
core.makeWorkspaceConfigLoader( core.makeWorkspaceConfigLoader(
function(){ function(){
@ -871,9 +826,7 @@ module.StatusBar = core.ImageGridFeatures.Feature({
} else { } else {
'status-bar' in workspace ? 'status-bar' in workspace ?
this.toggleStatusBar(workspace['status-bar']) this.toggleStatusBar(workspace['status-bar'])
: this.toggleStatusBar(this.config['status-bar']) : this.toggleStatusBar(this.config['status-bar']) } })],
}
})],
], ],
}) })

View File

@ -13,6 +13,7 @@
var sha1 = require('ext-lib/sha1') var sha1 = require('ext-lib/sha1')
var types = require('lib/types')
var object = require('lib/object') var object = require('lib/object')
var tags = require('imagegrid/tags') var tags = require('imagegrid/tags')
@ -223,6 +224,7 @@ var DataPrototype = {
ribbon_order: null, ribbon_order: null,
ribbons: null, ribbons: null,
//__current: null,
get current(){ get current(){
return this.__current = this.__current return this.__current = this.__current
|| this.getImages(this.ribbon_order[0])[0] || this.getImages(this.ribbon_order[0])[0]
@ -230,6 +232,7 @@ var DataPrototype = {
set current(value){ set current(value){
this.focusImage(value) }, this.focusImage(value) },
//__base: null,
get base(){ get base(){
return this.__base || this.ribbon_order[0] }, return this.__base || this.ribbon_order[0] },
set base(value){ set base(value){
@ -237,13 +240,18 @@ var DataPrototype = {
this.getRibbon(value) this.getRibbon(value)
: value }, : value },
// NOTE: experiments with wrapping data in Proxy yielded a
// significant slowdown on edits...
//__order: null,
get order(){ get order(){
return this.__order }, return this.__order },
set order(value){ set order(value){
delete this.__order_index delete this.__order_index
this.__order = value }, this.__order = value },
//__order_index: null,
get order_index(){ get order_index(){
return this.__order_index = this.__order_index || this.order.toKeys() }, return this.__order_index =
this.__order_index || this.order.toKeys() },
@ -1027,16 +1035,16 @@ var DataPrototype = {
// order. // order.
getImageOrder: function(context, target, mode, list){ getImageOrder: function(context, target, mode, list){
if(context == 'loaded' || context == 'global'){ if(context == 'loaded' || context == 'global'){
return this.getImages('loaded').indexOf(this.getImage(target, mode, list)) return this.getImages('loaded').lastIndexOf(this.getImage(target, mode, list))
} else if(context == 'ribbon'){ } else if(context == 'ribbon'){
var gid = this.getImage(target, mode, list) var gid = this.getImage(target, mode, list)
return this.getImages(gid).indexOf(gid) return this.getImages(gid).lastIndexOf(gid)
} else if(context == 'all'){ } else if(context == 'all'){
return this.order.indexOf(this.getImage(target, mode, list)) } return this.order.lastIndexOf(this.getImage(target, mode, list)) }
return this.order.indexOf(this.getImage(context, target, mode)) }, return this.order.lastIndexOf(this.getImage(context, target, mode)) },
// Get a list of image gids... // Get a list of image gids...
// //
@ -1183,7 +1191,6 @@ var DataPrototype = {
target = this.getImage(target) target = this.getImage(target)
|| this.getImage(target, 'after') || this.getImage(target, 'after')
var i = list.indexOf(target)
// prepare to slice the list... // prepare to slice the list...
if(mode == 'around' || mode == 'total'){ if(mode == 'around' || mode == 'total'){
@ -1204,6 +1211,10 @@ var DataPrototype = {
var res = [target] var res = [target]
// XXX can we avoid .indexOf(..) here???
//var i = list.indexOf(target)
//var i = list.index(target)
var i = list.lastIndexOf(target)
// pre... // pre...
for(var n = i-1; n >= 0 && pre > 0; n--){ for(var n = i-1; n >= 0 && pre > 0; n--){
// NOTE: list may be sparse so we skip the items that are not // NOTE: list may be sparse so we skip the items that are not
@ -1227,7 +1238,9 @@ var DataPrototype = {
// in the post section... // in the post section...
if(mode == 'total' && post > 0){ if(mode == 'total' && post > 0){
var pad = count - res.length var pad = count - res.length
var i = list.indexOf(res[0]) //var i = list.indexOf(res[0])
//var i = list.index(res[0])
var i = list.lastIndexOf(res[0])
res.reverse() res.reverse()
for(var n = i-1; n >= 0 && pad > 0; n--){ for(var n = i-1; n >= 0 && pad > 0; n--){

View File

@ -1,6 +1,6 @@
{ {
"name": "ImageGrid.Viewer.g4", "name": "ImageGrid.Viewer.g4",
"version": "4.0.0a", "version": "4.0.0-a",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -1110,9 +1110,9 @@
"integrity": "sha512-9kZM80Js9/eTwXN9VXwLDC1wDJ7gIAdYU9GIzb5KJmNcLAMaW+zhgFrwFFMrcSfggUuadgnqSrS41E4XLe8JZw==" "integrity": "sha512-9kZM80Js9/eTwXN9VXwLDC1wDJ7gIAdYU9GIzb5KJmNcLAMaW+zhgFrwFFMrcSfggUuadgnqSrS41E4XLe8JZw=="
}, },
"ig-types": { "ig-types": {
"version": "5.0.18", "version": "5.0.20",
"resolved": "https://registry.npmjs.org/ig-types/-/ig-types-5.0.18.tgz", "resolved": "https://registry.npmjs.org/ig-types/-/ig-types-5.0.20.tgz",
"integrity": "sha512-8c16slG/J0qC9oYW1Mx6oSriEYKEY/HLs4SvgWDLqac/qx/nMaa6HlEUA/fi+whGxvTk03t4s/IKca+MKWV9oQ==", "integrity": "sha512-d2IEwY3ZDSWxn2PY0e7XxMzuOPWzeK/py0sBgqfoCNbKlc4IHEogFwoQIv0C4EZdcXL0cJOsCo74NwbetoSWiA==",
"requires": { "requires": {
"ig-object": "^5.4.12", "ig-object": "^5.4.12",
"object-run": "^1.0.1" "object-run": "^1.0.1"

View File

@ -32,7 +32,7 @@
"ig-argv": "^2.15.0", "ig-argv": "^2.15.0",
"ig-features": "^3.4.2", "ig-features": "^3.4.2",
"ig-object": "^5.4.12", "ig-object": "^5.4.12",
"ig-types": "^5.0.18", "ig-types": "^5.0.20",
"moment": "^2.29.1", "moment": "^2.29.1",
"object-run": "^1.0.1", "object-run": "^1.0.1",
"requirejs": "^2.3.6", "requirejs": "^2.3.6",