mirror of
https://github.com/flynx/ImageGrid.git
synced 2025-11-01 11:50:07 +00:00
groups mostly working + substantial refactoring of data.js...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
8393adfb4f
commit
8e6e7de822
@ -381,8 +381,13 @@ var DataPrototype = {
|
||||
images.forEach(function(gid){ that.clear(gid) })
|
||||
}
|
||||
|
||||
if(that.base == gid){
|
||||
// no more ribbons left...
|
||||
if(that.ribbon_order.length == 0){
|
||||
that.base = null
|
||||
|
||||
// shift base up or to first image...
|
||||
} else if(that.base == gid){
|
||||
that.setBase(Math.max(0, r-1))
|
||||
}
|
||||
|
||||
// gid is an image...
|
||||
@ -390,9 +395,8 @@ var DataPrototype = {
|
||||
// remove from order...
|
||||
that.order.splice(i, 1)
|
||||
|
||||
// remove from ribbons...
|
||||
Object.keys(that.ribbons).forEach(function(r){
|
||||
that.ribbons[r].splice(i, 1)
|
||||
that.eachImageList(function(lst){
|
||||
lst.splice(i, 1)
|
||||
})
|
||||
|
||||
if(that.current == gid){
|
||||
@ -1044,15 +1048,96 @@ var DataPrototype = {
|
||||
return this
|
||||
},
|
||||
|
||||
// Sort images in ribbons via .order...
|
||||
__gid_lists: ['ribbons', 'groups'],
|
||||
|
||||
// Iterate through image lists...
|
||||
//
|
||||
// NOTE: this sorts in-place
|
||||
// NOTE: this will not change image order
|
||||
sortImages: function(){
|
||||
var ribbons = this.ribbons
|
||||
for(k in ribbons){
|
||||
ribbons[k] = this.makeSparseImages(ribbons[k])
|
||||
}
|
||||
// This accepts a function:
|
||||
// func(list, key, set)
|
||||
//
|
||||
// Where:
|
||||
// list - the sparse list of gids
|
||||
// key - the list key in set
|
||||
// set - the set name
|
||||
//
|
||||
// The function is called in the context of the data object.
|
||||
//
|
||||
// The arguments can be used to access the list directly like this:
|
||||
// this[set][key] -> list
|
||||
//
|
||||
eachImageList: function(func){
|
||||
var that = this
|
||||
this.__gid_lists.forEach(function(k){
|
||||
var lst = that[k]
|
||||
if(lst == null){
|
||||
return
|
||||
}
|
||||
Object.keys(lst).forEach(function(l){
|
||||
func.call(that, lst[l], l, k)
|
||||
})
|
||||
})
|
||||
return this
|
||||
},
|
||||
|
||||
// Update image position via .order...
|
||||
//
|
||||
// Full sort
|
||||
// .updateImagePositions()
|
||||
// -> data
|
||||
//
|
||||
// Reposition item(s)
|
||||
// .updateImagePositions(gid|index)
|
||||
// -> data
|
||||
//
|
||||
// Reposition item(s) and the item(s) they replace
|
||||
// .updateImagePositions(gid|index, 'keep')
|
||||
// -> data
|
||||
//
|
||||
// Hide item(s) from lists
|
||||
// .updateImagePositions(gid|index, 'hide')
|
||||
// -> data
|
||||
//
|
||||
// Remove item(s) from lists
|
||||
// .updateImagePositions(gid|index, 'remove')
|
||||
// -> data
|
||||
//
|
||||
// NOTE: hide will not change the order of other items while remove
|
||||
// will do a full sort...
|
||||
// NOTE: in any case other that the first this will not try to
|
||||
// correct any errors.
|
||||
//
|
||||
// XXX needs more thought....
|
||||
// do we need to move images by this???
|
||||
updateImagePositions: function(from, mode){
|
||||
from = from != null && from.constructor !== Array ? [from] : from
|
||||
|
||||
this.eachImageList(function(cur, key, set){
|
||||
set = this[set]
|
||||
|
||||
// resort...
|
||||
if(from == null){
|
||||
set[key] = this.makeSparseImages(cur)
|
||||
|
||||
// remove/hide elements...
|
||||
} else if(mode == 'remove' || mode == 'hide'){
|
||||
from.forEach(function(g){
|
||||
delete cur[cur.indexOf(g)]
|
||||
})
|
||||
// if we are removing we'll also need to resort...
|
||||
if(mode == 'remove'){
|
||||
set[key] = this.makeSparseImages(cur)
|
||||
}
|
||||
|
||||
// place and keep existing...
|
||||
} else if(mode == 'keep'){
|
||||
set[key] = this.makeSparseImages(from, cur, true)
|
||||
|
||||
// only place...
|
||||
} else {
|
||||
set[key] = this.makeSparseImages(from, cur)
|
||||
}
|
||||
})
|
||||
|
||||
return this
|
||||
},
|
||||
|
||||
@ -1063,23 +1148,36 @@ var DataPrototype = {
|
||||
// NOTE: this depends on setting length of an array, it works in
|
||||
// Chrome but will it work the same in other systems???
|
||||
reverseImages: function(){
|
||||
var ribbons = this.ribbons
|
||||
this.order.reverse()
|
||||
var l = this.order.length
|
||||
for(k in ribbons){
|
||||
// XXX will this work everywhere???
|
||||
// NOTE: ribbons may be truncated, so we need to explicitly
|
||||
// set their length...
|
||||
ribbons[k].length = l
|
||||
ribbons[k].reverse()
|
||||
}
|
||||
var order = this.order
|
||||
order.reverse()
|
||||
var l = order.length
|
||||
|
||||
var that = this
|
||||
this.eachImageList(function(lst){
|
||||
lst.length = l
|
||||
lst.reverse()
|
||||
})
|
||||
|
||||
return this
|
||||
},
|
||||
|
||||
// Sort images in ribbons via .order...
|
||||
//
|
||||
// NOTE: this sorts in-place
|
||||
// NOTE: this will not change image order
|
||||
sortImages: function(cmp){
|
||||
|
||||
// sort the order...
|
||||
this.order.sort(cmp)
|
||||
|
||||
return this.updateImagePositions()
|
||||
},
|
||||
|
||||
reverseRibbons: function(){
|
||||
this.ribbon_order.reverse()
|
||||
},
|
||||
|
||||
|
||||
// Gather gids into an connected section...
|
||||
//
|
||||
// The section is positioned relative to a reference gid, which also
|
||||
@ -1205,7 +1303,7 @@ var DataPrototype = {
|
||||
})
|
||||
|
||||
// XXX this is cheating...
|
||||
this.sortImages()
|
||||
this.updateImagePositions()
|
||||
}
|
||||
|
||||
return this
|
||||
@ -1298,15 +1396,7 @@ var DataPrototype = {
|
||||
// clear empty ribbon...
|
||||
r = r == 0 ? 1 : r
|
||||
if(this.ribbons[this.ribbon_order[r]].len == 0){
|
||||
var b = this.getRibbonOrder(this.base)-1
|
||||
|
||||
r = this.ribbon_order.splice(r, 1)[0]
|
||||
delete this.ribbons[r]
|
||||
|
||||
// shift base...
|
||||
if(!(this.base in this.ribbons)){
|
||||
this.setBase(Math.max(0, b))
|
||||
}
|
||||
this.clear(this.ribbon_order[r])
|
||||
}
|
||||
return res
|
||||
},
|
||||
@ -1320,15 +1410,7 @@ var DataPrototype = {
|
||||
var res = this.shiftImage(gid, r+1, 'vertical')
|
||||
// clear empty ribbon...
|
||||
if(this.ribbons[this.ribbon_order[r]].len == 0){
|
||||
var b = this.getRibbonOrder(this.base)-1
|
||||
|
||||
r = this.ribbon_order.splice(r, 1)[0]
|
||||
delete this.ribbons[r]
|
||||
|
||||
// shift base...
|
||||
if(!(this.base in this.ribbons)){
|
||||
this.setBase(Math.max(0, b))
|
||||
}
|
||||
this.clear(this.ribbon_order[r])
|
||||
}
|
||||
return res
|
||||
},
|
||||
@ -1377,6 +1459,189 @@ var DataPrototype = {
|
||||
shiftRibbonDown: function(gid){ return this.shiftRibbon(gid, 1, 'offset') },
|
||||
|
||||
|
||||
// XXX experimental...
|
||||
// ...not sure if storing groups in .groups here is the right
|
||||
// way to go...
|
||||
// XXX need to set default cover... (???)
|
||||
// XXX should these be here or in a separate class???
|
||||
isGroup: function(gid){
|
||||
gid = gid == null ? this.getImage() : gid
|
||||
return this.groups != null ? gid in this.groups : false
|
||||
},
|
||||
getGroup: function(gid){
|
||||
gid = gid == null ? this.getImage() : gid
|
||||
if(this.isGroup(gid)){
|
||||
return gid
|
||||
}
|
||||
if(this.groups == null){
|
||||
return null
|
||||
}
|
||||
|
||||
for(var k in this.groups){
|
||||
if(this.groups[k].indexOf(gid) >= 0){
|
||||
return k
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
},
|
||||
|
||||
group: function(gids, group){
|
||||
gids = gids == null ? this.getImage() : gids
|
||||
gids = gids.constructor !== Array ? [gids] : gids
|
||||
group = group == null ? this.newGid('G') : group
|
||||
|
||||
if(this.groups == null){
|
||||
this.groups = {}
|
||||
}
|
||||
|
||||
// existing group...
|
||||
if(group in this.groups){
|
||||
var lst = this.makeSparseImages(this.groups[group])
|
||||
var place = false
|
||||
|
||||
// new group...
|
||||
} else {
|
||||
var lst = []
|
||||
var place = true
|
||||
}
|
||||
|
||||
this.groups[group] = this.makeSparseImages(gids, lst)
|
||||
|
||||
// place group...
|
||||
if(place){
|
||||
var place = this.order.indexOf(gids[0])
|
||||
var r = this.getRibbon(gids[0])
|
||||
|
||||
// update order...
|
||||
this.order.splice(place, 0, group)
|
||||
|
||||
// update lists...
|
||||
this.eachImageList(function(lst, k, s){
|
||||
// insert a place for the group...
|
||||
lst.splice(place, 0, undefined)
|
||||
delete lst[place]
|
||||
})
|
||||
|
||||
// insert the group gid only in the correct ribbon...
|
||||
this.ribbons[r][place] = group
|
||||
|
||||
// collapse the new group...
|
||||
this.collapseGroup(group)
|
||||
|
||||
// when adding to a new group, collapse only if group is collapsed...
|
||||
} else if(this.getRibbon(group) != null){
|
||||
this.collapseGroup(group)
|
||||
}
|
||||
|
||||
return this
|
||||
},
|
||||
// NOTE: this will ungroup the image into the same ribbon as the
|
||||
// group...
|
||||
ungroup: function(group){
|
||||
group = this.getGroup(group)
|
||||
|
||||
if(group == null){
|
||||
return this
|
||||
}
|
||||
|
||||
this.expandGroup(group)
|
||||
|
||||
// remove the group...
|
||||
delete this.groups[group]
|
||||
this.clear(group)
|
||||
|
||||
return this
|
||||
},
|
||||
|
||||
expandGroup: function(groups){
|
||||
groups = groups == null ? this.getGroup() : groups
|
||||
groups = groups.constructor !== Array ? [groups] : groups
|
||||
|
||||
var that = this
|
||||
groups.forEach(function(group){
|
||||
group = that.getGroup(group)
|
||||
|
||||
if(group == null){
|
||||
return
|
||||
}
|
||||
|
||||
var lst = that.groups[group]
|
||||
var r = that.getRibbon(group)
|
||||
|
||||
// already expanded...
|
||||
if(r == null){
|
||||
return
|
||||
}
|
||||
|
||||
// place images...
|
||||
lst.forEach(function(gid, i){
|
||||
that.ribbons[r][i] = gid
|
||||
})
|
||||
|
||||
if(that.current == group){
|
||||
that.current = lst.compact()[0]
|
||||
}
|
||||
|
||||
// hide group...
|
||||
delete that.ribbons[r][that.order.indexOf(group)]
|
||||
})
|
||||
|
||||
return this
|
||||
},
|
||||
collapseGroup: function(groups){
|
||||
groups = groups == null ? this.getGroup() : groups
|
||||
groups = groups.constructor !== Array ? [groups] : groups
|
||||
|
||||
var that = this
|
||||
groups.forEach(function(group){
|
||||
group = that.getGroup(group)
|
||||
|
||||
if(group == null){
|
||||
return
|
||||
}
|
||||
|
||||
var lst = that.groups[group]
|
||||
var r = that.getRibbon(group)
|
||||
r = r == null ? that.getRibbon(that.groups[group].compact()[0]) : r
|
||||
|
||||
// remove grouped images from ribbons...
|
||||
lst.forEach(function(gid, i){
|
||||
Object.keys(that.ribbons).forEach(function(r){
|
||||
delete that.ribbons[r][i]
|
||||
})
|
||||
})
|
||||
|
||||
// insert group...
|
||||
that.ribbons[r][that.order.indexOf(group)] = group
|
||||
|
||||
// shift current...
|
||||
if(lst.indexOf(that.current) >= 0){
|
||||
that.current = group
|
||||
}
|
||||
})
|
||||
|
||||
return this
|
||||
},
|
||||
|
||||
cropGroup: function(group){
|
||||
group = this.getGroup(group)
|
||||
|
||||
if(group == null){
|
||||
return
|
||||
}
|
||||
|
||||
// XXX is this the correct way to do this???
|
||||
this.expandGroup(group)
|
||||
|
||||
var res = this.crop(this.groups[group])
|
||||
|
||||
this.collapseGroup(group)
|
||||
|
||||
return res
|
||||
},
|
||||
|
||||
|
||||
|
||||
/********************************************* Data-level edit ***/
|
||||
|
||||
@ -1585,7 +1850,6 @@ var DataPrototype = {
|
||||
// Crop the data...
|
||||
//
|
||||
// NOTE: this will not affect the original data object...
|
||||
// NOTE: this may result in empty ribbons...
|
||||
// NOTE: this will not crop the .order...
|
||||
crop: function(list, flatten){
|
||||
var crop = this.clone()
|
||||
@ -1607,13 +1871,7 @@ var DataPrototype = {
|
||||
}
|
||||
|
||||
// clear empty ribbons...
|
||||
Object.keys(crop.ribbons)
|
||||
.forEach(function(k){
|
||||
if(crop.ribbons[k].length == 0){
|
||||
crop.ribbon_order.splice(crop.ribbon_order.indexOf(k), 1)
|
||||
delete crop.ribbons[k]
|
||||
}
|
||||
})
|
||||
crop.clear('empty')
|
||||
|
||||
// set the current image in the crop...
|
||||
var r = this.getRibbon()
|
||||
@ -1647,7 +1905,7 @@ var DataPrototype = {
|
||||
this.order = crop.order.slice()
|
||||
// XXX sync these???
|
||||
this.ribbon_order = crop.ribbon_order.slice()
|
||||
this.sortImages()
|
||||
this.updateImagePositions()
|
||||
|
||||
//
|
||||
for(var k in crop.ribbons){
|
||||
@ -1784,7 +2042,7 @@ var DataPrototype = {
|
||||
// NOTE: this is slow-ish...
|
||||
removeDuplicateGIDs: function(){
|
||||
this.removeDuplicates(this.order)
|
||||
this.sortImages()
|
||||
this.updateImagePositions()
|
||||
return this
|
||||
},
|
||||
|
||||
@ -1841,6 +2099,11 @@ var DataPrototype = {
|
||||
|
||||
var DataWithTagsPrototype = {
|
||||
|
||||
// XXX hate manual super calls...
|
||||
// ....is there a way not to say DataPrototype here???
|
||||
__gid_lists: DataPrototype.__gid_lists.concat(['tags']),
|
||||
|
||||
|
||||
// XXX need a unified init/dump/load scheme...
|
||||
loadJSON: function(json){
|
||||
json = typeof(json) == typeof('str') ? JSON.parse(json) : json
|
||||
@ -1898,6 +2161,17 @@ var DataWithTagsPrototype = {
|
||||
|
||||
return clone
|
||||
},
|
||||
group: function(){
|
||||
var res = DataWithTagsPrototype.__proto__.group.apply(this, arguments)
|
||||
this.sortTags()
|
||||
return res
|
||||
},
|
||||
ungroup: function(){
|
||||
var res = DataWithTagsPrototype.__proto__.ungroup.apply(this, arguments)
|
||||
this.sortTags()
|
||||
return res
|
||||
},
|
||||
|
||||
|
||||
sortTags: function(){
|
||||
var that = this
|
||||
|
||||
@ -28,16 +28,12 @@ if(typeof(sha1) != 'undefined'){
|
||||
/*********************************************************************/
|
||||
|
||||
// A stub image, also here for documentation...
|
||||
var STUB_IMAGE_DATA =
|
||||
module.STUB_IMAGE_DATA = {
|
||||
var IMAGE_DATA =
|
||||
module.IMAGE_DATA = {
|
||||
// Entity GID...
|
||||
id: 'STUB-GID',
|
||||
id: 'GID',
|
||||
|
||||
// Entity type
|
||||
//
|
||||
// can be:
|
||||
// - 'image'
|
||||
// - 'group'
|
||||
type: 'image',
|
||||
|
||||
// Entity state
|
||||
@ -66,7 +62,7 @@ module.STUB_IMAGE_DATA = {
|
||||
|
||||
// Classes
|
||||
// XXX currently unused...
|
||||
classes: '',
|
||||
//classes: '',
|
||||
|
||||
// Image orientation (optional)
|
||||
//
|
||||
@ -79,7 +75,7 @@ module.STUB_IMAGE_DATA = {
|
||||
//
|
||||
// NOTE: use orientationExif2ImageGrid(..) to convert from EXIF
|
||||
// orientation format to ImageGrid format...
|
||||
orientation: 0,
|
||||
//orientation: 0,
|
||||
|
||||
// Image flip state (optional)
|
||||
//
|
||||
@ -93,24 +89,68 @@ module.STUB_IMAGE_DATA = {
|
||||
//
|
||||
// NOTE: use orientationExif2ImageGrid(..) to convert from EXIF
|
||||
// orientation format to ImageGrid format...
|
||||
flipped: null,
|
||||
//flipped: null,
|
||||
|
||||
// Image comment (optional)
|
||||
//
|
||||
// can be:
|
||||
// - null/undefined
|
||||
// - string
|
||||
comment: null,
|
||||
//comment: null,
|
||||
|
||||
// List of image tags (optional)
|
||||
//
|
||||
// can be:
|
||||
// - null/undefined
|
||||
// - array
|
||||
tags: null,
|
||||
//tags: null,
|
||||
}
|
||||
|
||||
|
||||
var GROUP_DATA =
|
||||
module.GROUP_DATA = {
|
||||
// Entity GID...
|
||||
id: 'GID',
|
||||
|
||||
// Entity type
|
||||
type: 'group',
|
||||
|
||||
// Entity state
|
||||
//
|
||||
// can be:
|
||||
// - 'single'
|
||||
// - 'grouped'
|
||||
// - 'hidden'
|
||||
// - ...
|
||||
state: 'single',
|
||||
|
||||
// image used to represent/display group...
|
||||
cover: 'GID',
|
||||
|
||||
// list of group contents, including .cover
|
||||
items: [
|
||||
'GID',
|
||||
],
|
||||
|
||||
// Classes
|
||||
// XXX currently unused...
|
||||
//classes: '',
|
||||
|
||||
// Image comment (optional)
|
||||
//
|
||||
// can be:
|
||||
// - null/undefined
|
||||
// - string
|
||||
//comment: null,
|
||||
|
||||
// List of image tags (optional)
|
||||
//
|
||||
// can be:
|
||||
// - null/undefined
|
||||
// - array
|
||||
//tags: null,
|
||||
}
|
||||
|
||||
// Calculate relative rotation angle...
|
||||
//
|
||||
// Calculate rotation angle relative to from:
|
||||
@ -371,7 +411,7 @@ module.ImagesPrototype = {
|
||||
if((img_data.preview == null
|
||||
|| Object.keys(img_data.preview).length == 0)
|
||||
&& img_data.path == null){
|
||||
img_data = STUB_IMAGE_DATA
|
||||
img_data = IMAGE_DATA
|
||||
}
|
||||
|
||||
var s
|
||||
|
||||
@ -986,7 +986,22 @@ var RibbonsPrototype = {
|
||||
// get the image data...
|
||||
var img_data = that.images[gid]
|
||||
if(img_data == null){
|
||||
img_data = images.STUB_IMAGE_DATA
|
||||
img_data = images.IMAGE_DATA
|
||||
}
|
||||
|
||||
// if we are a group, get the cover...
|
||||
// NOTE: groups can be nested...
|
||||
var seen = []
|
||||
while(img_data.type == 'group'){
|
||||
// error, recursive group...
|
||||
if(seen.indexOf(img_data.id) >= 0){
|
||||
img_data = images.IMAGE_DATA
|
||||
console.error('Recursice group:', gid)
|
||||
break
|
||||
}
|
||||
seen.push(img_data.id)
|
||||
|
||||
img_data = that.images[img_data.cover]
|
||||
}
|
||||
|
||||
/* XXX does not seem to be needing this...
|
||||
@ -1016,7 +1031,7 @@ var RibbonsPrototype = {
|
||||
that.flipImage(image, img_data.flipped == null ? [] : img_data.flipped)
|
||||
|
||||
// preview...
|
||||
var p_url = that.images.getBestPreview(gid, size, img_data).url
|
||||
var p_url = that.images.getBestPreview(img_data.id, size, img_data).url
|
||||
|
||||
// update the preview if it's a new image or...
|
||||
// XXX this should be pushed as far back as possible...
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user