diff --git a/Viewer/features/base.js b/Viewer/features/base.js index 30ca7401..33e961d5 100755 --- a/Viewer/features/base.js +++ b/Viewer/features/base.js @@ -1806,9 +1806,19 @@ module.Crop = core.ImageGridFeatures.Feature({ tag: 'crop', depends: [ 'base', + //'cache', ], actions: CropActions, + + handlers: [ + [[ + 'crop', + 'uncrop', + 'removeFromCrop', + ], + 'clearCache: "view(-.*)?" "*" -- Clear view cache'], + ], }) diff --git a/Viewer/features/collections.js b/Viewer/features/collections.js index 7140e666..2e3201b6 100755 --- a/Viewer/features/collections.js +++ b/Viewer/features/collections.js @@ -1779,6 +1779,13 @@ module.Collection = core.ImageGridFeatures.Feature({ // XXX }) }], + + // invalidate caches... + [[ + 'loadCollection', + 'uncollect', + ], + 'clearCache: "view(-.*)?" "*" -- Clear view cache'], ], }) diff --git a/Viewer/features/core.js b/Viewer/features/core.js index dc47e1df..e66a992a 100755 --- a/Viewer/features/core.js +++ b/Viewer/features/core.js @@ -1027,9 +1027,21 @@ module.Serialization = ImageGridFeatures.Feature({ // Cache... // XXX should this be in actions.js??? -// XXX should we invalidate the cache automatically??? -// XXX the cache can also be saved to localStorage and loaded until either -// the version changes or the feature list... +// XXX revise: cache group naming... +// currently the used groups are: +// 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({ config: { // Enable/disable caching... @@ -1062,11 +1074,30 @@ var CacheActions = actions.Actions({ // action is available... '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.. }, // Cache utility method... // + // .cache(title, handler) + // -> value + // + // .cache(group, title, handler) + // -> value + // + // // Example use: // someAction: [ // function(){ @@ -1086,18 +1117,106 @@ var CacheActions = actions.Actions({ // 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){ - return lister.call(this) - } + return handler.call(this) } + arguments.length > 2 + && ([group, title, handler] = arguments) var cache = this.__cache = this.__cache || {} + cache = cache[group] = cache[group] || {} return (cache[title] = title in cache ? - // pass the cached data for cloning/update to the lister... - lister.call(this, cache[title]) - : lister.call(this)) - }, + // pass the cached data for cloning/update to the handler... + handler.call(this, cache[title]) + : 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', doc`Run pre-cache... @@ -1120,8 +1239,7 @@ var CacheActions = actions.Actions({ var done = 0 var attrs = [] for(var k in this){ - attrs.push(k) - } + attrs.push(k) } var l = attrs.length var started = Date.now() @@ -1131,45 +1249,25 @@ var CacheActions = actions.Actions({ var a = Date.now() var b = a if(attrs.length == 0){ - return - } - + return } while(b - a < c){ this[attrs.pop()] b = Date.now() done += 1 - this.showProgress && (show === true || (show && b - started > show)) - && this.showProgress('Caching', done, l) - } - + && this.showProgress('Caching', done, l) } t === true ? tick() - : setTimeout(tick, t) - }.bind(this) + : setTimeout(tick, t) }.bind(this) - tick() - } - }], - clearCache: ['System/Clear cache', - function(title){ - if(title){ - delete (this.__cache|| {})[title] - - } else { - delete this.__cache - } - }], - - // XXX do we need this... + tick() } }], reCache: ['System/Re-cache', function(t){ this .clearCache() .preCache(t) }], - toggleHandlerCache: ['System/Action handler cache', makeConfigToggler('action-handler-cache', ['off', 'on']/*, @@ -1192,15 +1290,16 @@ module.Cache = ImageGridFeatures.Feature({ actions: CacheActions, handlers: [ + // System... ['start.pre', function(){ + this.clearCache() var t = this.config['pre-cache'] t === true ? this.preCache('now') : t >= 0 ? this.preCache() - : false - }], + : false }], ['start', function(){ // XXX this breaks loading... @@ -1208,7 +1307,6 @@ module.Cache = ImageGridFeatures.Feature({ // there seems to be no problems... //this.toggleHandlerCache(this.config['action-handler-cache'] || 'on') }], - /*/ XXX clear cache when feature/action topology changes... [[ 'inlineMixin', @@ -1222,6 +1320,16 @@ module.Cache = ImageGridFeatures.Feature({ 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)) } }], + + // 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, '*') }], ], }) diff --git a/Viewer/features/ui-status.js b/Viewer/features/ui-status.js index 0b3e1fd1..de6a752c 100755 --- a/Viewer/features/ui-status.js +++ b/Viewer/features/ui-status.js @@ -25,8 +25,7 @@ var base = require('features/base') var makeStateIndicator = function(type){ return $('
') - .addClass('state-indicator-container ' + type || '') -} + .addClass('state-indicator-container ' + type || '') } // XXX do we need this??? var makeStateIndicatorItem = function(container, type, text){ @@ -35,8 +34,7 @@ var makeStateIndicatorItem = function(container, type, text){ .attr('text', text) this.dom.find('.state-indicator-container.'+container) .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__: { /* item template... item: function(item){ @@ -133,8 +138,7 @@ var StatusBarActions = actions.Actions({ index: function(item, gid, img){ // cleanup... if(item == null){ - return - } + return } var that = this gid = gid || this.current @@ -162,8 +166,7 @@ var StatusBarActions = actions.Actions({ // toggle index state... .click(function(){ that.toggleStatusBarIndexMode() - that.updateStatusBar() - }) + that.updateStatusBar() }) // editable... : $('') .addClass('position editable') @@ -182,40 +185,35 @@ var StatusBarActions = actions.Actions({ //event.stopPropagation() (that.config['status-bar-index'] || {})['live-update-on-edit'] - && go(parseInt($(this).text())) - }) + && go(parseInt($(this).text())) }) .focus(function(){ - $(this).selectText() - }) + $(this).selectText() }) .blur(function(){ - that.updateStatusBar() - })) + that.updateStatusBar() })) .append($('') .addClass('length') .attr('info', 'Image count (click to toggle ribbon/global)') // toggle index state... .click(function(){ that.toggleStatusBarIndexMode() - that.updateStatusBar() - })) + that.updateStatusBar() })) } else { - var type = item.attr('type') - } + var type = item.attr('type') } // NOTE: using .toggleStatusBarIndexMode(..) here will fall // into an infinite recursion... var cls = (that.config['status-bar-index'] || {})['mode'] || 'normal' - // XXX get the cached length... - // XXX make this part of the status bar cache... - var cache = this.__statusbar_index_length_cache || [] - cache = cache[0] == cls ? - cache[1] + // get the cached length... + var cache = this.__statusbar_cache.index_total + cache = cache ? + (cache[0] == cls + && cache[1]) : null // empty view... - if(this.data){ + if(!this.data){ var i = -1 var l = 0 @@ -234,11 +232,16 @@ var StatusBarActions = actions.Actions({ // ribbon index... } else { var i = this.data.getImageOrder('ribbon', gid) - var l = cache = - cache || this.data.getImages(gid).len } + var r = this.current_ribbon + var l = cache + && cache instanceof Array + && cache[0] == r + && cache[1] + l = l || this.data.getImages(gid).len + cache = [r, l] } - // XXX save cache... - this.__statusbar_index_length_cache = [cls, cache] + // save cache... + this.__statusbar_cache.index_total = [cls, cache] // update... item @@ -250,13 +253,11 @@ var StatusBarActions = actions.Actions({ .find('.length') .text(l > 0 ? ('/' + l) : '') - return item - }, + return item }, ribbon: function(item, gid, img){ // cleanup... if(item == null){ - return - } + return } var that = this @@ -294,8 +295,7 @@ var StatusBarActions = actions.Actions({ })) .append($('') .addClass('ribbon-count') - .attr('info', 'Ribbon count')) - } + .attr('info', 'Ribbon count')) } item .find('.ribbon-number') @@ -312,22 +312,18 @@ var StatusBarActions = actions.Actions({ item[0].setAttribute('base', '') } else { - item[0].removeAttribute('base') - } + item[0].removeAttribute('base') } - return item - }, + return item }, changes: function(item, gid, img){ // cleanup... if(item == null){ - return - } + return } if(typeof(item) == typeof('str')){ item = $('') .addClass('changes') - .attr('info', 'Unsaved changes') - } + .attr('info', 'Unsaved changes') } //item.html(this.changes !== false ? // this.config['status-bar-changes-text'] || '*' @@ -337,14 +333,12 @@ var StatusBarActions = actions.Actions({ this.config['status-bar-changes-text'] || '*' : '') - return item - }, + return item }, // XXX handle path correctly... gid: function(item, gid, img){ // cleanup... if(item == null){ - return - } + return } var that = this gid = gid || this.current @@ -363,12 +357,10 @@ var StatusBarActions = actions.Actions({ // select the text... // XXX should this also copy??? .click(function(){ - $(this).selectText() - })) + $(this).selectText() })) } else { - var type = item.attr('type') - } + var type = item.attr('type') } // update... var txt = '' @@ -386,14 +378,14 @@ var StatusBarActions = actions.Actions({ text = (img && img.path && ((img.base_path || '') +'/'+ img.path) || '---') // remove /./ .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('.hidden').text(text) - return item - }, + return item }, path: 'gid', 'edit-mode': function(item){ // cleanup... @@ -401,21 +393,20 @@ var StatusBarActions = actions.Actions({ this.__edit_mode_indicator_update && this.off('keyPress', 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 - || (function(){ - var caps = this.keyboard.capslock - caps = typeof(event) != 'undefined' && event.getModifierState ? - event.getModifierState('CapsLock') - : caps - item - .attr('info', 'Edit mode ' - + (caps ? 'on' : 'off') - + ' (Click to update / Press CapsLock to toggle)') - [caps ? 'addClass' : 'removeClass']('on') - }).bind(this) + var update = this.__edit_mode_indicator_update = + this.__edit_mode_indicator_update + || (function(){ + var caps = this.keyboard.capslock + caps = typeof(event) != 'undefined' && event.getModifierState ? + event.getModifierState('CapsLock') + : caps + item + .attr('info', 'Edit mode ' + + (caps ? 'on' : 'off') + + ' (Click to update / Press CapsLock to toggle)') + [caps ? 'addClass' : 'removeClass']('on') }).bind(this) // cleanup interval handling... this.__edit_mode_indicator_update_interval @@ -426,8 +417,7 @@ var StatusBarActions = actions.Actions({ if(item == null){ this.off('keyPress', update) this.dom.off('focus', update) - return - } + return } // setup... if(typeof(item) == typeof('str')){ @@ -441,8 +431,7 @@ var StatusBarActions = actions.Actions({ .click(update) this.on('keyPress', update) - this.dom.focus(update) - } + this.dom.focus(update) } // update timer... // NOTE: this is needed so as to reflect changes to settings... @@ -454,15 +443,13 @@ var StatusBarActions = actions.Actions({ // update state... update() - return item - }, + return item }, // XXX show menu in the appropriate corner... // XXX remove the type+ed class... mark: function(item, gid, img){ // cleanup... if(item == null){ - return - } + return } gid = gid || this.current var that = this @@ -484,12 +471,10 @@ var StatusBarActions = actions.Actions({ evt.preventDefault() evt.stopPropagation() - that.browseActions('/'+ type.capitalize() +'/') - }) + that.browseActions('/'+ type.capitalize() +'/') }) } else { - var type = item.attr('type') - } + var type = item.attr('type') } // NOTE: we are not using .toggleMark('?') and friends // here to avoid recursion as we might be handling @@ -503,8 +488,7 @@ var StatusBarActions = actions.Actions({ 'removeClass' : 'addClass']('on') - return item - }, + return item }, bookmark: 'mark', }, @@ -520,8 +504,7 @@ var StatusBarActions = actions.Actions({ function(){ // no viewer yet... if(!this.ribbons || !this.dom){ - return $() - } + return $() } var bar = this.dom.find('.state-indicator-container.global-info') if(bar.length == 0){ @@ -543,17 +526,14 @@ var StatusBarActions = actions.Actions({ .on('mouseout', function(){ bar.find('.info').empty() }) - .appendTo(this.dom) - } - return bar - }, + .appendTo(this.dom) } + return bar }, function(){ return Object.keys(this.config['status-bars']).concat(['none']) }, // XXX check if we will be getting gid reliably... function(state, bar, gid){ // do not do anything unless the status bar exists... if(bar.length == 0){ - return - } + return } var that = this this.config['status-bar'] = state @@ -564,8 +544,7 @@ var StatusBarActions = actions.Actions({ var handler = elems[key] || base_elems[key] if(handler == null){ - return - } + return } // handle aliases... var seen = [] @@ -576,15 +555,13 @@ var StatusBarActions = actions.Actions({ if(seen.indexOf(handler) >= 0){ console.error('state indicator alias loop detected at:', key) handler = null - break - } - } + break } } - return handler - } + return handler } // clear... if(state == 'none' || !bar.hasClass(state)){ + this.clearStatusBarCache() // notify items that they are removed... bar.children() .each(function(i, item){ @@ -592,25 +569,21 @@ var StatusBarActions = actions.Actions({ var type = item.attr('type') if(type == null){ - return - } + return } var handler = _getHandler(type) if(handler != null){ - handler.call(that, null) - } + handler.call(that, null) } }) - bar.empty() - } + bar.empty() } if(state == 'none'){ !('none' in this.config['status-bars']) // XXX this feels like a hack... && setTimeout(function(){ this.toggleStatusBar(0) }.bind(this), 0) //return Object.keys(this.config['status-bars'])[0] - return - } + return } // build/update... gid = gid || this.current @@ -642,11 +615,9 @@ var StatusBarActions = actions.Actions({ item = (handler ? handler.call(that, item, gid, img) : $('')) - .attr('type', item) - } + .attr('type', item) } - bar.append(item) - }) + bar.append(item) }) // update... } else { @@ -656,17 +627,12 @@ var StatusBarActions = actions.Actions({ var type = item.attr('type') if(type == null){ - return - } + return } var handler = _getHandler(type) if(handler != null){ - handler.call(that, item, gid, img) - } - }) - } - }, + handler.call(that, item, gid, img) } }) } }, null)], updateStatusBar: ['- Interface/Update satus bar', 'toggleStatusBar: "!"'], @@ -675,8 +641,10 @@ var StatusBarActions = actions.Actions({ function(){ var mode = this.toggleStatusBar('?') 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??? statusItemBlink: ['- Interface/', @@ -685,8 +653,7 @@ var StatusBarActions = actions.Actions({ NOTE: type is the same as in .__statusbar_elements__`, function(type){ if(type == null){ - return - } + return } var gid = this.current var item = this.dom.find(`.state-indicator-container.global-info [type=${type}]`) @@ -695,42 +662,36 @@ var StatusBarActions = actions.Actions({ item .removeClass('blink') .addClass('blink') - .on('animationend', function(){ item.removeClass('blink') }) - }], + .on('animationend', function(){ item.removeClass('blink') }) }], // XXX should these be here??? // XXX should this show a dialog??? editStatusBarIndex: ['- Interface/Edit image focus position in statusbar', function(){ if((this.config['status-bar-index'] || {} )['editable']){ - this.toggleStatusBar('?') == 'none' && this.toggleStatusBar() - + this.toggleStatusBar('?') == 'none' + && this.toggleStatusBar() // 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', function(){ - this.toggleStatusBar('?') == 'none' && this.toggleStatusBar() - + this.toggleStatusBar('?') == 'none' + && this.toggleStatusBar() // 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', toggler.CSSClassToggler( function(){ return this.dom.find('.global-info .index') }, ['normal', 'loaded', 'global'], function(state){ - this.toggleStatusBar('?') == 'none' && this.toggleStatusBar() - + this.toggleStatusBar('?') == 'none' + && this.toggleStatusBar() // prepare for saving the config... this.config['status-bar-index'] = JSON.parse(JSON.stringify(this.config['status-bar-index'])) this.config['status-bar-index']['mode'] = state - - this.updateStatusBar() - })], + this.updateStatusBar() })], // XXX revise... showStatusBarInfo: ['- Interface/', @@ -807,12 +768,10 @@ module.StatusBar = core.ImageGridFeatures.Feature({ handlers: [ ['start', function(){ - this.toggleStatusBar(this.config['status-bar']) - }], + this.toggleStatusBar(this.config['status-bar']) }], ['focusImage clear markChanged refresh', function(){ - this.updateStatusBar() - }], + this.updateStatusBar() }], [[ 'tag', 'untag', @@ -823,14 +782,12 @@ module.StatusBar = core.ImageGridFeatures.Feature({ && (gids.indexOf('current') >= 0 || gids.indexOf(this.current) >= 0) || this.data.getImage(gids) == this.current){ - this.updateStatusBar() - } - }], + this.updateStatusBar() } }], ['ribbonPanning.post', function(_, gid){ - gid == this.data.getRibbon() && this.updateStatusBar() - }], + gid == this.data.getRibbon() + && this.updateStatusBar() }], // blink status mark indicators on toggle... ['toggleMark', @@ -853,13 +810,11 @@ module.StatusBar = core.ImageGridFeatures.Feature({ ], function(workspace){ if(!workspace || workspace in this.workspaces){ - return - } + return } this.config['status-bar'] = (this.config['status-bar-workspace-defaults'][workspace] - || this.config['status-bar']) - }], + || this.config['status-bar']) }], ['loadWorkspace', core.makeWorkspaceConfigLoader( function(){ @@ -871,9 +826,7 @@ module.StatusBar = core.ImageGridFeatures.Feature({ } else { 'status-bar' in workspace ? this.toggleStatusBar(workspace['status-bar']) - : this.toggleStatusBar(this.config['status-bar']) - } - })], + : this.toggleStatusBar(this.config['status-bar']) } })], ], }) diff --git a/Viewer/imagegrid/data.js b/Viewer/imagegrid/data.js index 98889a36..c8ec6333 100755 --- a/Viewer/imagegrid/data.js +++ b/Viewer/imagegrid/data.js @@ -13,6 +13,7 @@ var sha1 = require('ext-lib/sha1') +var types = require('lib/types') var object = require('lib/object') var tags = require('imagegrid/tags') @@ -223,6 +224,7 @@ var DataPrototype = { ribbon_order: null, ribbons: null, + //__current: null, get current(){ return this.__current = this.__current || this.getImages(this.ribbon_order[0])[0] @@ -230,6 +232,7 @@ var DataPrototype = { set current(value){ this.focusImage(value) }, + //__base: null, get base(){ return this.__base || this.ribbon_order[0] }, set base(value){ @@ -237,13 +240,18 @@ var DataPrototype = { this.getRibbon(value) : value }, + // NOTE: experiments with wrapping data in Proxy yielded a + // significant slowdown on edits... + //__order: null, get order(){ return this.__order }, set order(value){ delete this.__order_index this.__order = value }, + //__order_index: null, 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. getImageOrder: function(context, target, mode, list){ 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'){ var gid = this.getImage(target, mode, list) - return this.getImages(gid).indexOf(gid) + return this.getImages(gid).lastIndexOf(gid) } 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... // @@ -1183,7 +1191,6 @@ var DataPrototype = { target = this.getImage(target) || this.getImage(target, 'after') - var i = list.indexOf(target) // prepare to slice the list... if(mode == 'around' || mode == 'total'){ @@ -1204,6 +1211,10 @@ var DataPrototype = { 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... for(var n = i-1; n >= 0 && pre > 0; n--){ // NOTE: list may be sparse so we skip the items that are not @@ -1227,7 +1238,9 @@ var DataPrototype = { // in the post section... if(mode == 'total' && post > 0){ 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() for(var n = i-1; n >= 0 && pad > 0; n--){ diff --git a/Viewer/package-lock.json b/Viewer/package-lock.json index 16d9be8d..ae6cdfb3 100755 --- a/Viewer/package-lock.json +++ b/Viewer/package-lock.json @@ -1,6 +1,6 @@ { "name": "ImageGrid.Viewer.g4", - "version": "4.0.0a", + "version": "4.0.0-a", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1110,9 +1110,9 @@ "integrity": "sha512-9kZM80Js9/eTwXN9VXwLDC1wDJ7gIAdYU9GIzb5KJmNcLAMaW+zhgFrwFFMrcSfggUuadgnqSrS41E4XLe8JZw==" }, "ig-types": { - "version": "5.0.18", - "resolved": "https://registry.npmjs.org/ig-types/-/ig-types-5.0.18.tgz", - "integrity": "sha512-8c16slG/J0qC9oYW1Mx6oSriEYKEY/HLs4SvgWDLqac/qx/nMaa6HlEUA/fi+whGxvTk03t4s/IKca+MKWV9oQ==", + "version": "5.0.20", + "resolved": "https://registry.npmjs.org/ig-types/-/ig-types-5.0.20.tgz", + "integrity": "sha512-d2IEwY3ZDSWxn2PY0e7XxMzuOPWzeK/py0sBgqfoCNbKlc4IHEogFwoQIv0C4EZdcXL0cJOsCo74NwbetoSWiA==", "requires": { "ig-object": "^5.4.12", "object-run": "^1.0.1" diff --git a/Viewer/package.json b/Viewer/package.json index a6ab2f98..4ea92719 100755 --- a/Viewer/package.json +++ b/Viewer/package.json @@ -32,7 +32,7 @@ "ig-argv": "^2.15.0", "ig-features": "^3.4.2", "ig-object": "^5.4.12", - "ig-types": "^5.0.18", + "ig-types": "^5.0.20", "moment": "^2.29.1", "object-run": "^1.0.1", "requirejs": "^2.3.6",