2014-07-20 02:25:36 +04:00
|
|
|
/**********************************************************************
|
|
|
|
|
*
|
|
|
|
|
* Minomal UI API...
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
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-24 17:38:54 +04:00
|
|
|
// XXX is this correct...
|
|
|
|
|
require('ext-lib/jquery')
|
|
|
|
|
|
2014-07-22 17:09:25 +04:00
|
|
|
var data = require('data')
|
2014-07-28 06:36:02 +04:00
|
|
|
var images = require('images')
|
2014-07-22 17:09:25 +04:00
|
|
|
|
2014-07-20 02:25:36 +04:00
|
|
|
|
2014-07-21 18:33:31 +04:00
|
|
|
|
2014-07-28 19:45:51 +04:00
|
|
|
// XXX STUB
|
|
|
|
|
var IMAGE_UPDATERS =
|
|
|
|
|
module.IMAGE_UPDATERS = []
|
|
|
|
|
|
|
|
|
|
|
2014-07-21 02:30:24 +04:00
|
|
|
/*********************************************************************/
|
|
|
|
|
//
|
2014-07-24 17:38:54 +04:00
|
|
|
// This expects the following HTML structure...
|
2014-07-21 02:30:24 +04:00
|
|
|
//
|
|
|
|
|
// Unpopulated:
|
|
|
|
|
//
|
|
|
|
|
// <div class="viewer">
|
|
|
|
|
// <div class="ribbon-set"></div>
|
|
|
|
|
// </div>
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// Populated:
|
|
|
|
|
//
|
|
|
|
|
// <div class="viewer">
|
|
|
|
|
// <div class="ribbon-set">
|
|
|
|
|
// <div class="ribbon">
|
2014-07-24 17:38:54 +04:00
|
|
|
// <div class="image" gid="a"></div>
|
|
|
|
|
// <div class="image" gid="b"></div>
|
2014-07-21 02:30:24 +04:00
|
|
|
// ...
|
|
|
|
|
// </div>
|
|
|
|
|
// <div class="ribbon">
|
2014-07-24 17:38:54 +04:00
|
|
|
// <div class="image" gid="c"></div>
|
|
|
|
|
// <div class="current image" gid="d"></div>
|
|
|
|
|
// <div class="image" gid="e"></div>
|
|
|
|
|
// <div class="mark selected" gid="f"></div>
|
|
|
|
|
// <div class="image" gid="g"></div>
|
2014-07-21 02:30:24 +04:00
|
|
|
// ...
|
|
|
|
|
// </div>
|
|
|
|
|
// ...
|
|
|
|
|
// </div>
|
|
|
|
|
// </div>
|
|
|
|
|
//
|
|
|
|
|
//
|
2014-07-24 17:38:54 +04:00
|
|
|
// NOTE: there can be only one .ribbon-set element.
|
|
|
|
|
//
|
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-27 03:08:59 +04:00
|
|
|
// DOM 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-28 17:28:03 +04:00
|
|
|
createMark: function(cls, gid){
|
|
|
|
|
gid = gid != null ? gid+'' : gid
|
|
|
|
|
return $('<div class="mark">')
|
|
|
|
|
.addClass(cls)
|
|
|
|
|
.attr('gid', JSON.stringify(gid)
|
|
|
|
|
// this removes the extra quots...
|
|
|
|
|
.replace(/^"(.*)"$/g, '$1'))
|
|
|
|
|
},
|
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-28 06:36:02 +04:00
|
|
|
// .images (Images object)
|
|
|
|
|
//
|
2014-07-25 02:00:50 +04:00
|
|
|
// XXX to update images we need to know about images...
|
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-28 17:28:03 +04:00
|
|
|
createMark: RibbonsClassPrototype.createMark,
|
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-28 19:45:51 +04:00
|
|
|
// Helpers...
|
|
|
|
|
|
|
|
|
|
// Get visible image tile size...
|
|
|
|
|
//
|
|
|
|
|
// .getVisibleImageSize()
|
|
|
|
|
// .getVisibleImageSize('width')
|
|
|
|
|
// -> size
|
|
|
|
|
//
|
|
|
|
|
// .getVisibleImageSize('height')
|
|
|
|
|
// -> size
|
|
|
|
|
//
|
|
|
|
|
// .getVisibleImageSize('max')
|
|
|
|
|
// .getVisibleImageSize('min')
|
|
|
|
|
// -> size
|
|
|
|
|
//
|
|
|
|
|
// NOTE: this is similar to vh, vw, vmin and vmax CSS3 units, but
|
|
|
|
|
// gets the visible size of the image tile in pixels.
|
|
|
|
|
//
|
|
|
|
|
// XXX try and make image size the product of vmin and scale...
|
|
|
|
|
// XXX is this the right place for this???
|
|
|
|
|
// XXX uses jli.js getElementScale(..)
|
|
|
|
|
getVisibleImageSize: function(dim){
|
|
|
|
|
dim = dim == null ? 'width' : dim
|
|
|
|
|
var img = this.viewer.find('.image')
|
|
|
|
|
var scale = getElementScale(this.viewer.find('.ribbon-set'))
|
|
|
|
|
if(dim == 'height'){
|
|
|
|
|
return img.outerHeight(true) * scale
|
|
|
|
|
} else if(dim == 'width'){
|
|
|
|
|
return img.outerWidth(true) * scale
|
|
|
|
|
} else if(dim == 'max'){
|
|
|
|
|
return Math.max(img.outerHeight(true), img.outerWidth(true)) * scale
|
|
|
|
|
} else if(dim == 'min'){
|
|
|
|
|
return Math.min(img.outerHeight(true), img.outerWidth(true)) * scale
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
2014-07-22 20:27:11 +04:00
|
|
|
// Contextual getters...
|
2014-07-24 16:05:59 +04:00
|
|
|
|
|
|
|
|
// Get ribbon...
|
|
|
|
|
//
|
|
|
|
|
// Get current ribbon:
|
|
|
|
|
// .getRibbon()
|
2014-07-25 19:17:09 +04:00
|
|
|
// .getRibbon('current')
|
2014-07-24 16:05:59 +04:00
|
|
|
// -> ribbon
|
|
|
|
|
//
|
2014-07-25 19:17:09 +04:00
|
|
|
// Get base ribbon:
|
|
|
|
|
// .getRibbon('base')
|
|
|
|
|
// -> ribbon
|
|
|
|
|
//
|
|
|
|
|
// Get ribbon by its index/gid:
|
2014-07-24 16:05:59 +04:00
|
|
|
// .getRibbon(index)
|
|
|
|
|
// .getRibbon(gid)
|
|
|
|
|
// -> ribbon
|
|
|
|
|
//
|
2014-07-25 19:17:09 +04:00
|
|
|
// Get ribbon by image:
|
|
|
|
|
// .getRibbon(image)
|
|
|
|
|
// -> ribbon
|
|
|
|
|
// NOTE: image must be .getImage(..) compatible.
|
|
|
|
|
//
|
2014-07-24 16:05:59 +04:00
|
|
|
// Get ribbons from list:
|
|
|
|
|
// .getRibbon($(..))
|
|
|
|
|
// .getRibbon([..])
|
|
|
|
|
// -> ribbon(s)
|
|
|
|
|
// NOTE: this will filter the list but not search the tree...
|
|
|
|
|
//
|
2014-07-25 19:17:09 +04:00
|
|
|
//
|
|
|
|
|
// NOTE: if current image is unset then this will not be able to
|
|
|
|
|
// get it.
|
|
|
|
|
// NOTE: if base ribbon is unset this will return the first ribbon.
|
2014-07-20 02:25:36 +04:00
|
|
|
getRibbon: function(target){
|
2014-07-24 16:05:59 +04:00
|
|
|
// current...
|
2014-07-25 19:17:09 +04:00
|
|
|
if(target == null || target == 'current') {
|
|
|
|
|
return this.getImage().parents('.ribbon').first()
|
|
|
|
|
|
|
|
|
|
// base...
|
|
|
|
|
} else if(target == 'base'){
|
|
|
|
|
var r = this.viewer.find('.base.ribbon').first()
|
|
|
|
|
if(r.length == 0){
|
|
|
|
|
return this.viewer.find('.ribbon').first()
|
|
|
|
|
}
|
|
|
|
|
return r
|
2014-07-20 02:25:36 +04:00
|
|
|
|
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-25 19:17:09 +04:00
|
|
|
var r = this.viewer.find('.ribbon[gid='+JSON.stringify(target)+']')
|
|
|
|
|
// if no ribbon is found, try and get an image and it's ribbon...
|
|
|
|
|
return r.length == 0
|
|
|
|
|
? this.getImage(target).parents('.ribbon').first()
|
|
|
|
|
: r
|
2014-07-20 02:25:36 +04:00
|
|
|
}
|
|
|
|
|
return $(target).filter('.ribbon')
|
|
|
|
|
},
|
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))
|
|
|
|
|
},
|
|
|
|
|
|
2014-07-25 02:00:50 +04:00
|
|
|
// Get image...
|
2014-07-24 16:05:59 +04:00
|
|
|
//
|
|
|
|
|
// Get current image:
|
|
|
|
|
// .getImage()
|
2014-07-25 19:17:09 +04:00
|
|
|
// .getImage('current')
|
2014-07-24 16:05:59 +04:00
|
|
|
// -> image
|
|
|
|
|
//
|
|
|
|
|
// Get image by gid:
|
|
|
|
|
// .getImage(gid)
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
2014-07-25 19:17:09 +04:00
|
|
|
// Get image at offset relative to current image:
|
|
|
|
|
// .getImage('next')
|
|
|
|
|
// .getImage('prev')
|
|
|
|
|
// .getImage(offset)
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
|
|
|
|
// Get image at offset relative to image:
|
|
|
|
|
// .getImage(image, 'next')
|
|
|
|
|
// .getImage(image, 'prev')
|
|
|
|
|
// .getImage(image, offset)
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
2014-07-24 16:05:59 +04:00
|
|
|
// Get images from list:
|
|
|
|
|
// .getImage($(..))
|
|
|
|
|
// .getImage([..])
|
|
|
|
|
// -> image(s)
|
|
|
|
|
// NOTE: this will filter the list but not search the tree...
|
|
|
|
|
//
|
2014-07-25 19:17:09 +04:00
|
|
|
getImage: function(target, offset){
|
|
|
|
|
var img = null
|
|
|
|
|
|
|
|
|
|
// relative to current -- target is offset...
|
|
|
|
|
if(target == 'next'
|
|
|
|
|
|| target == 'prev'
|
|
|
|
|
|| typeof(target) == typeof(123)){
|
|
|
|
|
offset = target
|
|
|
|
|
target = 'current'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get the base image...
|
2014-07-24 16:05:59 +04:00
|
|
|
// current...
|
2014-07-25 19:17:09 +04:00
|
|
|
if(target == null || target == 'current') {
|
|
|
|
|
img = this.viewer.find('.current.image')
|
2014-07-20 02:25:36 +04:00
|
|
|
|
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-25 19:17:09 +04:00
|
|
|
img = this.viewer.find('.image[gid='+JSON.stringify(target)+']')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we got a collection...
|
|
|
|
|
if(img == null){
|
|
|
|
|
return $(target).filter('.image')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get the offset...
|
|
|
|
|
if(offset != null && offset != 0){
|
|
|
|
|
// relative keywords...
|
|
|
|
|
offset = offset == 'next' ? 1
|
|
|
|
|
: offset == 'prev' ? -1
|
|
|
|
|
: offset
|
|
|
|
|
var list = offset > 0 ? 'nextAll' : 'prevAll'
|
|
|
|
|
offset = Math.abs(offset)-1
|
|
|
|
|
var res = img[list]('.image')
|
|
|
|
|
// handle overflow...
|
|
|
|
|
res = res.eq(Math.min(offset, res.length-1))
|
|
|
|
|
img = res.length == 0 ? img : res
|
2014-07-20 02:25:36 +04:00
|
|
|
}
|
2014-07-25 19:17:09 +04:00
|
|
|
|
|
|
|
|
return img
|
2014-07-20 02:25:36 +04:00
|
|
|
},
|
|
|
|
|
|
2014-07-28 17:28:03 +04:00
|
|
|
// Get image marks...
|
|
|
|
|
//
|
|
|
|
|
// .getImageMarks(gid)
|
|
|
|
|
// .getImageMarks(image)
|
|
|
|
|
// -> marks
|
|
|
|
|
//
|
|
|
|
|
// .getImageMarks(gid, cls)
|
|
|
|
|
// .getImageMarks(image, cls)
|
|
|
|
|
// -> marks
|
|
|
|
|
//
|
2014-07-28 19:45:51 +04:00
|
|
|
// XXX should this be here or in a marks plugin...
|
2014-07-28 17:28:03 +04:00
|
|
|
getImageMarks: function(img, cls){
|
|
|
|
|
gid = typeof(img) == typeof('str') ? img : null
|
|
|
|
|
gid = gid == null ? this.getElemGID(img) : gid
|
|
|
|
|
|
|
|
|
|
var marks = this.viewer.find('.mark[gid='+JSON.stringify(gid)+']')
|
|
|
|
|
|
|
|
|
|
if(cls != null){
|
|
|
|
|
return marks.filter('.'+cls)
|
|
|
|
|
}
|
|
|
|
|
return marks
|
|
|
|
|
},
|
|
|
|
|
|
2014-07-20 02:25:36 +04:00
|
|
|
|
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...
|
|
|
|
|
//
|
2014-07-25 07:01:08 +04:00
|
|
|
// Place target at at offset from current position:
|
|
|
|
|
// .placeImage(target, offset)
|
2014-07-20 02:25:36 +04:00
|
|
|
// -> image
|
|
|
|
|
//
|
2014-07-25 07:01:08 +04:00
|
|
|
// Place target at image position:
|
|
|
|
|
// .placeImage(target, image)
|
|
|
|
|
// .placeImage(target, image, 'before')
|
|
|
|
|
// .placeImage(target, image, 'after')
|
2014-07-20 02:25:36 +04:00
|
|
|
// -> image
|
|
|
|
|
//
|
2014-07-25 06:49:36 +04:00
|
|
|
// NOTE: mode is defaults to 'before'.
|
2014-07-20 02:25:36 +04:00
|
|
|
// NOTE: if image gid does not exist it will be created.
|
2014-07-25 06:49:36 +04:00
|
|
|
//
|
2014-07-20 02:25:36 +04:00
|
|
|
// XXX interaction animation...
|
2014-07-25 06:49:36 +04:00
|
|
|
// XXX mode is ugly...
|
2014-07-28 06:36:02 +04:00
|
|
|
// XXX should this be strongly or weakly coupled to images.updateImage(..)???
|
2014-07-25 06:49:36 +04:00
|
|
|
placeImage: function(target, to, mode){
|
|
|
|
|
mode = mode == null ? 'before' : mode
|
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
|
|
|
|
2014-07-25 06:49:36 +04:00
|
|
|
// offset on same ribbon...
|
|
|
|
|
if(typeof(to) == typeof(123)){
|
2014-07-25 07:12:57 +04:00
|
|
|
// moving the image to itself...
|
2014-07-25 06:49:36 +04:00
|
|
|
if(to == 0){
|
2014-07-25 07:01:08 +04:00
|
|
|
return img
|
2014-07-25 06:49:36 +04:00
|
|
|
}
|
|
|
|
|
var i = to
|
|
|
|
|
var images = img[i > 0 ? 'nextAll' : 'prevAll']('.image')
|
|
|
|
|
to = images.length > 0
|
|
|
|
|
? images.eq(Math.min(Math.abs(i), images.length)-1)
|
|
|
|
|
: img
|
|
|
|
|
// relative to image...
|
|
|
|
|
} else {
|
|
|
|
|
var i = mode == 'before' ? -1 : 1
|
|
|
|
|
to = this.getImage(to)
|
2014-07-25 07:12:57 +04:00
|
|
|
// moving the image to itself...
|
2014-07-25 07:01:08 +04:00
|
|
|
if(to[0] == img[0]){
|
|
|
|
|
return img
|
|
|
|
|
}
|
2014-07-25 06:49:36 +04:00
|
|
|
var images = to[mode]('.image')
|
2014-07-20 02:25:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// place the image...
|
2014-07-25 06:49:36 +04:00
|
|
|
if(images.length <= i){
|
|
|
|
|
to.parents('.ribbon').append(img)
|
|
|
|
|
// after...
|
|
|
|
|
} else if(i > 0){
|
|
|
|
|
to.next('.image').before(img)
|
|
|
|
|
// before...
|
2014-07-20 02:25:36 +04:00
|
|
|
} else {
|
2014-07-25 06:49:36 +04:00
|
|
|
to.before(img)
|
2014-07-20 02:25:36 +04:00
|
|
|
}
|
|
|
|
|
|
2014-07-28 17:28:03 +04:00
|
|
|
return this.updateImage(img)
|
2014-07-20 02:25:36 +04:00
|
|
|
},
|
|
|
|
|
|
2014-07-22 19:57:57 +04:00
|
|
|
|
2014-07-28 19:45:51 +04:00
|
|
|
// Loading and updating...
|
|
|
|
|
|
|
|
|
|
// XXX this needs:
|
|
|
|
|
// IMAGE_UPDATERS -- make it a callback/event (node/jquery)...
|
|
|
|
|
updateImageIndicators: function(gid, image){
|
|
|
|
|
gid = gid == null ? this.getElemGID() : gid
|
|
|
|
|
image = image == null ? this.getImage() : $(image)
|
|
|
|
|
|
|
|
|
|
IMAGE_UPDATERS.forEach(function(update){
|
|
|
|
|
update(gid, image)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return image
|
|
|
|
|
},
|
|
|
|
|
_loadImagePreviewURL: function(image, url){
|
|
|
|
|
// pre-cache and load image...
|
|
|
|
|
// NOTE: this will make images load without a blackout...
|
|
|
|
|
var img = new Image()
|
|
|
|
|
img.onload = function(){
|
|
|
|
|
image.css({
|
|
|
|
|
'background-image': 'url("'+ url +'")',
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
img.src = url
|
|
|
|
|
return img
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Update image(s)...
|
|
|
|
|
//
|
|
|
|
|
// Update current image:
|
|
|
|
|
// .updateImage()
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
|
|
|
|
// Update all image:
|
|
|
|
|
// .updateImage('*')
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
|
|
|
|
load_img_sync: false,
|
|
|
|
|
//
|
|
|
|
|
updateImage: function(image, gid, size, sync){
|
|
|
|
|
image = image == null ? this.getImage()
|
|
|
|
|
: image == '*' ? this.viewer.find('.image')
|
|
|
|
|
: $(image)
|
|
|
|
|
sync = sync == null ? this.load_img_sync : sync
|
|
|
|
|
size = size == null ? this.getVisibleImageSize('max') : size
|
|
|
|
|
|
|
|
|
|
var that = this
|
|
|
|
|
return image.each(function(){
|
|
|
|
|
var image = $(this)
|
|
|
|
|
var old_gid = that.getElemGID(image)
|
|
|
|
|
|
|
|
|
|
// same image -- update...
|
|
|
|
|
if(old_gid == gid || gid == null){
|
|
|
|
|
var gid = old_gid
|
|
|
|
|
|
|
|
|
|
// reuse for different image -- reconstruct...
|
|
|
|
|
} else {
|
|
|
|
|
// remove old marks...
|
|
|
|
|
if(typeof(old_gid) == typeof('str')){
|
|
|
|
|
that.getImageMarks(old_gid).remove()
|
|
|
|
|
}
|
|
|
|
|
// reset gid...
|
|
|
|
|
image
|
|
|
|
|
.attr('gid', JSON.stringify(gid)
|
|
|
|
|
// this removes the extra quots...
|
|
|
|
|
.replace(/^"(.*)"$/g, '$1'))
|
|
|
|
|
.css({
|
|
|
|
|
// clear the old preview...
|
|
|
|
|
'background-image': '',
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if not images data defined drop out...
|
|
|
|
|
if(that.images == null){
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get the image data...
|
|
|
|
|
var img_data = that.images[gid]
|
|
|
|
|
if(img_data == null){
|
|
|
|
|
img_data = images.STUB_IMAGE_DATA
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* XXX does not seem to be needing this...
|
|
|
|
|
// set the current class...
|
|
|
|
|
if(gid == DATA.current){
|
|
|
|
|
image.addClass('current')
|
|
|
|
|
} else {
|
|
|
|
|
image.removeClass('current')
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
// main attrs...
|
|
|
|
|
image
|
|
|
|
|
.attr({
|
|
|
|
|
orientation: [null, 0].indexOf(img_data.orientation) < 0
|
|
|
|
|
? img_data.orientation,
|
|
|
|
|
: null
|
|
|
|
|
flipped: img_data.flipped != null
|
|
|
|
|
? img_data.flipped.join(', '),
|
|
|
|
|
: null
|
|
|
|
|
})
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// image state...
|
|
|
|
|
that.rotateImage(image, img_data.orientation == null ? 0 : img_data.orientation)
|
|
|
|
|
that.flipImage(image, img_data.flipped == null ? [] : img_data.flipped)
|
|
|
|
|
|
|
|
|
|
// preview...
|
|
|
|
|
var p_url = that.images.getBestPreview(gid, size, img_data).url
|
|
|
|
|
|
|
|
|
|
// update the preview if it's a new image or...
|
|
|
|
|
// XXX this should be pushed as far back as possible...
|
|
|
|
|
if(old_gid != gid
|
|
|
|
|
// the new preview (purl) is different to current...
|
|
|
|
|
|| image.css('background-image').indexOf(encodeURI(p_url)) < 0){
|
|
|
|
|
// sync load...
|
|
|
|
|
if(sync){
|
|
|
|
|
that._loadImagePreviewURL(image, p_url)
|
|
|
|
|
|
|
|
|
|
// async load...
|
|
|
|
|
} else {
|
|
|
|
|
// NOTE: storing the url in .data() makes the image load the
|
|
|
|
|
// last requested preview and in a case when we manage to
|
|
|
|
|
// call updateImage(...) on the same element multiple times
|
|
|
|
|
// before the previews get loaded...
|
|
|
|
|
// ...setting the data().loading is sync while loading an
|
|
|
|
|
// image is not, and if several loads are done in sequence
|
|
|
|
|
// there is no guarantee that they will happen in the same
|
|
|
|
|
// order as requested...
|
|
|
|
|
image.data().loading = p_url
|
|
|
|
|
setTimeout(function(){
|
|
|
|
|
that._loadImagePreviewURL(image, image.data().loading)
|
|
|
|
|
}, 0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NOTE: this only has effect on non-square image blocks...
|
|
|
|
|
// XXX this needs the loaded image, thus should be done right after preview loading...
|
|
|
|
|
that.correctImageProportionsForRotation(image)
|
|
|
|
|
|
|
|
|
|
// marks and other indicators...
|
|
|
|
|
that.updateImageIndicators(gid, image)
|
|
|
|
|
})
|
|
|
|
|
},
|
2014-07-22 19:57:57 +04:00
|
|
|
|
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-28 06:36:02 +04:00
|
|
|
//
|
|
|
|
|
// XXX should this be strongly or weakly coupled to images.updateImage(..)???
|
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-28 17:28:03 +04:00
|
|
|
that.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...
|
|
|
|
|
//
|
2014-07-25 19:17:09 +04:00
|
|
|
// .updateData(data, settings)
|
|
|
|
|
// -> ribbons
|
|
|
|
|
//
|
|
|
|
|
//
|
2014-07-24 16:05:59 +04:00
|
|
|
// 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
|
2014-07-25 19:17:09 +04:00
|
|
|
// to place the images.
|
|
|
|
|
//
|
|
|
|
|
// This uses data.base and data.current to set the base ribbon and
|
|
|
|
|
// current image respectively.
|
|
|
|
|
//
|
|
|
|
|
// All the data fields are optional, but for this to make a change
|
|
|
|
|
// at least one must be present.
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// Settings format:
|
|
|
|
|
// {
|
|
|
|
|
// // if true keep the unchanged ribbons (default: false)
|
|
|
|
|
// // NOTE: untouched ribbons are the ones loaded into DOM but
|
|
|
|
|
// // not included in any of:
|
|
|
|
|
// // - data.ribbon_order
|
|
|
|
|
// // - data.ribbons
|
|
|
|
|
// // - data.base
|
|
|
|
|
// keep_ribbons: bool,
|
|
|
|
|
//
|
|
|
|
|
// // if true do not update the base ribbon (default: false)
|
|
|
|
|
// keep_base: bool,
|
|
|
|
|
//
|
|
|
|
|
// // if true do not update the current image (default: false)
|
|
|
|
|
// keep_current: bool,
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// // a shorthand setting all the above to true (default: false).
|
|
|
|
|
// // NOTE: if this is set to true all other settings will be
|
|
|
|
|
// // ignored...
|
|
|
|
|
// keep_all: bool,
|
|
|
|
|
// }
|
2014-07-24 16:05:59 +04:00
|
|
|
//
|
|
|
|
|
// NOTE: this will not clear the ribbons object explicitly.
|
2014-07-25 19:17:09 +04:00
|
|
|
// 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
|
2014-07-24 16:05:59 +04:00
|
|
|
// 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)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-25 19:17:09 +04:00
|
|
|
if(!settings.keep_all){
|
|
|
|
|
// set base ribbon...
|
|
|
|
|
if(!settings.keep_base && data.base != null){
|
|
|
|
|
this.setBaseRibbon(data.base)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set base ribbon...
|
|
|
|
|
if(!settings.keep_current && data.current != null){
|
|
|
|
|
this.focusImage(data.current)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// clear the ribbons that did not get updated...
|
|
|
|
|
if(!settings.keep_ribbons
|
|
|
|
|
&& (data.ribbon_order != null || data.ribbons != null)){
|
|
|
|
|
var ribbons = []
|
|
|
|
|
ribbons = data.ribbon_order != null
|
|
|
|
|
? ribbons.concat(Object.keys(data.ribbon_order))
|
|
|
|
|
: ribbons
|
|
|
|
|
ribbons = data.ribbons != null
|
|
|
|
|
? ribbons.concat(Object.keys(data.ribbons))
|
|
|
|
|
: ribbons
|
|
|
|
|
ribbons.push(data.base)
|
|
|
|
|
|
|
|
|
|
that.viewer.find('.ribbon').each(function(){
|
|
|
|
|
var r = $(this)
|
|
|
|
|
if(ribbons.indexOf(that.getElemGID(r)) < 0){
|
|
|
|
|
r.remove()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
2014-07-24 16:05:59 +04:00
|
|
|
}
|
|
|
|
|
|
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)){
|
2014-07-25 19:17:09 +04:00
|
|
|
return this.focusImage(this.getImage(gid))
|
2014-07-24 16:36:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cur.removeClass('current')
|
2014-07-20 02:25:36 +04:00
|
|
|
return this.getImage(gid)
|
|
|
|
|
.addClass('current')
|
|
|
|
|
},
|
|
|
|
|
|
2014-07-28 19:45:51 +04:00
|
|
|
// Set base ribbon...
|
|
|
|
|
//
|
2014-07-25 19:17:09 +04:00
|
|
|
// XXX should this support keywords a-la .focusImage(..)???
|
|
|
|
|
setBaseRibbon: function(gid){
|
|
|
|
|
this.viewer.find('.base.ribbon').removeClass('base')
|
|
|
|
|
return this.getRibbon(gid).addClass('base')
|
|
|
|
|
},
|
|
|
|
|
|
2014-07-20 02:25:36 +04:00
|
|
|
|
2014-07-28 19:45:51 +04:00
|
|
|
// Image manipulation...
|
|
|
|
|
|
2014-07-28 17:28:03 +04:00
|
|
|
// Mark an image...
|
|
|
|
|
//
|
2014-07-28 19:45:51 +04:00
|
|
|
// Toggle current image cls mark:
|
|
|
|
|
// .toggleImageMark(cls)
|
|
|
|
|
// .toggleImageMark(cls, 'toggle')
|
|
|
|
|
// -> mark
|
|
|
|
|
//
|
|
|
|
|
// Set current image cls mark on or off explicitly:
|
|
|
|
|
// .toggleImageMark(cls, 'on')
|
|
|
|
|
// .toggleImageMark(cls, 'off')
|
|
|
|
|
// -> mark
|
|
|
|
|
//
|
|
|
|
|
// Toggle image cls mark:
|
|
|
|
|
// .toggleImageMark(image, cls)
|
|
|
|
|
// .toggleImageMark(image, cls, 'toggle')
|
2014-07-28 17:28:03 +04:00
|
|
|
// -> mark
|
|
|
|
|
//
|
2014-07-28 19:45:51 +04:00
|
|
|
// Set image cls mark on or off explicitly:
|
|
|
|
|
// .toggleImageMark(image, cls, 'on')
|
|
|
|
|
// .toggleImageMark(image, cls, 'off')
|
2014-07-28 17:28:03 +04:00
|
|
|
// -> mark
|
|
|
|
|
//
|
2014-07-28 19:45:51 +04:00
|
|
|
// Get image cls mark state:
|
|
|
|
|
// .toggleImageMark(cls, '?')
|
|
|
|
|
// .toggleImageMark(image, cls, '?')
|
|
|
|
|
// -> 'on'
|
|
|
|
|
// -> 'off'
|
|
|
|
|
// NOTE: this will only test the first image.
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// NOTE: cls can be a list...
|
|
|
|
|
// NOTE: this can operate on multiple images...
|
2014-07-28 17:28:03 +04:00
|
|
|
// NOTE: this will reuse existing marks...
|
2014-07-28 19:45:51 +04:00
|
|
|
//
|
|
|
|
|
// XXX use a cssToggler???
|
|
|
|
|
toggleImageMark: function(image, cls, action){
|
|
|
|
|
var that = this
|
|
|
|
|
if(cls == null || ['toggle', 'on', 'off', '?'].indexOf(cls) >= 0 ){
|
|
|
|
|
action = cls
|
|
|
|
|
cls = image
|
|
|
|
|
image = null
|
|
|
|
|
}
|
|
|
|
|
image = this.getImage(image)
|
|
|
|
|
cls = cls.constructor.name != 'Array' ? [cls] : cls
|
|
|
|
|
action = action == null ? 'toggle' : action
|
2014-07-28 17:28:03 +04:00
|
|
|
|
|
|
|
|
// no image is loaded...
|
|
|
|
|
if(image.length == 0){
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-28 19:45:51 +04:00
|
|
|
// get marked state...
|
|
|
|
|
if(action == '?'){
|
|
|
|
|
var gid = this.getElemGID(image)
|
|
|
|
|
var res = 0
|
|
|
|
|
cls.forEach(function(cls){
|
|
|
|
|
res += that.getImageMarks(gid, cls).length != 0 ? 1 : 0
|
|
|
|
|
})
|
|
|
|
|
return res == cls.length ? 'on' : 'off'
|
2014-07-28 06:36:02 +04:00
|
|
|
}
|
|
|
|
|
|
2014-07-28 19:45:51 +04:00
|
|
|
// set the marks...
|
|
|
|
|
image.each(function(){
|
2014-07-28 06:36:02 +04:00
|
|
|
var image = $(this)
|
2014-07-28 19:45:51 +04:00
|
|
|
var gid = that.getElemGID(image)
|
|
|
|
|
cls.forEach(function(cls){
|
|
|
|
|
var mark = that.getImageMarks(gid, cls)
|
|
|
|
|
|
|
|
|
|
// set the mark...
|
|
|
|
|
if(mark.length == 0
|
|
|
|
|
&& (action == 'toggle'
|
|
|
|
|
|| action == 'on')){
|
|
|
|
|
that.createMark(cls, gid)
|
|
|
|
|
.insertAfter(image)
|
|
|
|
|
|
|
|
|
|
// clear the mark...
|
|
|
|
|
} else if(action != 'on') {
|
|
|
|
|
mark.remove()
|
2014-07-28 06:36:02 +04:00
|
|
|
}
|
2014-07-28 19:45:51 +04:00
|
|
|
})
|
2014-07-28 06:36:02 +04:00
|
|
|
})
|
|
|
|
|
|
2014-07-28 19:45:51 +04:00
|
|
|
return image
|
2014-07-28 06:36:02 +04:00
|
|
|
},
|
|
|
|
|
|
2014-07-20 02:25:36 +04:00
|
|
|
// Rotate an image...
|
|
|
|
|
//
|
2014-07-24 16:46:32 +04:00
|
|
|
// Rotate image clockwise:
|
|
|
|
|
// .rotateImage(target, 'cw')
|
|
|
|
|
// -> image
|
2014-07-20 02:25:36 +04:00
|
|
|
//
|
2014-07-24 16:46:32 +04:00
|
|
|
// Rotate image counterclockwise:
|
|
|
|
|
// .rotateImage(target, 'ccw')
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
2014-07-28 06:36:02 +04:00
|
|
|
// Set explicit image rotation angle:
|
|
|
|
|
// .rotateImage(target, 0|90|180|270)
|
|
|
|
|
// .rotateImage(target, -90|-180|-270)
|
|
|
|
|
// -> image
|
2014-07-24 16:46:32 +04:00
|
|
|
//
|
|
|
|
|
// NOTE: target must be .getImage(..) compatible.
|
|
|
|
|
// NOTE: this can be applied in bulk, e.g.
|
|
|
|
|
// this.rotateImage($('.image'), 'cw') will rotate all the
|
|
|
|
|
// loaded images clockwise.
|
|
|
|
|
//
|
2014-07-28 06:36:02 +04:00
|
|
|
// XXX should this be strongly or weakly coupled to images.updateImage(..)
|
|
|
|
|
// or images.correctImageProportionsForRotation(..)???
|
|
|
|
|
// XXX should .correctImageProportionsForRotation(..) be in images???
|
2014-07-20 02:25:36 +04:00
|
|
|
rotateImage: function(target, direction){
|
|
|
|
|
target = this.getImage(target)
|
2014-07-28 06:36:02 +04:00
|
|
|
|
|
|
|
|
// validate direction...
|
|
|
|
|
if(images.calcRelativeRotation(direction) == null){
|
|
|
|
|
return target
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var that = this
|
2014-07-20 02:25:36 +04:00
|
|
|
target.each(function(i, e){
|
|
|
|
|
var img = $(this)
|
2014-07-28 06:36:02 +04:00
|
|
|
var o = direction == 'cw' || direction == 'ccw'
|
|
|
|
|
? images.calcRelativeRotation(img.attr('orientation'), direction)
|
|
|
|
|
: direction*1
|
|
|
|
|
if(o == 0){
|
2014-07-20 02:25:36 +04:00
|
|
|
img.removeAttr('orientation')
|
|
|
|
|
} else {
|
|
|
|
|
img.attr('orientation', o)
|
|
|
|
|
}
|
|
|
|
|
// account for proportions...
|
2014-07-28 06:36:02 +04:00
|
|
|
that.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-28 17:28:03 +04:00
|
|
|
//that.updateImage(img)
|
2014-07-20 02:25:36 +04:00
|
|
|
})
|
|
|
|
|
return target
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Flip an image...
|
|
|
|
|
//
|
2014-07-28 17:28:03 +04:00
|
|
|
// Flip image:
|
2014-07-24 16:46:32 +04:00
|
|
|
// .flipImage(target, 'horizontal')
|
|
|
|
|
// .flipImage(target, 'vertical')
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
2014-07-28 17:28:03 +04:00
|
|
|
// Set an explicit state:
|
|
|
|
|
// .flipImage(target, [ .. ])
|
|
|
|
|
// -> image
|
|
|
|
|
//
|
2014-07-24 16:46:32 +04:00
|
|
|
// NOTE: target must be .getImage(..) compatible.
|
|
|
|
|
// NOTE: this can be applied in bulk, e.g.
|
|
|
|
|
// this.flipImage($('.image'), 'vertical') will rotate all the
|
|
|
|
|
// loaded images vertically.
|
2014-07-20 02:25:36 +04:00
|
|
|
flipImage: function(target, direction){
|
|
|
|
|
target = this.getImage(target)
|
2014-07-28 17:28:03 +04:00
|
|
|
var set_state = direction.constructor.name == 'Array' ? direction : null
|
2014-07-20 02:25:36 +04:00
|
|
|
target.each(function(i, e){
|
|
|
|
|
var img = $(this)
|
|
|
|
|
|
2014-07-28 17:28:03 +04:00
|
|
|
// update existing state...
|
|
|
|
|
if(set_state == null){
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set an explicit state...
|
2014-07-20 02:25:36 +04:00
|
|
|
} else {
|
2014-07-28 17:28:03 +04:00
|
|
|
var state = set_state.slice()
|
2014-07-20 02:25:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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:46:32 +04:00
|
|
|
//rotateCW: function(target){ return this.rotateImage(target, 'cw') },
|
|
|
|
|
//rotateCCW: function(target){ return this.rotateImage(target, 'ccw') },
|
|
|
|
|
//flipVertical: function(target){ return this.flipImage(target, 'vertical') },
|
|
|
|
|
//flipHorizontal: function(target){ return this.flipImage(target, 'horizontal') },
|
2014-07-24 16:05:59 +04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// UI manipulation...
|
|
|
|
|
|
2014-07-28 19:45:51 +04:00
|
|
|
// Compensate for viewer proportioned and rotated images.
|
|
|
|
|
//
|
|
|
|
|
// This will set the margins so as to make the rotated image offset the
|
|
|
|
|
// same space as it is occupying visually...
|
|
|
|
|
//
|
|
|
|
|
// NOTE: this is not needed for square image blocks.
|
|
|
|
|
// NOTE: if an image block is square, this will remove the margins.
|
|
|
|
|
correctImageProportionsForRotation: function(images){
|
|
|
|
|
// XXX
|
|
|
|
|
var W = this.viewer.innerWidth()
|
|
|
|
|
var H = this.viewer.innerHeight()
|
|
|
|
|
|
|
|
|
|
var viewer_p = W > H ? 'landscape' : 'portrait'
|
|
|
|
|
|
|
|
|
|
return $(images).each(function(i, e){
|
|
|
|
|
var image = $(this)
|
|
|
|
|
// orientation...
|
|
|
|
|
var o = image.attr('orientation')
|
|
|
|
|
o = o == null ? 0 : o
|
|
|
|
|
var w = image.outerWidth()
|
|
|
|
|
var h = image.outerHeight()
|
|
|
|
|
|
|
|
|
|
// non-square image...
|
|
|
|
|
if(w != h){
|
|
|
|
|
|
|
|
|
|
var image_p = w > h ? 'landscape' : 'portrait'
|
|
|
|
|
|
|
|
|
|
// when the image is turned 90deg/270deg and its
|
|
|
|
|
// proportions are the same as the screen...
|
|
|
|
|
if((o == 90 || o == 270) && image_p == viewer_p){
|
|
|
|
|
image.css({
|
|
|
|
|
width: h,
|
|
|
|
|
height: w,
|
|
|
|
|
})
|
|
|
|
|
image.css({
|
|
|
|
|
'margin-top': -((w - h)/2),
|
|
|
|
|
'margin-bottom': -((w - h)/2),
|
|
|
|
|
'margin-left': (w - h)/2,
|
|
|
|
|
'margin-right': (w - h)/2,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
} else if((o == 0 || o == 180) && image_p != viewer_p){
|
|
|
|
|
image.css({
|
|
|
|
|
width: h,
|
|
|
|
|
height: w,
|
|
|
|
|
})
|
|
|
|
|
image.css({
|
|
|
|
|
'margin': '',
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// square image...
|
|
|
|
|
} else {
|
|
|
|
|
image.css({
|
|
|
|
|
'margin': '',
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
2014-07-25 02:00:50 +04:00
|
|
|
},
|
|
|
|
|
|
2014-07-24 16:05:59 +04:00
|
|
|
// 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
|
|
|
|
|
|
|
|
|
2014-07-28 06:36:02 +04:00
|
|
|
_setup: function(viewer, images){
|
2014-07-20 02:25:36 +04:00
|
|
|
this.viewer = $(viewer)
|
2014-07-28 06:36:02 +04:00
|
|
|
this.images = images
|
2014-07-20 02:25:36 +04:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Main Ribbons object...
|
|
|
|
|
//
|
2014-07-21 18:33:31 +04:00
|
|
|
var Ribbons =
|
|
|
|
|
module.Ribbons =
|
2014-07-28 06:36:02 +04:00
|
|
|
function Ribbons(viewer, images){
|
2014-07-20 02:25:36 +04:00
|
|
|
// in case this is called as a function (without new)...
|
|
|
|
|
if(this.constructor.name != 'Ribbons'){
|
2014-07-28 19:45:51 +04:00
|
|
|
return new Ribbons(viewer, images)
|
2014-07-20 02:25:36 +04:00
|
|
|
}
|
|
|
|
|
|
2014-07-28 06:36:02 +04:00
|
|
|
this._setup(viewer, images)
|
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 })
|