From 6b15446bcc1c2a3067fcf8964ff22889570f5ee2 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Sun, 27 Aug 2017 21:28:02 +0300 Subject: [PATCH] collections are not separate from crops + some refactoring and fixes... Signed-off-by: Alex A. Naanou --- ui (gen4)/features/base.js | 29 +++++- ui (gen4)/features/collections.js | 141 +++++++++++++++++++++++++----- ui (gen4)/features/location.js | 78 +++++++++-------- ui (gen4)/lib/widget/browse.js | 8 ++ 4 files changed, 194 insertions(+), 62 deletions(-) diff --git a/ui (gen4)/features/base.js b/ui (gen4)/features/base.js index 16d46518..5e629a1b 100755 --- a/ui (gen4)/features/base.js +++ b/ui (gen4)/features/base.js @@ -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) }], + + }) diff --git a/ui (gen4)/features/collections.js b/ui (gen4)/features/collections.js index 0c7d5dc0..5ddcc763 100755 --- a/ui (gen4)/features/collections.js +++ b/ui (gen4)/features/collections.js @@ -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) + + if((json.location || {}).collection){ + this.location.collection = json.location.collection + } Object.keys(c).forEach(function(title){ - var d = data.Data - .fromJSON(c[title].data) + 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 + })) - // XXX make this reflect the format automatically... - collections[title] = { + 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){ diff --git a/ui (gen4)/features/location.js b/ui (gen4)/features/location.js index 11db7171..baf59aa6 100755 --- a/ui (gen4)/features/location.js +++ b/ui (gen4)/features/location.js @@ -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 - }], ], }) diff --git a/ui (gen4)/lib/widget/browse.js b/ui (gen4)/lib/widget/browse.js index a489ef5d..b918ee2d 100755 --- a/ui (gen4)/lib/widget/browse.js +++ b/ui (gen4)/lib/widget/browse.js @@ -437,6 +437,10 @@ function(list){ // // process each dom element... // each: , // +// // if true disable all items, if list then disable all items +// // from that list... +// disabled: | [ , ... ], +// // // 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