action .mode -> .browseMode, reworked .sync(..) (ctrl_R)...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-05-20 20:31:19 +03:00
parent d912ce2ebe
commit 78cb4bdff8
20 changed files with 372 additions and 245 deletions

View File

@ -124,7 +124,7 @@ var NWHostActions = actions.Actions({
// XXX add ability to use devtools on background page (node context)... // XXX add ability to use devtools on background page (node context)...
// XXX get the devtools stage... // XXX get the devtools stage...
showDevTools: ['Interface|Development/Show Dev Tools', showDevTools: ['Interface|Development/Show Dev Tools',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
function(action){ function(action){
if(action == '?'){ if(action == '?'){
// XXX get the devtools stage... // XXX get the devtools stage...
@ -145,7 +145,7 @@ var NWHostActions = actions.Actions({
}], }],
toggleSplashScreen: ['Interface/', toggleSplashScreen: ['Interface/',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
function(){ function(){
}], }],
}) })
@ -246,7 +246,7 @@ var ElectronHostActions = actions.Actions({
// XXX should this be a toggler??? // XXX should this be a toggler???
showDevTools: ['Interface|Development/Show Dev Tools', showDevTools: ['Interface|Development/Show Dev Tools',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
function(action){ function(action){
var w = electron.remote.getCurrentWindow() var w = electron.remote.getCurrentWindow()
@ -277,7 +277,7 @@ var ElectronHostActions = actions.Actions({
// XXX make this a real toggler... // XXX make this a real toggler...
toggleSplashScreen: ['Interface/', toggleSplashScreen: ['Interface/',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
function(action){ function(action){
var splash = this.splash = (!this.splash || this.splash.isDestroyed()) ? var splash = this.splash = (!this.splash || this.splash.isDestroyed()) ?
electron.remote.getGlobal('splash') electron.remote.getGlobal('splash')
@ -560,7 +560,7 @@ var WindowedAppControlActions = actions.Actions({
}], }],
toggleSplashScreenShowing: ['Interface/Splash screen on start', toggleSplashScreenShowing: ['Interface/Splash screen on start',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
core.makeConfigToggler('show-splash-screen', core.makeConfigToggler('show-splash-screen',
['on', 'off'], ['on', 'off'],
function(action){ function(action){

View File

@ -401,7 +401,7 @@ actions.Actions({
this.images && this.images.replaceGID(from, to) this.images && this.images.replaceGID(from, to)
}], }],
// basic navigation... // basic navigation...
// //
focusImage: ['- Navigate/Focus image', focusImage: ['- Navigate/Focus image',
@ -537,7 +537,7 @@ actions.Actions({
.focusImage(0) .focusImage(0)
.focusImage(0, 'global') .focusImage(0, 'global')
`, `,
{browseMode: function(target){ {mode: function(target){
return this.data.getImageOrder('ribbon', target) == 0 && 'disabled' }}, return this.data.getImageOrder('ribbon', target) == 0 && 'disabled' }},
function(all){ this.focusImage(0, all == null ? 'ribbon' : 'global') }], function(all){ this.focusImage(0, all == null ? 'ribbon' : 'global') }],
lastImage: ['Navigate/Last image in current ribbon', lastImage: ['Navigate/Last image in current ribbon',
@ -549,7 +549,7 @@ actions.Actions({
NOTE: this is symmetrical to .firstImage(..) see docs for that. NOTE: this is symmetrical to .firstImage(..) see docs for that.
`, `,
{browseMode: function(target){ {mode: function(target){
return this.data.getImageOrder('ribbon', target) return this.data.getImageOrder('ribbon', target)
== this.data.getImageOrder('ribbon', -1) && 'disabled' }}, == this.data.getImageOrder('ribbon', -1) && 'disabled' }},
function(all){ this.focusImage(-1, all == null ? 'ribbon' : 'global') }], function(all){ this.focusImage(-1, all == null ? 'ribbon' : 'global') }],
@ -561,7 +561,7 @@ actions.Actions({
Shorthand for: Shorthand for:
.firstImage('global') .firstImage('global')
`, `,
{browseMode: function(){ {mode: function(){
return this.data.getImageOrder() == 0 && 'disabled' }}, return this.data.getImageOrder() == 0 && 'disabled' }},
function(){ this.firstImage(true) }], function(){ this.firstImage(true) }],
lastGlobalImage: ['Navigate/Last image globally', lastGlobalImage: ['Navigate/Last image globally',
@ -572,7 +572,7 @@ actions.Actions({
NOTE: this symmetrical to .firstGlobalImage(..) see docs for that. NOTE: this symmetrical to .firstGlobalImage(..) see docs for that.
`, `,
{browseMode: function(){ {mode: function(){
return this.data.getImageOrder() == this.data.getImageOrder(-1) && 'disabled' }}, return this.data.getImageOrder() == this.data.getImageOrder(-1) && 'disabled' }},
function(){ this.lastImage(true) }], function(){ this.lastImage(true) }],
@ -584,7 +584,7 @@ actions.Actions({
NOTE: this also modifies .direction NOTE: this also modifies .direction
NOTE: this is .symmetrical to .nextImage(..) see it for docs. NOTE: this is .symmetrical to .nextImage(..) see it for docs.
`, `,
{browseMode: 'firstImage'}, {mode: 'firstImage'},
function(a, mode){ function(a, mode){
// keep track of traverse direction... // keep track of traverse direction...
this.direction = 'left' this.direction = 'left'
@ -627,7 +627,7 @@ actions.Actions({
NOTE: this also modifies .direction NOTE: this also modifies .direction
`, `,
{browseMode: 'lastImage'}, {mode: 'lastImage'},
function(a, mode){ function(a, mode){
// keep track of traverse direction... // keep track of traverse direction...
this.direction = 'right' this.direction = 'right'
@ -693,19 +693,19 @@ actions.Actions({
}], }],
firstRibbon: ['Navigate/First ribbon', firstRibbon: ['Navigate/First ribbon',
{browseMode: function(target){ {mode: function(target){
return this.data.getRibbonOrder(target) == 0 && 'disabled'}}, return this.data.getRibbonOrder(target) == 0 && 'disabled'}},
function(){ this.focusRibbon('first') }], function(){ this.focusRibbon('first') }],
lastRibbon: ['Navigate/Last ribbon', lastRibbon: ['Navigate/Last ribbon',
{browseMode: function(target){ {mode: function(target){
return this.data.getRibbonOrder(target) return this.data.getRibbonOrder(target)
== this.data.getRibbonOrder(-1) && 'disabled'}}, == this.data.getRibbonOrder(-1) && 'disabled'}},
function(){ this.focusRibbon('last') }], function(){ this.focusRibbon('last') }],
prevRibbon: ['Navigate/Previous ribbon', prevRibbon: ['Navigate/Previous ribbon',
{browseMode: 'firstRibbon'}, {mode: 'firstRibbon'},
function(){ this.focusRibbon('before') }], function(){ this.focusRibbon('before') }],
nextRibbon: ['Navigate/Next ribbon', nextRibbon: ['Navigate/Next ribbon',
{browseMode: 'lastRibbon'}, {mode: 'lastRibbon'},
function(){ this.focusRibbon('after') }], function(){ this.focusRibbon('after') }],
}) })
@ -720,6 +720,7 @@ core.ImageGridFeatures.Feature({
'serialization', 'serialization',
], ],
suggested: [ suggested: [
'sync',
'edit', 'edit',
//'tags', //'tags',
//'sort', //'sort',
@ -734,8 +735,7 @@ core.ImageGridFeatures.Feature({
function(res){ function(res){
// we save .current unconditionally (if it exists)... // we save .current unconditionally (if it exists)...
if(res.raw.data){ if(res.raw.data){
res.index.current = res.raw.data.current res.index.current = res.raw.data.current }
}
var changes = res.changes var changes = res.changes
@ -743,10 +743,11 @@ core.ImageGridFeatures.Feature({
return return
} }
// data... // basic sections...
if((changes === true || changes.data) && res.raw.data){ // NOTE: config is local config...
res.index.data = res.raw.data ;['config', 'data'].forEach(function(section){
} if((changes === true || chages[section]) && res.raw[section]){
res.index[section] = res.raw[section] } })
// images (full)... // images (full)...
if(res.raw.images if(res.raw.images
@ -756,11 +757,11 @@ core.ImageGridFeatures.Feature({
// images-diff... // images-diff...
} else if(changes && changes.images){ } else if(changes && changes.images){
var diff = res.index['images-diff'] = {} var diff = res.index['images-diff'] = {}
changes.images.forEach(function(gid){ changes.images
diff[gid] = res.raw.images[gid] .forEach(function(gid){
}) diff[gid] = res.raw.images[gid] }) }
}
}], }],
// XXX restore local .config....
['prepareIndexForLoad', ['prepareIndexForLoad',
function(res, json, base_path){ function(res, json, base_path){
// build data and images... // build data and images...
@ -773,7 +774,9 @@ core.ImageGridFeatures.Feature({
var img = images.Images(json.images) var img = images.Images(json.images)
// this is needed for loading multiple indexes... // handle base-path...
// XXX do we actually need this???
// ...this is also done in 'location'
if(base_path){ if(base_path){
d.base_path = base_path d.base_path = base_path
// XXX STUB remove ASAP... // XXX STUB remove ASAP...
@ -829,7 +832,7 @@ actions.Actions({
// NOTE: resetting this option will clear the last direction... // NOTE: resetting this option will clear the last direction...
toggleShiftsAffectDirection: ['Interface/Shifts affect direction', toggleShiftsAffectDirection: ['Interface/Shifts affect direction',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
core.makeConfigToggler('shifts-affect-direction', core.makeConfigToggler('shifts-affect-direction',
['off', 'on'], ['off', 'on'],
function(action){ function(action){
@ -847,7 +850,7 @@ actions.Actions({
state.base = this.base }, state.base = this.base },
undo: function(state){ undo: function(state){
this.setBaseRibbon(state.base) }, this.setBaseRibbon(state.base) },
browseMode: function(target){ mode: function(target){
return this.current_ribbon == this.base && 'disabled' }}, return this.current_ribbon == this.base && 'disabled' }},
function(target){ this.data.setBase(target) }], function(target){ this.data.setBase(target) }],
@ -954,7 +957,7 @@ actions.Actions({
}], }],
shiftImageLeft: ['Edit|Sort|Image/Shift image left', { shiftImageLeft: ['Edit|Sort|Image/Shift image left', {
undo: undoShift('shiftImageRight'), undo: undoShift('shiftImageRight'),
browseMode: 'prevImage'}, mode: 'prevImage'},
function(target){ function(target){
if(target == null){ if(target == null){
this.direction = 'left' this.direction = 'left'
@ -964,7 +967,7 @@ actions.Actions({
}], }],
shiftImageRight: ['Edit|Sort|Image/Shift image right', { shiftImageRight: ['Edit|Sort|Image/Shift image right', {
undo: undoShift('shiftImageLeft'), undo: undoShift('shiftImageLeft'),
browseMode: 'nextImage'}, mode: 'nextImage'},
function(target){ function(target){
if(target == null){ if(target == null){
this.direction = 'right' this.direction = 'right'
@ -975,7 +978,7 @@ actions.Actions({
shiftRibbonUp: ['Ribbon|Edit|Sort/Shift ribbon up', { shiftRibbonUp: ['Ribbon|Edit|Sort/Shift ribbon up', {
undo: undoShift('shiftRibbonDown'), undo: undoShift('shiftRibbonDown'),
browseMode: 'prevRibbon'}, mode: 'prevRibbon'},
function(target){ function(target){
this.data.shiftRibbonUp(target) this.data.shiftRibbonUp(target)
// XXX is this the right way to go/??? // XXX is this the right way to go/???
@ -983,7 +986,7 @@ actions.Actions({
}], }],
shiftRibbonDown: ['Ribbon|Edit|Sort/Shift ribbon down', { shiftRibbonDown: ['Ribbon|Edit|Sort/Shift ribbon down', {
undo: undoShift('shiftRibbonUp'), undo: undoShift('shiftRibbonUp'),
browseMode: 'nextRibbon'}, mode: 'nextRibbon'},
function(target){ function(target){
this.data.shiftRibbonDown(target) this.data.shiftRibbonDown(target)
// XXX is this the right way to go/??? // XXX is this the right way to go/???
@ -1046,16 +1049,16 @@ actions.Actions({
this.data.getImages( this.data.getImages(
this.data.getRibbon(ribbon || 'current'))) }], this.data.getRibbon(ribbon || 'current'))) }],
mergeRibbonUp: ['Edit|Ribbon/Merge ribbon up', mergeRibbonUp: ['Edit|Ribbon/Merge ribbon up',
{browseMode: function(){ {mode: function(){
return this.data.ribbon_order[0] == this.current_ribbon && 'disabled' }}, return this.data.ribbon_order[0] == this.current_ribbon && 'disabled' }},
'mergeRibbon: "up" ...'], 'mergeRibbon: "up" ...'],
mergeRibbonDown: ['Edit|Ribbon/Merge ribbon down', mergeRibbonDown: ['Edit|Ribbon/Merge ribbon down',
{browseMode: function(){ {mode: function(){
return this.data.ribbon_order.slice(-1)[0] == this.current_ribbon && 'disabled' }}, return this.data.ribbon_order.slice(-1)[0] == this.current_ribbon && 'disabled' }},
'mergeRibbon: "down" ...'], 'mergeRibbon: "down" ...'],
// XXX should this accept a list of ribbons to flatten??? // XXX should this accept a list of ribbons to flatten???
flattenRibbons: ['Edit|Ribbon/Flatten', flattenRibbons: ['Edit|Ribbon/Flatten',
{browseMode: function(){ {mode: function(){
return this.data.ribbon_order.length <= 1 && 'disabled' }}, return this.data.ribbon_order.length <= 1 && 'disabled' }},
function(){ function(){
var ribbons = this.data.ribbons var ribbons = this.data.ribbons
@ -1245,16 +1248,16 @@ core.ImageGridFeatures.Feature({
var ImageGroupActions = var ImageGroupActions =
module.ImageGroupActions = actions.Actions({ module.ImageGroupActions = actions.Actions({
expandGroup: ['Group/Expand group', expandGroup: ['Group/Expand group',
{browseMode: 'ungroup'}, {mode: 'ungroup'},
function(target){ this.data.expandGroup(target || this.current) }], function(target){ this.data.expandGroup(target || this.current) }],
collapseGroup: ['Group/Collapse group', { collapseGroup: ['Group/Collapse group', {
journal: true, journal: true,
browseMode: 'ungroup'}, mode: 'ungroup'},
function(target){ this.data.collapseGroup(target || this.current) }], function(target){ this.data.collapseGroup(target || this.current) }],
cropGroup: ['Crop|Group/Crop group', { cropGroup: ['Crop|Group/Crop group', {
journal: true, journal: true,
browseMode: 'ungroup'}, mode: 'ungroup'},
function(target){ this.crop(this.data.cropGroup(target || this.current)) }], function(target){ this.crop(this.data.cropGroup(target || this.current)) }],
}) })
@ -1285,7 +1288,7 @@ module.ImageEditGroupActions = actions.Actions({
function(gids, group){ this.data.group(gids, group) }], function(gids, group){ this.data.group(gids, group) }],
ungroup: ['Group|Edit/Ungroup images', ungroup: ['Group|Edit/Ungroup images',
{journal: true}, {journal: true},
{browseMode: function(){ {mode: function(){
return this.data.getGroup() == null && 'disabled' }}, return this.data.getGroup() == null && 'disabled' }},
function(gids, group){ this.data.ungroup(gids, group) }], function(gids, group){ this.data.ungroup(gids, group) }],
@ -1500,7 +1503,7 @@ module.CropActions = actions.Actions({
} }
}], }],
uncrop: ['Crop/Uncrop', uncrop: ['Crop/Uncrop',
{browseMode: function(){ return this.cropped || 'disabled' }}, {mode: function(){ return this.cropped || 'disabled' }},
function(level, restore_current, keep_crop_order){ function(level, restore_current, keep_crop_order){
level = level || 1 level = level || 1
@ -1538,13 +1541,13 @@ module.CropActions = actions.Actions({
} }
}], }],
uncropAll: ['Crop/Uncrop all', uncropAll: ['Crop/Uncrop all',
{browseMode: 'uncrop'}, {mode: 'uncrop'},
function(restore_current){ this.uncrop('all', restore_current) }], function(restore_current){ this.uncrop('all', restore_current) }],
// XXX see if we need to do this on this level?? // XXX see if we need to do this on this level??
// ...might be a good idea to do this in data... // ...might be a good idea to do this in data...
uncropAndKeepOrder: ['Crop|Edit/Uncrop keeping image order', { uncropAndKeepOrder: ['Crop|Edit/Uncrop keeping image order', {
journal: true, journal: true,
browseMode: 'uncrop'}, mode: 'uncrop'},
function(level, restore_current){ this.uncrop(level, restore_current, true) }], function(level, restore_current){ this.uncrop(level, restore_current, true) }],
// XXX same as uncrop but will also try and merge changes... // XXX same as uncrop but will also try and merge changes...
// - the order is simple and already done above... // - the order is simple and already done above...
@ -1552,7 +1555,7 @@ module.CropActions = actions.Actions({
// only problem here is how to deal with new ribbons... // only problem here is how to deal with new ribbons...
mergeCrop: ['- Crop|Edit/Merge crop', { mergeCrop: ['- Crop|Edit/Merge crop', {
journal: true, journal: true,
browseMode: 'uncrop'}, mode: 'uncrop'},
function(){ function(){
// XXX // XXX
}], }],
@ -1573,7 +1576,7 @@ module.CropActions = actions.Actions({
// XXX not sure if we actually need this... // XXX not sure if we actually need this...
cropFlatten: ['Crop/$Flatten', cropFlatten: ['Crop/$Flatten',
{browseMode: function(){ {mode: function(){
return this.data.ribbon_order.length <= 1 && 'disabled' }}, return this.data.ribbon_order.length <= 1 && 'disabled' }},
function(list){ this.data.length > 0 && this.crop(list, true) }], function(list){ this.data.length > 0 && this.crop(list, true) }],
cropRibbon: ['Crop|Ribbon/Crop $ribbon', cropRibbon: ['Crop|Ribbon/Crop $ribbon',
@ -1733,7 +1736,7 @@ module.CropActions = actions.Actions({
core.doc` core.doc`
`, `,
{ {
browseMode: 'uncrop', mode: 'uncrop',
getUndoState: function(d){ getUndoState: function(d){
d.placements = this.data.getImagePositions(d.args[0]) }, d.placements = this.data.getImagePositions(d.args[0]) },
undo: function(d){ undo: function(d){
@ -1796,7 +1799,7 @@ module.CropActions = actions.Actions({
NOTE: this is a shorthand for .removeFromCrop(..) but only supports NOTE: this is a shorthand for .removeFromCrop(..) but only supports
ribbon removal.`, ribbon removal.`,
{browseMode: 'uncrop',}, {mode: 'uncrop',},
function(gids){ function(gids){
var that = this var that = this
gids = gids || this.current_ribbon gids = gids || this.current_ribbon

View File

@ -745,7 +745,7 @@ var CollectionActions = actions.Actions({
.collectionToTop(gid) .collectionToTop(gid)
-> this -> this
`, `,
{browseMode: 'uncollect'}, {mode: 'uncollect'},
function(collection){ function(collection){
collection = collection || this.collection collection = collection || this.collection
collection = this.collectionGIDs[collection] || collection collection = this.collectionGIDs[collection] || collection
@ -984,7 +984,7 @@ var CollectionActions = actions.Actions({
NOTE: this will remove any gid, be it image or ribbon. NOTE: this will remove any gid, be it image or ribbon.
`, `,
{ {
browseMode: function(){ return !this.collection && 'disabled' }, mode: function(){ return !this.collection && 'disabled' },
// XXX two ways to go: // XXX two ways to go:
// - .collect(..) + .data.placeImage(..) // - .collect(..) + .data.placeImage(..)
// - rewrite .collect(..) to use .data.placeImage(..) (like: .addToCrop(..)) // - rewrite .collect(..) to use .data.placeImage(..) (like: .addToCrop(..))
@ -1079,7 +1079,7 @@ var CollectionActions = actions.Actions({
i.e. each gid given will be resolved to a ribbon which will be i.e. each gid given will be resolved to a ribbon which will be
removed. removed.
`, `,
{browseMode: 'uncollect'}, {mode: 'uncollect'},
function(gids, collection){ function(gids, collection){
var that = this var that = this
gids = gids || 'current' gids = gids || 'current'
@ -1282,7 +1282,7 @@ var CollectionActions = actions.Actions({
// Config and interface stuff... // Config and interface stuff...
// //
toggleCollectionCropRetention: ['Interface/Collection crop save mode', toggleCollectionCropRetention: ['Interface/Collection crop save mode',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
core.makeConfigToggler( core.makeConfigToggler(
'collection-save-crop-state', 'collection-save-crop-state',
[ [
@ -2718,7 +2718,7 @@ var UICollectionActions = actions.Actions({
collectionGetterWrapper(function(title){ this.loadCollection(title) })], collectionGetterWrapper(function(title){ this.loadCollection(title) })],
loadMainCollection: ['Collections/Exit collection view', loadMainCollection: ['Collections/Exit collection view',
{ {
browseMode: 'uncollect', mode: 'uncollect',
// prevent this from showing up in .uiDialogs list... // prevent this from showing up in .uiDialogs list...
__dialog__: false, __dialog__: false,
}, },
@ -2750,7 +2750,7 @@ var UICollectionActions = actions.Actions({
// XXX do we need this??? // XXX do we need this???
cropImagesInCollection: ['Collections|Crop/Crop images in collection...', cropImagesInCollection: ['Collections|Crop/Crop images in collection...',
{browseMode: function(){ {mode: function(){
return (!this.collections return (!this.collections
|| Object.keys(this.collections).length == 0) || Object.keys(this.collections).length == 0)
&& 'disabled' }}, && 'disabled' }},
@ -2764,7 +2764,7 @@ var UICollectionActions = actions.Actions({
}) })
}, null, false)], }, null, false)],
cropOutImagesInCollection: ['Collections|Crop/Remove collection images from crop...', cropOutImagesInCollection: ['Collections|Crop/Remove collection images from crop...',
{browseMode: 'cropImagesInCollection'}, {mode: 'cropImagesInCollection'},
mixedModeCollectionAction(function(title){ mixedModeCollectionAction(function(title){
var that = this var that = this
this.ensureCollection(title) this.ensureCollection(title)
@ -2900,7 +2900,7 @@ var CollectionMarksActions = actions.Actions({
function(collection){ function(collection){
return this.collect(this.marked, collection) }], return this.collect(this.marked, collection) }],
uncollectMarked: ['Collections|Mark/Remove marked from collection', uncollectMarked: ['Collections|Mark/Remove marked from collection',
{browseMode: function(){ {mode: function(){
return (!this.collection || this.marked.length == 0) && 'disabled' }}, return (!this.collection || this.marked.length == 0) && 'disabled' }},
function(collection){ function(collection){
return this.uncollect(this.marked, collection) }], return this.uncollect(this.marked, collection) }],
@ -2910,7 +2910,7 @@ var CollectionMarksActions = actions.Actions({
function(collection){ function(collection){
return this.collectTagged('bookmark', collection) }], return this.collectTagged('bookmark', collection) }],
uncollectBookmarked: ['Collections|Bookmark/Remove bookmarked from collection', uncollectBookmarked: ['Collections|Bookmark/Remove bookmarked from collection',
{browseMode: function(){ {mode: function(){
return (!this.collection || this.bookmarked.length == 0) && 'disabled' }}, return (!this.collection || this.bookmarked.length == 0) && 'disabled' }},
function(collection){ function(collection){
return this.uncollectTagged('bookmark', collection) }], return this.uncollectTagged('bookmark', collection) }],
@ -2939,7 +2939,7 @@ var UICollectionMarksActions = actions.Actions({
// UI... // UI...
// XXX should these be a separate feature??? // XXX should these be a separate feature???
markImagesInCollection: ['Collections|Mark/$Mark images in collection...', markImagesInCollection: ['Collections|Mark/$Mark images in collection...',
{browseMode: 'cropImagesInCollection'}, {mode: 'cropImagesInCollection'},
mixedModeCollectionAction(function(title){ mixedModeCollectionAction(function(title){
var that = this var that = this
this.ensureCollection(title) this.ensureCollection(title)
@ -2950,7 +2950,7 @@ var UICollectionMarksActions = actions.Actions({
}) })
})], })],
addMarkedToCollection: ['Collections|Mark/Add marked to $collection...', addMarkedToCollection: ['Collections|Mark/Add marked to $collection...',
{browseMode: function(){ {mode: function(){
return this.marked.length == 0 && 'disabled' }}, return this.marked.length == 0 && 'disabled' }},
mixedModeCollectionAction(function(title){ this.collectMarked(title) })], mixedModeCollectionAction(function(title){ this.collectMarked(title) })],
}) })

View File

@ -112,7 +112,7 @@ var FileSystemCommentsActions = actions.Actions({
// XXX this will not save comments for merged indexes... // XXX this will not save comments for merged indexes...
saveComments: ['- File/', saveComments: ['- File/',
function(path, date, logger){ function(path, date, logger){
if(this.location.method != 'loadIndex' if(this.location.load != 'loadIndex'
|| this.location.loaded.length > 1){ || this.location.loaded.length > 1){
return return
} }
@ -135,7 +135,7 @@ var FileSystemCommentsActions = actions.Actions({
//*/ //*/
loadComments: ['- File/', loadComments: ['- File/',
function(path, date, logger){ function(path, date, logger){
if(this.location.method != 'loadIndex'){ if(this.location.load != 'loadIndex'){
return return
} }

View File

@ -485,6 +485,58 @@ var IntrospectionActions = actions.Actions({
isEvent: isEvent:
actions.doWithRootAction(function(action){ actions.doWithRootAction(function(action){
return !!action.__event__ }), return !!action.__event__ }),
// XXX revise...
getActionMode: ['- Interface/',
doc`Get action browse mode...
Get and action's .mode(..) method and return its result.
Expected values:
'disabled' - actions is disabled
'hidden' - actions is hidden
NOTE: other values are ignored.
`,
function(action, mode_cache){
var m = action
var visited = [m]
var last
// check cache...
if(m in (mode_cache || {})){
return mode_cache[m] }
// handle aliases...
do {
last = m
m = this.getActionAttr(m, 'mode')
// check cache...
if(m in (mode_cache || {})){
return mode_cache[m] }
// check for loops...
if(m && visited[m] != null){
m = null
break
}
visited.push(m)
} while(typeof(m) == typeof('str'))
//return m ? m.call(this) : undefined
return m ?
// no cache...
(mode_cache == null ?
m.call(this)
// cache hit...
: last in mode_cache ?
mode_cache[last]
// call check and populate cache...
: (mode_cache[action] =
mode_cache[last] =
m.call(this)))
: actions.UNDEFINED }],
}) })
@ -1799,7 +1851,7 @@ var JournalActions = actions.Actions({
.journal up until and including the undone action. .journal up until and including the undone action.
NOTE: only the undone action is pushed to .rjournal NOTE: only the undone action is pushed to .rjournal
`, `,
{browseMode: function(){ {mode: function(){
return (this.journal && this.journal.length > 0) || 'disabled' }}, return (this.journal && this.journal.length > 0) || 'disabled' }},
function(){ function(){
var journal = this.journal.slice() || [] var journal = this.journal.slice() || []
@ -1854,7 +1906,7 @@ var JournalActions = actions.Actions({
Essentially this will remove and re-run the last action in .rjournal Essentially this will remove and re-run the last action in .rjournal
`, `,
{browseMode: function(){ {mode: function(){
return (this.rjournal && this.rjournal.length > 0) || 'disabled' }}, return (this.rjournal && this.rjournal.length > 0) || 'disabled' }},
function(){ function(){
if(!this.rjournal || this.rjournal.length == 0){ if(!this.rjournal || this.rjournal.length == 0){

View File

@ -206,7 +206,7 @@ var ExampleActions = actions.Actions({
// target... // target...
// XXX more docs! // XXX more docs!
null, null,
// state accessor... // state getter...
function(_, state){ function(_, state){
// get the state... // get the state...
if(state == null){ if(state == null){
@ -324,7 +324,7 @@ var ExampleUIActions = actions.Actions({
}], }],
exampleActionDisabled: ['Test/$Disabled example action', exampleActionDisabled: ['Test/$Disabled example action',
{browseMode: function(){ return 'disabled' }}, {mode: function(){ return 'disabled' }},
function(){ function(){
console.log('Disabled action called:', [...arguments]) }], console.log('Disabled action called:', [...arguments]) }],

View File

@ -382,13 +382,15 @@ var FileSystemLoaderActions = actions.Actions({
!index !index
&& console.error('Failed to load index from:', paths) && console.error('Failed to load index from:', paths)
// prepare the location data... // prepare the location data...
index.location = { index.location =
path: path, Object.assign(
loaded: loaded, index.location || {},
method: 'loadIndex', {
} path: path,
loaded: loaded,
load: 'loadIndex',
})
if(from_date){ if(from_date){
index.location.from = from_date index.location.from = from_date
} }
@ -597,7 +599,8 @@ var FileSystemLoaderActions = actions.Actions({
location: { location: {
path: path, path: path,
method: 'loadImages', load: 'loadImages',
sync: 'syncIndexWithDir',
} }
}) })
.then(function(){ .then(function(){
@ -675,7 +678,7 @@ var FileSystemLoaderActions = actions.Actions({
// XXX revise logger... // XXX revise logger...
// XXX revise alignment... // XXX revise alignment...
loadNewImages: ['File/Load new images', loadNewImages: ['File/Load new images to index',
core.doc`Load new images... core.doc`Load new images...
Load new images from current path... Load new images from current path...
@ -691,6 +694,10 @@ var FileSystemLoaderActions = actions.Actions({
NOTE: this will not load images that are already loaded. NOTE: this will not load images that are already loaded.
`, `,
{ locationSync: true,
mode: function(){
return ['loadIndex', 'loadImages'].includes(this.location.load)
|| 'disabled' }, },
function(path, logger){ function(path, logger){
path = path || this.location.path path = path || this.location.path
@ -843,6 +850,8 @@ var FileSystemLoaderActions = actions.Actions({
NOTE: no actual data is removed. NOTE: no actual data is removed.
NOTE: this will not remove generated previews from index. NOTE: this will not remove generated previews from index.
`, `,
{ locationSync: true,
mode: 'loadNewImages', },
function(logger){ function(logger){
var that = this var that = this
logger = logger || this.logger logger = logger || this.logger
@ -887,7 +896,7 @@ var FileSystemLoaderActions = actions.Actions({
// XXX EXPERIMENTAL... // XXX EXPERIMENTAL...
// shorthand... // shorthand...
syncIndexWithDir: ['- File/', syncIndexWithDir: ['File/Synchronize index to path',
core.doc`Load new and remove deleted images... core.doc`Load new and remove deleted images...
.syncIndexWithDir() .syncIndexWithDir()
@ -898,6 +907,8 @@ var FileSystemLoaderActions = actions.Actions({
.loadNewImages() .loadNewImages()
.removeMissingImages() .removeMissingImages()
`, `,
{ locationSync: true,
mode: 'loadNewImages', },
function(logger){ function(logger){
return Promise.all([ return Promise.all([
this.loadNewImages(), this.loadNewImages(),
@ -1137,7 +1148,7 @@ var FileSystemLoaderUIActions = actions.Actions({
var dialog = this var dialog = this
var path = that.location.path var path = that.location.path
if(that.location.method != 'loadIndex'){ if(that.location.load != 'loadIndex'){
make('No indexes loaded...', null, true) make('No indexes loaded...', null, true)
return return
} }
@ -1405,7 +1416,7 @@ var FileSystemSaveHistoryUIActions = actions.Actions({
// Unsaved changes will be saved to .unsaved_index when switching // Unsaved changes will be saved to .unsaved_index when switching
// from current to a historic state. // from current to a historic state.
// //
// NOTE: this will show no history if .location.method is not 'loadIndex'.. // NOTE: this will show no history if .location.load is not 'loadIndex'..
// NOTE: this will set changes to all when loading a historic state // NOTE: this will set changes to all when loading a historic state
// that the latest and to non otherwise.... // that the latest and to non otherwise....
// //
@ -1441,7 +1452,7 @@ var FileSystemSaveHistoryUIActions = actions.Actions({
} }
// only search for history if we have an index loaded... // only search for history if we have an index loaded...
if(that.location.method != 'loadIndex'){ if(that.location.load != 'loadIndex'){
make('No history...', {disabled: true}) make('No history...', {disabled: true})
// select the 'Unsaved' item... // select the 'Unsaved' item...
@ -1758,7 +1769,7 @@ var FileSystemWriterActions = actions.Actions({
} }
// XXX // XXX
if(path == null && this.location.method != 'loadIndex'){ if(path == null && this.location.load != 'loadIndex'){
path = this.location.path path = this.location.path
} }
@ -1798,7 +1809,7 @@ var FileSystemWriterActions = actions.Actions({
.spawn('attrib', ['+h', full_path]) .spawn('attrib', ['+h', full_path])
}) })
.then(function(){ .then(function(){
location.method = 'loadIndex' location.load = 'loadIndex'
location.from = index.date location.from = index.date
//return location //return location

View File

@ -144,7 +144,7 @@ var URLHistoryActions = actions.Actions({
this.url_history = this.url_history || {} this.url_history = this.url_history || {}
var item = !clear ? (this.url_history[url] || {}) : {} var item = !clear ? (this.url_history[url] || {}) : {}
open = item.open = open || this.location.method open = item.open = open || this.location.load
check = item.check = check || this.location.check || 'checkPath' check = item.check = check || this.location.check || 'checkPath'
// remove the old value... // remove the old value...
@ -429,7 +429,7 @@ var URLHistoryLocalStorageActions = actions.Actions({
}) })
} }
this.openURLFromHistory(l.path, l.method) this.openURLFromHistory(l.path, l.load)
} else { } else {
this.openURLFromHistory(0) this.openURLFromHistory(0)
@ -514,17 +514,17 @@ module.URLHistoryFSWriter = core.ImageGridFeatures.Feature({
res.then(function(l){ res.then(function(l){
// push saved to top... // push saved to top...
if(that.config['url-history-push-to-top-on-save']){ if(that.config['url-history-push-to-top-on-save']){
that.pushURLToHistory(l.path, l.method) that.pushURLToHistory(l.path, l.load)
// update... // update...
} else { } else {
var e = that.url_history[l.path] var e = that.url_history[l.path]
if(e != null){ if(e != null){
e.open = l.method e.open = l.load
that.storeURLHistory() that.storeURLHistory()
} else { } else {
that.pushURLToHistory(l.path, l.method) that.pushURLToHistory(l.path, l.load)
} }
} }
}) })

View File

@ -263,9 +263,7 @@ module.GLOBAL_KEYBOARD = {
ctrl_F: 'F11', ctrl_F: 'F11',
meta_F: 'F11', meta_F: 'F11',
// XXX EXPERIMENTAL: which should it be??? ctrl_R: 'sync!',
//ctrl_R: 'loadNewImages!',
ctrl_R: 'syncIndexWithDir!',
ctrl_alt_R: 'reload!', ctrl_alt_R: 'reload!',
ctrl_shift_R: 'F5', ctrl_shift_R: 'F5',
@ -616,7 +614,7 @@ var KeyboardActions = actions.Actions({
// check if we have no doc... // check if we have no doc...
if(doc == null || doc == ''){ if(doc == null || doc == ''){
console.warn('Action has no doc: "' console.warn('Action has no short doc: "'
+ a.action +'" at: "'+ code +'"') + a.action +'" at: "'+ code +'"')
// XXX ??? // XXX ???
return return

View File

@ -12,6 +12,7 @@ var object = require('lib/object')
var actions = require('lib/actions') var actions = require('lib/actions')
var features = require('lib/features') var features = require('lib/features')
var toggler = require('lib/toggler')
var core = require('features/core') var core = require('features/core')
@ -22,26 +23,17 @@ var core = require('features/core')
// XXX need the other .location stuff to be visible/accessible... // XXX need the other .location stuff to be visible/accessible...
// ...now this only shows path... // ...now this only shows path...
var LocationProto = { var Location =
//module.Location =
object.Constructor('Location', {
get path(){ get path(){
return this.__actions.__location.path return this.__actions.__location.path },
},
set path(value){ set path(value){
this.__actions.location = value this.__actions.location = value },
},
__init__: function(actions){ __init__: function(actions){
this.__actions = actions this.__actions = actions },
})
// XXX this does not work...
// ...the oother way around seems best:
// actions.__location.__proto__ = this
//this.__proto__ = actions.__location
},
}
var Location = object.Constructor('Location', LocationProto)
@ -59,13 +51,18 @@ var Location = object.Constructor('Location', LocationProto)
var LocationActions = actions.Actions({ var LocationActions = actions.Actions({
config: { config: {
'default-load-method': null, 'default-load-method': null,
'location-stored-attrs': [
'sync',
],
}, },
// Format: // Format:
// { // {
// path: <base-path>,
// method: <load-method>,
// current: <current-gid>, // current: <current-gid>,
// load: <load-method>,
// sync: <sync-method>,
// path: <base-path>,
// ... // ...
// } // }
// //
@ -100,10 +97,6 @@ var LocationActions = actions.Actions({
this.loadLocation(value) }, this.loadLocation(value) },
clearLoaction: ['File/Clear location',
function(){ delete this.__location }],
// Load location... // Load location...
// //
// Reload current location... // Reload current location...
@ -131,7 +124,7 @@ var LocationActions = actions.Actions({
if(typeof(location) == typeof('str')){ if(typeof(location) == typeof('str')){
location = { location = {
path: path, path: path,
method: (this.__location && this.__location.method) load: (this.__location && this.__location.load)
|| this.config['default-load-method'], || this.config['default-load-method'],
current: this.current, current: this.current,
} }
@ -142,8 +135,8 @@ var LocationActions = actions.Actions({
location = JSON.parse(JSON.stringify(location)) location = JSON.parse(JSON.stringify(location))
} }
var method = location.method var load = location.load
|| this.location.method || this.location.load
|| this.config['default-load-method'] || this.config['default-load-method']
var cur = location.current var cur = location.current
var path = location.path var path = location.path
@ -158,7 +151,7 @@ var LocationActions = actions.Actions({
//this.__location = location //this.__location = location
// NOTE: the method should set the proper location if it uses .clear()... // NOTE: the method should set the proper location if it uses .clear()...
var res = method && this[method](path) var res = load && this[load](path)
// load current... // load current...
@ -177,6 +170,10 @@ var LocationActions = actions.Actions({
return res return res
}], }],
clearLoaction: ['File/Clear location',
function(){ delete this.__location }],
// XXX // XXX
// XXX should these have the same effect as .dispatch('location:*:load', location)??? // XXX should these have the same effect as .dispatch('location:*:load', location)???
// ...another way to put it is should we call this from dispatch? // ...another way to put it is should we call this from dispatch?
@ -186,20 +183,19 @@ var LocationActions = actions.Actions({
_loadLocation: ['- File/Save location', _loadLocation: ['- File/Save location',
{protocol: 'location:*:load'}, {protocol: 'location:*:load'},
function(location){ function(location){
this.location.method = this.locationMethod(location) this.location.load = this.locationMethod(location)
this.dispatch('location:*:load', location) this.dispatch('location:*:load', location)
}], }],
_saveLocation: ['- File/Save location', _saveLocation: ['- File/Save location',
{protocol: 'location:*:save'}, {protocol: 'location:*:save'},
function(location){ function(location){
this.location.method = this.locationMethod(location) this.location.load = this.locationMethod(location)
this.dispatch('location:*:save', location) }], this.dispatch('location:*:save', location) }],
_locationMethod: ['- File/', _locationMethod: ['- File/',
{protocol: 'location:?'}, {protocol: 'location:?'},
function(location){ function(location){
return (location || this.location).method || null }], return (location || this.location).load || null }],
//
// format: // format:
// { // {
// 'protocol:method': 'actionName', // 'protocol:method': 'actionName',
@ -212,8 +208,7 @@ var LocationActions = actions.Actions({
get protocols(){ get protocols(){
var cache = this.__location_protocol_cache = this.__location_protocol_cache var cache = this.__location_protocol_cache = this.__location_protocol_cache
|| this.cacheProtocols() || this.cacheProtocols()
return cache return cache },
},
cacheProtocols: ['- File/', cacheProtocols: ['- File/',
function(){ function(){
var that = this var that = this
@ -221,11 +216,8 @@ var LocationActions = actions.Actions({
this.actions.forEach(function(n){ this.actions.forEach(function(n){
var proto = that.getActionAttr(n, 'protocol') var proto = that.getActionAttr(n, 'protocol')
if(proto){ if(proto){
res[proto] = n res[proto] = n } })
} return res }],
})
return res
}],
// XXX how do we call the dispatched actions and all the matching // XXX how do we call the dispatched actions and all the matching
// pattern actions??? // pattern actions???
// One way to go would be: // One way to go would be:
@ -316,6 +308,91 @@ var LocationActions = actions.Actions({
} }
}], }],
// sync API...
//
get location_sync_methods(){
var that = this
return (this.__location_sync_methods_cache =
this.__location_sync_methods_cache
|| this.actions
.filter(function(n){
return that.getActionAttr(n, 'locationSync') })
.reduce(function(res, n){
res[n] =
(that.getActionAttr(n, 'doc') || '')
.split(/[\\\/]/)
.pop()
res[n] = res[n] == '' ?
n
: res[n]
return res
}, {})) },
sync: ['- System/Synchronize index',
core.doc`Synchronize index...
.sync()
-> promise
NOTE: it is up to the client to detect and implement the actual
sync mechanics.
NOTE: this expects the return value of the sync handler to be
a promise...
`,
function(){
var method = this.location.sync
return method in this ?
// NOTE: this should return a promise...
this[method](...arguments)
: Promise.resolve() }],
toggleSyncMethod: ['File/Index synchronization method',
core.doc`Toggle index synchronization method
NOTE: this will not show disabled methods.`,
toggler.Toggler(null,
function(_, state){
var dict = this.location_sync_methods
// get...
if(state == null){
return dict[this.location.sync]
|| this.location.sync
|| 'none' }
// clear...
if(state == 'none'){
delete this.location.sync
// set...
} else {
// reverse dict...
var rdict = new Map(
Object.entries(dict)
.map(function([k, v]){
return [v, k] }))
// normalize state to action name...
state = state in dict ?
state
: (rdict.get(state) || state)
this.location.sync = state
}
this.markChanged
&& this.markChanged('config')
},
function(){
var that = this
return ['none',
...Object.entries(this.location_sync_methods)
.filter(function([n, d]){
// do not list disabled methods...
return that.getActionMode(n) != 'disabled' })
.map(function([n, d]){ return d }) ] })],
// 1) store .location // 1) store .location
// 2) cleanup .images[..].base_path // 2) cleanup .images[..].base_path
// //
@ -335,9 +412,7 @@ var LocationActions = actions.Actions({
if(l.path == img.base_path){ if(l.path == img.base_path){
delete img.base_path delete img.base_path
} }
}) }) } }}],
}
}}],
load: [function(){ load: [function(){
return function(_, data){ return function(_, data){
var that = this var that = this
@ -356,14 +431,12 @@ var LocationActions = actions.Actions({
if(img.base_path == null){ if(img.base_path == null){
img.base_path = l.path img.base_path = l.path
} }
}) }) }}],
}}],
clone: [function(){ clone: [function(){
return function(res){ return function(res){
if(this.location){ if(this.location){
res.__location = JSON.parse(JSON.stringify(this.__location)) res.__location = JSON.parse(JSON.stringify(this.__location))
} } }}],
}}],
clear: [function(){ clear: [function(){
this.clearLoaction() }], this.clearLoaction() }],
}) })
@ -380,6 +453,36 @@ module.Location = core.ImageGridFeatures.Feature({
actions: LocationActions, actions: LocationActions,
handlers: [ handlers: [
// handle:
// - local configuration...
// .location <-> .config
// XXX should this handle image .base_path ???
['prepareIndexForWrite',
function(res){
if(res.changes === true || res.changes.config){
var data = {}
;(this.config['location-stored-attrs'] || [])
.forEach(function(attr){
attr in res.raw.location
&& (data[attr] = res.raw.location[attr]) })
Object.keys(data).length > 0
&& (res.index.config =
Object.assign(
res.index.config || {},
data)) } }],
['prepareIndexForLoad',
function(res, json, base_path){
if(json.config){
var data = {}
;(this.config['location-stored-attrs'] || [])
.forEach(function(attr){
attr in json.config
&& (data[attr] = json.config[attr]) })
Object.keys(data).length > 0
&& (res.location =
Object.assign(
res.location || {},
data)) } }],
], ],
}) })

View File

@ -257,37 +257,37 @@ var ImageMarkActions = actions.Actions({
}], }],
prevMarked: ['Mark|Navigate/Previous marked image', prevMarked: ['Mark|Navigate/Previous marked image',
{browseMode: function(target){ {mode: function(target){
return this.data.getImage('current', 'before', this.marked) == null && 'disabled' }}, return this.data.getImage('current', 'before', this.marked) == null && 'disabled' }},
function(mode){ this.prevTagged('marked', mode) }], function(mode){ this.prevTagged('marked', mode) }],
nextMarked: ['Mark|Navigate/Next marked image', nextMarked: ['Mark|Navigate/Next marked image',
{browseMode: function(target){ {mode: function(target){
return this.data.getImage('current', 'after', this.marked) == null && 'disabled' }}, return this.data.getImage('current', 'after', this.marked) == null && 'disabled' }},
function(mode){ this.nextTagged('marked', mode) }], function(mode){ this.nextTagged('marked', mode) }],
cropMarked: ['Mark|Crop/Crop $marked images', cropMarked: ['Mark|Crop/Crop $marked images',
{browseMode: function(target){ {mode: function(target){
return this.marked.length == 0 && 'disabled' }}, return this.marked.length == 0 && 'disabled' }},
'crop: "marked" ...'], 'crop: "marked" ...'],
//function(flatten){ this.cropTagged('marked', flatten) }], //function(flatten){ this.cropTagged('marked', flatten) }],
//function(flatten){ this.cropTagged('marked', 'any', flatten) }], //function(flatten){ this.cropTagged('marked', 'any', flatten) }],
removeMarkedFromCrop: ['Mark|Crop/Remove marked from crop', removeMarkedFromCrop: ['Mark|Crop/Remove marked from crop',
{browseMode: function(target){ {mode: function(target){
return (this.marked.length == 0 || !this.cropped) && 'disabled' }}, return (this.marked.length == 0 || !this.cropped) && 'disabled' }},
'removeFromCrop: marked'], 'removeFromCrop: marked'],
rotateMarkedCW: ['Mark/Rotate marked clockwise', rotateMarkedCW: ['Mark/Rotate marked clockwise',
{browseMode: 'cropMarked'}, {mode: 'cropMarked'},
'rotateCW: marked'], 'rotateCW: marked'],
rotateMarkedCCW: ['Mark/Rotate marked counterclockwise', rotateMarkedCCW: ['Mark/Rotate marked counterclockwise',
{browseMode: 'cropMarked'}, {mode: 'cropMarked'},
'rotateCCW: marked'], 'rotateCCW: marked'],
flipMarkedVertical: ['Mark/Flip marked vertically', flipMarkedVertical: ['Mark/Flip marked vertically',
{browseMode: 'cropMarked'}, {mode: 'cropMarked'},
'flipVertical: marked'], 'flipVertical: marked'],
flipMarkedHorizontal: ['Mark/Flip marked horizontally', flipMarkedHorizontal: ['Mark/Flip marked horizontally',
{browseMode: 'cropMarked'}, {mode: 'cropMarked'},
'flipHorizontal: marked'], 'flipHorizontal: marked'],
}) })
@ -396,29 +396,29 @@ var ImageMarkEditActions = actions.Actions({
shiftMarkedUp: ['Mark/Shift marked u$p', shiftMarkedUp: ['Mark/Shift marked u$p',
{undo: undoShift('shiftMarkedDown'), {undo: undoShift('shiftMarkedDown'),
browseMode: 'cropMarked'}, mode: 'cropMarked'},
shiftMarked('up')], shiftMarked('up')],
shiftMarkedDown: ['Mark/Shift marked $down', shiftMarkedDown: ['Mark/Shift marked $down',
{undo: undoShift('shiftMarkedUp'), {undo: undoShift('shiftMarkedUp'),
browseMode: 'cropMarked'}, mode: 'cropMarked'},
shiftMarked('down')], shiftMarked('down')],
// XXX undo... // XXX undo...
shiftMarkedAfter: ['Mark|Image/Shift marked $after', shiftMarkedAfter: ['Mark|Image/Shift marked $after',
{browseMode: 'cropMarked'}, {mode: 'cropMarked'},
function(target){ function(target){
this.shiftImageTo(this.marked, target || 'current', 'after') }], this.shiftImageTo(this.marked, target || 'current', 'after') }],
// XXX undo... // XXX undo...
shiftMarkedBefore: ['Mark|Image/Shift marked $b$efore', shiftMarkedBefore: ['Mark|Image/Shift marked $b$efore',
{browseMode: 'cropMarked'}, {mode: 'cropMarked'},
function(target){ function(target){
this.shiftImageTo(this.marked, target || 'current', 'before') }], this.shiftImageTo(this.marked, target || 'current', 'before') }],
unmarkRibbon: ['Mark/Unmark ribbon', unmarkRibbon: ['Mark/Unmark ribbon',
{browseMode: 'cropMarked'}, {mode: 'cropMarked'},
'toggleMark: "ribbon" "off"'], 'toggleMark: "ribbon" "off"'],
unmarkLoaded: ['Mark/$Unmark all', unmarkLoaded: ['Mark/$Unmark all',
{browseMode: 'cropMarked'}, {mode: 'cropMarked'},
'toggleMark: "loaded" "off"'], 'toggleMark: "loaded" "off"'],
}) })
@ -445,7 +445,7 @@ var ImageMarkGroupActions = actions.Actions({
// NOTE: this will only group loaded images... // NOTE: this will only group loaded images...
groupMarked: ['Group|Mark/-70:Group loaded marked images', groupMarked: ['Group|Mark/-70:Group loaded marked images',
{journal: true, {journal: true,
browseMode: 'cropMarked'}, mode: 'cropMarked'},
function(){ function(){
this.group(this.data.getImages(this.marked)) }], this.group(this.data.getImages(this.marked)) }],
}) })
@ -524,16 +524,16 @@ var ImageBookmarkActions = actions.Actions({
: this.data.sortViaOrder(this.data.tagQuery('bookmark')) }, : this.data.sortViaOrder(this.data.tagQuery('bookmark')) },
prevBookmarked: ['Bookmark|Navigate/Previous bookmarked image', prevBookmarked: ['Bookmark|Navigate/Previous bookmarked image',
{browseMode: function(target){ {mode: function(target){
return this.data.getImage('current', 'before', this.bookmarked) == null && 'disabled' }}, return this.data.getImage('current', 'before', this.bookmarked) == null && 'disabled' }},
function(mode){ this.prevTagged('bookmark', mode) }], function(mode){ this.prevTagged('bookmark', mode) }],
nextBookmarked: ['Bookmark|Navigate/Next bookmarked image', nextBookmarked: ['Bookmark|Navigate/Next bookmarked image',
{browseMode: function(target){ {mode: function(target){
return this.data.getImage('current', 'after', this.bookmarked) == null && 'disabled' }}, return this.data.getImage('current', 'after', this.bookmarked) == null && 'disabled' }},
function(mode){ this.nextTagged('bookmark', mode) }], function(mode){ this.nextTagged('bookmark', mode) }],
cropBookmarked: ['Bookmark|Crop/Crop $bookmarked images', cropBookmarked: ['Bookmark|Crop/Crop $bookmarked images',
{browseMode: function(target){ {mode: function(target){
return this.bookmarked.length == 0 && 'disabled' }}, return this.bookmarked.length == 0 && 'disabled' }},
'crop: "bookmarked" ...'], 'crop: "bookmarked" ...'],
//function(flatten){ this.cropTagged('bookmark', 'any', flatten) }], //function(flatten){ this.cropTagged('bookmark', 'any', flatten) }],
@ -572,7 +572,7 @@ var ImageBookmarkEditActions = actions.Actions({
// 'off' - toggle all off // 'off' - toggle all off
// 'next' - toggle each image to next state // 'next' - toggle each image to next state
toggleBookmarkOnMarked: ['Bookmark|Mark/-70:Toggle bookmark on maked images', toggleBookmarkOnMarked: ['Bookmark|Mark/-70:Toggle bookmark on maked images',
{browseMode: 'cropMarked'}, {mode: 'cropMarked'},
function(action){ function(action){
return this.toggleBookmark(this.marked, action) }], return this.toggleBookmark(this.marked, action) }],
}) })

View File

@ -352,7 +352,7 @@ var MetadataUIActions = actions.Actions({
function(){ return this.config['metadata-auto-select-modes'] })], function(){ return this.config['metadata-auto-select-modes'] })],
toggleMetadataGraph: ['Interface/Metadata graph display', toggleMetadataGraph: ['Interface/Metadata graph display',
{ browseMode: function(){ { mode: function(){
return (!graph || this.config['browse-advanced-mode'] != 'on') && 'hidden' }}, return (!graph || this.config['browse-advanced-mode'] != 'on') && 'hidden' }},
core.makeConfigToggler('metadata-graph', ['on', 'off'])], core.makeConfigToggler('metadata-graph', ['on', 'off'])],

View File

@ -172,7 +172,7 @@ module.TagsEditActions = actions.Actions({
// NOTE: setting source to 'both' and mode to 'reset' is the same as // NOTE: setting source to 'both' and mode to 'reset' is the same as
// 'images' and 'reset' as all .data tags will be lost on first // 'images' and 'reset' as all .data tags will be lost on first
// pass... // pass...
syncTags: ['Tag/-10:Synchoronize tags between data and images', syncTags: ['Tag/-10:Synchronize tags between data and images',
{journal: true}, {journal: true},
function(source, mode){ function(source, mode){
// can't do anything if either .data or .images are not // can't do anything if either .data or .images are not

View File

@ -28,7 +28,7 @@ var PreCacheActions = actions.Actions({
// NOTE: this will not work from chrome when loading from a local fs... // NOTE: this will not work from chrome when loading from a local fs...
// XXX experimental... // XXX experimental...
startCacheWorker: ['Interface/', startCacheWorker: ['Interface/',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
function(){ function(){
// a worker is started already... // a worker is started already...
if(this.cacheWorker != null){ if(this.cacheWorker != null){
@ -63,7 +63,7 @@ var PreCacheActions = actions.Actions({
this.cacheWorker.url = url this.cacheWorker.url = url
}], }],
stopCacheWorker: ['Interface/', stopCacheWorker: ['Interface/',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
function(){ function(){
if(this.cacheWorker){ if(this.cacheWorker){
this.cacheWorker.terminate() this.cacheWorker.terminate()

View File

@ -101,7 +101,7 @@ var RangeActions = actions.Actions({
}], }],
clearRange: ['Range/Clear range', clearRange: ['Range/Clear range',
// XXX not sure if this is the right way to go... // XXX not sure if this is the right way to go...
{browseMode: function(){ return !this.data.__range && 'disabled' }}, {mode: function(){ return !this.data.__range && 'disabled' }},
function(image){ function(image){
var r = this.dom.find('.ribbon') var r = this.dom.find('.ribbon')
@ -162,7 +162,7 @@ var RangeActions = actions.Actions({
cropRange: ['Range|Crop/Crop range', cropRange: ['Range|Crop/Crop range',
// XXX not sure if this is the right way to go... // XXX not sure if this is the right way to go...
{browseMode: function(){ return !this.data.__range && 'disabled' }}, {mode: function(){ return !this.data.__range && 'disabled' }},
function(){ function(){
var range = this.data.__range var range = this.data.__range
var order = this.data.order var order = this.data.order
@ -175,7 +175,7 @@ var RangeActions = actions.Actions({
}], }],
cropRangeOut: ['Range|Crop/Crop out range', cropRangeOut: ['Range|Crop/Crop out range',
// XXX not sure if this is the right way to go... // XXX not sure if this is the right way to go...
{browseMode: function(){ return !this.data.__range && 'disabled' }}, {mode: function(){ return !this.data.__range && 'disabled' }},
function(){ function(){
var range = this.data.__range var range = this.data.__range
var order = this.data.order var order = this.data.order

View File

@ -224,7 +224,7 @@ var SlideshowActions = actions.Actions({
NOTE: this will have no effect if the slideshow is not running... NOTE: this will have no effect if the slideshow is not running...
`, `,
{browseMode: function(){ return this.toggleSlideshow('?') == 'off' && 'disabled' }}, {mode: function(){ return this.toggleSlideshow('?') == 'off' && 'disabled' }},
toggler.Toggler(null, toggler.Toggler(null,
function(_, state){ function(_, state){
if(state == null){ if(state == null){

View File

@ -852,12 +852,12 @@ var StatusLogActions = actions.Actions({
// XXX should this be here or in a separate feature??? // XXX should this be here or in a separate feature???
statusLog: ['Interface/Show status log', statusLog: ['Interface/Show status log',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
function(){ function(){
// XXX use list // XXX use list
}], }],
clearStatusLog: ['Interface/Clear status log', clearStatusLog: ['Interface/Clear status log',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
function(){ function(){
delete this.__status_log delete this.__status_log
}], }],

View File

@ -904,7 +904,7 @@ var DialogsActions = actions.Actions({
listDialogs: ['Interface|System/Dialog/Dialog list...', listDialogs: ['Interface|System/Dialog/Dialog list...',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
makeUIDialog(function(){ makeUIDialog(function(){
var actions = this var actions = this
@ -931,7 +931,7 @@ var DialogsActions = actions.Actions({
})], })],
toggleOverlayBlur: ['Interface/Dialog overlay blur', toggleOverlayBlur: ['Interface/Dialog overlay blur',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
toggler.CSSClassToggler( toggler.CSSClassToggler(
function(){ return this.dom }, function(){ return this.dom },
'overlay-blur-enabled', 'overlay-blur-enabled',
@ -2587,7 +2587,7 @@ var BrowseActionsActions = actions.Actions({
// ...this would help with the (global) search -- switch to // ...this would help with the (global) search -- switch to
// flat if searching in root mode... // flat if searching in root mode...
browseActions: ['Interface/Dialog/Actions...', browseActions: ['Interface/Dialog/Actions...',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
core.doc`Browse actions dialog... core.doc`Browse actions dialog...
This uses action definition to build and present an action tree. This uses action definition to build and present an action tree.
@ -2615,33 +2615,33 @@ var BrowseActionsActions = actions.Actions({
Action mode (disabled/hidden) and also be controlled dynamically: Action mode (disabled/hidden) and also be controlled dynamically:
- .browseMode() action method is called with actions as base. - .mode() action method is called with actions as base.
Example: Example:
someAction: ['Path/To/Some action', someAction: ['Path/To/Some action',
{browseMode: function(){ ... }}, {mode: function(){ ... }},
function(){ function(){
... ...
}], }],
someOtherAction: ['Path/To/Some action', someOtherAction: ['Path/To/Some action',
// alias // alias
{browseMode: 'someAction'}, {mode: 'someAction'},
function(){ function(){
... ...
}], }],
.browseMode can be: .mode can be:
<function> - action method. <function> - action method.
<action-name> - alias, name of action to get the <action-name> - alias, name of action to get the
method from. method from.
.browseMode() can return: .mode() can return:
'disabled' - item will be disabled. 'disabled' - item will be disabled.
'hidden' - item will be both hidden and disabled. 'hidden' - item will be both hidden and disabled.
NOTE: disabling in path has priority over .browseMode(), thus NOTE: disabling in path has priority over .mode(), thus
it is possible to hide/disable an enabled item but not it is possible to hide/disable an enabled item but not
possible to enable a disabled by default path. possible to enable a disabled by default path.
NOTE: .browseMode() can be defined in any action in chain, NOTE: .mode() can be defined in any action in chain,
though only the last one is called... though only the last one is called...
@ -2704,52 +2704,12 @@ var BrowseActionsActions = actions.Actions({
// Get action browse mode (disabled or hidden)... // Get action browse mode (disabled or hidden)...
// //
// NOTE: this will cache and reuse action's browseMode, this // NOTE: this will cache and reuse action's mode, this
// will make things faster when lots of actions use the // will make things faster when lots of actions use the
// same mode test (alias)... // same mode test (alias)...
var mode_cache = {} var mode_cache = {}
var getMode = function(action){ var getMode = function(action){
var m = action return actions.getActionMode(action, mode_cache) }
var visited = [m]
var last
// check cache...
if(m in (mode_cache || {})){
return mode_cache[m]
}
// handle aliases...
do {
last = m
m = actions.getActionAttr(m, 'browseMode')
// check cache...
if(m in (mode_cache || {})){
return mode_cache[m]
}
// check for loops...
if(m && visited[m] != null){
m = null
break
}
visited.push(m)
} while(typeof(m) == typeof('str'))
//return m ? m.call(actions) : undefined
return m ?
// no cache...
(mode_cache == null ?
m.call(actions)
// cache hit...
: last in mode_cache ?
mode_cache[last]
// call check and populate cache...
: (mode_cache[action] =
mode_cache[last] =
m.call(actions)))
: undefined
}
// Wait for dialog... // Wait for dialog...
var waitFor = function(dialog, child){ var waitFor = function(dialog, child){
@ -2944,7 +2904,7 @@ var BrowseActionsActions = actions.Actions({
false false
// hide dirs containing only (statically) // hide dirs containing only (statically)
// hidden items... // hidden items...
// NOTE: we are not checking browseMode // NOTE: we are not checking mode
// of other items actively here at // of other items actively here at
// this point to avoid side-effects... // this point to avoid side-effects...
: Object.keys(cur[key]) : Object.keys(cur[key])
@ -2988,7 +2948,7 @@ var BrowseActionsActions = actions.Actions({
['off', 'on'])], ['off', 'on'])],
toggleBrowseActionKeys: ['Interface/Show keys in menu', toggleBrowseActionKeys: ['Interface/Show keys in menu',
{browseMode: function(){ {mode: function(){
return this.config['browse-advanced-mode'] != 'on' && 'hidden' }}, return this.config['browse-advanced-mode'] != 'on' && 'hidden' }},
core.makeConfigToggler( core.makeConfigToggler(
'browse-actions-keys', 'browse-actions-keys',
@ -3034,7 +2994,7 @@ module.ContextActionMenu = core.ImageGridFeatures.Feature({
actions: actions.Actions({ actions: actions.Actions({
showContextMenu: ['Interface/Show context menu...', showContextMenu: ['Interface/Show context menu...',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
uiDialog(function(){ uiDialog(function(){
return this.current ? return this.current ?
this.browseActions('/Image/') this.browseActions('/Image/')
@ -3193,13 +3153,13 @@ var ButtonsActions = actions.Actions({
}, },
toggleMainButtons: ['Interface/Main buttons', toggleMainButtons: ['Interface/Main buttons',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
makeButtonControlsToggler('main-buttons')], makeButtonControlsToggler('main-buttons')],
toggleSecondaryButtons: ['Interface/Secondary buttons', toggleSecondaryButtons: ['Interface/Secondary buttons',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
makeButtonControlsToggler('secondary-buttons')], makeButtonControlsToggler('secondary-buttons')],
toggleAppButtons: ['Interface/App buttons', toggleAppButtons: ['Interface/App buttons',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
makeButtonControlsToggler('app-buttons')], makeButtonControlsToggler('app-buttons')],
toggleSideButtons: ['Interface/70: Touch buttons', toggleSideButtons: ['Interface/70: Touch buttons',
@ -3216,7 +3176,7 @@ var ButtonsActions = actions.Actions({
})()], })()],
toggleButtonHighlightColor: ['Interface/Theme/Button highlight color', toggleButtonHighlightColor: ['Interface/Theme/Button highlight color',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
core.makeConfigToggler( core.makeConfigToggler(
'button-highlight-color', 'button-highlight-color',
function(){ return this.config['button-highlight-colors'] }, function(){ return this.config['button-highlight-colors'] },

View File

@ -361,7 +361,7 @@ module.ViewerActions = actions.Actions({
.centerImage(target) .centerImage(target)
.centerRibbon(target) }], .centerRibbon(target) }],
alignRibbons: ['Interface/Align ribbons', alignRibbons: ['Interface/Align ribbons',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
function(target, scale, now){ function(target, scale, now){
if(target == 'now'){ if(target == 'now'){
now = true now = true
@ -392,7 +392,7 @@ module.ViewerActions = actions.Actions({
// XXX skip off-screen ribbons (???) // XXX skip off-screen ribbons (???)
// XXX should the timeout be configurable??? // XXX should the timeout be configurable???
alignByOrder: ['Interface/Align ribbons by image order', alignByOrder: ['Interface/Align ribbons by image order',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
function(target, scale, now){ function(target, scale, now){
if(target == 'now'){ if(target == 'now'){
now = true now = true
@ -457,7 +457,7 @@ module.ViewerActions = actions.Actions({
} }
}], }],
alignByFirst: ['Interface/Align ribbons except current to first image', alignByFirst: ['Interface/Align ribbons except current to first image',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
function(target){ function(target){
target = target == 'now' ? null : target target = target == 'now' ? null : target
@ -591,7 +591,7 @@ module.ViewerActions = actions.Actions({
// Zooming is done by multiplying the current scale by .config['zoom-step'] // Zooming is done by multiplying the current scale by .config['zoom-step']
// and rounding to nearest discrete number of images to fit on screen. // and rounding to nearest discrete number of images to fit on screen.
zoomIn: ['Zoom/Zoom in', zoomIn: ['Zoom/Zoom in',
{browseMode: function(){ {mode: function(){
return Math.min(this.screenwidth, this.screenheight) <= 1 && 'disabled' }}, return Math.min(this.screenwidth, this.screenheight) <= 1 && 'disabled' }},
function(){ function(){
var d = (this.config['zoom-step'] || 1.2) var d = (this.config['zoom-step'] || 1.2)
@ -606,7 +606,7 @@ module.ViewerActions = actions.Actions({
} }
}], }],
zoomOut: ['Zoom/Zoom out', zoomOut: ['Zoom/Zoom out',
{browseMode: function(){ {mode: function(){
return this.screenwidth >= this.config['max-screen-images'] && 'disabled' }}, return this.screenwidth >= this.config['max-screen-images'] && 'disabled' }},
function(){ function(){
var max = this.config['max-screen-images'] var max = this.config['max-screen-images']
@ -647,7 +647,7 @@ module.ViewerActions = actions.Actions({
this.ribbonRotation('-='+ (a || this.config['ribbon-rotation-step'] || 10)) }], this.ribbonRotation('-='+ (a || this.config['ribbon-rotation-step'] || 10)) }],
resetRibbonRotation: ['Interface|Ribbon/Reset ribbon rotation', resetRibbonRotation: ['Interface|Ribbon/Reset ribbon rotation',
{browseMode: function(){ {mode: function(){
return this.ribbonRotation() == 0 && 'disabled' }}, return this.ribbonRotation() == 0 && 'disabled' }},
function(){ this.ribbonRotation(0) }], function(){ this.ribbonRotation(0) }],
@ -656,7 +656,7 @@ module.ViewerActions = actions.Actions({
// XXX make this play nice with crops... // XXX make this play nice with crops...
// ...should this be a crop??? // ...should this be a crop???
toggleRibbonList: ['Interface|Ribbon/Ribbons as images view', toggleRibbonList: ['Interface|Ribbon/Ribbons as images view',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
function(){ function(){
if(this._full_data == null){ if(this._full_data == null){
// XXX do a better name here... // XXX do a better name here...
@ -697,7 +697,7 @@ module.ViewerActions = actions.Actions({
function(angle){ }], function(angle){ }],
toggleImageRendering: ['Interface/Image rendering', toggleImageRendering: ['Interface/Image rendering',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
toggler.CSSClassToggler( toggler.CSSClassToggler(
function(){ return this.dom }, function(){ return this.dom },
['crisp-resize', 'default-resize'], ['crisp-resize', 'default-resize'],
@ -936,7 +936,7 @@ module.Cursor = core.ImageGridFeatures.Feature({
actions: actions.Actions({ actions: actions.Actions({
toggleHiddenCursor: ['Interface/Cursor hidden', toggleHiddenCursor: ['Interface/Cursor hidden',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
toggler.CSSClassToggler( toggler.CSSClassToggler(
function(){ return this.dom }, function(){ return this.dom },
'cursor-hidden', 'cursor-hidden',
@ -1011,7 +1011,7 @@ module.Cursor = core.ImageGridFeatures.Feature({
// .config['cursor-show-threshold'] // .config['cursor-show-threshold']
// //
toggleAutoHideCursor: ['Interface/Cursor auto-hide', toggleAutoHideCursor: ['Interface/Cursor auto-hide',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
toggler.CSSClassToggler( toggler.CSSClassToggler(
function(){ return this.dom }, function(){ return this.dom },
'cursor-autohide', 'cursor-autohide',
@ -1127,13 +1127,13 @@ module.Cursor = core.ImageGridFeatures.Feature({
})], })],
toggleAutoHideCursorTimeout: ['Interface/Hide cursor on timeout', toggleAutoHideCursorTimeout: ['Interface/Hide cursor on timeout',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
core.makeConfigToggler('cursor-autohide-on-timeout', core.makeConfigToggler('cursor-autohide-on-timeout',
['on', 'off'], ['on', 'off'],
function(){ function(){
this.toggleAutoHideCursor('!') })], this.toggleAutoHideCursor('!') })],
toggleAutoHideCursorKeyboard: ['Interface/Hide cursor on keyboard', toggleAutoHideCursorKeyboard: ['Interface/Hide cursor on keyboard',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
core.makeConfigToggler('cursor-autohide-on-keyboard', core.makeConfigToggler('cursor-autohide-on-keyboard',
['on', 'off'], ['on', 'off'],
function(){ function(){
@ -1224,7 +1224,7 @@ var ControlActions = actions.Actions({
from reaching the viewer. from reaching the viewer.
NOTE: this defines the focus/blur handlers on the window object.`, NOTE: this defines the focus/blur handlers on the window object.`,
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
core.makeConfigToggler('lock-unfocused', core.makeConfigToggler('lock-unfocused',
['off', 'on'], ['off', 'on'],
function(state){ function(state){
@ -1378,7 +1378,7 @@ var ControlActions = actions.Actions({
// XXX depends on .ribbons... // XXX depends on .ribbons...
// XXX uses: .focusImage(..) // XXX uses: .focusImage(..)
toggleImageClickHandling: ['Interface/Image click handling', toggleImageClickHandling: ['Interface/Image click handling',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
toggler.Toggler(null, toggler.Toggler(null,
function(_, new_state){ function(_, new_state){
return new_state ? return new_state ?
@ -1631,7 +1631,7 @@ var ControlActions = actions.Actions({
// XXX depends on .ribbons... // XXX depends on .ribbons...
// XXX uses: .focusImage(..) // XXX uses: .focusImage(..)
toggleRibbonPanHandling: ['Interface/Ribbon pan handling', toggleRibbonPanHandling: ['Interface/Ribbon pan handling',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
toggler.Toggler(null, toggler.Toggler(null,
function(_, new_state){ function(_, new_state){
return new_state ? return new_state ?
@ -1871,7 +1871,7 @@ var ControlActions = actions.Actions({
// XXX depends on .ribbons... // XXX depends on .ribbons...
// XXX uses: .focusImage(..) // XXX uses: .focusImage(..)
toggleMouseWheelHandling: ['Interface/Mouse wheel handling', toggleMouseWheelHandling: ['Interface/Mouse wheel handling',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
toggler.Toggler(null, toggler.Toggler(null,
function(_, new_state){ function(_, new_state){
return new_state ? return new_state ?
@ -1976,7 +1976,7 @@ var ControlActions = actions.Actions({
})], })],
togglePinchHandling: ['Interface/Pinch zoom handling', togglePinchHandling: ['Interface/Pinch zoom handling',
{browseMode: 'toggleBrowseActionKeys'}, {mode: 'toggleBrowseActionKeys'},
function(){ function(){
// XXX // XXX
}], }],
@ -1986,7 +1986,7 @@ var ControlActions = actions.Actions({
// ...allow ui features to control this... // ...allow ui features to control this...
// XXX depends on .ribbons... // XXX depends on .ribbons...
toggleSwipeHandling: ['Interface/Swipe handling', toggleSwipeHandling: ['Interface/Swipe handling',
//{browseMode: 'toggleBrowseActionKeys'}, //{mode: 'toggleBrowseActionKeys'},
toggler.Toggler(null, toggler.Toggler(null,
function(_, state){ function(_, state){
return state ? return state ?

View File

@ -98,7 +98,7 @@ var VirtualBlocksActions = actions.Actions({
... ...
} }
`, `,
{ browseMode: function(){ return !this.collection && 'disabled' }, }, { mode: function(){ return !this.collection && 'disabled' }, },
function(ref, offset, img){ function(ref, offset, img){
ref = ref || 'current' ref = ref || 'current'
offset = offset || 'after' offset = offset || 'after'
@ -153,11 +153,11 @@ var VirtualBlocksActions = actions.Actions({
core.doc`Add block before... core.doc`Add block before...
This is the same as .makeVirtualBlock(.., 'before', ..)`, This is the same as .makeVirtualBlock(.., 'before', ..)`,
{ browseMode: 'makeVirtualBlock', }, { mode: 'makeVirtualBlock', },
'makeVirtualBlock: $0 "before" ...'], 'makeVirtualBlock: $0 "before" ...'],
cloneVirtualBlock: ['Virtual block/$Clone block', cloneVirtualBlock: ['Virtual block/$Clone block',
{ browseMode: function(){ { mode: function(){
return (this.image || {}).type != 'virtual' && 'disabled' }, }, return (this.image || {}).type != 'virtual' && 'disabled' }, },
function(ref, offset, img){ function(ref, offset, img){
var img = Object.assign({}, var img = Object.assign({},
@ -169,15 +169,15 @@ var VirtualBlocksActions = actions.Actions({
// crop... // crop...
// XXX would be nice to avoid these and just register a list and context... // XXX would be nice to avoid these and just register a list and context...
cropVirtualBlocks: ['Virtual block|Crop/$Crop $virtual $blocks', cropVirtualBlocks: ['Virtual block|Crop/$Crop $virtual $blocks',
{ browseMode: 'makeVirtualBlock' }, { mode: 'makeVirtualBlock' },
'crop: "virtual" ...'], 'crop: "virtual" ...'],
cropVirtualBlocksOut: ['Virtual block|Crop/Crop virtual blocks out', cropVirtualBlocksOut: ['Virtual block|Crop/Crop virtual blocks out',
{ browseMode: 'cropVirtualBlocks' }, { mode: 'cropVirtualBlocks' },
'crop: "!virtual" ...'], 'crop: "!virtual" ...'],
// marks... // marks...
toggleMarkVirtualBlocks: ['Virtual block|Mark/Toggle $mark on $virtual blocks', toggleMarkVirtualBlocks: ['Virtual block|Mark/Toggle $mark on $virtual blocks',
{ browseMode: 'makeVirtualBlock' }, { mode: 'makeVirtualBlock' },
'toggleMark: "virtual"'], 'toggleMark: "virtual"'],
// remove... // remove...
@ -358,7 +358,7 @@ var VirtualBlocksEditUIActions = actions.Actions({
// XXX should we also add a preview (preview constructor from features/metadata.js)??? // XXX should we also add a preview (preview constructor from features/metadata.js)???
// XXX should we do a sanity check for image type??? // XXX should we do a sanity check for image type???
editVirtualBlock: ['Virtual block/$Edit...', editVirtualBlock: ['Virtual block/$Edit...',
{ browseMode: 'cloneVirtualBlock' }, { mode: 'cloneVirtualBlock' },
widgets.makeUIDialog(function(gid){ widgets.makeUIDialog(function(gid){
var that = this var that = this