2014-07-20 02:25:36 +04:00
|
|
|
/**********************************************************************
|
|
|
|
|
*
|
|
|
|
|
* Minomal UI API...
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
// XXX this is a stub, here untill image.js is done...
|
|
|
|
|
_UPDATE_IMAGE = false
|
|
|
|
|
|
2014-07-21 16:38:06 +04:00
|
|
|
define(function(require){ var module = {}
|
2014-07-21 18:33:31 +04:00
|
|
|
console.log('>>> ribbons')
|
2014-07-21 16:38:06 +04:00
|
|
|
|
2014-07-20 02:25:36 +04:00
|
|
|
//var DEBUG = DEBUG != null ? DEBUG : true
|
|
|
|
|
|
2014-07-22 17:09:25 +04:00
|
|
|
var data = require('data')
|
|
|
|
|
var image = require('image')
|
|
|
|
|
|
2014-07-20 02:25:36 +04:00
|
|
|
|
2014-07-21 18:33:31 +04:00
|
|
|
|
2014-07-21 02:30:24 +04:00
|
|
|
/*********************************************************************/
|
|
|
|
|
//
|
|
|
|
|
// This xpects the folowing HTML structure...
|
|
|
|
|
//
|
|
|
|
|
// Unpopulated:
|
2014-07-21 18:33:31 +04:00
|
|
|
// NOTE: there can be only one .ribbon-set element.
|
2014-07-21 02:30:24 +04:00
|
|
|
//
|
|
|
|
|
// <div class="viewer">
|
|
|
|
|
// <div class="ribbon-set"></div>
|
|
|
|
|
// </div>
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// Populated:
|
|
|
|
|
//
|
|
|
|
|
// <div class="viewer">
|
|
|
|
|
// <div class="ribbon-set">
|
|
|
|
|
// <div class="ribbon">
|
|
|
|
|
// <div class="image"></div>
|
|
|
|
|
// <div class="image"></div>
|
|
|
|
|
// ...
|
|
|
|
|
// </div>
|
|
|
|
|
// <div class="ribbon">
|
|
|
|
|
// <div class="image"></div>
|
|
|
|
|
// <div class="current image"></div>
|
|
|
|
|
// <div class="image"></div>
|
|
|
|
|
// <div class="mark selected"></div>
|
|
|
|
|
// <div class="image"></div>
|
|
|
|
|
// ...
|
|
|
|
|
// </div>
|
|
|
|
|
// ...
|
|
|
|
|
// </div>
|
|
|
|
|
// </div>
|
|
|
|
|
//
|
|
|
|
|
//
|
2014-07-20 02:25:36 +04:00
|
|
|
/*********************************************************************/
|
|
|
|
|
|
2014-07-21 18:33:31 +04:00
|
|
|
var RibbonsClassPrototype =
|
2014-07-21 16:38:06 +04:00
|
|
|
module.RibbonsClassPrototype = {
|
2014-07-24 16:05:59 +04:00
|
|
|
// Generic getters...
|
2014-07-22 20:27:11 +04:00
|
|
|
getElemGID: function(elem){
|
|
|
|
|
return JSON.parse('"' + elem.attr('gid') + '"')
|
|
|
|
|
},
|
|
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
// Constructors...
|
2014-07-21 02:30:24 +04:00
|
|
|
// NOTE: these will return unattached objects...
|
|
|
|
|
createViewer: function(){
|
|
|
|
|
return $('<div>')
|
|
|
|
|
.addClass('viewer')
|
|
|
|
|
.append($('<div>')
|
|
|
|
|
.addClass('ribbon-set'))
|
|
|
|
|
},
|
2014-07-22 17:09:25 +04:00
|
|
|
// XXX NOTE: quots removal might render this incompatible with older data formats...
|
2014-07-21 02:30:24 +04:00
|
|
|
createRibbon: function(gid){
|
2014-07-22 19:57:57 +04:00
|
|
|
gid = gid != null ? gid+'' : gid
|
2014-07-21 02:30:24 +04:00
|
|
|
return $('<div>')
|
|
|
|
|
.addClass('ribbon')
|
2014-07-22 17:09:25 +04:00
|
|
|
.attr('gid', JSON.stringify(gid)
|
|
|
|
|
// this removes the extra quots...
|
2014-07-22 19:57:57 +04:00
|
|
|
.replace(/^"(.*)"$/g, '$1'))
|
2014-07-21 02:30:24 +04:00
|
|
|
},
|
2014-07-22 17:09:25 +04:00
|
|
|
// XXX NOTE: quots removal might render this incompatible with older data formats...
|
2014-07-21 02:30:24 +04:00
|
|
|
createImage: function(gid){
|
2014-07-22 19:57:57 +04:00
|
|
|
gid = gid != null ? gid+'' : gid
|
2014-07-21 02:30:24 +04:00
|
|
|
return $('<div>')
|
|
|
|
|
.addClass('image')
|
2014-07-22 17:09:25 +04:00
|
|
|
.attr('gid', JSON.stringify(gid)
|
|
|
|
|
// this removes the extra quots...
|
2014-07-22 19:57:57 +04:00
|
|
|
.replace(/^"(.*)"$/g, '$1'))
|
2014-07-21 02:30:24 +04:00
|
|
|
},
|
2014-07-20 02:25:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
// NOTE: this is a low level interface, not a set of actions...
|
2014-07-21 18:33:31 +04:00
|
|
|
var RibbonsPrototype =
|
2014-07-21 16:38:06 +04:00
|
|
|
module.RibbonsPrototype = {
|
2014-07-20 02:25:36 +04:00
|
|
|
//
|
|
|
|
|
// .viewer (jQuery object)
|
|
|
|
|
//
|
2014-07-21 02:30:24 +04:00
|
|
|
|
|
|
|
|
// Constructors...
|
2014-07-21 18:33:31 +04:00
|
|
|
createViewer: RibbonsClassPrototype.createViewer,
|
|
|
|
|
createRibbon: RibbonsClassPrototype.createRibbon,
|
|
|
|
|
createImage: RibbonsClassPrototype.createImage,
|
2014-07-20 02:25:36 +04:00
|
|
|
|
2014-07-22 20:27:11 +04:00
|
|
|
// Generic getters...
|
|
|
|
|
getElemGID: RibbonsClassPrototype.getElemGID,
|
2014-07-22 19:57:57 +04:00
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
|
2014-07-22 20:27:11 +04:00
|
|
|
// Contextual getters...
|
2014-07-24 16:05:59 +04:00
|
|
|
|
|
|
|
|
// Get ribbon...
|
|
|
|
|
//
|
|
|
|
|
// Get current ribbon:
|
|
|
|
|
// .getRibbon()
|
|
|
|
|
// -> ribbon
|
|
|
|
|
//
|
|
|
|
|
// Get ribbon by index/gid:
|
|
|
|
|
// .getRibbon(index)
|
|
|
|
|
// .getRibbon(gid)
|
|
|
|
|
// -> ribbon
|
|
|
|
|
//
|
|
|
|
|
// Get ribbons from list:
|
|
|
|
|
// .getRibbon($(..))
|
|
|
|
|
// .getRibbon([..])
|
|
|
|
|
// -> ribbon(s)
|
|
|
|
|
// NOTE: this will filter the list but not search the tree...
|
|
|
|
|
//
|
2014-07-20 02:25:36 +04:00
|
|
|
getRibbon: function(target){
|
2014-07-24 16:05:59 +04:00
|
|
|
// current...
|
2014-07-20 02:25:36 +04:00
|
|
|
if(target == null) {
|
|
|
|
|
return this.viewer.find('.current.image').parents('.ribbon').first()
|
|
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
// index...
|
|
|
|
|
} else if(typeof(target) == typeof(123)){
|
|
|
|
|
return this.viewer.find('.ribbon').eq(target)
|
|
|
|
|
|
|
|
|
|
// gid...
|
2014-07-20 02:25:36 +04:00
|
|
|
} else if(typeof(target) == typeof('str')){
|
2014-07-22 17:09:25 +04:00
|
|
|
//return this.viewer.find('.ribbon[gid="'+JSON.stringify(target)+'"]')
|
2014-07-20 02:25:36 +04:00
|
|
|
return this.viewer.find('.ribbon[gid='+JSON.stringify(target)+']')
|
|
|
|
|
}
|
|
|
|
|
return $(target).filter('.ribbon')
|
|
|
|
|
},
|
2014-07-24 16:36:25 +04:00
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
// Like .getRibbon(..) but returns ribbon index instead of the actual
|
|
|
|
|
// ribbon object...
|
|
|
|
|
getRibbonIndex: function(target){
|
|
|
|
|
return this.viewer.find('.ribbon').index(this.getRibbon(target))
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Get ribbon...
|
|
|
|
|
//
|
|
|
|
|
// Get current image:
|
|
|
|
|
// .getImage()
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
|
|
|
|
// Get image by gid:
|
|
|
|
|
// .getImage(gid)
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
|
|
|
|
// Get images from list:
|
|
|
|
|
// .getImage($(..))
|
|
|
|
|
// .getImage([..])
|
|
|
|
|
// -> image(s)
|
|
|
|
|
// NOTE: this will filter the list but not search the tree...
|
|
|
|
|
//
|
2014-07-20 02:25:36 +04:00
|
|
|
getImage: function(target){
|
2014-07-24 16:05:59 +04:00
|
|
|
// current...
|
2014-07-20 02:25:36 +04:00
|
|
|
if(target == null) {
|
|
|
|
|
return this.viewer.find('.current.image')
|
|
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
// gid...
|
2014-07-20 02:25:36 +04:00
|
|
|
} else if(typeof(target) == typeof('str')){
|
2014-07-22 17:09:25 +04:00
|
|
|
//return this.viewer.find('.image[gid="'+JSON.stringify(target)+'"]')
|
2014-07-20 02:25:36 +04:00
|
|
|
return this.viewer.find('.image[gid='+JSON.stringify(target)+']')
|
|
|
|
|
}
|
|
|
|
|
return $(target).filter('.image')
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
// Basic manipulation...
|
|
|
|
|
|
2014-07-20 02:25:36 +04:00
|
|
|
// Place a ribbon...
|
|
|
|
|
//
|
2014-07-24 16:05:59 +04:00
|
|
|
// Append target ribbon:
|
|
|
|
|
// .placeRibbon(target)
|
|
|
|
|
// -> ribbon
|
|
|
|
|
//
|
|
|
|
|
// Place target ribbon at position:
|
|
|
|
|
// .placeRibbon(target, index)
|
|
|
|
|
// .placeRibbon(target, ribbon-gid)
|
|
|
|
|
// .placeRibbon(target, ribbon)
|
|
|
|
|
// -> ribbon
|
|
|
|
|
//
|
|
|
|
|
// The ribbon will be placed at the new position shifting the next
|
|
|
|
|
// ribbon(s), if present, by one.
|
|
|
|
|
//
|
|
|
|
|
// Indexes if used, can be negative. Negative indexes are relative
|
|
|
|
|
// to the end, e.g. -1 is the same as length-1.
|
|
|
|
|
// Placing an element at a negative index will place it AFTER the
|
|
|
|
|
// target element, this is in contrast to positive indexes where an
|
|
|
|
|
// element is placed before the target. In both of the above cases
|
|
|
|
|
// (positive and negative indexes) the resulting target position
|
|
|
|
|
// will AT the passed position.
|
|
|
|
|
//
|
|
|
|
|
// NOTE: negative and positive indexes overflow to 0 and length
|
|
|
|
|
// respectively.
|
|
|
|
|
// NOTE: both target and position must be .getRibbon(..) compatible.
|
|
|
|
|
// NOTE: if target ribbon does not exist a new ribbon will be created.
|
|
|
|
|
// NOTE: if position ribbon (gid,ribbon) does not exist or is not
|
|
|
|
|
// attached then the target will be appended to the end.
|
|
|
|
|
// NOTE: this uses the DOM data for placement, this may differ from
|
|
|
|
|
// the actual data.
|
2014-07-20 02:25:36 +04:00
|
|
|
//
|
|
|
|
|
// XXX interaction animation...
|
2014-07-24 16:05:59 +04:00
|
|
|
placeRibbon: function(target, position){
|
2014-07-20 02:25:36 +04:00
|
|
|
// get create the ribbon...
|
2014-07-24 16:05:59 +04:00
|
|
|
var ribbon = this.getRibbon(target)
|
|
|
|
|
var i = this.getRibbonIndex(ribbon)
|
|
|
|
|
ribbon = ribbon.length == 0 ? this.createRibbon(target) : ribbon
|
2014-07-20 02:25:36 +04:00
|
|
|
|
|
|
|
|
var ribbons = this.viewer.find('.ribbon')
|
|
|
|
|
// normalize the position...
|
2014-07-24 16:05:59 +04:00
|
|
|
if(typeof(position) == typeof(123)){
|
|
|
|
|
position = position < 0 ? ribbons.length + position + 1 : position
|
|
|
|
|
position = position < 0 ? 0 : position
|
|
|
|
|
} else {
|
|
|
|
|
var p = this.getRibbonIndex(position)
|
|
|
|
|
// XXX what do we do if the target does not exist, i.e. p == -1 ????
|
|
|
|
|
}
|
2014-07-20 02:25:36 +04:00
|
|
|
|
|
|
|
|
// place the ribbon...
|
2014-07-22 19:57:57 +04:00
|
|
|
if(ribbons.length == 0 || ribbons.length <= position){
|
2014-07-22 17:09:25 +04:00
|
|
|
this.viewer.find('.ribbon-set').append(ribbon)
|
2014-07-21 02:30:24 +04:00
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
} else if(i != position) {
|
2014-07-20 02:25:36 +04:00
|
|
|
ribbons.eq(position).before(ribbon)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// XXX do we need to update the ribbon here???
|
|
|
|
|
return ribbon
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Place an image...
|
|
|
|
|
//
|
|
|
|
|
// Place gid at image position and image ribbon:
|
|
|
|
|
// .placeImage(gid, image)
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
|
|
|
|
// Place gid at index in current ribbon:
|
|
|
|
|
// .placeImage(gid, position)
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
|
|
|
|
// Place gid at position in ribbon:
|
|
|
|
|
// .placeImage(gid, ribbon, position)
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// NOTE: if image gid does not exist it will be created.
|
|
|
|
|
// NOTE: index can be negative indicating the position from the tail.
|
|
|
|
|
// NOTE: if index is an image or a gid then the ribbon argument will
|
|
|
|
|
// be ignored and the actual ribbon will be derived from the
|
|
|
|
|
// image given.
|
|
|
|
|
// XXX interaction animation...
|
2014-07-24 16:05:59 +04:00
|
|
|
placeImage: function(target, ribbon, position){
|
2014-07-20 02:25:36 +04:00
|
|
|
// get/create the image...
|
2014-07-24 16:05:59 +04:00
|
|
|
var img = this.getImage(target)
|
|
|
|
|
img = img.length == 0 ? this.createImage(target) : img
|
2014-07-20 02:25:36 +04:00
|
|
|
|
|
|
|
|
// normalize the position, ribbon and images...
|
|
|
|
|
if(position == null){
|
|
|
|
|
position = ribbon
|
|
|
|
|
ribbon = null
|
|
|
|
|
}
|
|
|
|
|
var p = this.getImage(position)
|
|
|
|
|
ribbon = p.hasClass('image')
|
|
|
|
|
? p.parents('.ribbon').first()
|
|
|
|
|
: this.getRibbon(ribbon)
|
|
|
|
|
var images = ribbon.find('.image')
|
|
|
|
|
position = p.hasClass('image') ? images.index(p) : position
|
2014-07-22 19:57:57 +04:00
|
|
|
position = position < 0 ? images.length + position + 1 : position
|
2014-07-20 02:25:36 +04:00
|
|
|
position = position < 0 ? 0 : position
|
|
|
|
|
|
|
|
|
|
// place the image...
|
2014-07-21 02:30:24 +04:00
|
|
|
if(images.length == 0 || images.length <= position){
|
2014-07-22 19:57:57 +04:00
|
|
|
ribbon.append(img)
|
2014-07-21 02:30:24 +04:00
|
|
|
|
2014-07-20 02:25:36 +04:00
|
|
|
} else {
|
2014-07-22 19:57:57 +04:00
|
|
|
images.eq(position).before(img)
|
2014-07-20 02:25:36 +04:00
|
|
|
}
|
|
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
return _UPDATE_IMAGE ? image.updateImage(img) : img
|
2014-07-20 02:25:36 +04:00
|
|
|
},
|
|
|
|
|
|
2014-07-20 03:00:24 +04:00
|
|
|
// XXX do we need shorthands like shiftImageUp/shiftImageDown/... here?
|
|
|
|
|
|
2014-07-22 19:57:57 +04:00
|
|
|
|
|
|
|
|
// Bulk manipulation...
|
|
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
// update a set of images in a ribbon...
|
|
|
|
|
//
|
|
|
|
|
// This will reuse the images that already exist, thus if updating or
|
|
|
|
|
// adding images to an already loaded set this should be very fast.
|
|
|
|
|
//
|
2014-07-22 19:57:57 +04:00
|
|
|
// NOTE: gids and ribbon must be .getImage(..) and .getRibbon(..)
|
|
|
|
|
// compatible...
|
2014-07-24 16:05:59 +04:00
|
|
|
updateRibbon: function(gids, ribbon){
|
2014-07-22 19:57:57 +04:00
|
|
|
// get/create the ribbon...
|
|
|
|
|
var r = this.getRibbon(ribbon)
|
|
|
|
|
if(r.length == 0){
|
|
|
|
|
// no such ribbon exists, then create and append it...
|
|
|
|
|
r = this.placeRibbon(ribbon, this.viewer.find('.ribbon').length)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var loaded = r.find('.image')
|
|
|
|
|
|
|
|
|
|
var that = this
|
|
|
|
|
$(gids).each(function(i, gid){
|
|
|
|
|
// get/create image...
|
|
|
|
|
var img = that.getImage(gid)
|
|
|
|
|
img = img.length == 0 ? that.createImage(gid) : img
|
|
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
// clear a chunk of images that are not in gids until one that is...
|
2014-07-22 19:57:57 +04:00
|
|
|
var g = loaded.length > i ? that.getElemGID(loaded.eq(i)) : null
|
|
|
|
|
while(g != null && gids.indexOf(g) < 0){
|
|
|
|
|
that.clear(g)
|
|
|
|
|
loaded.splice(i, 1)
|
|
|
|
|
g = loaded.length > i ? that.getElemGID(loaded.eq(i)) : null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check if we need to reattach the image...
|
|
|
|
|
if(gid != g){
|
|
|
|
|
// append the image to set...
|
|
|
|
|
if(loaded.length == 0 || loaded.length <= i){
|
|
|
|
|
r.append(img.detach())
|
|
|
|
|
|
|
|
|
|
// attach the image at i...
|
|
|
|
|
} else {
|
|
|
|
|
// update the DOM...
|
|
|
|
|
loaded.eq(i).before(img.detach())
|
|
|
|
|
|
|
|
|
|
// update the loaded list...
|
|
|
|
|
var l = loaded.index(img)
|
|
|
|
|
if(l >= 0){
|
|
|
|
|
loaded.splice(l, 1)
|
|
|
|
|
}
|
|
|
|
|
loaded.splice(i, 0, img)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
_UPDATE_IMAGE && image.updateImage(img)
|
2014-07-22 19:57:57 +04:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// remove the rest of the stuff in ribbon...
|
|
|
|
|
if(loaded.length > gids.length){
|
|
|
|
|
loaded.eq(gids.length).nextAll().remove()
|
|
|
|
|
loaded.eq(gids.length).remove()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this
|
|
|
|
|
},
|
2014-07-24 16:05:59 +04:00
|
|
|
|
|
|
|
|
// Update a data object in ribbons...
|
|
|
|
|
//
|
|
|
|
|
// This uses .updateRibbon(..) to load individual ribbons, for
|
|
|
|
|
// more info see docs for that.
|
|
|
|
|
//
|
|
|
|
|
// This uses data.ribbon_order to place the ribbons and data.ribbons
|
|
|
|
|
// place the images, either is optional, but at least one of the two
|
|
|
|
|
// must exist for this to work.
|
|
|
|
|
//
|
|
|
|
|
// NOTE: this will not clear the ribbons object explicitly.
|
|
|
|
|
// NOTE: this will clear the ribbons that are not present in
|
|
|
|
|
// data.ribbon_order (if given) unless keep_untouched_ribbons
|
|
|
|
|
// is set.
|
|
|
|
|
updateData: function(data, keep_untouched_ribbons){
|
|
|
|
|
// load the data...
|
2014-07-22 19:57:57 +04:00
|
|
|
var that = this
|
2014-07-24 16:05:59 +04:00
|
|
|
|
|
|
|
|
// place images...
|
|
|
|
|
if(data.ribbons != null){
|
|
|
|
|
Object.keys(data.ribbons).forEach(function(gid){
|
|
|
|
|
that.updateRibbon(data.ribbons[gid], gid)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// place ribbons...
|
|
|
|
|
if(data.ribbon_order != null){
|
|
|
|
|
data.ribbon_order.forEach(function(gid, i){
|
|
|
|
|
that.placeRibbon(gid, i)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// clear the ribbons that did not get updated...
|
|
|
|
|
if(!keep_untouched_ribbons && data.ribbon_order != null){
|
|
|
|
|
var ribbons = data.ribbon_order
|
|
|
|
|
that.viewer.find('.ribbon').each(function(){
|
|
|
|
|
var r = $(this)
|
|
|
|
|
if(ribbons.indexOf(that.getElemGID(r)) < 0){
|
|
|
|
|
r.remove()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-22 19:57:57 +04:00
|
|
|
return this
|
|
|
|
|
},
|
2014-07-22 20:27:11 +04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clear elements...
|
|
|
|
|
//
|
|
|
|
|
// Clear all elements:
|
|
|
|
|
// .clear()
|
|
|
|
|
// .clear('*')
|
|
|
|
|
// -> Ribbons
|
|
|
|
|
//
|
|
|
|
|
// Clear an image or a ribbon by gid:
|
|
|
|
|
// .clear(gid)
|
|
|
|
|
// -> Ribbons
|
|
|
|
|
//
|
|
|
|
|
// Clear a set of elements:
|
|
|
|
|
// .clear([gid, ...])
|
|
|
|
|
// -> Ribbons
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// NOTE: another way to remove a ribbon or an image just to use
|
|
|
|
|
// .getRibbon(..).remove() and .getImage(...).remove() respectivly.
|
2014-07-22 19:57:57 +04:00
|
|
|
clear: function(gids){
|
|
|
|
|
// clear all...
|
|
|
|
|
if(gids == null || gids == '*'){
|
|
|
|
|
this.viewer.find('.ribbon').remove()
|
|
|
|
|
|
|
|
|
|
// clear one or more gids...
|
|
|
|
|
} else {
|
|
|
|
|
gids = gids.constructor.name != 'Array' ? [gids] : gids
|
|
|
|
|
var that = this
|
|
|
|
|
gids.forEach(function(g){
|
|
|
|
|
that.viewer.find('[gid='+JSON.stringify(g)+']').remove()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
return this
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
2014-07-24 16:36:25 +04:00
|
|
|
// Focus image...
|
|
|
|
|
//
|
|
|
|
|
// Focus image by gid:
|
|
|
|
|
// .focusImage(gid)
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
|
|
|
|
// Focus next/prev image relative to current:
|
|
|
|
|
// .focusImage('next')
|
|
|
|
|
// .focusImage('prev')
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
|
|
|
|
// Focus image at offset from current:
|
|
|
|
|
// .focusImage(offset)
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
|
|
|
|
// NOTE: gid must be a .getImage(..) compatible object.
|
|
|
|
|
// NOTE: for keyword and offset to work an image must be focused.
|
|
|
|
|
// NOTE: overflowing offset will focus first/last image.
|
|
|
|
|
//
|
2014-07-20 02:25:36 +04:00
|
|
|
// XXX interaction animation...
|
|
|
|
|
focusImage: function(gid){
|
2014-07-24 16:36:25 +04:00
|
|
|
var cur = this.viewer
|
2014-07-20 02:25:36 +04:00
|
|
|
.find('.current.image')
|
2014-07-24 16:36:25 +04:00
|
|
|
|
|
|
|
|
// relative keywords...
|
|
|
|
|
gid = gid == 'next' ? 1
|
|
|
|
|
: gid == 'prev' ? -1
|
|
|
|
|
: gid
|
|
|
|
|
|
|
|
|
|
// offset...
|
|
|
|
|
if(typeof(gid) == typeof(123)){
|
|
|
|
|
if(gid != 0){
|
|
|
|
|
var list = gid > 0 ? 'nextAll' : 'prevAll'
|
|
|
|
|
gid = Math.abs(gid)-1
|
|
|
|
|
var target = cur[list]('.image')
|
|
|
|
|
// handle overflow...
|
|
|
|
|
target = target.eq(Math.min(gid, target.length-1))
|
|
|
|
|
if(target.length > 0){
|
|
|
|
|
return this.focusImage(target)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return cur
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cur.removeClass('current')
|
2014-07-20 02:25:36 +04:00
|
|
|
return this.getImage(gid)
|
|
|
|
|
.addClass('current')
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Image manipulation...
|
|
|
|
|
|
|
|
|
|
// Rotate an image...
|
|
|
|
|
//
|
|
|
|
|
// direction can be:
|
|
|
|
|
// XXX not sure if we need these as attrs...
|
|
|
|
|
CW: 'cw',
|
|
|
|
|
CCW: 'ccw',
|
|
|
|
|
//
|
|
|
|
|
// rotation tables...
|
|
|
|
|
// NOTE: setting a value to null will remove the attribute, 0 will
|
|
|
|
|
// set 0 explicitly...
|
|
|
|
|
_cw: {
|
|
|
|
|
null: 90,
|
|
|
|
|
0: 90,
|
|
|
|
|
90: 180,
|
|
|
|
|
180: 270,
|
|
|
|
|
//270: 0,
|
|
|
|
|
270: null,
|
|
|
|
|
},
|
|
|
|
|
_ccw: {
|
|
|
|
|
null: 270,
|
|
|
|
|
0: 270,
|
|
|
|
|
//90: 0,
|
|
|
|
|
90: null,
|
|
|
|
|
180: 90,
|
|
|
|
|
270: 180,
|
|
|
|
|
},
|
|
|
|
|
rotateImage: function(target, direction){
|
2014-07-22 20:27:11 +04:00
|
|
|
var r_table = direction == this.CW ? this._cw : this._ccw
|
2014-07-20 02:25:36 +04:00
|
|
|
target = this.getImage(target)
|
|
|
|
|
target.each(function(i, e){
|
|
|
|
|
var img = $(this)
|
2014-07-22 20:27:11 +04:00
|
|
|
var o = img.attr('orientation')
|
|
|
|
|
o = r_table[ o == null ? null : o ]
|
2014-07-20 02:25:36 +04:00
|
|
|
if(o == null){
|
|
|
|
|
img.removeAttr('orientation')
|
|
|
|
|
} else {
|
|
|
|
|
img.attr('orientation', o)
|
|
|
|
|
}
|
|
|
|
|
// account for proportions...
|
2014-07-22 17:09:25 +04:00
|
|
|
image.correctImageProportionsForRotation(img)
|
2014-07-20 02:25:36 +04:00
|
|
|
// XXX this is a bit of an overkill but it will update the
|
|
|
|
|
// preview if needed...
|
2014-07-22 17:09:25 +04:00
|
|
|
//image.updateImage(img)
|
2014-07-20 02:25:36 +04:00
|
|
|
})
|
|
|
|
|
return target
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Flip an image...
|
|
|
|
|
//
|
|
|
|
|
// direction can be:
|
|
|
|
|
// XXX not sure if we need these as attrs...
|
|
|
|
|
VERTICAL: 'vertical',
|
|
|
|
|
HORIZONTAL: 'horizontal',
|
|
|
|
|
flipImage: function(target, direction){
|
|
|
|
|
target = this.getImage(target)
|
|
|
|
|
target.each(function(i, e){
|
|
|
|
|
var img = $(this)
|
|
|
|
|
|
|
|
|
|
// get the state...
|
|
|
|
|
var state = img.attr('flipped')
|
|
|
|
|
state = (state == null ? '' : state)
|
|
|
|
|
.split(',')
|
|
|
|
|
.map(function(e){ return e.trim() })
|
|
|
|
|
.filter(function(e){ return e != '' })
|
|
|
|
|
|
|
|
|
|
// toggle the specific state...
|
|
|
|
|
var i = state.indexOf(direction)
|
|
|
|
|
if(i >= 0){
|
|
|
|
|
state.splice(i, 1)
|
|
|
|
|
} else {
|
|
|
|
|
state.push(direction)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// write the state...
|
|
|
|
|
if(state.length == 0){
|
|
|
|
|
img.removeAttr('flipped')
|
|
|
|
|
} else {
|
|
|
|
|
img.attr('flipped', state.join(', '))
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
return target
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// shorthands...
|
|
|
|
|
// XXX should these be here???
|
2014-07-24 16:05:59 +04:00
|
|
|
rotateCW: function(target){ return this.rotateImage(target, this.CW) },
|
|
|
|
|
rotateCCW: function(target){ return this.rotateImage(target, this.CCW) },
|
|
|
|
|
flipVertical: function(target){ return this.flipImage(target, this.VERTICAL) },
|
|
|
|
|
flipHorizontal: function(target){ return this.flipImage(target, this.HORIZONTAL) },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// UI manipulation...
|
|
|
|
|
|
|
|
|
|
// XXX if target is an image align the ribbon both vertically and horizontally...
|
|
|
|
|
alignRibbon: function(target, mode){
|
|
|
|
|
// XXX
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// XXX
|
|
|
|
|
fitNImages: function(n){
|
|
|
|
|
// XXX
|
|
|
|
|
},
|
2014-07-20 02:25:36 +04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
_setup: function(viewer){
|
|
|
|
|
this.viewer = $(viewer)
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Main Ribbons object...
|
|
|
|
|
//
|
2014-07-21 18:33:31 +04:00
|
|
|
var Ribbons =
|
|
|
|
|
module.Ribbons =
|
2014-07-20 02:25:36 +04:00
|
|
|
function Ribbons(viewer){
|
|
|
|
|
// in case this is called as a function (without new)...
|
|
|
|
|
if(this.constructor.name != 'Ribbons'){
|
|
|
|
|
return new Ribbons(viewer)
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
this._setup(viewer)
|
2014-07-22 17:09:25 +04:00
|
|
|
|
2014-07-20 02:25:36 +04:00
|
|
|
return this
|
|
|
|
|
}
|
2014-07-21 18:33:31 +04:00
|
|
|
Ribbons.__proto__ = RibbonsClassPrototype
|
|
|
|
|
Ribbons.prototype = RibbonsPrototype
|
2014-07-20 02:25:36 +04:00
|
|
|
Ribbons.prototype.constructor = Ribbons
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
|
* vim:set ts=4 sw=4 : */
|
2014-07-21 16:38:06 +04:00
|
|
|
return module })
|