collections are not separate from crops + some refactoring and fixes...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2017-08-27 21:28:02 +03:00
parent 4fe084948d
commit 6b15446bcc
4 changed files with 194 additions and 62 deletions

View File

@ -214,8 +214,12 @@ actions.Actions({
this.clear()
return function(){
this.images = images.Images(d.images)
this.data = data.Data(d.data)
this.images = d.images instanceof images.Images ?
d.images
: images.Images(d.images)
this.data = d.data instanceof data.Data ?
d.data
: data.Data(d.data)
}
}],
// XXX should this clear or load empty???
@ -1447,11 +1451,28 @@ module.CropActions = actions.Actions({
&& this.crop_stack
&& this.crop_stack.length > 0){
res.crop_stack = this.crop_stack.map(function(c){
return c.dumpJSON()
return c
.dumpJSON()
.run(function(){
delete this.tags })
})
}
}
}],
load: [function(state){
return function(){
var that = this
if(state.crop_stack){
that.crop_stack = (state.crop_stack || [])
.map(function(d){
return d instanceof data.Data ? d : data.Data(d) })
// merge the tags...
that.crop_stack.forEach(function(d){ d.tags = that.data.tags })
}
}
}],
// true if current viewer is cropped...
get cropped(){
@ -1666,6 +1687,8 @@ module.CropActions = actions.Actions({
var selector = mode == 'any' ? 'getTaggedByAny' : 'getTaggedByAll'
this.crop(this.data[selector](tags), flatten)
}],
})

View File

@ -26,6 +26,8 @@ var widgets = require('features/ui-widgets')
// logical, would simplify control, etc.
//
var MAIN_COLLECTION_TITLE = 'All'
// XXX things we need to do to collections:
// - auto-collections
// - tags -- adding/removing images adds/removes tags
@ -200,6 +202,34 @@ var CollectionActions = actions.Actions({
var collection_data = this.collections[collection]
var handlers = this.collection_handlers
// main view -> save it...
if(this.collection == null){
this.collections[MAIN_COLLECTION_TITLE] = {
title: MAIN_COLLECTION_TITLE,
data: this.data,
crop_stack: this.crop_stack,
}
}
// load main collection...
if(collection == MAIN_COLLECTION_TITLE){
var state = this.collections[MAIN_COLLECTION_TITLE]
this.load({
data: state.data,
crop_stack: state.crop_stack,
// keep the collections...
collections: this.collections,
collection_order: this.collection_order,
})
delete this.collections[MAIN_COLLECTION_TITLE]
return new Promise(function(resolve){ resolve(data) })
}
// load collection...
for(var format in handlers){
if(collection_data[format]){
return this[handlers[format]](collection, collection_data)
@ -216,13 +246,15 @@ var CollectionActions = actions.Actions({
|| that.data.getImage(current, data.order)
|| data.current
that.crop.chainCall(that, function(){
// NOTE: the collection and .data may have different
// orders and/or sets of elements, this we need
// to sync, and do it BEFORE all the rendering
// happens...
this.data.updateImagePositions()
}, data)
// XXX
//data.tags = that.data.tags
that.load({
data: data,
collections: that.collections,
collection_order: that.collection_order,
})
// NOTE: we need this to sync the possible different
// states (order, ...) of the collection and .data...
@ -268,7 +300,7 @@ var CollectionActions = actions.Actions({
var that = this
collection = collection || this.collection
if(collection == null){
if(collection == null || collection == MAIN_COLLECTION_TITLE){
return
}
@ -433,23 +465,45 @@ var CollectionActions = actions.Actions({
}],
// manage serialization and loading...
// XXX make this reflect the format automatically...
//
// NOTE: this will handle collection title and data only, the rest
// is copied in as-is.
// It is the responsibility of the extending features to transform
// their data on load as needed.
load: [function(json){
var that = this
var collections = {}
var c = json.collections || {}
var order = json.collection_order || Object.keys(c)
Object.keys(c).forEach(function(title){
var d = data.Data
.fromJSON(c[title].data)
if((json.location || {}).collection){
this.location.collection = json.location.collection
}
// XXX make this reflect the format automatically...
collections[title] = {
Object.keys(c).forEach(function(title){
var d = c[title].data instanceof data.Data ?
c[title].data
: data.Data
.fromJSON(c[title].data
.run(function(){
this.tags = this.tags || that.data.tags
}))
var state = collections[title] = {
title: title,
data: d,
}
// copy the rest of collection data as-is...
Object.keys(c[title])
.forEach(function(key){
if(key in state){
return
}
state[key] = c[title][key]
})
})
return function(){
@ -459,32 +513,74 @@ var CollectionActions = actions.Actions({
}
}
}],
//
// Supported modes:
// current (default) - ignore collections
// base - save only base data in each collection and
// the main collection is saved as current
// full - full current state.
//
// NOTE: we do not store .collection_order here, because we order
// the collections in the object.
// ...when saving a partial collection set, for example in
// .prepareIndexForWrite(..) it would be necessary to add it
// in to maintain the correct order when merging... (XXX)
// XXX make this reflect the format automatically...
json: [function(){ return function(res){
// NOTE: currently this only stores title and data, it is the
// responsibility of extending features to store their specific
// data in collections...
json: [function(mode){ return function(res){
mode = mode || 'current'
var collections = this.collections
if(collections){
// NOTE: if mode is 'current' ignore collections...
if(mode != 'current' && collections){
var order = this.collection_order
// in base mode save the main view as current...
if(mode == 'base' && this.collection){
var main = collections[MAIN_COLLECTION_TITLE]
res.data = (main.crop_stack ?
(main.crop_stack[0] || main.data)
: main.data)
.dumpJSON()
delete res.location.collection
}
res.collections = {}
order.forEach(function(title){
var data = collections[title].data.dumpJSON()
// in base mode skip the main collection...
if(mode == 'base' && title == MAIN_COLLECTION_TITLE){
return
}
var state = collections[title]
var data = ((mode == 'base' && state.crop_stack) ?
(state.crop_stack[0] || state.data)
: state.data)
.dumpJSON()
delete data.tags
// XXX make this reflect the format automatically...
res.collections[title] = {
var s = res.collections[title] = {
title: title,
data: data,
}
// handle .crop_stack of collection...
// NOTE: in base mode, crop_stack is ignored...
if(mode != 'base' && state.crop_stack){
s.crop_stack = state.crop_stack
.map(function(d){ return d.dumpJSON() })
}
})
}
} }],
// XXX
clone: [function(){
// XXX
}],
clear: [function(){
this.collection
&& this.collectionUnloaded('*')
@ -503,6 +599,7 @@ module.Collection = core.ImageGridFeatures.Feature({
tag: 'collections',
depends: [
'base',
'location',
'crop',
],
suggested: [
@ -631,10 +728,12 @@ var UICollectionActions = actions.Actions({
action ?
that.newCollection(title)
: that.saveCollection(title) },
disabled: action ? [MAIN_COLLECTION_TITLE] : false,
})
}, {
// focus current collection...
selected: that.collection,
selected: that.collection || MAIN_COLLECTION_TITLE,
})
.close(function(){
to_remove.forEach(function(title){

View File

@ -316,6 +316,43 @@ var LocationActions = actions.Actions({
}
}],
// 1) store .location
// 2) cleanup .images[..].base_path
//
// XXX might be good to make the .base_path relative to location
// if possible...
// XXX not sure if this is the right place for .images[..].base_path
// handling...
json: [function(){
return function(res){
if(this.location){
var l = res.location = JSON.parse(JSON.stringify(this.location))
// cleanup base_path...
Object.keys(res.images || {}).forEach(function(gid){
var img = res.images[gid]
if(l.path == img.base_path){
delete img.base_path
}
})
}
}}],
load: [function(){
return function(_, data){
// NOTE: we are setting this after the load because the
// loader may .clear() the viewer, thus clearing the
// .location too...
this.__location = data.location
}}],
clone: [
function(res){
if(this.location){
res.__location = JSON.parse(JSON.stringify(this.__location))
}
}],
clear: [function(){
this.clearLoaction() }],
})
module.Location = core.ImageGridFeatures.Feature({
@ -323,48 +360,13 @@ module.Location = core.ImageGridFeatures.Feature({
doc: '',
tag: 'location',
depends: [
'base',
],
actions: LocationActions,
handlers: [
['clone',
function(res){
if(this.location){
res.__location = JSON.parse(JSON.stringify(this.__location))
}
}],
['clear',
function(){ this.clearLoaction() }],
// 1) store .location
// 2) cleanup .images[..].base_path
//
// XXX might be good to make the .base_path relative to location
// if possible...
// XXX not sure if this is the right place for .images[..].base_path
// handling...
['json',
function(res){
if(this.location){
var l = res.location = JSON.parse(JSON.stringify(this.location))
// cleanup base_path...
Object.keys(res.images || {}).forEach(function(gid){
var img = res.images[gid]
if(l.path == img.base_path){
delete img.base_path
}
})
}
}],
['load',
function(_, data){
// NOTE: we are setting this after the load because the
// loader may .clear() the viewer, thus clearing the
// .location too...
this.__location = data.location
}],
],
})

View File

@ -437,6 +437,10 @@ function(list){
// // process each dom element...
// each: <function>,
//
// // if true disable all items, if list then disable all items
// // from that list...
// disabled: <bool> | [ <item>, ... ],
//
// // see: make(..) for additional option info.
// ...
// }
@ -491,6 +495,10 @@ function(data, options){
}
})
if(opts.disabled && opts.disabled instanceof Array){
opts.disabled = opts.disabled.indexOf(txt || k) >= 0
}
if((opts.disabled && opts.skipDisabledItems)
|| (opts.hidden && opts.skipHiddenItems)){
return