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
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, <ribbon-gid>)
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...

View File

@ -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() })
}
})
}

View File

@ -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()

View File

@ -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',

View File

@ -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: {
// <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
// 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 =

View File

@ -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)

View File

@ -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: "<error>" 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()
}

View File

@ -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) }) },