preparing to move to new tags (data format 3.1)...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2018-12-05 18:15:37 +03:00
parent 9993323d5c
commit 2a99cd9889
8 changed files with 186 additions and 85 deletions

View File

@ -361,17 +361,17 @@ actions.Actions({
This will collect JSON data from every available attribute supporting This will collect JSON data from every available attribute supporting
the .dumpJSON() method. the .json() method.
Attributes starting with '__' will be ignored. Attributes starting with '_' will be ignored.
`, `,
function(mode){ function(mode){
return function(res){ return function(res){
for(var k in this){ for(var k in this){
if(!k.startsWith('__') if(!k.startsWith('_')
&& this[k] != null && this[k] != null
&& this[k].dumpJSON != null){ && this[k].json != null){
res[k] = this[k].dumpJSON() res[k] = this[k].json()
} }
} }
} }
@ -588,7 +588,7 @@ actions.Actions({
NOTE: this is .symmetrical to .nextImage(..) see it for docs. NOTE: this is .symmetrical to .nextImage(..) see it for docs.
`, `,
{browseMode: 'firstImage'}, {browseMode: 'firstImage'},
function(a){ function(a, mode){
// keep track of traverse direction... // keep track of traverse direction...
this.direction = 'left' this.direction = 'left'
@ -598,6 +598,10 @@ actions.Actions({
// go to the first image if it's closer than s... // go to the first image if it's closer than s...
|| this.data.getImage('first')) || this.data.getImage('first'))
} else if(a instanceof Array && mode){
mode = mode == 'ribbon' ? 'current' : mode
this.focusImage('prev', this.data.getImages(a, mode))
} else { } else {
this.focusImage('prev', a) this.focusImage('prev', a)
} }
@ -617,10 +621,17 @@ actions.Actions({
Focus next image globally... Focus next image globally...
.nextImage('global') .nextImage('global')
Focus next image in list...
.nextImage(list)
Focus next image in list constrained to current ribbon...
.nextImage(list, 'ribbon')
.nextImage(list, <ribbon-gid>)
NOTE: this also modifies .direction NOTE: this also modifies .direction
`, `,
{browseMode: 'lastImage'}, {browseMode: 'lastImage'},
function(a){ function(a, mode){
// keep track of traverse direction... // keep track of traverse direction...
this.direction = 'right' this.direction = 'right'
@ -630,6 +641,10 @@ actions.Actions({
// go to the first image if it's closer than s... // go to the first image if it's closer than s...
|| this.data.getImage('last')) || this.data.getImage('last'))
} else if(a instanceof Array && mode){
mode = mode == 'ribbon' ? 'current' : mode
this.focusImage('next', this.data.getImages(a, mode))
} else { } else {
this.focusImage('next', a) this.focusImage('next', a)
} }
@ -1161,23 +1176,12 @@ var makeTagWalker =
module.makeTagWalker = module.makeTagWalker =
function(direction, dfl_tag){ function(direction, dfl_tag){
var meth = direction == 'next' ? 'nextImage' : 'prevImage' var meth = direction == 'next' ? 'nextImage' : 'prevImage'
return function(tag, mode){ return function(tag, mode){
mode = mode == null ? 'all' : mode this[meth](
tag = tag || dfl_tag this.data.version >= '3.1' ?
this.data.tags.values(tag || dfl_tag)
// account for no tags or no images tagged... : (this.data.tags || {})[tag || dfl_tag] || [],
var lst = this.data.tags != null ? this.data.tags[tag] : [] mode) } }
lst = lst || []
if(mode == 'ribbon'){
this[meth](this.data.getImages(lst, 'current'))
} else {
this[meth](lst)
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1550,12 +1554,12 @@ module.CropActions = actions.Actions({
return function(res){ return function(res){
if(this.cropped){ if(this.cropped){
if(mode == 'base'){ if(mode == 'base'){
res.data = this.crop_stack[0].dumpJSON() res.data = this.crop_stack[0].json()
} else if(mode == 'full'){ } else if(mode == 'full'){
res.crop_stack = this.crop_stack.map(function(c){ res.crop_stack = this.crop_stack.map(function(c){
return c return c
.dumpJSON() .json()
.run(function(){ .run(function(){
delete this.tags }) delete this.tags })
}) })
@ -1790,6 +1794,12 @@ module.CropActions = actions.Actions({
}], }],
// XXX should this be here??? // 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', cropTagged: ['- Tag|Crop/Crop tagged images',
function(tags, mode, flatten){ function(tags, mode, flatten){
if(this.data.length == 0){ if(this.data.length == 0){
@ -1798,6 +1808,7 @@ module.CropActions = actions.Actions({
var selector = mode == 'any' ? 'getTaggedByAny' : 'getTaggedByAll' var selector = mode == 'any' ? 'getTaggedByAny' : 'getTaggedByAll'
this.crop(this.data[selector](tags), flatten) this.crop(this.data[selector](tags), flatten)
}], }],
//*/
// crop edit actions... // crop edit actions...

View File

@ -1195,7 +1195,7 @@ var CollectionActions = actions.Actions({
res.data = (main.crop_stack ? res.data = (main.crop_stack ?
(main.crop_stack[0] || main.data) (main.crop_stack[0] || main.data)
: main.data) : main.data)
.dumpJSON() .json()
delete res.location.collection delete res.location.collection
} }
@ -1225,7 +1225,7 @@ var CollectionActions = actions.Actions({
(state.crop_stack[0] || state.data) (state.crop_stack[0] || state.data)
: state.data) : state.data)
if(data){ if(data){
s.data = data.dumpJSON() s.data = data.json()
s.count = data.length s.count = data.length
} else if(state.count) { } else if(state.count) {
@ -1236,7 +1236,7 @@ var CollectionActions = actions.Actions({
// NOTE: in base mode, crop_stack is ignored... // NOTE: in base mode, crop_stack is ignored...
if(mode != 'base' && state.crop_stack){ if(mode != 'base' && state.crop_stack){
s.crop_stack = state.crop_stack s.crop_stack = state.crop_stack
.map(function(d){ return d.dumpJSON() }) .map(function(d){ return d.json() })
} }
}) })
} }

View File

@ -21,7 +21,7 @@ var core = require('features/core')
var demo_data = var demo_data =
module.demo_data = { module.demo_data = {
varsion: '3.0', version: '3.0',
current: '3', current: '3',
base: 'r0', base: 'r0',
@ -76,7 +76,7 @@ module.demo_images = {
//demo_data = data.Data(demo_data) //demo_data = data.Data(demo_data)
// .tagsToImages(demo_images, 'merge') // .tagsToImages(demo_images, 'merge')
// .tagsFromImages(demo_images, 'merge') // .tagsFromImages(demo_images, 'merge')
// .dumpJSON() // .json()

View File

@ -79,6 +79,7 @@ function makeTagTogglerAction(tag){
return action == '??' ? ['off', 'on'] : 'off' return action == '??' ? ['off', 'on'] : 'off'
// special case: multiple targets and toggle action... // special case: multiple targets and toggle action...
// XXX do we need this???
} else if((target == 'all' || target == 'loaded' || target == 'ribbon' } else if((target == 'all' || target == 'loaded' || target == 'ribbon'
|| target instanceof Array) || target instanceof Array)
&& (action == null || action == 'next' || action == 'prev' && (action == null || action == 'next' || action == 'prev'
@ -229,12 +230,13 @@ var ImageMarkActions = actions.Actions({
// chunk of memory... // chunk of memory...
get marked(){ get marked(){
if(this.data == null if(this.data == null
|| this.data.tags == null || this.data.tags == null){
|| !('marked' in this.data.tags)){
return [] return []
} }
//return this.data.tags['marked'].slice() // XXX remove the version test here....
return this.data.getImages(this.data.tags['marked']) return this.data.version >= '3.1' ?
this.data.tagQuery('marked')
: this.data.getImages((this.data.tags || {marked:[]})['marked'])
}, },
markedInRibbon: ['- Mark|Ribbon/', markedInRibbon: ['- Mark|Ribbon/',
@ -508,12 +510,14 @@ var ImageBookmarkActions = actions.Actions({
// chunk of memory... // chunk of memory...
get bookmarked(){ get bookmarked(){
if(this.data == null if(this.data == null
|| this.data.tags == null || this.data.tags == null){
|| !('bookmark' in this.data.tags)){
return [] return []
} }
//return this.data.tags['bookmark'].slice() //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', prevBookmarked: ['Bookmark|Navigate/Previous bookmarked image',

View File

@ -11,7 +11,6 @@
(function(require){ var module={} // make module AMD/node compatible... (function(require){ var module={} // make module AMD/node compatible...
/*********************************************************************/ /*********************************************************************/
var sha1 = require('ext-lib/sha1') var sha1 = require('ext-lib/sha1')
var object = require('lib/object') var object = require('lib/object')
@ -20,9 +19,21 @@ var tags = require('imagegrid/tags')
var formats = require('imagegrid/formats') 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' module.DATA_VERSION = '3.0'
/*********************************************************************/ /*********************************************************************/
// //
// General format info... // General format info...
@ -46,6 +57,20 @@ module.DATA_VERSION = '3.0'
// //
// //
// Data format change history: // Data format change history:
// 3.1 - Moved to the new tag implementation -- changed the tag JSON
// format:
// {
// aliases: {
// <alias>: <tag>,
// },
// persistent: [<tag>, ...],
// tags: {
// <tag>: [<gid>, ...],
// ...
// }
// }
// (see: tags.js for more info)
// (still in development)
// 3.0 - Gen4 DATA format, introduced several backwards incompatible // 3.0 - Gen4 DATA format, introduced several backwards incompatible
// changes: // changes:
// - added ribbon GIDs, .ribbons now is a gid indexed object // - 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??? // XXX is this the right way to construct data???
fromJSON: function(data){ fromJSON: function(data){
//return new Data().loadJSON(data) //return new Data().load(data)
return new this().loadJSON(data) return new this().load(data)
}, },
} }
@ -142,6 +167,10 @@ var DataClassPrototype = {
// //
var DataPrototype = { var DataPrototype = {
get version(){
return DATA_VERSION },
/*****************************************************************/ /*****************************************************************/
// //
// Base Terminology: // Base Terminology:
@ -2769,7 +2798,8 @@ var DataPrototype = {
// Clone/copy the data object... // Clone/copy the data object...
// //
clone: function(){ clone: function(){
var res = new Data() //var res = new Data()
var res = new this.constructor()
res.base = this.base res.base = this.base
res.current = this.current res.current = this.current
res.order = this.order.slice() res.order = this.order.slice()
@ -2806,10 +2836,10 @@ var DataPrototype = {
// //
// NOTE: this loads in-place, use .fromJSON(..) to create new data... // NOTE: this loads in-place, use .fromJSON(..) to create new data...
// XXX should this process defaults for unset values??? // XXX should this process defaults for unset values???
loadJSON: function(data, clean){ load: function(data, clean){
var that = this var that = this
data = typeof(data) == typeof('str') ? JSON.parse(data) : data data = typeof(data) == typeof('str') ? JSON.parse(data) : data
data = formats.updateData(data) data = formats.updateData(data, DATA_VERSION)
this.base = data.base this.base = data.base
this.order = data.order.slice() this.order = data.order.slice()
this.ribbon_order = data.ribbon_order.slice() this.ribbon_order = data.ribbon_order.slice()
@ -2842,11 +2872,9 @@ var DataPrototype = {
// Generate JSON from data... // Generate JSON from data...
// //
// NOTE: if mode is either 'str' or 'string' then this will stringify json: function(){
// the result...
dumpJSON: function(mode){
var res = { var res = {
version: module.DATA_VERSION, version: DATA_VERSION,
base: this.base, base: this.base,
current: this.current, current: this.current,
order: this.order.slice(), order: this.order.slice(),
@ -2860,9 +2888,6 @@ var DataPrototype = {
} }
res[s][k] = lst.compact() res[s][k] = lst.compact()
}) })
if(mode == 'string' || mode == 'str'){
res = JSON.stringify(res)
}
return res return res
}, },
@ -2873,7 +2898,7 @@ var DataPrototype = {
__init__: function(json){ __init__: function(json){
// load initial state... // load initial state...
if(json != null){ if(json != null){
this.loadJSON(json) this.load(json)
} else { } else {
this._reset() this._reset()
@ -2886,6 +2911,7 @@ var DataPrototype = {
/*********************************************************************/ /*********************************************************************/
// XXX should this handle .split(..) / .join(..)
var DataWithTagsPrototype = { var DataWithTagsPrototype = {
__proto__: DataPrototype, __proto__: DataPrototype,
@ -3288,7 +3314,10 @@ var DataWithTags2Prototype = {
get tags(){ get tags(){
return (this.__tags = this.__tags || new tags.Tags()) }, return (this.__tags = this.__tags || new tags.Tags()) },
set tags(value){
this.__tags = value },
// XXX do we need these???
hasTag: function(gid, ...tags){ hasTag: function(gid, ...tags){
return this.tags.tags(this.getImage(gid), ...tags) }, return this.tags.tags(this.getImage(gid), ...tags) },
getTags: function(gids){ getTags: function(gids){
@ -3309,29 +3338,37 @@ var DataWithTags2Prototype = {
tag: function(tags, gids){ tag: function(tags, gids){
var that = this var that = this
gids = gids == null || gids == 'current' ? this.getImage() : gids gids = gids == null || gids == 'current' ? this.getImage() : gids
gids = gids instanceof Array ? gids : [gids]
gids ;(gids instanceof Array ? gids : [gids])
.forEach(function(gid){ .forEach(function(gid){
this.tags.tag(tags, gid) }) that.tags.tag(tags, gid) })
return this return this
}, },
untag: function(tags, gids){ untag: function(tags, gids){
var that = this var that = this
gids = gids == null || gids == 'current' ? this.getImage() : gids gids = gids == null || gids == 'current' ? this.getImage() : gids
gids = gids instanceof Array ? gids : [gids]
gids ;(gids instanceof Array ? gids : [gids])
.forEach(function(gid){ .forEach(function(gid){
this.tags.untag(tags, gid) }) that.tags.untag(tags, gid) })
return this 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 var res = this.tags.toggleTag(tag, gids, action)
toggleTag: function(){
// XXX 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(..) ??? // XXX should these be .tags.query(..) ???
@ -3340,8 +3377,10 @@ var DataWithTags2Prototype = {
// Utils... // Utils...
// XXX // XXX
tagsFromImages: function(){}, tagsFromImages: function(){
tagsToImages: function(){}, throw Error('.tagsFromImages(..): Not implemented.') },
tagsToImages: function(){
throw Error('.tagsToImages(..): Not implemented.') },
// XXX compatibility... // XXX compatibility...
@ -3358,22 +3397,49 @@ var DataWithTags2Prototype = {
: this.getImages(res) }, : this.getImages(res) },
// NOTE: this is here only to make the tags mutable... // Extended methods...
//
// special case: make the tags mutable...
crop: function(){ crop: function(){
var crop = DataWithTags2Prototype.__proto__.crop.apply(this, arguments) var crop = DataWithTags2Prototype.__proto__.crop.apply(this, arguments)
crop.tags = this.tags
// make the tags mutable...
if(this.tags != null){
crop.tags = this.tags
}
return crop return crop
}, },
// XXX
join: function(){
// XXX serialization... var res = DataWithTags2Prototype.__proto__.join.apply(this, arguments)
// XXX
// XXX init... 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 = module.DataWithTags =
object.makeConstructor('DataWithTags', object.makeConstructor('DataWithTags',
DataClassPrototype, DataClassPrototype,
DataWithTagsPrototype) // XXX remove the version test here....
DATA_VERSION >= '3.1' ?
DataWithTags2Prototype
: DataWithTagsPrototype)
var Data = var Data =

View File

@ -42,6 +42,7 @@ function(data){
module.VERSIONS['2.0'] = module.VERSIONS['2.0'] =
function(data, cmp){ function(data, cmp){
//data = data.version < '2.0' ? module.VERSIONS['2.0'](data) : data //data = data.version < '2.0' ? module.VERSIONS['2.0'](data) : data
console.log('Updating data to: ', '2.0')
var res = { var res = {
data: { data: {
@ -102,11 +103,14 @@ function(data){
var res = {} var res = {}
res.version = '3.0' res.version = '3.0'
console.log('Updating data to: ', res.version)
res.current = data.current res.current = data.current
res.order = data.order.slice() res.order = data.order.slice()
res.ribbon_order = data.ribbon_order == null ? [] : data.ribbon_order.slice() res.ribbon_order = data.ribbon_order == null ? [] : data.ribbon_order.slice()
res.ribbons = {} res.ribbons = {}
// generate gids... // generate gids...
// NOTE: this will use the structures stored in data if available, // NOTE: this will use the structures stored in data if available,
// otherwise new structures will be generated... // otherwise new structures will be generated...
@ -128,13 +132,26 @@ function(data){
} }
/* XXX template...
module.VERSIONS['3.1'] = module.VERSIONS['3.1'] =
function(data){ function(data){
var res = data.version < '3.0' ? module.VERSIONS['3.0'](data) : data var res = data.version < '3.0' ? module.VERSIONS['3.0'](data) : data
res.version = '3.1' 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 // XXX
@ -165,8 +182,8 @@ module.getLatestUpdaterVersion = function(){
// format. // format.
// NOTE: if data is already in the latest format this will return it // NOTE: if data is already in the latest format this will return it
// as-is. // as-is.
module.updateData = function(data, clean){ module.updateData = function(data, version, clean){
var v = module.getLatestUpdaterVersion() var v = version || module.getLatestUpdaterVersion()
var res = data.version < v var res = data.version < v
? module.VERSIONS[v](data) ? module.VERSIONS[v](data)
: completeData(data) : completeData(data)

View File

@ -344,7 +344,7 @@ module.ImagesClassPrototype = {
return images return images
}, },
fromJSON: function(data){ fromJSON: function(data){
return new this().loadJSON(data) return new this().load(data)
}, },
} }
@ -689,7 +689,7 @@ module.ImagesPrototype = {
clone: function(){ 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, // NOTE: this will join the other data into the current object in-place,
// use .clone() to preserve current data... // use .clone() to preserve current data...
join: function(other){ join: function(other){
@ -703,7 +703,7 @@ module.ImagesPrototype = {
}, },
// serialization... // serialization...
loadJSON: function(data){ load: function(data){
data = typeof(data) == typeof('str') data = typeof(data) == typeof('str')
? JSON.parse(data) ? JSON.parse(data)
: JSON.parse(JSON.stringify(data)) : JSON.parse(JSON.stringify(data))
@ -727,7 +727,7 @@ module.ImagesPrototype = {
}, },
// XXX this is really odd: renaming this to 'toJSON' breaks JavaScript // XXX this is really odd: renaming this to 'toJSON' breaks JavaScript
// making chrome/node just say: "<error>" and a filename... // making chrome/node just say: "<error>" and a filename...
dumpJSON: function(data){ json: function(data){
var res = JSON.parse(JSON.stringify(this)) var res = JSON.parse(JSON.stringify(this))
// XXX // XXX
res.version = '3.0' res.version = '3.0'
@ -742,7 +742,7 @@ module.ImagesPrototype = {
__init__: function(json){ __init__: function(json){
// load initial state... // load initial state...
if(json != null){ if(json != null){
this.loadJSON(json) this.load(json)
} else { } else {
this._reset() this._reset()
} }

View File

@ -628,7 +628,7 @@ var TagsPrototype = {
return that.tags(v, tag) ? return that.tags(v, tag) ?
(that.untag(tag, v), false) (that.untag(tag, v), false)
// NOTE: we set only if we are not a pattern... // NOTE: we set only if we are not a pattern...
: (pattern ? : (!pattern ?
(that.tag(tag, v), true) (that.tag(tag, v), true)
: null) }) }, : null) }) },