diff --git a/ui (gen4)/features/base.js b/ui (gen4)/features/base.js index 184f0d72..65e26642 100755 --- a/ui (gen4)/features/base.js +++ b/ui (gen4)/features/base.js @@ -361,17 +361,17 @@ actions.Actions({ This will collect JSON data from every available attribute supporting - the .dumpJSON() method. - Attributes starting with '__' will be ignored. + the .json() method. + Attributes starting with '_' will be ignored. `, function(mode){ return function(res){ for(var k in this){ - if(!k.startsWith('__') + if(!k.startsWith('_') && this[k] != null - && this[k].dumpJSON != null){ - res[k] = this[k].dumpJSON() + && this[k].json != null){ + res[k] = this[k].json() } } } @@ -588,7 +588,7 @@ actions.Actions({ NOTE: this is .symmetrical to .nextImage(..) see it for docs. `, {browseMode: 'firstImage'}, - function(a){ + function(a, mode){ // keep track of traverse direction... this.direction = 'left' @@ -598,6 +598,10 @@ actions.Actions({ // go to the first image if it's closer than s... || this.data.getImage('first')) + } else if(a instanceof Array && mode){ + mode = mode == 'ribbon' ? 'current' : mode + this.focusImage('prev', this.data.getImages(a, mode)) + } else { this.focusImage('prev', a) } @@ -617,10 +621,17 @@ actions.Actions({ Focus next image globally... .nextImage('global') + Focus next image in list... + .nextImage(list) + + Focus next image in list constrained to current ribbon... + .nextImage(list, 'ribbon') + .nextImage(list, ) + NOTE: this also modifies .direction `, {browseMode: 'lastImage'}, - function(a){ + function(a, mode){ // keep track of traverse direction... this.direction = 'right' @@ -630,6 +641,10 @@ actions.Actions({ // go to the first image if it's closer than s... || this.data.getImage('last')) + } else if(a instanceof Array && mode){ + mode = mode == 'ribbon' ? 'current' : mode + this.focusImage('next', this.data.getImages(a, mode)) + } else { this.focusImage('next', a) } @@ -1161,23 +1176,12 @@ var makeTagWalker = module.makeTagWalker = function(direction, dfl_tag){ var meth = direction == 'next' ? 'nextImage' : 'prevImage' - return function(tag, mode){ - mode = mode == null ? 'all' : mode - tag = tag || dfl_tag - - // account for no tags or no images tagged... - var lst = this.data.tags != null ? this.data.tags[tag] : [] - lst = lst || [] - - if(mode == 'ribbon'){ - this[meth](this.data.getImages(lst, 'current')) - - } else { - this[meth](lst) - } - } -} + this[meth]( + this.data.version >= '3.1' ? + this.data.tags.values(tag || dfl_tag) + : (this.data.tags || {})[tag || dfl_tag] || [], + mode) } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1550,12 +1554,12 @@ module.CropActions = actions.Actions({ return function(res){ if(this.cropped){ if(mode == 'base'){ - res.data = this.crop_stack[0].dumpJSON() + res.data = this.crop_stack[0].json() } else if(mode == 'full'){ res.crop_stack = this.crop_stack.map(function(c){ return c - .dumpJSON() + .json() .run(function(){ delete this.tags }) }) @@ -1790,6 +1794,12 @@ module.CropActions = actions.Actions({ }], // XXX should this be here??? + /* + cropTagged: ['- Tag|Crop/Crop tagged images', + function(query, flatten){ + return this.crop(this.data.tagQuery(query), flatten) }], + //*/ + //* cropTagged: ['- Tag|Crop/Crop tagged images', function(tags, mode, flatten){ if(this.data.length == 0){ @@ -1798,6 +1808,7 @@ module.CropActions = actions.Actions({ var selector = mode == 'any' ? 'getTaggedByAny' : 'getTaggedByAll' this.crop(this.data[selector](tags), flatten) }], + //*/ // crop edit actions... diff --git a/ui (gen4)/features/collections.js b/ui (gen4)/features/collections.js index 2cdea8ef..dc6d0d90 100755 --- a/ui (gen4)/features/collections.js +++ b/ui (gen4)/features/collections.js @@ -1195,7 +1195,7 @@ var CollectionActions = actions.Actions({ res.data = (main.crop_stack ? (main.crop_stack[0] || main.data) : main.data) - .dumpJSON() + .json() delete res.location.collection } @@ -1225,7 +1225,7 @@ var CollectionActions = actions.Actions({ (state.crop_stack[0] || state.data) : state.data) if(data){ - s.data = data.dumpJSON() + s.data = data.json() s.count = data.length } else if(state.count) { @@ -1236,7 +1236,7 @@ var CollectionActions = actions.Actions({ // 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() }) + .map(function(d){ return d.json() }) } }) } diff --git a/ui (gen4)/features/demo.js b/ui (gen4)/features/demo.js index a6188c14..5e029d9f 100755 --- a/ui (gen4)/features/demo.js +++ b/ui (gen4)/features/demo.js @@ -21,7 +21,7 @@ var core = require('features/core') var demo_data = module.demo_data = { - varsion: '3.0', + version: '3.0', current: '3', base: 'r0', @@ -76,7 +76,7 @@ module.demo_images = { //demo_data = data.Data(demo_data) // .tagsToImages(demo_images, 'merge') // .tagsFromImages(demo_images, 'merge') -// .dumpJSON() +// .json() diff --git a/ui (gen4)/features/marks.js b/ui (gen4)/features/marks.js index ccf260c6..2f4cd7cd 100755 --- a/ui (gen4)/features/marks.js +++ b/ui (gen4)/features/marks.js @@ -79,6 +79,7 @@ function makeTagTogglerAction(tag){ return action == '??' ? ['off', 'on'] : 'off' // special case: multiple targets and toggle action... + // XXX do we need this??? } else if((target == 'all' || target == 'loaded' || target == 'ribbon' || target instanceof Array) && (action == null || action == 'next' || action == 'prev' @@ -229,12 +230,13 @@ var ImageMarkActions = actions.Actions({ // chunk of memory... get marked(){ if(this.data == null - || this.data.tags == null - || !('marked' in this.data.tags)){ + || this.data.tags == null){ return [] } - //return this.data.tags['marked'].slice() - return this.data.getImages(this.data.tags['marked']) + // XXX remove the version test here.... + return this.data.version >= '3.1' ? + this.data.tagQuery('marked') + : this.data.getImages((this.data.tags || {marked:[]})['marked']) }, markedInRibbon: ['- Mark|Ribbon/', @@ -508,12 +510,14 @@ var ImageBookmarkActions = actions.Actions({ // chunk of memory... get bookmarked(){ if(this.data == null - || this.data.tags == null - || !('bookmark' in this.data.tags)){ + || this.data.tags == null){ return [] } //return this.data.tags['bookmark'].slice() - return this.data.getImages(this.data.tags['bookmark']) + // XXX remove the version test here.... + return this.data.version >= '3.1' ? + this.data.tagQuery('bookmark') + : this.data.getImages((this.data.tags || {bookmark:[]})['bookmark']) }, prevBookmarked: ['Bookmark|Navigate/Previous bookmarked image', diff --git a/ui (gen4)/imagegrid/data.js b/ui (gen4)/imagegrid/data.js index 927a780b..485167a9 100755 --- a/ui (gen4)/imagegrid/data.js +++ b/ui (gen4)/imagegrid/data.js @@ -11,7 +11,6 @@ (function(require){ var module={} // make module AMD/node compatible... /*********************************************************************/ - var sha1 = require('ext-lib/sha1') var object = require('lib/object') @@ -20,9 +19,21 @@ var tags = require('imagegrid/tags') var formats = require('imagegrid/formats') + +/*********************************************************************/ + +// NOTE: this actively indicates the format used, changing this will +// affect the loading of serialized data, do not change unless you +// know what you are doing. +// ...this is done to gradually migrate to new format versions with +// minimal changes. +var DATA_VERSION = +// XXX 3.1 not ready for production yet... +//module.DATA_VERSION = '3.1' module.DATA_VERSION = '3.0' + /*********************************************************************/ // // General format info... @@ -46,6 +57,20 @@ module.DATA_VERSION = '3.0' // // // Data format change history: +// 3.1 - Moved to the new tag implementation -- changed the tag JSON +// format: +// { +// aliases: { +// : , +// }, +// persistent: [, ...], +// tags: { +// : [, ...], +// ... +// } +// } +// (see: tags.js for more info) +// (still in development) // 3.0 - Gen4 DATA format, introduced several backwards incompatible // changes: // - added ribbon GIDs, .ribbons now is a gid indexed object @@ -129,8 +154,8 @@ var DataClassPrototype = { }, // XXX is this the right way to construct data??? fromJSON: function(data){ - //return new Data().loadJSON(data) - return new this().loadJSON(data) + //return new Data().load(data) + return new this().load(data) }, } @@ -142,6 +167,10 @@ var DataClassPrototype = { // var DataPrototype = { + get version(){ + return DATA_VERSION }, + + /*****************************************************************/ // // Base Terminology: @@ -2769,7 +2798,8 @@ var DataPrototype = { // Clone/copy the data object... // clone: function(){ - var res = new Data() + //var res = new Data() + var res = new this.constructor() res.base = this.base res.current = this.current res.order = this.order.slice() @@ -2806,10 +2836,10 @@ var DataPrototype = { // // NOTE: this loads in-place, use .fromJSON(..) to create new data... // XXX should this process defaults for unset values??? - loadJSON: function(data, clean){ + load: function(data, clean){ var that = this data = typeof(data) == typeof('str') ? JSON.parse(data) : data - data = formats.updateData(data) + data = formats.updateData(data, DATA_VERSION) this.base = data.base this.order = data.order.slice() this.ribbon_order = data.ribbon_order.slice() @@ -2842,11 +2872,9 @@ var DataPrototype = { // Generate JSON from data... // - // NOTE: if mode is either 'str' or 'string' then this will stringify - // the result... - dumpJSON: function(mode){ + json: function(){ var res = { - version: module.DATA_VERSION, + version: DATA_VERSION, base: this.base, current: this.current, order: this.order.slice(), @@ -2860,9 +2888,6 @@ var DataPrototype = { } res[s][k] = lst.compact() }) - if(mode == 'string' || mode == 'str'){ - res = JSON.stringify(res) - } return res }, @@ -2873,7 +2898,7 @@ var DataPrototype = { __init__: function(json){ // load initial state... if(json != null){ - this.loadJSON(json) + this.load(json) } else { this._reset() @@ -2886,6 +2911,7 @@ var DataPrototype = { /*********************************************************************/ +// XXX should this handle .split(..) / .join(..) var DataWithTagsPrototype = { __proto__: DataPrototype, @@ -3288,7 +3314,10 @@ var DataWithTags2Prototype = { get tags(){ return (this.__tags = this.__tags || new tags.Tags()) }, + set tags(value){ + this.__tags = value }, + // XXX do we need these??? hasTag: function(gid, ...tags){ return this.tags.tags(this.getImage(gid), ...tags) }, getTags: function(gids){ @@ -3309,29 +3338,37 @@ var DataWithTags2Prototype = { tag: function(tags, gids){ var that = this gids = gids == null || gids == 'current' ? this.getImage() : gids - gids = gids instanceof Array ? gids : [gids] - gids + ;(gids instanceof Array ? gids : [gids]) .forEach(function(gid){ - this.tags.tag(tags, gid) }) + that.tags.tag(tags, gid) }) return this }, untag: function(tags, gids){ var that = this gids = gids == null || gids == 'current' ? this.getImage() : gids - gids = gids instanceof Array ? gids : [gids] - gids + ;(gids instanceof Array ? gids : [gids]) .forEach(function(gid){ - this.tags.untag(tags, gid) }) + that.tags.untag(tags, gid) }) return this }, + // XXX should all togglers return true/false or 'on'/'off'??? + toggleTag: function(tag, gids, action){ + gids = gids == null || gids == 'current' ? this.getImage() : gids - // XXX - toggleTag: function(){ - // XXX + var res = this.tags.toggleTag(tag, gids, action) + + return res === this.tags ? + this + : res === true ? + 'on' + : res === false ? + 'off' + : res + .map(function(r){ return r ? 'on' : 'off' }) }, // XXX should these be .tags.query(..) ??? @@ -3340,8 +3377,10 @@ var DataWithTags2Prototype = { // Utils... // XXX - tagsFromImages: function(){}, - tagsToImages: function(){}, + tagsFromImages: function(){ + throw Error('.tagsFromImages(..): Not implemented.') }, + tagsToImages: function(){ + throw Error('.tagsToImages(..): Not implemented.') }, // XXX compatibility... @@ -3358,22 +3397,49 @@ var DataWithTags2Prototype = { : this.getImages(res) }, - // NOTE: this is here only to make the tags mutable... + // Extended methods... + // + // special case: make the tags mutable... crop: function(){ var crop = DataWithTags2Prototype.__proto__.crop.apply(this, arguments) - - // make the tags mutable... - if(this.tags != null){ - crop.tags = this.tags - } - + crop.tags = this.tags return crop }, - - - // XXX serialization... - - // XXX init... + // XXX + join: function(){ + var res = DataWithTags2Prototype.__proto__.join.apply(this, arguments) + // XXX + throw Error('.join(..): Not implemented.') + return res + }, + // XXX + split: function(){ + var res = DataWithTags2Prototype.__proto__.split.apply(this, arguments) + // XXX + throw Error('.split(..): Not implemented.') + return res + }, + clone: function(){ + var res = DataWithTags2Prototype.__proto__.clone.apply(this, arguments) + res.tags = this.tags.clone() + return res + }, + _reset: function(){ + var res = DataWithTags2Prototype.__proto__._reset.apply(this, arguments) + delete this.__tags + return res + }, + json: function(){ + var json = DataWithTags2Prototype.__proto__.json.apply(this, arguments) + json.tags = this.tags.json() + return json + }, + load: function(data, clean){ + var res = DataWithTags2Prototype.__proto__.load.apply(this, arguments) + data.tags + && res.tags.load(data.tags) + return res + }, } @@ -3408,7 +3474,10 @@ var DataWithTags = module.DataWithTags = object.makeConstructor('DataWithTags', DataClassPrototype, - DataWithTagsPrototype) + // XXX remove the version test here.... + DATA_VERSION >= '3.1' ? + DataWithTags2Prototype + : DataWithTagsPrototype) var Data = diff --git a/ui (gen4)/imagegrid/formats.js b/ui (gen4)/imagegrid/formats.js index 03a35038..ed9e7e4d 100755 --- a/ui (gen4)/imagegrid/formats.js +++ b/ui (gen4)/imagegrid/formats.js @@ -42,6 +42,7 @@ function(data){ module.VERSIONS['2.0'] = function(data, cmp){ //data = data.version < '2.0' ? module.VERSIONS['2.0'](data) : data + console.log('Updating data to: ', '2.0') var res = { data: { @@ -102,11 +103,14 @@ function(data){ var res = {} res.version = '3.0' + console.log('Updating data to: ', res.version) + res.current = data.current res.order = data.order.slice() res.ribbon_order = data.ribbon_order == null ? [] : data.ribbon_order.slice() res.ribbons = {} + // generate gids... // NOTE: this will use the structures stored in data if available, // otherwise new structures will be generated... @@ -128,13 +132,26 @@ function(data){ } - -/* XXX template... module.VERSIONS['3.1'] = function(data){ var res = data.version < '3.0' ? module.VERSIONS['3.0'](data) : data res.version = '3.1' + console.log('Updating data to: ', res.version) + + data.tags + && (res.tags = { tags: data.tags }) + + return res +} + + +/* XXX template... +module.VERSIONS['3.2'] = +function(data){ + var res = data.version < '3.1' ? module.VERSIONS['3.1'](data) : data + + res.version = '3.2' // XXX @@ -165,8 +182,8 @@ module.getLatestUpdaterVersion = function(){ // format. // NOTE: if data is already in the latest format this will return it // as-is. -module.updateData = function(data, clean){ - var v = module.getLatestUpdaterVersion() +module.updateData = function(data, version, clean){ + var v = version || module.getLatestUpdaterVersion() var res = data.version < v ? module.VERSIONS[v](data) : completeData(data) diff --git a/ui (gen4)/imagegrid/images.js b/ui (gen4)/imagegrid/images.js index f74e3c20..b907085d 100755 --- a/ui (gen4)/imagegrid/images.js +++ b/ui (gen4)/imagegrid/images.js @@ -344,7 +344,7 @@ module.ImagesClassPrototype = { return images }, fromJSON: function(data){ - return new this().loadJSON(data) + return new this().load(data) }, } @@ -689,7 +689,7 @@ module.ImagesPrototype = { clone: function(){ - return (new Images()).loadJSON(this.dumpJSON()) }, + return (new Images()).load(this.json()) }, // NOTE: this will join the other data into the current object in-place, // use .clone() to preserve current data... join: function(other){ @@ -703,7 +703,7 @@ module.ImagesPrototype = { }, // serialization... - loadJSON: function(data){ + load: function(data){ data = typeof(data) == typeof('str') ? JSON.parse(data) : JSON.parse(JSON.stringify(data)) @@ -727,7 +727,7 @@ module.ImagesPrototype = { }, // XXX this is really odd: renaming this to 'toJSON' breaks JavaScript // making chrome/node just say: "" and a filename... - dumpJSON: function(data){ + json: function(data){ var res = JSON.parse(JSON.stringify(this)) // XXX res.version = '3.0' @@ -742,7 +742,7 @@ module.ImagesPrototype = { __init__: function(json){ // load initial state... if(json != null){ - this.loadJSON(json) + this.load(json) } else { this._reset() } diff --git a/ui (gen4)/imagegrid/tags.js b/ui (gen4)/imagegrid/tags.js index 5ae8831c..5f3c8cfe 100755 --- a/ui (gen4)/imagegrid/tags.js +++ b/ui (gen4)/imagegrid/tags.js @@ -628,7 +628,7 @@ var TagsPrototype = { return that.tags(v, tag) ? (that.untag(tag, v), false) // NOTE: we set only if we are not a pattern... - : (pattern ? + : (!pattern ? (that.tag(tag, v), true) : null) }) },