mirror of
https://github.com/flynx/ImageGrid.git
synced 2025-10-28 18:00:09 +00:00
reworked collection handlers, added auto-collection-tags, tweaks, fixes and cleanup...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
b48e31f37d
commit
c825cb050c
@ -140,7 +140,7 @@ var CollectionActions = actions.Actions({
|
||||
//
|
||||
// XXX should these get auto-sorted???
|
||||
get collection_handlers(){
|
||||
var handlers = this.__collection_handlers || {}
|
||||
var handlers = this.__collection_handlers = this.__collection_handlers || {}
|
||||
|
||||
if(Object.keys(handlers).length == 0){
|
||||
var that = this
|
||||
@ -153,9 +153,15 @@ var CollectionActions = actions.Actions({
|
||||
})
|
||||
}
|
||||
|
||||
// cleanup...
|
||||
if(handlers['data'] == null){
|
||||
delete handlers['data']
|
||||
}
|
||||
|
||||
return handlers
|
||||
},
|
||||
|
||||
/*/ XXX do we actually need this????
|
||||
collectionDataLoader: ['- Collections/',
|
||||
core.doc`Collection data loader
|
||||
|
||||
@ -173,7 +179,10 @@ var CollectionActions = actions.Actions({
|
||||
{collectionFormat: 'data'},
|
||||
function(title, data){
|
||||
return new Promise(function(resolve){ resolve(data.data) }) }],
|
||||
//*/
|
||||
|
||||
// XXX revise loader protocol...
|
||||
// ...should it be cooperative???
|
||||
loadCollection: ['- Collections/',
|
||||
core.doc`Load collection...
|
||||
|
||||
@ -204,6 +213,8 @@ var CollectionActions = actions.Actions({
|
||||
To invalidate such a cache .data should simply be deleted.
|
||||
|
||||
NOTE: cached collection state is persistent.
|
||||
NOTE: when current collection is removed from .collections this
|
||||
will not save state when loading another collection...
|
||||
`,
|
||||
function(collection){
|
||||
var that = this
|
||||
@ -224,6 +235,8 @@ var CollectionActions = actions.Actions({
|
||||
// save current collection state...
|
||||
//
|
||||
// main view...
|
||||
// NOTE: we save here unconditionally because MAIN_COLLECTION_TITLE
|
||||
// is stored ONLY when we load some other collection...
|
||||
if(this.collection == null){
|
||||
this.saveCollection(
|
||||
MAIN_COLLECTION_TITLE,
|
||||
@ -231,17 +244,24 @@ var CollectionActions = actions.Actions({
|
||||
true)
|
||||
|
||||
// collection...
|
||||
} else {
|
||||
// NOTE: we only save if the current collection exists, it
|
||||
// may not exist if it was just removed...
|
||||
} else if(this.collection in this.collections){
|
||||
this.saveCollection(
|
||||
this.collection,
|
||||
crop_mode == 'all' ? 'crop': null)
|
||||
}
|
||||
|
||||
// load collection...
|
||||
for(var format in handlers){
|
||||
if(collection_data[format]){
|
||||
return this[handlers[format]](collection, collection_data)
|
||||
.then(function(data){
|
||||
Promise
|
||||
.all(Object.keys(handlers)
|
||||
.filter(function(format){
|
||||
return format == '*' || collection_data[format] })
|
||||
.map(function(format){
|
||||
return that[handlers[format]](collection, collection_data) }))
|
||||
.then(function(){
|
||||
var data = collection_data.data
|
||||
|
||||
if(!data){
|
||||
return
|
||||
}
|
||||
@ -297,8 +317,6 @@ var CollectionActions = actions.Actions({
|
||||
},
|
||||
collection)
|
||||
})
|
||||
}
|
||||
}
|
||||
}],
|
||||
|
||||
// events...
|
||||
@ -332,15 +350,23 @@ var CollectionActions = actions.Actions({
|
||||
saveCollection: ['- Collections/',
|
||||
core.doc`Save current state to collection
|
||||
|
||||
Save Current state to current collection
|
||||
Save current state to current collection
|
||||
.saveCollection()
|
||||
.saveCollection('current')
|
||||
-> this
|
||||
NOTE: this will do nothing if no collection is loaded.
|
||||
|
||||
Save Current state as collection
|
||||
Save state as collection...
|
||||
.saveCollection(collection)
|
||||
-> this
|
||||
NOTE: if saving to self the default mode is 'crop' else
|
||||
it is 'current' (see below for info on respective
|
||||
modes)...
|
||||
|
||||
Save current state as collection ignoring crop stack
|
||||
.saveCollection(collection, 0)
|
||||
.saveCollection(collection, 'current')
|
||||
-> this
|
||||
|
||||
Save new empty collection
|
||||
.saveCollection(collection, 'empty')
|
||||
@ -358,6 +384,13 @@ var CollectionActions = actions.Actions({
|
||||
.saveCollection(collection, 'base')
|
||||
-> this
|
||||
|
||||
NOTE: this will overwrite collection .data and .crop_stack only,
|
||||
the rest of the data is untouched...
|
||||
NOTE: if it is needed to overwrite an existing collection then
|
||||
first remove it then save anew:
|
||||
this
|
||||
.removeCollection(x)
|
||||
.saveCollection(x, 'crop')
|
||||
`,
|
||||
function(collection, mode, force){
|
||||
var that = this
|
||||
@ -365,48 +398,64 @@ var CollectionActions = actions.Actions({
|
||||
collection = collection == 'current' ? this.collection : collection
|
||||
|
||||
if(!force
|
||||
&& (collection == null
|
||||
|| collection == MAIN_COLLECTION_TITLE)){
|
||||
&& (collection == null || collection == MAIN_COLLECTION_TITLE)){
|
||||
return
|
||||
}
|
||||
|
||||
var collections = this.collections = this.collections || {}
|
||||
var depth = typeof(mode) == typeof(123) ? mode : null
|
||||
mode = depth == 0 ? null
|
||||
mode = depth == 0 ? 'current'
|
||||
: depth ? 'crop'
|
||||
: mode
|
||||
// default mode -- if saving to self then 'crop' else 'current'
|
||||
if(!mode){
|
||||
mode = ((collection in collections
|
||||
&& collection == this.collection)
|
||||
|| collection == MAIN_COLLECTION_TITLE) ?
|
||||
'crop'
|
||||
: 'current'
|
||||
}
|
||||
|
||||
var collections = this.collections = this.collections || {}
|
||||
|
||||
var state = collections[collection] = {
|
||||
title: collection,
|
||||
|
||||
// save the data...
|
||||
var state = collections[collection] = collections[collection] || {}
|
||||
state.title = state.title || collection
|
||||
// NOTE: we do not need to care about tags here as they
|
||||
// will get overwritten on load...
|
||||
data: (mode == 'empty' ?
|
||||
state.data = (mode == 'empty' ?
|
||||
(new this.data.constructor())
|
||||
: mode == 'base' && this.crop_stack ?
|
||||
(this.crop_stack[0] || this.data.clone())
|
||||
: mode == 'crop' ?
|
||||
this.data.clone()
|
||||
// current...
|
||||
: this.data.clone()
|
||||
.run(function(){
|
||||
var d = this
|
||||
this.collection = collection
|
||||
})
|
||||
.clear('unloaded')),
|
||||
}
|
||||
.clear('unloaded'))
|
||||
|
||||
// crop mode -> handle crop stack...
|
||||
if(mode == 'crop' && this.crop_stack && depth != 0){
|
||||
depth = depth || this.crop_stack.length
|
||||
depth = this.crop_stack.length - Math.min(depth, this.crop_stack.length)
|
||||
|
||||
state.crop_stack = this.crop_stack.slice(depth)
|
||||
|
||||
// other modes...
|
||||
} else {
|
||||
delete state.crop_stack
|
||||
}
|
||||
}],
|
||||
newCollection: ['- Collections/',
|
||||
function(collection){ return this.saveCollection(collection, 'empty') }],
|
||||
// XXX should we do anything special if collection is loaded???
|
||||
removeCollection: ['- Collections/',
|
||||
core.doc`
|
||||
|
||||
NOTE: when removing the currently loaded collection this will
|
||||
just remove it from .collections and do nothing...`,
|
||||
function(collection){
|
||||
if(collection == MAIN_COLLECTION_TITLE){
|
||||
return
|
||||
@ -714,6 +763,8 @@ module.Collection = core.ImageGridFeatures.Feature({
|
||||
],
|
||||
suggested: [
|
||||
'collection-tags',
|
||||
'auto-collection-tags',
|
||||
|
||||
'ui-collections',
|
||||
'fs-collections',
|
||||
],
|
||||
@ -721,6 +772,9 @@ module.Collection = core.ImageGridFeatures.Feature({
|
||||
actions: CollectionActions,
|
||||
|
||||
handlers: [
|
||||
// XXX do we need this???
|
||||
['json.pre',
|
||||
function(){ this.saveCollection() }],
|
||||
// XXX maintain changes...
|
||||
// - collection-level: mark collections as changed...
|
||||
// - in-collection:
|
||||
@ -848,6 +902,8 @@ module.CollectionTags = core.ImageGridFeatures.Feature({
|
||||
tags[tag] = local_tags[tag] || []
|
||||
})
|
||||
|
||||
;(this.crop_stack || [])
|
||||
.forEach(function(d){ d.tags = tags })
|
||||
this.data.tags = tags
|
||||
this.data.sortTags()
|
||||
}
|
||||
@ -864,6 +920,7 @@ module.CollectionTags = core.ImageGridFeatures.Feature({
|
||||
['saveCollection.pre',
|
||||
function(title, mode, force){
|
||||
var that = this
|
||||
title = title || this.collection || MAIN_COLLECTION_TITLE
|
||||
var local_tag_names = this.config['collection-local-tags'] || []
|
||||
|
||||
// do not do anything for main collection unless force is true...
|
||||
@ -911,11 +968,32 @@ module.CollectionTags = core.ImageGridFeatures.Feature({
|
||||
// NOTE: we do not need to explicitly load anything as .load()
|
||||
// will load everything we need and .collectionLoading(..)
|
||||
// will .sortTags() for us...
|
||||
//
|
||||
// XXX handle 'base' mode...
|
||||
['json',
|
||||
function(res, mode){
|
||||
var c = this.collections
|
||||
var rc = res.collections
|
||||
|
||||
// in 'base' mode set .data.tags and .local_tags to
|
||||
// the base collection data...
|
||||
if(mode == 'base'
|
||||
&& this.collection != null
|
||||
&& this.collection != MAIN_COLLECTION_TITLE){
|
||||
// NOTE: at this point .crop_stack is handled, so we
|
||||
// do not need to care about it...
|
||||
var tags = c[MAIN_COLLECTION_TITLE].local_tags || {}
|
||||
var rtags =
|
||||
res.data.tags =
|
||||
res.collections[this.collection].data.tags || {}
|
||||
|
||||
// compact and overwrite the local tags for the base...
|
||||
Object.keys(tags)
|
||||
.forEach(function(tag){
|
||||
rtags[tag] = tags[tag].compact() })
|
||||
}
|
||||
|
||||
// clear and compact tags for all collections...
|
||||
rc
|
||||
&& Object.keys(rc || {})
|
||||
.forEach(function(title){
|
||||
@ -923,7 +1001,7 @@ module.CollectionTags = core.ImageGridFeatures.Feature({
|
||||
var rtags = rc[title].local_tags = {}
|
||||
|
||||
// compact the local tags...
|
||||
Object.keys(c[title].local_tags)
|
||||
Object.keys(tags)
|
||||
.forEach(function(tag){
|
||||
rtags[tag] = tags[tag].compact() })
|
||||
|
||||
@ -937,6 +1015,61 @@ module.CollectionTags = core.ImageGridFeatures.Feature({
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
var AutoTagCollectionsActions = actions.Actions({
|
||||
// initial load...
|
||||
// XXX should this be a real tag query???
|
||||
collectionAutoTagsLoader: ['- Collections/',
|
||||
core.doc`
|
||||
|
||||
NOTE: this will ignore local tags.
|
||||
NOTE: this will prepend new matching items to the saved state.
|
||||
`,
|
||||
{collectionFormat: 'tag_query'},
|
||||
function(title, state){
|
||||
return new Promise((function(resolve){
|
||||
var local_tag_names = this.config['collection-local-tags'] || []
|
||||
|
||||
var tags = (state.tag_query || [])
|
||||
// filter out local tags...
|
||||
.filter(function(tag){ return local_tag_names.indexOf(tag) < 0 })
|
||||
|
||||
// XXX should this be a real tag query???
|
||||
var gids = this.data.getTaggedByAll(tags)
|
||||
|
||||
// get unmatching...
|
||||
var remove = state.data ?
|
||||
state.data.order
|
||||
.filter(function(gid){ return gids.indexOf(gid) < 0 })
|
||||
: []
|
||||
|
||||
// build data...
|
||||
state.data = data.Data.fromArray(gids)
|
||||
// join with saved state...
|
||||
.join(state.data || data.Data())
|
||||
// remove unmatching...
|
||||
.clear(remove)
|
||||
|
||||
resolve(state.data)
|
||||
}).bind(this)) }],
|
||||
})
|
||||
|
||||
var AutoTagCollections =
|
||||
module.AutoTagCollections = core.ImageGridFeatures.Feature({
|
||||
title: 'Collection tag handling',
|
||||
doc: core.doc``,
|
||||
|
||||
tag: 'auto-collection-tags',
|
||||
depends: [
|
||||
'collections',
|
||||
],
|
||||
|
||||
actions: AutoTagCollectionsActions,
|
||||
})
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
// XXX show collections in image metadata...
|
||||
|
||||
@ -1761,7 +1761,7 @@ var ButtonsActions = actions.Actions({
|
||||
// }
|
||||
'main-buttons': {
|
||||
'☰': ['menu', 'browseActions -- Action menu...'],
|
||||
'◲<sub/>': ['collections', 'browseCollections -- Collections...'],
|
||||
'◲<sub/><sup/>': ['collections', 'browseCollections -- Collections...'],
|
||||
'C<sub/>': ['crop', 'browseActions: "Crop/" -- Crop menu...'],
|
||||
//'▤<sub/>': ['collections', 'browseCollections -- Collections...'],
|
||||
//'⛶': ['view', 'toggleSingleImage -- Single image / ribbon toggle'],
|
||||
@ -1871,6 +1871,7 @@ module.Buttons = core.ImageGridFeatures.Feature({
|
||||
'clear',
|
||||
'reload',
|
||||
'saveCollection',
|
||||
'removeCollection',
|
||||
'collectionLoaded',
|
||||
'collectionUnloaded',
|
||||
],
|
||||
@ -1882,12 +1883,25 @@ module.Buttons = core.ImageGridFeatures.Feature({
|
||||
})
|
||||
|
||||
var l = this.collections_length
|
||||
|
||||
// current collection unsaved indicator...
|
||||
$('.main-buttons.buttons .collections.button sup')
|
||||
.css({
|
||||
'display': 'inline-block',
|
||||
'position': 'absolute',
|
||||
'margin-top': '-0.3em',
|
||||
'overflow': 'visible',
|
||||
})
|
||||
.text((this.collection && !(this.collection in this.collections)) ?
|
||||
'*'
|
||||
: '')
|
||||
|
||||
// collection count...
|
||||
$('.main-buttons.buttons .collections.button sub')
|
||||
.css({
|
||||
'display': 'inline-block',
|
||||
'width': '0px',
|
||||
'overflow': 'visible',
|
||||
//'color': this.collection ? 'yellow' : '',
|
||||
})
|
||||
.text(l > 99 ? '99+'
|
||||
: l == 0 ? ''
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user