2013-04-26 05:30:56 +04:00
|
|
|
/**********************************************************************
|
|
|
|
|
*
|
2013-05-02 19:47:04 +04:00
|
|
|
* Viewer Generation III
|
|
|
|
|
*
|
|
|
|
|
* Split the API into the following sections:
|
|
|
|
|
* - main control actions
|
|
|
|
|
* do main domain tasks like image and ribbon manipulation.
|
|
|
|
|
* - serialization and deserialization
|
|
|
|
|
* load and save data
|
|
|
|
|
* - UI
|
|
|
|
|
* basic align, animation and modes
|
|
|
|
|
*
|
|
|
|
|
*
|
2013-05-05 19:53:06 +04:00
|
|
|
* TODO wrap the actions into an object and make all queries relative to
|
|
|
|
|
* a single root viewer...
|
|
|
|
|
* ...this will make the code reusable multiple times...
|
2013-04-26 05:30:56 +04:00
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
2013-12-15 18:56:21 +04:00
|
|
|
var CONFIG = {
|
2014-01-15 07:05:50 +04:00
|
|
|
min_image_size: 100,
|
2013-12-15 18:56:21 +04:00
|
|
|
zoom_step_scale: 1.2,
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-10 16:10:16 +04:00
|
|
|
// can be:
|
|
|
|
|
// - animate
|
|
|
|
|
// - css
|
2013-05-17 15:34:45 +04:00
|
|
|
var TRANSITION_MODE_DEFAULT = 'animate'
|
2013-05-13 02:31:09 +04:00
|
|
|
|
|
|
|
|
|
2013-04-26 05:30:56 +04:00
|
|
|
|
|
|
|
|
/**********************************************************************
|
2013-05-02 19:47:04 +04:00
|
|
|
* Helpers
|
2013-04-26 05:30:56 +04:00
|
|
|
*/
|
|
|
|
|
|
2013-05-19 17:43:28 +04:00
|
|
|
// Match the results of two functions
|
|
|
|
|
//
|
|
|
|
|
// If the results are not the same then print a warning.
|
|
|
|
|
//
|
|
|
|
|
// NOTE: this is here for testing.
|
|
|
|
|
// NOTE: this expects that none of the functions will modify the
|
|
|
|
|
// arguments...
|
|
|
|
|
// NOTE: this will return the result of the first function.
|
|
|
|
|
function match2(f0, f1){
|
|
|
|
|
return function(){
|
|
|
|
|
var a = f0.apply(f0, arguments)
|
|
|
|
|
var b = f1.apply(f1, arguments)
|
|
|
|
|
if(a != b){
|
|
|
|
|
console.warn('Result mismatch: f0:'+a+' f1:'+b)
|
|
|
|
|
}
|
|
|
|
|
return a
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-06-03 04:40:55 +04:00
|
|
|
|
|
|
|
|
|
2013-05-19 17:43:28 +04:00
|
|
|
// Same as match2 but can take an arbitrary number of functions.
|
|
|
|
|
// XXX test
|
|
|
|
|
function matchN(){
|
2013-05-19 22:48:28 +04:00
|
|
|
var funcs = arguments
|
2013-05-19 17:43:28 +04:00
|
|
|
return function(){
|
|
|
|
|
var res = []
|
|
|
|
|
var err = false
|
|
|
|
|
var r
|
|
|
|
|
// call everything...
|
|
|
|
|
for(var i=0; i < funcs.lenght; i++){
|
|
|
|
|
r = f0.apply(f0, arguments)
|
|
|
|
|
// match the results...
|
|
|
|
|
if(r != res[res.length-1]){
|
|
|
|
|
err = false
|
|
|
|
|
}
|
|
|
|
|
res.push(r)
|
|
|
|
|
}
|
|
|
|
|
if(err){
|
|
|
|
|
console.warn('Not all results matched:', r)
|
|
|
|
|
}
|
|
|
|
|
return res[0]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-05-03 04:18:47 +04:00
|
|
|
// XXX might need shift left/right indicators (later)...
|
|
|
|
|
|
|
|
|
|
|
2013-05-14 18:10:33 +04:00
|
|
|
function getImage(gid){
|
2013-05-28 21:59:38 +04:00
|
|
|
var res
|
|
|
|
|
// current or first (no gid given)
|
|
|
|
|
if(gid == null){
|
|
|
|
|
res = $('.current.image')
|
|
|
|
|
return res.length == 0 ? $('.image').first() : res
|
2013-05-14 18:10:33 +04:00
|
|
|
}
|
2013-05-28 21:59:38 +04:00
|
|
|
|
2013-06-02 23:07:18 +04:00
|
|
|
// order...
|
|
|
|
|
if(typeof(gid) == typeof(1)){
|
|
|
|
|
res = $('.image[order="'+ JSON.stringify(gid) +'"]')
|
|
|
|
|
if(res.length != null){
|
|
|
|
|
return res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-14 18:10:33 +04:00
|
|
|
// gid...
|
2013-06-02 23:07:18 +04:00
|
|
|
res = $('.image[gid="'+ JSON.stringify(gid) +'"]')
|
2013-05-28 21:59:38 +04:00
|
|
|
if(res.length != null){
|
|
|
|
|
return res
|
|
|
|
|
}
|
2013-05-14 18:10:33 +04:00
|
|
|
|
2013-05-28 21:59:38 +04:00
|
|
|
return null
|
2013-05-05 23:39:35 +04:00
|
|
|
}
|
|
|
|
|
|
2013-05-06 23:43:38 +04:00
|
|
|
|
2013-05-06 02:18:36 +04:00
|
|
|
function getImageOrder(image){
|
2013-05-28 21:59:38 +04:00
|
|
|
image = image == null ? getImage() : $(image)
|
2013-05-06 02:18:36 +04:00
|
|
|
if(image.length == 0){
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
return JSON.parse(image.attr('order'))
|
|
|
|
|
}
|
2013-05-06 23:43:38 +04:00
|
|
|
|
|
|
|
|
|
2013-05-06 02:18:36 +04:00
|
|
|
function getImageGID(image){
|
2013-05-28 21:59:38 +04:00
|
|
|
image = image == null ? getImage() : $(image)
|
2013-05-06 02:18:36 +04:00
|
|
|
if(image.length == 0){
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
return JSON.parse(image.attr('gid'))
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-06 23:43:38 +04:00
|
|
|
|
2013-12-26 03:57:32 +04:00
|
|
|
// Get mark elements associated with image...
|
2013-12-04 23:18:23 +04:00
|
|
|
//
|
|
|
|
|
// img can be:
|
|
|
|
|
// - literal gid
|
|
|
|
|
// - image
|
|
|
|
|
// - null -- assume current image
|
|
|
|
|
//
|
|
|
|
|
// NOTE: this does not understand selectors as arguments...
|
|
|
|
|
function getImageMarks(img){
|
|
|
|
|
gid = typeof(img) == typeof('str') ? img : null
|
|
|
|
|
gid = gid == null ? getImageGID(img) : gid
|
|
|
|
|
|
|
|
|
|
return $('.mark.'+gid)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-11-19 06:00:26 +04:00
|
|
|
function getRibbon(a){
|
|
|
|
|
a = a == null ? getImage() : a
|
|
|
|
|
|
|
|
|
|
// a is an index...
|
|
|
|
|
if(typeof(a) == typeof(123)){
|
|
|
|
|
return $($('.ribbon')[a])
|
|
|
|
|
|
|
|
|
|
// a is a gid...
|
|
|
|
|
} else if(typeof(a) == typeof('str')){
|
|
|
|
|
a = getImage(a)
|
|
|
|
|
|
|
|
|
|
// a was an elem...
|
|
|
|
|
} else {
|
|
|
|
|
a = $(a)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// a is an element...
|
|
|
|
|
return a.closest('.ribbon')
|
2013-05-28 21:59:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-09-13 23:13:16 +04:00
|
|
|
// XXX make this not depend on DOM... a-la getImageBefore vs. getGIDBefore
|
2013-05-28 21:59:38 +04:00
|
|
|
// NOTE: elem is optional and if given can be an image or a ribbon...
|
|
|
|
|
function getRibbonIndex(elem){
|
|
|
|
|
if(elem == null){
|
|
|
|
|
var ribbon = getRibbon()
|
|
|
|
|
} else {
|
|
|
|
|
elem = $(elem)
|
|
|
|
|
if(elem.hasClass('image')){
|
|
|
|
|
ribbon = getRibbon(elem)
|
|
|
|
|
} else {
|
|
|
|
|
ribbon = elem
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $('.ribbon').index(ribbon)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-05-06 23:43:38 +04:00
|
|
|
// Calculate relative position between two elements
|
|
|
|
|
//
|
2013-05-17 02:30:24 +04:00
|
|
|
// NOTE: tried to make this as brain-dead-stupidly-simple as possible...
|
|
|
|
|
// ...looks spectacular comparing to either gen2 or gen1 ;)
|
|
|
|
|
// NOTE: if used during an animation/transition this will give the
|
|
|
|
|
// position at the exact frame of the animation, this might not be
|
|
|
|
|
// the desired "final" data...
|
2013-05-02 19:47:04 +04:00
|
|
|
function getRelativeVisualPosition(outer, inner){
|
|
|
|
|
outer = $(outer).offset()
|
|
|
|
|
inner = $(inner).offset()
|
|
|
|
|
return {
|
|
|
|
|
top: inner.top - outer.top,
|
|
|
|
|
left: inner.left - outer.left
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-05-03 04:18:47 +04:00
|
|
|
// Returns the image size (width) as viewed on screen...
|
2013-05-17 16:03:40 +04:00
|
|
|
//
|
2013-05-17 16:21:03 +04:00
|
|
|
// dim can be:
|
|
|
|
|
// - 'width' (default)
|
|
|
|
|
// - 'height'
|
|
|
|
|
// - 'min'
|
|
|
|
|
// - 'max'
|
2013-05-23 22:51:04 +04:00
|
|
|
//
|
2013-05-30 07:29:07 +04:00
|
|
|
// NOTE: we do not need to worry about rotation here as the size change is
|
|
|
|
|
// compensated with margins...
|
2013-05-17 16:03:40 +04:00
|
|
|
function getVisibleImageSize(dim){
|
2013-05-17 16:21:03 +04:00
|
|
|
dim = dim == null ? 'width' : dim
|
|
|
|
|
var scale = getElementScale($('.ribbon-set'))
|
|
|
|
|
if(dim == 'height'){
|
2013-05-23 23:01:21 +04:00
|
|
|
return $('.image').outerHeight(true) * scale
|
2013-05-17 16:21:03 +04:00
|
|
|
} else if(dim == 'width'){
|
2013-05-23 23:01:21 +04:00
|
|
|
return $('.image').outerWidth(true) * scale
|
2013-05-17 16:21:03 +04:00
|
|
|
} else if(dim == 'max'){
|
2013-05-23 23:01:21 +04:00
|
|
|
return Math.max($('.image').outerHeight(true), $('.image').outerWidth(true)) * scale
|
2013-05-17 16:21:03 +04:00
|
|
|
} else if(dim == 'min'){
|
2013-05-23 23:01:21 +04:00
|
|
|
return Math.min($('.image').outerHeight(true), $('.image').outerWidth(true)) * scale
|
2013-05-17 16:21:03 +04:00
|
|
|
}
|
2013-05-03 02:27:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-05-03 04:18:47 +04:00
|
|
|
// Return the number of images that can fit to viewer width...
|
2013-12-18 02:18:14 +04:00
|
|
|
function getScreenWidthInImages(size, dim){
|
|
|
|
|
size = size == null ? getVisibleImageSize(dim) : size
|
2013-05-17 01:04:20 +04:00
|
|
|
return $('.viewer').innerWidth() / size
|
2013-05-03 02:27:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-05-03 17:08:59 +04:00
|
|
|
// NOTE: this will return an empty jquery object if no image is before
|
|
|
|
|
// the target...
|
2013-05-02 23:48:55 +04:00
|
|
|
// NOTE: this might return an empty target if the ribbon is empty...
|
2013-05-06 23:43:38 +04:00
|
|
|
// NOTE: this only "sees" the loaded images, for a full check use
|
|
|
|
|
// getGIDBefore(...) that will check the full data...
|
2013-07-03 20:44:24 +04:00
|
|
|
function getImageBefore(image, ribbon){
|
2013-05-28 21:59:38 +04:00
|
|
|
image = image == null ? getImage() : $(image)
|
2013-05-02 19:47:04 +04:00
|
|
|
if(ribbon == null){
|
2013-05-05 19:53:06 +04:00
|
|
|
ribbon = getRibbon(image)
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
2013-07-03 20:44:24 +04:00
|
|
|
var images = $(ribbon).find('.image')
|
2013-05-13 02:45:36 +04:00
|
|
|
var order = getImageOrder(image)
|
2013-05-03 17:08:59 +04:00
|
|
|
var prev = []
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
images.each(function(){
|
2013-05-13 02:45:36 +04:00
|
|
|
if(order < getImageOrder($(this))){
|
2013-05-02 19:47:04 +04:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
prev = this
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return $(prev)
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-06 23:43:38 +04:00
|
|
|
|
2013-12-26 03:57:32 +04:00
|
|
|
// NOTE: this just shifts the image, it does not care about either
|
|
|
|
|
// aligning nor focus...
|
|
|
|
|
// NOTE: the shiftedImage event is fired BEFORE any ribbons are removed...
|
2013-05-02 19:47:04 +04:00
|
|
|
function shiftTo(image, ribbon){
|
2013-07-03 20:44:24 +04:00
|
|
|
var target = getImageBefore(image, ribbon)
|
2013-05-05 19:53:06 +04:00
|
|
|
var cur_ribbon = getRibbon(image)
|
2013-12-04 23:18:23 +04:00
|
|
|
var marks = getImageMarks(image)
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
// insert before the first image if nothing is before the target...
|
|
|
|
|
if(target.length == 0){
|
|
|
|
|
image.prependTo($(ribbon))
|
|
|
|
|
|
2013-12-26 03:57:32 +04:00
|
|
|
// insert the image...
|
|
|
|
|
// NOTE: we need to take care to insert the image not just after the
|
|
|
|
|
// target, but also after the target's marks...
|
2013-05-02 19:47:04 +04:00
|
|
|
} else {
|
2013-12-04 23:18:23 +04:00
|
|
|
var target_marks = getImageMarks(target).last()
|
|
|
|
|
image.insertAfter(
|
|
|
|
|
// if target has marks, insert after them...
|
|
|
|
|
target_marks.length > 0
|
|
|
|
|
? target_marks
|
|
|
|
|
: target)
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
|
|
|
|
|
2013-12-04 23:18:23 +04:00
|
|
|
// move the marks...
|
|
|
|
|
image.after(marks)
|
|
|
|
|
|
2013-12-26 03:57:32 +04:00
|
|
|
// NOTE: this is intentionally fired BEFORE removing a ribbon...
|
2013-05-05 23:39:35 +04:00
|
|
|
$('.viewer').trigger('shiftedImage', [image, cur_ribbon, ribbon])
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
// if removing last image out of a ribbon, remove the ribbon....
|
|
|
|
|
if(cur_ribbon.find('.image').length == 0){
|
2013-05-06 05:57:38 +04:00
|
|
|
// XXX check if the ribbon outside the loaded area is empty...
|
2013-05-17 02:30:24 +04:00
|
|
|
// ...do we need this check? it might be interesting to
|
2013-05-06 05:57:38 +04:00
|
|
|
// "collapse" disjoint, empty areas...
|
|
|
|
|
// ......if so, will also need to do this in DATA...
|
2013-05-05 23:39:35 +04:00
|
|
|
removeRibbon(cur_ribbon)
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return image
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-06 23:43:38 +04:00
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
function shiftImage(direction, image, force_create_ribbon){
|
2013-05-28 21:59:38 +04:00
|
|
|
image = image == null ? getImage() : $(image)
|
2013-05-05 19:53:06 +04:00
|
|
|
var old_ribbon = getRibbon(image)
|
2013-05-02 19:47:04 +04:00
|
|
|
var ribbon = old_ribbon[direction]('.ribbon')
|
|
|
|
|
|
|
|
|
|
// need to create a new ribbon...
|
|
|
|
|
if(ribbon.length == 0 || force_create_ribbon == true){
|
2013-05-05 23:39:35 +04:00
|
|
|
var index = getRibbonIndex(old_ribbon)
|
2013-05-07 00:26:35 +04:00
|
|
|
index = direction == 'next' ? index + 1 : index
|
2013-05-05 23:39:35 +04:00
|
|
|
|
|
|
|
|
ribbon = createRibbon(index)
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
shiftTo(image, ribbon)
|
|
|
|
|
} else {
|
|
|
|
|
shiftTo(image, ribbon)
|
|
|
|
|
}
|
|
|
|
|
return image
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-05-02 22:32:20 +04:00
|
|
|
/**********************************************************************
|
|
|
|
|
* Constructors
|
|
|
|
|
*/
|
|
|
|
|
|
2013-05-06 23:43:38 +04:00
|
|
|
// NOTE: unless force_create_new is set to true this will clone an
|
|
|
|
|
// image if one is available...
|
|
|
|
|
// NOTE: this will not attach the created images.
|
|
|
|
|
function createImage(n, force_create_new){
|
2013-05-02 22:32:20 +04:00
|
|
|
if(n == null){
|
2013-05-17 02:30:24 +04:00
|
|
|
// XXX do we need this?
|
2013-05-02 22:32:20 +04:00
|
|
|
if(window._n == null){
|
|
|
|
|
window._n = 0
|
|
|
|
|
}
|
|
|
|
|
n = _n
|
|
|
|
|
_n += 1
|
|
|
|
|
}
|
|
|
|
|
var img = $('.image')
|
2013-05-06 23:43:38 +04:00
|
|
|
if(!force_create_new && img.length > 0){
|
2013-05-02 22:32:20 +04:00
|
|
|
return img.first().clone()
|
|
|
|
|
.attr({
|
2013-05-05 23:39:35 +04:00
|
|
|
'order': JSON.stringify(n),
|
|
|
|
|
'gid': JSON.stringify(n),
|
2013-05-02 22:32:20 +04:00
|
|
|
// need to strip extra classes...
|
|
|
|
|
'class': 'image'
|
|
|
|
|
})
|
|
|
|
|
} else {
|
2013-12-04 23:18:23 +04:00
|
|
|
return $('<div/>')
|
|
|
|
|
.attr({
|
|
|
|
|
order: n,
|
|
|
|
|
gid: JSON.stringify(n),
|
|
|
|
|
// need to strip extra classes...
|
|
|
|
|
'class': 'image',
|
|
|
|
|
})
|
2013-05-02 22:32:20 +04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-06 23:43:38 +04:00
|
|
|
|
|
|
|
|
// Create a set of new images, reusing a list of existing elements if
|
|
|
|
|
// given.
|
|
|
|
|
// NOTE: this will not attach the created images.
|
2013-05-02 22:32:20 +04:00
|
|
|
function createImages(need, have){
|
2013-05-12 18:07:31 +04:00
|
|
|
have = have == null ? $([]) : $(have)
|
2013-05-02 22:32:20 +04:00
|
|
|
|
|
|
|
|
// we have enough elements in the cache...
|
|
|
|
|
if(have.length >= need){
|
|
|
|
|
return $(have.splice(0, need))
|
|
|
|
|
|
|
|
|
|
// need to create additional elements...
|
|
|
|
|
} else {
|
|
|
|
|
return $(have.toArray().concat(new Array(need - have.length)))
|
|
|
|
|
.map(function(i, elem){
|
|
|
|
|
if(elem != null){
|
|
|
|
|
return elem
|
|
|
|
|
}
|
|
|
|
|
return createImage()[0]
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-06 23:43:38 +04:00
|
|
|
|
|
|
|
|
// NOTE: if index is given, this will also attach the created ribbon to
|
2013-12-28 06:17:05 +04:00
|
|
|
// that position and trigger the event...
|
2013-05-05 23:39:35 +04:00
|
|
|
function createRibbon(index){
|
|
|
|
|
var ribbon = $('<div class="ribbon"/>')
|
|
|
|
|
|
|
|
|
|
if(index == null){
|
|
|
|
|
return ribbon
|
|
|
|
|
}
|
|
|
|
|
var ribbons = $('.ribbon')
|
|
|
|
|
if(index >= ribbons.length){
|
|
|
|
|
ribbons.last().after(ribbon)
|
|
|
|
|
} else {
|
|
|
|
|
ribbons.eq(index).before(ribbon)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$('.viewer').trigger('createdRibbon', [ribbon])
|
|
|
|
|
|
|
|
|
|
return ribbon
|
2013-05-02 22:32:20 +04:00
|
|
|
}
|
|
|
|
|
|
2013-05-06 23:43:38 +04:00
|
|
|
|
2013-05-05 23:39:35 +04:00
|
|
|
// NOTE: this will pass the index where the ribbon was to the event,
|
|
|
|
|
// rather than an actual ribbon...
|
2013-05-06 05:57:38 +04:00
|
|
|
// XXX check if ribbon is empty...
|
2013-05-05 23:39:35 +04:00
|
|
|
function removeRibbon(ribbon){
|
|
|
|
|
// ribbon can be an index...
|
|
|
|
|
if(typeof(ribbon) == typeof(1)){
|
|
|
|
|
ribbon = $('.ribbon').eq(ribbon)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$('.viewer').trigger('removedRibbon', [getRibbonIndex(ribbon)])
|
|
|
|
|
|
|
|
|
|
return $(ribbon).remove()
|
|
|
|
|
}
|
2013-05-02 22:32:20 +04:00
|
|
|
|
|
|
|
|
|
2013-05-06 05:57:38 +04:00
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
|
* Infinite ribbon machinery
|
|
|
|
|
*/
|
|
|
|
|
|
2013-05-14 16:21:45 +04:00
|
|
|
// Extend the ribbon...
|
|
|
|
|
//
|
|
|
|
|
// This will add/remove images to/from ribbon's head and/or tail.
|
|
|
|
|
//
|
|
|
|
|
// NOTE: negative left or right will contract the ribbon -- remove
|
|
|
|
|
// elements...
|
2013-05-13 18:16:16 +04:00
|
|
|
// NOTE: this will compensate for left position changes so as the images
|
|
|
|
|
// that did not change will stay in the same position.
|
|
|
|
|
// to disable this, set no_compensate_shift to true.
|
2013-11-15 01:27:22 +04:00
|
|
|
//
|
2013-05-14 16:21:45 +04:00
|
|
|
// NOTE: for position compensation to work with scaling need to set the
|
|
|
|
|
// origin on the scaled element ($('.ribbon-set')) to top left
|
|
|
|
|
// (instead of the default 50% 50% 0) to avoid element size
|
|
|
|
|
// affecting it's perceived position...
|
2013-11-15 01:27:22 +04:00
|
|
|
// NOTE: this will remove everything out of a ribbon if left/right are
|
|
|
|
|
// more than the length of the ribbon...
|
2013-05-13 18:16:16 +04:00
|
|
|
function extendRibbon(left, right, ribbon, no_compensate_shift){
|
2013-12-04 23:18:23 +04:00
|
|
|
ribbon = ribbon == null ? getRibbon() : $(ribbon)
|
2013-05-06 05:57:38 +04:00
|
|
|
left = left == null ? 0 : left
|
|
|
|
|
right = right == null ? 0 : right
|
|
|
|
|
var images = ribbon.children('.image')
|
2013-11-15 01:27:22 +04:00
|
|
|
|
|
|
|
|
// total length of the result...
|
|
|
|
|
var len = left + right + images.length
|
|
|
|
|
len = len < 0 ? 0 : len
|
|
|
|
|
var cur_len = images.length
|
|
|
|
|
|
2013-05-06 05:57:38 +04:00
|
|
|
var removed = []
|
|
|
|
|
var res = {
|
|
|
|
|
left: $([]),
|
|
|
|
|
right: $([])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// truncate...
|
|
|
|
|
// NOTE: we save the detached elements to reuse them on extending,
|
|
|
|
|
// if needed...
|
|
|
|
|
if(left < 0){
|
2013-11-16 02:22:21 +04:00
|
|
|
removed = removed.concat($(images.splice(0, -left)).detach().toArray())
|
2013-05-06 05:57:38 +04:00
|
|
|
}
|
|
|
|
|
if(right < 0){
|
|
|
|
|
var l = images.length
|
2013-11-16 02:22:21 +04:00
|
|
|
removed = removed.concat($(images.splice(l+right, l)).detach().toArray())
|
2013-05-06 05:57:38 +04:00
|
|
|
}
|
2013-11-15 01:27:22 +04:00
|
|
|
// calculate the maximum number of new elements left to create...
|
|
|
|
|
cur_len -= removed.length
|
|
|
|
|
len -= cur_len
|
2013-05-06 05:57:38 +04:00
|
|
|
|
|
|
|
|
// extend...
|
2013-11-15 01:27:22 +04:00
|
|
|
// XXX do we need to balance the len between left/right...
|
|
|
|
|
// ...likely no.
|
2013-05-06 05:57:38 +04:00
|
|
|
if (left > 0){
|
2013-11-15 01:27:22 +04:00
|
|
|
left = left > len ? len : left
|
2013-05-06 05:57:38 +04:00
|
|
|
res.left = createImages(left, removed).prependTo(ribbon)
|
|
|
|
|
}
|
|
|
|
|
if (right > 0){
|
2013-11-15 01:27:22 +04:00
|
|
|
right = right > len ? len : right
|
2013-05-06 05:57:38 +04:00
|
|
|
res.right = createImages(right, removed).appendTo(ribbon)
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-04 23:18:23 +04:00
|
|
|
// cleanup...
|
|
|
|
|
$(removed).each(function(){
|
|
|
|
|
getImageMarks($(this)).remove()
|
|
|
|
|
})
|
|
|
|
|
|
2013-11-15 01:27:22 +04:00
|
|
|
// compensate the position...
|
2013-05-13 17:44:24 +04:00
|
|
|
// NOTE: this is fool-proof as it's based on relative visual
|
|
|
|
|
// position...
|
2013-06-05 00:42:41 +04:00
|
|
|
//var scale = getElementScale($('.ribbon-set'))
|
2013-05-13 17:59:19 +04:00
|
|
|
var l = parseFloat(ribbon.css('left'))
|
|
|
|
|
l = isNaN(l) ? 0 : l
|
2013-05-13 18:16:16 +04:00
|
|
|
// compensate for left shift...
|
|
|
|
|
if(!no_compensate_shift && left != 0){
|
2013-06-15 02:45:19 +04:00
|
|
|
l -= left * images.outerWidth(true)
|
2013-05-14 16:04:57 +04:00
|
|
|
|
2013-05-06 05:57:38 +04:00
|
|
|
ribbon.css({
|
2013-05-13 17:59:19 +04:00
|
|
|
left: l,
|
2013-05-06 05:57:38 +04:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Roll the ribbon n positions to the left.
|
|
|
|
|
//
|
|
|
|
|
// NOTE: if n is negative the ribbon will be rolled right.
|
|
|
|
|
// NOTE: rollRibbon(N, R) is equivalent to extendRibbon(-N, N, R)
|
|
|
|
|
// NOTE: this will return a single list of relocated elements...
|
2013-11-25 04:27:20 +04:00
|
|
|
// NOTE: if extend is non-zero the extension will happen ONLY in the
|
|
|
|
|
// direction of the roll...
|
2013-05-14 00:01:03 +04:00
|
|
|
function rollRibbon(n, ribbon, extend, no_compensate_shift){
|
2013-11-25 04:27:20 +04:00
|
|
|
var l = extend == null || n >= 0 ? 0 : extend
|
|
|
|
|
var r = extend == null || n < 0 ? 0 : extend
|
|
|
|
|
var res = extendRibbon(-n-l, n+r, ribbon, no_compensate_shift)
|
2013-05-06 05:57:38 +04:00
|
|
|
return n > 0 ? res.right : res.left
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
/**********************************************************************
|
|
|
|
|
* Layout
|
2013-04-26 05:30:56 +04:00
|
|
|
*/
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
function focusImage(image){
|
2013-11-25 03:01:56 +04:00
|
|
|
image = typeof(image) == typeof('str') ? getImage(image) : image
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
image.closest('.viewer').find('.current.image').removeClass('current')
|
2013-06-13 01:37:30 +04:00
|
|
|
image.addClass('current')
|
2013-05-12 18:29:16 +04:00
|
|
|
$('.viewer').trigger('focusingImage', [image])
|
2013-06-13 01:37:30 +04:00
|
|
|
return image
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
|
2013-05-03 15:58:22 +04:00
|
|
|
/*
|
2013-05-06 23:43:38 +04:00
|
|
|
// Generic align
|
|
|
|
|
//
|
2013-05-03 15:58:22 +04:00
|
|
|
// XXX need to split this into two:
|
|
|
|
|
// - offset calculator
|
|
|
|
|
// - actual move
|
|
|
|
|
// XXX this does not account for scale at this point...
|
|
|
|
|
// XXX for this to be generic, need a uniform way to get any element scale
|
|
|
|
|
// regardless of weather it was scaled directly or is within one or
|
|
|
|
|
// several scaled elements...
|
|
|
|
|
function alignVia(container, elem, via, valign, halign, mode){
|
|
|
|
|
container = $(container)
|
|
|
|
|
elem = $(elem)
|
|
|
|
|
via = $(via)
|
|
|
|
|
|
|
|
|
|
valign = valign == null ? 'center' : valign
|
|
|
|
|
halign = halign == null ? 'center' : halign
|
2013-05-17 15:34:45 +04:00
|
|
|
mode = mode == null ? TRANSITION_MODE_DEFAULT : mode
|
2013-05-03 15:58:22 +04:00
|
|
|
|
|
|
|
|
var pos = getRelativeVisualPosition(container, elem)
|
|
|
|
|
var dt = pos.top
|
|
|
|
|
var dl = pos.left
|
|
|
|
|
var target = {}
|
|
|
|
|
|
|
|
|
|
var t = parseFloat(via.css('top'))
|
|
|
|
|
t = !isNaN(t) ? t : 0
|
|
|
|
|
var l = parseFloat(via.css('left'))
|
|
|
|
|
l = !isNaN(l) ? l : 0
|
|
|
|
|
|
|
|
|
|
if(valign == 'center'){
|
|
|
|
|
var H = container.innerHeight()
|
2013-06-15 03:04:06 +04:00
|
|
|
var h = elem.outerHeight(true)
|
2013-05-03 15:58:22 +04:00
|
|
|
target.top = t - dt + (H - h)/2,
|
|
|
|
|
} else if(valign == 'top'){
|
|
|
|
|
target.top = t - dt
|
|
|
|
|
} else if(valign == 'bottom'){
|
2013-06-15 03:04:06 +04:00
|
|
|
var h = elem.outerHeight(true)
|
2013-05-03 15:58:22 +04:00
|
|
|
target.top = t - dt - h
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(halign == 'center'){
|
|
|
|
|
var W = container.innerWidth()
|
2013-06-15 03:04:06 +04:00
|
|
|
var w = elem.outerWidth(true)
|
2013-05-03 15:58:22 +04:00
|
|
|
target.left = l - dl + (W - w)/2
|
|
|
|
|
} else if(halign == 'left'){
|
|
|
|
|
target.left = l - dl
|
|
|
|
|
} else if(halign == 'right'){
|
2013-06-15 03:04:06 +04:00
|
|
|
var w = elem.outerWidth(true)
|
2013-05-03 15:58:22 +04:00
|
|
|
target.left = l - dl - w
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// do the actual work...
|
|
|
|
|
if(mode == 'animate'){
|
|
|
|
|
via.stop().animate(target, 100, 'linear')
|
|
|
|
|
} else {
|
|
|
|
|
via.css(target)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// XXX ???
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
2013-05-06 23:43:38 +04:00
|
|
|
// XXX make this more configurable (centering, ...)...
|
2013-06-07 04:27:49 +04:00
|
|
|
// XXX do a version using setElementTransform(...)
|
2013-05-13 01:33:13 +04:00
|
|
|
function centerView(image, mode){
|
2013-05-17 15:34:45 +04:00
|
|
|
mode = mode == null ? TRANSITION_MODE_DEFAULT : mode
|
2013-05-06 21:16:30 +04:00
|
|
|
|
2013-05-13 01:33:13 +04:00
|
|
|
$('.viewer').trigger('preCenteringView', [getRibbon(image), image])
|
2013-05-06 21:16:30 +04:00
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
if(image == null || image.length == 0){
|
2013-05-28 21:59:38 +04:00
|
|
|
image = getImage()
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
|
|
|
|
var viewer = $('.viewer')
|
|
|
|
|
// XXX should these be "inner"???
|
|
|
|
|
var W = viewer.innerWidth()
|
|
|
|
|
var H = viewer.innerHeight()
|
|
|
|
|
|
|
|
|
|
var ribbons = $('.ribbon-set')
|
|
|
|
|
var scale = getElementScale(ribbons)
|
|
|
|
|
// NOTE: these are scalable, this needs to get normalized...
|
2013-05-23 23:01:21 +04:00
|
|
|
var w = image.outerWidth(true)*scale
|
|
|
|
|
var h = image.outerHeight(true)*scale
|
2013-05-02 19:47:04 +04:00
|
|
|
|
2013-05-23 23:01:21 +04:00
|
|
|
var pos = getRelativeVisualPosition(viewer, image)
|
|
|
|
|
//var pos = getRelativeImagePosition(image)
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
// zero out top/left if set to anything other than a specific number...
|
|
|
|
|
var t = parseFloat(ribbons.css('top'))
|
2013-05-03 05:38:40 +04:00
|
|
|
t = !isNaN(t) ? t : 0
|
2013-05-02 19:47:04 +04:00
|
|
|
var l = parseFloat(ribbons.css('left'))
|
2013-05-03 05:38:40 +04:00
|
|
|
l = !isNaN(l) ? l : 0
|
2013-05-02 19:47:04 +04:00
|
|
|
|
2013-05-02 23:22:43 +04:00
|
|
|
|
|
|
|
|
var res = {
|
2013-05-02 19:47:04 +04:00
|
|
|
'top': t - pos.top + (H - h)/2,
|
|
|
|
|
'left': l - pos.left + (W - w)/2
|
2013-05-02 23:22:43 +04:00
|
|
|
}
|
|
|
|
|
// do the actual work...
|
|
|
|
|
if(mode == 'animate'){
|
2013-05-03 02:11:24 +04:00
|
|
|
ribbons.stop().animate(res, 100, 'linear')
|
2013-05-02 23:22:43 +04:00
|
|
|
} else {
|
2013-05-03 02:11:24 +04:00
|
|
|
ribbons.css(res)
|
2013-05-02 23:22:43 +04:00
|
|
|
}
|
2013-05-03 02:11:24 +04:00
|
|
|
|
2013-05-13 01:33:13 +04:00
|
|
|
$('.viewer').trigger('centeringView', [getRibbon(image), image])
|
2013-05-03 17:08:59 +04:00
|
|
|
|
2013-05-03 02:11:24 +04:00
|
|
|
return image
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
2013-05-02 19:47:04 +04:00
|
|
|
|
2013-05-03 15:58:22 +04:00
|
|
|
|
|
|
|
|
// Center a ribbon...
|
|
|
|
|
//
|
|
|
|
|
// This behaves differently for different ribbons:
|
2013-05-13 01:33:13 +04:00
|
|
|
// - ribbon containing the current image
|
|
|
|
|
// center
|
2013-05-03 15:58:22 +04:00
|
|
|
// - any other ribbon
|
|
|
|
|
// center relative to target (given) via the ribbon left
|
|
|
|
|
// only left coordinate is changed...
|
|
|
|
|
//
|
2013-05-28 21:59:38 +04:00
|
|
|
// NOTE: image defaults to getImage().
|
2013-05-03 15:58:22 +04:00
|
|
|
//
|
|
|
|
|
// XXX might be good to merge this and centerImage...
|
|
|
|
|
// ...or make a generic centering function...
|
|
|
|
|
//
|
2013-05-03 19:01:00 +04:00
|
|
|
// XXX this does not work in marked-only mode...
|
2013-05-06 23:43:38 +04:00
|
|
|
// XXX this needs the image to exist... should be GID compatible... (???)
|
2013-06-07 04:27:49 +04:00
|
|
|
// XXX do a version using setElementTransform(...)
|
2013-05-03 15:58:22 +04:00
|
|
|
function centerRibbon(ribbon, image, mode){
|
2013-05-17 15:34:45 +04:00
|
|
|
mode = mode == null ? TRANSITION_MODE_DEFAULT : mode
|
2013-05-25 14:24:29 +04:00
|
|
|
ribbon = ribbon == null ? getRibbon() : $(ribbon)
|
2013-05-28 21:59:38 +04:00
|
|
|
image = image == null ? getImage() : $(image)
|
2013-05-03 05:38:40 +04:00
|
|
|
|
2013-05-06 21:16:30 +04:00
|
|
|
$('.viewer').trigger('preCenteringRibbon', [ribbon, image])
|
|
|
|
|
|
2013-05-03 05:38:40 +04:00
|
|
|
var scale = getElementScale($('.ribbon-set'))
|
2013-05-03 19:01:00 +04:00
|
|
|
var target = getImageBefore(image, ribbon, null)
|
2013-05-13 01:33:13 +04:00
|
|
|
var offset = 0
|
|
|
|
|
var l = parseFloat(ribbon.css('left'))
|
|
|
|
|
l = !isNaN(l) ? l : 0
|
2013-05-23 23:01:21 +04:00
|
|
|
var w = $('.image').outerWidth(true)
|
2013-05-13 01:33:13 +04:00
|
|
|
|
|
|
|
|
//if(ribbon.find('.image').index(image) >= 0){
|
|
|
|
|
if(ribbon.find('.current.image').length > 0){
|
|
|
|
|
offset = w/2
|
|
|
|
|
}
|
2013-05-03 05:38:40 +04:00
|
|
|
|
|
|
|
|
if(target.length > 0){
|
2013-05-23 23:01:21 +04:00
|
|
|
var dl = getRelativeVisualPosition(target, image).left/scale
|
2013-05-13 01:33:13 +04:00
|
|
|
l = {
|
|
|
|
|
left: l + dl - (w/2) + offset
|
|
|
|
|
}
|
2013-05-03 05:38:40 +04:00
|
|
|
|
2013-05-25 14:24:29 +04:00
|
|
|
// we are at the start of a ribbon -- nothing before...
|
2013-05-03 05:38:40 +04:00
|
|
|
} else {
|
2013-05-25 14:24:29 +04:00
|
|
|
// get first image in ribbon...
|
2013-07-03 20:44:24 +04:00
|
|
|
target = ribbon.find('.image').first()
|
2013-05-23 23:01:21 +04:00
|
|
|
var dl = getRelativeVisualPosition(target, image).left/scale
|
2013-05-13 01:33:13 +04:00
|
|
|
l = {
|
|
|
|
|
left: l + dl + (w/2) + offset
|
|
|
|
|
}
|
2013-05-03 05:38:40 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(mode == 'animate'){
|
|
|
|
|
ribbon.stop().animate(l, 100, 'linear')
|
|
|
|
|
} else {
|
2013-05-12 18:07:31 +04:00
|
|
|
ribbon.css(l)
|
2013-05-03 05:38:40 +04:00
|
|
|
}
|
|
|
|
|
|
2013-05-06 02:18:36 +04:00
|
|
|
$('.viewer').trigger('centeringRibbon', [ribbon, image])
|
2013-05-03 17:08:59 +04:00
|
|
|
|
2013-05-03 15:58:22 +04:00
|
|
|
// XXX should this return a ribbon or the target image???
|
2013-05-03 05:38:40 +04:00
|
|
|
return ribbon
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-06 23:43:38 +04:00
|
|
|
|
2013-05-03 05:38:40 +04:00
|
|
|
// a shorthand...
|
2013-12-09 21:56:53 +04:00
|
|
|
function centerRibbons(mode, no_skip_current, no_skip_hidden){
|
|
|
|
|
var R = $('.viewer').height()/2
|
|
|
|
|
var cur = getImage()
|
|
|
|
|
var h = cur.height()
|
|
|
|
|
|
2013-05-03 05:47:26 +04:00
|
|
|
return $('.ribbon')
|
2013-05-15 00:24:33 +04:00
|
|
|
.each(function(){
|
2013-12-09 21:56:53 +04:00
|
|
|
var ribbon = $(this)
|
|
|
|
|
|
2013-09-06 03:16:48 +04:00
|
|
|
// // skip empty ribbons...
|
|
|
|
|
// if($(this).find('.image').length == 0){
|
|
|
|
|
// return
|
|
|
|
|
// }
|
2013-12-09 21:56:53 +04:00
|
|
|
|
|
|
|
|
// skip ribbon containing current image...
|
|
|
|
|
if(no_skip_current == true && ribbon.find('.current.image').length > 0){
|
2013-05-15 00:24:33 +04:00
|
|
|
return
|
|
|
|
|
}
|
2013-12-09 21:56:53 +04:00
|
|
|
|
2013-12-09 21:59:18 +04:00
|
|
|
// skip hidden ribbons...
|
2013-12-09 21:56:53 +04:00
|
|
|
if(no_skip_hidden != true){
|
2013-12-09 21:59:18 +04:00
|
|
|
/* NOTE: this is commented out as it is not really needed now
|
|
|
|
|
* uncomment if a need arises...
|
|
|
|
|
// skip ribbons that are not visible or are not displayed...
|
|
|
|
|
// NOTE: we do not make an attempt to test each and every
|
|
|
|
|
// way a ribbon can be hidden...
|
|
|
|
|
if(ribbon.css('visibility') == 'hidden'
|
|
|
|
|
|| ribbon.css('display') == 'none'
|
|
|
|
|
|| ribbon.css('opacity') == 0){
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// skip ribbons outside of the viewer...
|
|
|
|
|
// NOTE: we are accounting for position relative to image...
|
|
|
|
|
// NOTE: we need to factor in image height as the distance is
|
|
|
|
|
// between cleanly ribbon centers will mean that half
|
|
|
|
|
// hidden ribbons will not get updated...
|
2013-12-09 21:56:53 +04:00
|
|
|
var d = Math.abs(getRelativeVisualPosition(cur, ribbon).top)
|
|
|
|
|
if( d - h/2 >= R ){
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
centerRibbon(ribbon, null, mode)
|
2013-05-15 00:24:33 +04:00
|
|
|
})
|
2013-05-03 05:38:40 +04:00
|
|
|
}
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
|
2013-05-05 23:39:35 +04:00
|
|
|
/**********************************************************************
|
|
|
|
|
* Event handlers...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// NOTE: this is on purpose done relative...
|
|
|
|
|
function clickHandler(evt){
|
|
|
|
|
var img = $(evt.target).closest('.image')
|
|
|
|
|
|
2013-07-03 20:44:24 +04:00
|
|
|
if(img.length > 0){
|
2013-05-17 15:48:39 +04:00
|
|
|
centerView(focusImage(img))
|
2013-05-05 23:39:35 +04:00
|
|
|
|
2013-05-17 15:48:39 +04:00
|
|
|
centerRibbons()
|
|
|
|
|
}
|
2013-05-05 23:39:35 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-06-07 01:36:49 +04:00
|
|
|
// XXX this does not work correctly because it also generates two clicks,
|
|
|
|
|
// and this messes things up...
|
2013-05-17 15:34:45 +04:00
|
|
|
function dblClickHandler(evt){
|
2013-06-07 01:36:49 +04:00
|
|
|
//setTimeout(toggleSingleImageMode, 100)
|
2013-05-17 15:34:45 +04:00
|
|
|
toggleSingleImageMode()
|
2013-06-07 01:36:49 +04:00
|
|
|
return false
|
2013-05-17 15:34:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-05-05 23:39:35 +04:00
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
/**********************************************************************
|
|
|
|
|
* User actions
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// basic navigation actions...
|
2013-07-03 20:44:24 +04:00
|
|
|
function nextImage(n){
|
2013-05-03 02:27:54 +04:00
|
|
|
n = n == null ? 1 : n
|
2013-07-03 20:44:24 +04:00
|
|
|
var target = getImage().nextAll('.image')
|
2013-05-03 19:24:06 +04:00
|
|
|
if(target.length < n){
|
|
|
|
|
target = target.last()
|
2013-06-13 01:37:30 +04:00
|
|
|
target = target.length == 0 ? getImage() : target
|
2013-05-14 16:21:45 +04:00
|
|
|
// XXX this fires if we hit the end of the currently loaded
|
2013-05-07 00:26:35 +04:00
|
|
|
// images while scrolling very fast rather than when we are
|
|
|
|
|
// out of images in the current ribbon...
|
2013-05-03 19:24:06 +04:00
|
|
|
flashIndicator('end')
|
|
|
|
|
} else {
|
|
|
|
|
target = target.eq(n-1)
|
|
|
|
|
}
|
2013-05-13 01:33:13 +04:00
|
|
|
return centerView(focusImage(target))
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
2013-07-03 20:44:24 +04:00
|
|
|
function prevImage(n){
|
2013-05-03 02:27:54 +04:00
|
|
|
n = n == null ? 1 : n
|
2013-07-03 20:44:24 +04:00
|
|
|
var target = getImage().prevAll('.image')
|
2013-05-03 19:24:06 +04:00
|
|
|
if(target.length < n){
|
|
|
|
|
target = target.last()
|
2013-06-13 01:37:30 +04:00
|
|
|
target = target.length == 0 ? getImage() : target
|
2013-05-14 16:21:45 +04:00
|
|
|
// XXX this fires if we hit the end of the currently loaded
|
2013-05-07 00:26:35 +04:00
|
|
|
// images while scrolling very fast rather than when we are
|
|
|
|
|
// out of images in the current ribbon...
|
2013-05-03 19:24:06 +04:00
|
|
|
flashIndicator('start')
|
|
|
|
|
} else {
|
|
|
|
|
target = target.eq(n-1)
|
|
|
|
|
}
|
2013-05-13 01:33:13 +04:00
|
|
|
return centerView(focusImage(target))
|
2013-05-03 02:27:54 +04:00
|
|
|
}
|
2013-05-06 23:43:38 +04:00
|
|
|
|
|
|
|
|
|
2013-07-03 20:44:24 +04:00
|
|
|
function nextScreenImages(){
|
2013-12-20 06:44:29 +04:00
|
|
|
return nextImage(Math.floor(getScreenWidthInImages())-1)
|
2013-05-03 02:27:54 +04:00
|
|
|
}
|
2013-07-03 20:44:24 +04:00
|
|
|
function prevScreenImages(){
|
2013-12-20 06:44:29 +04:00
|
|
|
return prevImage(Math.floor(getScreenWidthInImages())-1)
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
2013-05-06 23:43:38 +04:00
|
|
|
|
|
|
|
|
|
2013-05-03 19:24:06 +04:00
|
|
|
// XXX revise...
|
2013-07-03 20:44:24 +04:00
|
|
|
function firstImage(){
|
2013-05-05 19:53:06 +04:00
|
|
|
$('.viewer').trigger('requestedFirstImage', [getRibbon()])
|
|
|
|
|
|
2013-11-25 02:26:38 +04:00
|
|
|
// if we are already there, flash the indicator...
|
2013-07-03 20:44:24 +04:00
|
|
|
if(getImage().prevAll('.image').length == 0){
|
2013-05-03 19:24:06 +04:00
|
|
|
flashIndicator('start')
|
|
|
|
|
}
|
2013-05-13 01:33:13 +04:00
|
|
|
return centerView(
|
2013-05-02 19:47:04 +04:00
|
|
|
focusImage(
|
2013-07-03 20:44:24 +04:00
|
|
|
getRibbon().find('.image').first()))
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
2013-05-03 19:24:06 +04:00
|
|
|
// XXX revise...
|
2013-07-03 20:44:24 +04:00
|
|
|
function lastImage(){
|
2013-05-05 19:53:06 +04:00
|
|
|
$('.viewer').trigger('requestedLastImage', [getRibbon()])
|
|
|
|
|
|
2013-11-25 02:26:38 +04:00
|
|
|
// if we are already there, flash the indicator...
|
2013-07-03 20:44:24 +04:00
|
|
|
if(getImage().nextAll('.image').length == 0){
|
2013-05-03 19:24:06 +04:00
|
|
|
flashIndicator('end')
|
|
|
|
|
}
|
2013-05-13 01:33:13 +04:00
|
|
|
return centerView(
|
2013-05-02 19:47:04 +04:00
|
|
|
focusImage(
|
2013-07-03 20:44:24 +04:00
|
|
|
getRibbon().find('.image').last()))
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NOTE: if moving is 'next' these will chose the image after the current's order.
|
|
|
|
|
// NOTE: if an image with the same order is found, moving argument has no effect.
|
2013-07-03 20:44:24 +04:00
|
|
|
function prevRibbon(){
|
2013-05-28 21:59:38 +04:00
|
|
|
var cur = getImage()
|
2013-07-03 20:44:24 +04:00
|
|
|
var target_ribbon = getRibbon(cur).prevAll('.ribbon').first()
|
2013-06-08 02:29:14 +04:00
|
|
|
var target = getImageBefore(cur, target_ribbon)
|
|
|
|
|
|
2013-06-13 01:37:30 +04:00
|
|
|
// no ribbon above...
|
2013-06-08 02:29:14 +04:00
|
|
|
if(target_ribbon.length == 0){
|
|
|
|
|
flashIndicator('top')
|
2013-06-13 01:37:30 +04:00
|
|
|
target = getImage()
|
2013-05-20 17:42:18 +04:00
|
|
|
} else {
|
2013-06-13 01:37:30 +04:00
|
|
|
// first image...
|
|
|
|
|
if(target.length == 0){
|
2013-07-03 20:44:24 +04:00
|
|
|
target = target_ribbon.find('.image').first()
|
2013-06-13 01:37:30 +04:00
|
|
|
|
|
|
|
|
} else {
|
2013-07-03 20:44:24 +04:00
|
|
|
var next = target.nextAll('.image').first()
|
2013-06-13 01:37:30 +04:00
|
|
|
target = next.length > 0 ? next : target
|
|
|
|
|
}
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
2013-09-13 21:51:58 +04:00
|
|
|
var res = centerView(focusImage(target))
|
|
|
|
|
$('.viewer').trigger('focusedPrevRibbon', [getRibbonIndex()])
|
|
|
|
|
return res
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
2013-07-03 20:44:24 +04:00
|
|
|
function nextRibbon(){
|
2013-05-28 21:59:38 +04:00
|
|
|
var cur = getImage()
|
2013-07-03 20:44:24 +04:00
|
|
|
var target_ribbon = getRibbon(cur).nextAll('.ribbon').first()
|
2013-06-08 02:29:14 +04:00
|
|
|
var target = getImageBefore(cur, target_ribbon)
|
|
|
|
|
|
2013-06-13 01:37:30 +04:00
|
|
|
// no ribbon below...
|
2013-06-08 02:29:14 +04:00
|
|
|
if(target_ribbon.length == 0){
|
|
|
|
|
flashIndicator('bottom')
|
2013-06-13 01:37:30 +04:00
|
|
|
target = getImage()
|
|
|
|
|
} else {
|
|
|
|
|
// first image...
|
|
|
|
|
if(target.length == 0){
|
2013-07-03 20:44:24 +04:00
|
|
|
target = target_ribbon.find('.image').first()
|
2013-06-13 01:37:30 +04:00
|
|
|
}
|
2013-06-08 02:29:14 +04:00
|
|
|
}
|
2013-05-20 17:42:18 +04:00
|
|
|
|
2013-09-13 21:51:58 +04:00
|
|
|
var res = centerView(focusImage(target))
|
|
|
|
|
$('.viewer').trigger('focusedNextRibbon', [getRibbonIndex()])
|
|
|
|
|
return res
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
|
2013-05-07 00:26:35 +04:00
|
|
|
|
2013-05-23 17:17:31 +04:00
|
|
|
/******************************************************** Rotating ***/
|
|
|
|
|
|
2013-06-03 22:45:01 +04:00
|
|
|
// Compensate for viewer proportioned and rotated images.
|
|
|
|
|
//
|
2013-11-25 05:12:01 +04:00
|
|
|
// 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.
|
2014-02-05 02:51:43 +04:00
|
|
|
function correctImageProportionsForRotation(images, container){
|
|
|
|
|
container = container == null ? $('.viewer') : container
|
|
|
|
|
|
|
|
|
|
var W = container.innerWidth()
|
|
|
|
|
var H = container.innerHeight()
|
2013-06-03 22:45:01 +04:00
|
|
|
|
|
|
|
|
var viewer_p = W > H ? 'landscape' : 'portrait'
|
|
|
|
|
|
|
|
|
|
return $(images).each(function(i, e){
|
2013-05-23 18:58:45 +04:00
|
|
|
var image = $(this)
|
2013-05-24 17:08:16 +04:00
|
|
|
// orientation...
|
2013-05-23 18:58:45 +04:00
|
|
|
var o = image.attr('orientation')
|
|
|
|
|
o = o == null ? 0 : o
|
2013-05-23 17:17:31 +04:00
|
|
|
var w = image.outerWidth()
|
|
|
|
|
var h = image.outerHeight()
|
|
|
|
|
|
2013-06-03 17:48:27 +04:00
|
|
|
// non-square image...
|
2013-05-23 17:17:31 +04:00
|
|
|
if(w != h){
|
2013-06-03 22:45:01 +04:00
|
|
|
|
|
|
|
|
var image_p = w > h ? 'landscape' : 'portrait'
|
2013-05-24 17:08:16 +04:00
|
|
|
|
2013-05-23 18:58:45 +04:00
|
|
|
// when the image is turned 90deg/270deg and its
|
|
|
|
|
// proportions are the same as the screen...
|
2013-06-03 22:45:01 +04:00
|
|
|
if((o == 90 || o == 270) && image_p == viewer_p){
|
2013-05-23 18:58:45 +04:00
|
|
|
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,
|
|
|
|
|
})
|
2013-06-03 22:45:01 +04:00
|
|
|
|
|
|
|
|
} else if((o == 0 || o == 180) && image_p != viewer_p){
|
2013-05-23 18:58:45 +04:00
|
|
|
image.css({
|
|
|
|
|
width: h,
|
|
|
|
|
height: w,
|
|
|
|
|
})
|
|
|
|
|
image.css({
|
|
|
|
|
'margin': '',
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-03 17:48:27 +04:00
|
|
|
// square image...
|
2013-05-23 18:58:45 +04:00
|
|
|
} else {
|
2013-05-23 17:17:31 +04:00
|
|
|
image.css({
|
2013-05-23 18:58:45 +04:00
|
|
|
'margin': '',
|
2013-05-23 17:17:31 +04:00
|
|
|
})
|
|
|
|
|
}
|
2013-05-23 18:58:45 +04:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-25 14:24:29 +04:00
|
|
|
|
|
|
|
|
var _cw = {
|
|
|
|
|
null: 0,
|
|
|
|
|
0: 90,
|
|
|
|
|
90: 180,
|
|
|
|
|
180: 270,
|
|
|
|
|
270: 0,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var _ccw = {
|
|
|
|
|
null: 0,
|
|
|
|
|
0: 270,
|
|
|
|
|
90: 0,
|
|
|
|
|
180: 90,
|
|
|
|
|
270: 180,
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-04 23:29:44 +04:00
|
|
|
// NOTE: this works only on loaded images, if something more global is
|
|
|
|
|
// needed, then one should write a GID based version (data.js)
|
|
|
|
|
// XXX do we need a GID based version?
|
2013-05-23 18:58:45 +04:00
|
|
|
function rotateImage(direction, image){
|
2013-05-25 14:24:29 +04:00
|
|
|
var r_table = direction == 'left' ? _cw : _ccw
|
2013-05-28 21:59:38 +04:00
|
|
|
image = image == null ? getImage() : $(image)
|
2013-05-23 18:58:45 +04:00
|
|
|
image.each(function(i, e){
|
|
|
|
|
var img = $(this)
|
|
|
|
|
var o = r_table[img.attr('orientation')]
|
|
|
|
|
img.attr('orientation', o)
|
|
|
|
|
|
|
|
|
|
// account for proportions...
|
|
|
|
|
correctImageProportionsForRotation(img, direction)
|
2013-05-23 17:17:31 +04:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
$('.viewer').trigger('rotating' + direction.capitalize(), [image])
|
2013-06-04 16:32:33 +04:00
|
|
|
|
|
|
|
|
return image
|
2013-05-23 17:17:31 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function rotateLeft(image){
|
2013-06-04 16:32:33 +04:00
|
|
|
return rotateImage('left', image)
|
2013-05-23 17:17:31 +04:00
|
|
|
}
|
|
|
|
|
function rotateRight(image){
|
2013-06-04 16:32:33 +04:00
|
|
|
return rotateImage('right', image)
|
2013-05-23 17:17:31 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************** Flipping ***/
|
|
|
|
|
|
2013-06-04 16:32:33 +04:00
|
|
|
function getImageFlipState(image){
|
|
|
|
|
image = image == null ? getImage() : $(image)
|
|
|
|
|
var state = image.attr('flipped')
|
|
|
|
|
|
|
|
|
|
if(state == null){
|
|
|
|
|
return []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
state = state.split(',').map(function(e){ return e.trim() })
|
|
|
|
|
|
|
|
|
|
return state
|
|
|
|
|
}
|
|
|
|
|
function setImageFlipState(image, state){
|
|
|
|
|
image = image == null ? getImage() : $(image)
|
|
|
|
|
|
|
|
|
|
if(state.length == 0){
|
|
|
|
|
image.removeAttr('flipped')
|
|
|
|
|
} else if(state != null){
|
|
|
|
|
image.attr('flipped', state.join(', '))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return image
|
2013-05-23 17:17:31 +04:00
|
|
|
}
|
|
|
|
|
|
2013-06-04 22:01:41 +04:00
|
|
|
// direction can be:
|
|
|
|
|
// - 'vertical'
|
|
|
|
|
// - 'horizontal'
|
2013-06-04 23:29:44 +04:00
|
|
|
//
|
|
|
|
|
// NOTE: this works only on loaded images, if something more global is
|
|
|
|
|
// needed, then one should write a GID based version (data.js)
|
|
|
|
|
// XXX do we need a GID based version?
|
2013-06-04 16:32:33 +04:00
|
|
|
function flipImage(direction, image){
|
|
|
|
|
image = image == null ? getImage() : $(image)
|
|
|
|
|
image.each(function(i, e){
|
|
|
|
|
var img = $(this)
|
|
|
|
|
var state = getImageFlipState(img)
|
|
|
|
|
var i = state.indexOf(direction)
|
|
|
|
|
|
|
|
|
|
if(i >= 0){
|
|
|
|
|
state.splice(i, 1)
|
|
|
|
|
} else {
|
|
|
|
|
state.push(direction)
|
|
|
|
|
}
|
|
|
|
|
setImageFlipState(image, state)
|
|
|
|
|
})
|
2013-05-23 17:17:31 +04:00
|
|
|
|
2013-06-04 16:32:33 +04:00
|
|
|
$('.viewer').trigger('flipping' + direction.capitalize(), [image])
|
|
|
|
|
|
|
|
|
|
return image
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function flipVertical(image){
|
|
|
|
|
return flipImage('vertical')
|
|
|
|
|
}
|
2013-05-23 17:17:31 +04:00
|
|
|
function flipHorizontal(image){
|
2013-06-04 16:32:33 +04:00
|
|
|
return flipImage('horizontal')
|
2013-05-23 17:17:31 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-06-04 23:29:44 +04:00
|
|
|
/***************************************************** Image reset ***/
|
|
|
|
|
|
2013-06-10 08:00:31 +04:00
|
|
|
// Reset to original image state.
|
|
|
|
|
//
|
|
|
|
|
// This will remove flip and rotation data from an image and show it
|
|
|
|
|
// as-is.
|
|
|
|
|
//
|
2013-06-04 23:29:44 +04:00
|
|
|
// NOTE: this works only on loaded images, if something more global is
|
|
|
|
|
// needed, then one should write a GID based version (data.js)
|
|
|
|
|
// XXX do we need a GID based version?
|
|
|
|
|
function resetToOriginalImage(image){
|
|
|
|
|
image = image == null ? getImage() : $(image)
|
|
|
|
|
|
|
|
|
|
image.each(function(i, e){
|
|
|
|
|
$(e).removeAttr('flipped orientation')
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
$('.viewer').trigger('resetToOriginalImage' + direction.capitalize(), [image])
|
|
|
|
|
|
|
|
|
|
return image
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-05-07 00:26:35 +04:00
|
|
|
/********************************************************* Zooming ***/
|
|
|
|
|
|
2013-06-10 08:00:31 +04:00
|
|
|
// NOTE: n can be a float win obvious meaning -- 1.5 means fit one and
|
|
|
|
|
// a half images...
|
|
|
|
|
// NOTE: fixed_proportions if true will make this set the size using the
|
|
|
|
|
// image square, disregarding actual proportions.
|
|
|
|
|
// NOTE: fixed_proportions may result in and image bleading off screen.
|
2013-08-30 01:14:29 +04:00
|
|
|
function fitNImages(n, fixed_proportions, no_strict_fit){
|
2013-06-09 02:26:22 +04:00
|
|
|
var viewer = $('.viewer')
|
|
|
|
|
|
|
|
|
|
viewer.trigger('preFittingImages', [n])
|
|
|
|
|
|
2013-05-28 21:59:38 +04:00
|
|
|
var image = getImage()
|
2013-05-24 00:09:13 +04:00
|
|
|
var w = image.outerWidth(true)
|
|
|
|
|
var h = image.outerHeight(true)
|
2013-05-05 23:39:35 +04:00
|
|
|
|
2013-06-10 07:49:20 +04:00
|
|
|
// XXX needs testing -- might be wrong for fit-viewer + different
|
|
|
|
|
// viewer proportions...
|
2013-06-10 08:00:31 +04:00
|
|
|
// ...an exceptionally wide image might blead off screen...
|
2013-06-10 07:49:20 +04:00
|
|
|
if(fixed_proportions){
|
|
|
|
|
w = Math.min(w, h)
|
|
|
|
|
h = w
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-05 23:39:35 +04:00
|
|
|
var W = viewer.innerWidth()
|
|
|
|
|
var H = viewer.innerHeight()
|
|
|
|
|
|
2013-05-24 00:09:13 +04:00
|
|
|
var scale = Math.min(W / (w * n), H / h)
|
2013-05-05 23:39:35 +04:00
|
|
|
|
2013-08-30 01:14:29 +04:00
|
|
|
// special case: unless fitting one image to screen, do not fill the
|
|
|
|
|
// whole height...
|
|
|
|
|
// NOTE: we do not need to check width as it's already used for
|
|
|
|
|
// scaling...
|
|
|
|
|
if(!no_strict_fit && n != 1 && h*scale == H){
|
|
|
|
|
scale *= 0.8
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NOTE: if animating, the next two lines must be animated together...
|
2013-05-05 23:39:35 +04:00
|
|
|
setElementScale($('.ribbon-set'), scale)
|
2013-05-13 01:33:13 +04:00
|
|
|
centerView(image, 'css')
|
2013-05-12 14:31:03 +04:00
|
|
|
|
2013-06-03 22:45:01 +04:00
|
|
|
viewer.trigger('fittingImages', [n])
|
|
|
|
|
|
|
|
|
|
return scale
|
2013-05-05 23:39:35 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-05-06 23:43:38 +04:00
|
|
|
function zoomIn(){
|
2013-05-24 00:09:13 +04:00
|
|
|
var w = getScreenWidthInImages()
|
2013-05-06 23:43:38 +04:00
|
|
|
if(w > 1){
|
2013-12-15 18:56:21 +04:00
|
|
|
w = w / CONFIG.zoom_step_scale
|
2013-05-07 00:26:35 +04:00
|
|
|
fitNImages(w >= 1 ? w : 1)
|
2013-05-06 23:43:38 +04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
function zoomOut(){
|
2013-05-24 00:09:13 +04:00
|
|
|
var w = getScreenWidthInImages()
|
2014-01-15 07:05:50 +04:00
|
|
|
var max = getScreenWidthInImages(CONFIG.min_image_size)
|
|
|
|
|
if(w <= max){
|
2013-12-15 18:56:21 +04:00
|
|
|
w = w * CONFIG.zoom_step_scale
|
2014-01-15 07:05:50 +04:00
|
|
|
fitNImages(w <= max ? w : max)
|
2013-05-06 23:43:38 +04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-05 23:39:35 +04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************** Editor Actions ***/
|
2014-01-01 07:41:53 +04:00
|
|
|
// NOTE: for shiftImageRight/shiftImageLeft see sort.js, as they depend
|
2013-06-08 18:28:10 +04:00
|
|
|
// on data ordering...
|
2013-05-02 19:47:04 +04:00
|
|
|
|
2013-07-03 20:44:24 +04:00
|
|
|
function shiftImageTo(image, direction, moving, force_create_ribbon){
|
2013-05-02 19:47:04 +04:00
|
|
|
if(image == null){
|
2013-05-28 21:59:38 +04:00
|
|
|
image = getImage()
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// account move for direction...
|
|
|
|
|
// XXX get the value from some place more logical than the argument...
|
2013-05-03 00:57:26 +04:00
|
|
|
var a = moving == 'prev' ? 'prevAll' : 'nextAll'
|
|
|
|
|
var b = moving == 'prev' ? 'nextAll' : 'prevAll'
|
2013-07-03 20:44:24 +04:00
|
|
|
var target = image[a]('.image').first()
|
2013-05-02 19:47:04 +04:00
|
|
|
|
2013-12-26 03:57:32 +04:00
|
|
|
target = target.length == 0 ? image[b]('.image').first() : target
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
shiftImage(direction, image, force_create_ribbon)
|
2013-12-26 03:57:32 +04:00
|
|
|
|
2013-05-13 01:33:13 +04:00
|
|
|
return centerView(focusImage(target), 'css')
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
2013-05-03 00:57:26 +04:00
|
|
|
function shiftImageUp(image, moving){
|
2013-05-06 23:43:38 +04:00
|
|
|
return shiftImageTo(image, 'prev', moving)
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
2013-05-03 00:57:26 +04:00
|
|
|
function shiftImageDown(image, moving){
|
2013-05-06 23:43:38 +04:00
|
|
|
return shiftImageTo(image, 'next')
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
2013-05-03 00:57:26 +04:00
|
|
|
function shiftImageUpNewRibbon(image, moving){
|
2013-05-06 23:43:38 +04:00
|
|
|
return shiftImageTo(image, 'prev', moving, true)
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
2013-05-03 00:57:26 +04:00
|
|
|
function shiftImageDownNewRibbon(image, moving){
|
2013-11-27 07:12:32 +04:00
|
|
|
return shiftImageTo(image, 'next', moving, true)
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
|
* vim:set sw=4 ts=4 : */
|