diff --git a/ui (gen4)/data.js b/ui (gen4)/data.js index 8ce29d72..4f221c53 100755 --- a/ui (gen4)/data.js +++ b/ui (gen4)/data.js @@ -1036,6 +1036,139 @@ module.DataPrototype = { this.ribbon_order.reverse() }, + // Gather gids into an connected section... + // + // The section is positioned relative to a reference gid, which also + // determines the ribbon. + // + // Gather images relative to current image + // .gatherImages(images) + // .gatherImages(images, 'current') + // -> data + // + // Gather images relative to image/ribbon + // .gatherImages(images, image|ribbon) + // -> data + // + // Gather images relative to first/last image in given images + // .gatherImages(images, 'first') + // .gatherImages(images, 'last') + // -> data + // + // Gather images relative to image/ribbon and place them strictly + // after (default) or before it... + // .gatherImages(images, 'auto') + // .gatherImages(images, 'after') + // .gatherImages(images, 'before') + // .gatherImages(images, image|ribbon, 'auto') + // .gatherImages(images, image|ribbon, 'after') + // .gatherImages(images, image|ribbon, 'before') + // -> data + // + // Gather images only in one explicit dimension... + // .gatherImages(.., 'horizontal') + // .gatherImages(.., 'vertical') + // -> data + // + // NOTE: if mode is 'vertical' then place is ignored... + // + // XXX needs testing... + gatherImages: function(gids, reference, place, mode){ + gids = this.makeSparseImages(gids) + + var that = this + + var modes = /vertical|horizontal|both/ + var placements = /before|after|auto/ + + // parse arguments... + var _mode = mode + mode = modes.test(reference) ? reference + : modes.test(place) ? place + : mode + mode = mode || 'both' + + place = placements.test(reference) ? reference + : placements.test(_mode) ? _mode + : place + place = place == 'auto' ? null : place + + reference = modes.test(reference) || placements.test(reference) ? null : reference + reference = reference == 'first' ? gids[0] + : reference == 'last' ? gids.slice(-1)[0] + : reference + + //console.log('reference:', reference, '\nplace:', place, '\nmode:', mode) + + // shift all gids to a reference ribbon... + if(mode == 'both' || mode == 'vertical'){ + var ref = this.getRibbon(reference) + + var ribbons = this.ribbons + gids.forEach(function(gid, i){ + var r = that.getRibbon(gid) + + // do the move... + if(r != ref){ + ribbons[ref][i] = gid + delete ribbons[r][i] + } + }) + } + + // shift all gids to a reference image... + if(mode == 'both' || mode == 'horizontal'){ + var order = this.order + var ref = this.getImage(reference) + + place = gids.indexOf(ref) < 0 && place == null ? 'after' : place + + // NOTE: the reference index will not move as nothing will + // ever change it's position relative to it... + var ri = this.order.indexOf(ref) + var l = ri + + gids.forEach(function(gid){ + if(gid == ref){ + return + } + + // we need to get this live as we are moving images around... + var f = this.order.indexOf(gid) + + // target is left of the reference -- place at reference... + // NOTE: we are moving left to right, thus the final order + // of images will stay the same. + if(f < ri){ + if(place == 'after'){ + order.splice(l, 0, order.splice(f, 1)[0]) + + } else { + order.splice(ri-1, 0, order.splice(f, 1)[0]) + } + + // target is right of the reference -- place each new image + // at an offset from reference, the offset is equal to + // the number of the target image the right of the reference + } else { + if(place == 'before'){ + order.splice(l, 0, order.splice(f, 1)[0]) + l += 1 + + } else { + l += 1 + order.splice(l, 0, order.splice(f, 1)[0]) + } + } + }) + + // XXX this is cheating... + this.sortImages() + } + + return this + }, + // Shift image... // // Shift image to target position: @@ -1064,123 +1197,38 @@ module.DataPrototype = { // NOTE: .getImage(..) defaults to 'before' thus this to defaults // to 'after' // - // XXX check for corner cases: - // - first/last in ribbon offset - // - first/last in order offset - // - first/last ribbon up/down - // do we create new ribbons and round??? - // XXX when shifting groups of images we are using the first as a - // base, should we use last as a base for right shifting??? - // ...another way to go could be using current as a reference - // XXX test vertical.. - // XXX should this be called .placeImage(..)??? - shiftImage: function(from, target, mode){ - from = from == null ? this.current : from - from = from == 'current' ? this.current : from + shiftImage: function(from, target, mode, direction){ + from = from == null || from == 'current' ? this.current : from from = from.constructor !== Array ? [from] : from - mode = mode == null ? 'after' : mode - var ribbons = this.ribbons - var order = this.order - first = this.getImage(from[0]) - var f = order.indexOf(first) + var place // target is an offset... if(mode == 'offset'){ - var t = this.getImage(first, target) - - // if we hit start/end of ribbon get index if first/last image resp. - // XXX for multiple images what should we do if we hit ribbon start/end??? - t = t == null && target > 0 ? this.getImage('last', this.getRibbon(first)) - : t == null && target < 0 ? this.getImage('first', this.getRibbon(first)) - : t - var t = this.getImageOrder(t) - - - var ribbon = this.getRibbon(first) - - // target is ribbon order... - // XXX range checking??? - } else if(typeof(target) == typeof(123)){ - var t = f - - // normalize the target... - // XXX is this the correct way to go??? - target = Math.max(0, Math.min(this.ribbon_order.length-1, target)) - - var ribbon = this.ribbon_order[target] - - // target is a ribbon gid... - } else if(target in this.ribbons){ - var t = f - - var ribbon = target - - // target is a gid or order... - } else { - target = this.getImage(target) - var t = order.indexOf(target) - t = mode == 'after' ? t+1 : t - - var ribbon = this.getRibbon(target) - } - - var from_ribbon = this.getRibbon(first) - - // do vertical shift... - // NOTE: image order here is not changed... - if(ribbon != from_ribbon || from.length > 1){ - var that = this - from.forEach(function(e){ - var i = order.indexOf(e) - var from_ribbon = that.getRibbon(e) - - that.ribbons[ribbon][i] = e - delete that.ribbons[from_ribbon][i] - }) - } - - // do horizontal shift... - // NOTE: images are packed horizontally together... - if(f != t){ - for(var i=0; i t+i){ - r.splice(t+i, 0, e) - - // remove the null/undefined if it was just inserted... - // NOTE: this needs to be done as splice inserts the 3'rd - // argument explicitly regardless of it's value, - // this if not done we'll end up with undefined - // inserted into a sparse ribbon which will be - // considered as an element... - if(e == null){ - delete r[t+i] - } - - } else if(e != null){ - r[t+i] = e - } - } + if(target > 0){ + var t = this.getImage(from.slice(-1)[0], target) + || this.getImage('last', from.slice(-1)[0]) + place = from.indexOf(t) >= 0 ? null : 'after' + } else { + var t = this.getImage(from[0], target) + || this.getImage('first', from[0]) + place = from.indexOf(t) >= 0 ? null : 'before' } + + // target is ribbon index... + } else if(typeof(target) == typeof(123)){ + var t = this.getImage(this.getRibbon(target)) + // in case of an empty ribbon... + || this.getRibbon(target) + place = mode || 'after' + + // target is an image... + } else { + var t = this.getImage(target) + place = mode || 'after' } - return this + return this.gatherImages(from, t, place, direction) }, // Shorthand actions... @@ -1191,17 +1239,18 @@ module.DataPrototype = { // shifting the last image out... // NOTE: none of these change .current // - shiftImageLeft: function(gid){ return this.shiftImage(gid, -1, 'offset') }, // Gen2 - shiftImageRight: function(gid){ return this.shiftImage(gid, 1, 'offset') }, // Gen2 + shiftImageLeft: function(gid){ return this.shiftImage(gid, -1, 'offset') }, + shiftImageRight: function(gid){ return this.shiftImage(gid, 1, 'offset') }, // XXX these can remove ribbons, do we need to shift base ribbon??? shiftImageUp: function(gid){ var g = gid.constructor === Array ? gid[0] : gid var r = this.getRibbonOrder(g) // check if we need to create a ribbon here... if(r == 0){ + r += 1 this.newRibbon(g) } - var res = this.shiftImage(gid, r-1) + var res = this.shiftImage(gid, r-1, 'vertical') // clear empty ribbon... r = r == 0 ? 1 : r if(this.ribbons[this.ribbon_order[r]].len() == 0){ @@ -1217,7 +1266,7 @@ module.DataPrototype = { if(r == this.ribbon_order.length-1){ this.newRibbon(g, 'below') } - var res = this.shiftImage(gid, r+1) + var res = this.shiftImage(gid, r+1, 'vertical') // clear empty ribbon... if(this.ribbons[this.ribbon_order[r]].len() == 0){ r = this.ribbon_order.splice(r, 1)[0] @@ -1267,8 +1316,8 @@ module.DataPrototype = { // Shorthand actions... // // XXX should these be here?? - shiftRibbonUp: function(gid){ return this.shiftRibbon(gid, -1, 'offset') }, // Gen2 - shiftRibbonDown: function(gid){ return this.shiftRibbon(gid, 1, 'offset') }, // Gen2 + shiftRibbonUp: function(gid){ return this.shiftRibbon(gid, -1, 'offset') }, + shiftRibbonDown: function(gid){ return this.shiftRibbon(gid, 1, 'offset') }, diff --git a/ui (gen4)/ribbons.js b/ui (gen4)/ribbons.js index d4be82d5..ad40ed4f 100755 --- a/ui (gen4)/ribbons.js +++ b/ui (gen4)/ribbons.js @@ -76,22 +76,28 @@ module.RibbonsClassPrototype = { .addClass('ribbon-set')) }, // XXX NOTE: quots removal might render this incompatible with older data formats... - createRibbon: function(gid){ - gid = gid != null ? gid+'' : gid - return $('
') - .addClass('ribbon') - .attr('gid', JSON.stringify(gid) - // this removes the extra quots... - .replace(/^"(.*)"$/g, '$1')) + createRibbon: function(gids){ + gids = gids.constructor !== Array ? [gids] : gids + return $(gids.map(function(gid){ + gid = gid != null ? gid+'' : gid + return $('
') + .addClass('ribbon') + .attr('gid', JSON.stringify(gid) + // this removes the extra quots... + .replace(/^"(.*)"$/g, '$1'))[0] + })) }, // XXX NOTE: quots removal might render this incompatible with older data formats... - createImage: function(gid){ - gid = gid != null ? gid+'' : gid - return $('
') - .addClass('image') - .attr('gid', JSON.stringify(gid) - // this removes the extra quots... - .replace(/^"(.*)"$/g, '$1')) + createImage: function(gids){ + gids = gids.constructor !== Array ? [gids] : gids + return $(gids.map(function(gid){ + gid = gid != null ? gid+'' : gid + return $('
') + .addClass('image') + .attr('gid', JSON.stringify(gid) + // this removes the extra quots... + .replace(/^"(.*)"$/g, '$1'))[0] + })) }, createMark: function(cls, gid){ gid = gid != null ? gid+'' : gid @@ -725,10 +731,23 @@ module.RibbonsPrototype = { // // NOTE: mode defaults to 'before'. // NOTE: if image gid does not exist it will be created. + // NOTE: if target is a list of gids, this will place the gids in + // the same order as given, not as they were before placing... + // + // XXX is this too complicated??? placeImage: function(target, to, mode){ mode = mode == null ? 'before' : mode - var img = this.getImage(target) - img = img.length == 0 ? this.createImage(target) : img + + target = target == null || target.constructor !== Array ? [target] : target + + // get or make images... + var that = this + var img = $($(target) + .map(function(_, e){ + var i = that.getImage(e) + return (i.length == 0 ? that.createImage(e) : i)[0] + })) + var i = this.getImage(to) var r = this.getRibbon(to) @@ -739,13 +758,11 @@ module.RibbonsPrototype = { return img } var i = to - var images = img[i > 0 ? 'nextAll' : 'prevAll']('.image') + var images = img[i > 0 ? 'last' : 'first']() + [i > 0 ? 'nextAll' : 'prevAll']('.image') to = images.length > 0 ? images.eq(Math.min(Math.abs(i), images.length)-1) : img - if(to === img){ - return to - } // append/prepend to ribbon... } else if(i.length == 0 && r.length > 0 && r.hasClass('ribbon')){ @@ -1113,7 +1130,7 @@ module.RibbonsPrototype = { // NOTE: this will never remove the ribbons included in any of the // data.base, data.ribbon_order or data.ribbons... updateData: function(data, settings){ - var settings = settings == null ? {} : settings + settings = settings == null ? {} : settings // load the data... var that = this @@ -1322,6 +1339,8 @@ module.RibbonsPrototype = { return image }, + // Get image rotation... + // getImageRotation: function(target){ return (this.getImage(target).attr('orientation') || 0)*1 }, @@ -1373,6 +1392,8 @@ module.RibbonsPrototype = { return this }, + // Get image flip... + // getImageFlip: function(target){ return (this.getImage(target).attr('flipped') || '') .split(',') diff --git a/ui (gen4)/viewer.js b/ui (gen4)/viewer.js index 76a72e84..5f4a55c6 100755 --- a/ui (gen4)/viewer.js +++ b/ui (gen4)/viewer.js @@ -32,13 +32,14 @@ function reloadAfter(transitions){ } // XXX make this compatible with multiple images... +// XXX for muptiple targets this will just do a .reload()... var updateImagePosition = module.updateImagePosition = function updateImagePosition(actions, target){ + target = target || actions.current target = target instanceof jQuery ? actions.ribbons.getElemGID(target) : target - target = target || actions.current var source_ribbon = actions.ribbons.getElemGID(actions.ribbons.getRibbon(target)) var source_order = actions.data.getImageOrder(target) @@ -46,6 +47,12 @@ function updateImagePosition(actions, target){ return function(){ actions.ribbons.preventTransitions() + // XXX hack... + if(target.constructor === Array){ + actions.reload() + return + } + var target_ribbon = actions.data.getRibbon(target) // nothing changed... @@ -534,8 +541,6 @@ actions.Actions(Client, { // XXX make this better support partial data view... // ...at this point this first loads the full data and then // .focusImage(..) triggers a reload... - // .....another approach would be to avoid .reload() where - // possible... reload: ['Reload viewer', function(){ this.ribbons.preventTransitions() @@ -808,13 +813,15 @@ actions.Actions(Client, { shiftImageDown: [ function(target){ return updateImagePosition(this, target) }], + // XXX these produce jumpy animation when gathering images from the + // left from outside of the loaded partial ribbon... shiftImageLeft: [ - function(target){ - this.ribbons.placeImage(target, -1) + function(target){ + this.ribbons.placeImage(target, -1) }], shiftImageRight: [ function(target){ - this.ribbons.placeImage(target, 1) + this.ribbons.placeImage(target, 1) }], shiftRibbonUp: [ @@ -1069,21 +1076,30 @@ module.AlignRibbonsToFirstImage = Feature({ //--------------------------------------------------------------------- +// XXX at this point this does not support target lists... var ShiftAnimation = module.ShiftAnimation = Feature({ tag: 'ui-animation', setup: function(actions){ var animate = function(target){ - var s = this.ribbons.makeShadow(target, true) - return function(){ s() } + // XXX do not do target lists... + if(target != null && target.constructor === Array){ + return } + var s = this.ribbons.makeShadow(target, true) + return function(){ s() } + } // NOTE: this will keep the shadow in place -- the shadow will not // go to the mountain, the mountain will come to the shadow ;) var noanimate = function(target){ - var s = this.ribbons.makeShadow(target) - return function(){ s() } + // XXX do not do target lists... + if(target != null && target.constructor === Array){ + return } + var s = this.ribbons.makeShadow(target) + return function(){ s() } + } var tag = this.tag return actions .on('shiftImageUp.pre', tag, animate)