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
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* TODO group all actions into an object, referencing the viewer...
|
|
|
|
|
* ...this will make this reusable multiple times.
|
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-05-05 19:53:06 +04:00
|
|
|
// Data format...
|
|
|
|
|
var DATA = {
|
|
|
|
|
// the ribbon cache...
|
|
|
|
|
// in the simplest form this is a list of lists of GIDs
|
|
|
|
|
ribbons: [
|
2013-05-05 23:39:35 +04:00
|
|
|
$(new Array(100)).map(function(i){return i}).toArray()
|
2013-05-05 19:53:06 +04:00
|
|
|
],
|
|
|
|
|
// flat ordered list of images in current context...
|
|
|
|
|
// in the simplest form this is a list of GIDs.
|
2013-05-06 02:18:36 +04:00
|
|
|
order: $(new Array(100)).map(function(i){return i}).toArray(),
|
2013-05-05 19:53:06 +04:00
|
|
|
// the images object, this is indexed by image GID and contains all
|
|
|
|
|
// the needed data...
|
|
|
|
|
images: {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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-03 04:18:47 +04:00
|
|
|
// XXX need ribbon end indicators...
|
|
|
|
|
|
|
|
|
|
// XXX might need shift left/right indicators (later)...
|
|
|
|
|
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
function flashIndicator(direction){
|
2013-05-03 19:24:06 +04:00
|
|
|
$({
|
|
|
|
|
prev: '.up-indicator',
|
|
|
|
|
next: '.down-indicator',
|
|
|
|
|
// XXX not implemented yet...
|
|
|
|
|
start: '.start-indicator',
|
|
|
|
|
end: '.end-indicator',
|
|
|
|
|
}[direction])
|
2013-05-02 23:48:55 +04:00
|
|
|
// NOTE: this needs to be visible in all cases and key press
|
|
|
|
|
// rhythms...
|
|
|
|
|
.show()
|
|
|
|
|
.delay(20)
|
|
|
|
|
.fadeOut(200)
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-05-05 19:53:06 +04:00
|
|
|
function getRibbon(image){
|
|
|
|
|
image = image == null ? $('.current.image') : $(image)
|
|
|
|
|
return image.closest('.ribbon')
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-05 23:39:35 +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 02:18:36 +04:00
|
|
|
function getImageOrder(image){
|
|
|
|
|
image = image == null ? $('.current.image') : $(image)
|
|
|
|
|
if(image.length == 0){
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
return JSON.parse(image.attr('order'))
|
|
|
|
|
}
|
|
|
|
|
function getImageGID(image){
|
|
|
|
|
image = image == null ? $('.current.image') : $(image)
|
|
|
|
|
if(image.length == 0){
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
return JSON.parse(image.attr('gid'))
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
// ...tried to make this as brain-dead-stupidly-simple as possible...
|
|
|
|
|
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-03 02:27:54 +04:00
|
|
|
function getVisibleImageSize(){
|
|
|
|
|
return $('.image').outerWidth() * getElementScale($('.ribbon-set'))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-05-03 04:18:47 +04:00
|
|
|
// Return the number of images that can fit to viewer width...
|
2013-05-03 02:27:54 +04:00
|
|
|
function getScreenWidthInImages(){
|
|
|
|
|
return $('.viewer').innerWidth() / getVisibleImageSize()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
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...
|
|
|
|
|
// XXX need tp make this loadable ribbon compatible -- the target may
|
|
|
|
|
// not be loaded...
|
2013-05-03 17:08:59 +04:00
|
|
|
function getImageBefore(image, ribbon, mode){
|
|
|
|
|
mode = mode == null ? NAV_DEFAULT : mode
|
2013-05-02 23:48:55 +04:00
|
|
|
image = image == null ? $('.current.image') : $(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
|
|
|
}
|
|
|
|
|
var images = $(ribbon).find('.image').filter(mode)
|
2013-05-02 23:22:43 +04:00
|
|
|
// XXX need to process/format this correctly...
|
|
|
|
|
var order = JSON.parse(image.attr('order'))
|
2013-05-03 17:08:59 +04:00
|
|
|
var prev = []
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
images.each(function(){
|
2013-05-05 23:39:35 +04:00
|
|
|
if(order < JSON.parse($(this).attr('order'))){
|
2013-05-02 19:47:04 +04:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
prev = this
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return $(prev)
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-06 02:18:36 +04:00
|
|
|
// same as getImageBefore, but uses gids and searches in DATA...
|
|
|
|
|
// XXX check for corner cases...
|
2013-05-06 02:46:48 +04:00
|
|
|
// XXX getGIDBefore(1, 1) does not work
|
2013-05-06 02:18:36 +04:00
|
|
|
function getGIDBefore(gid, ribbon){
|
|
|
|
|
ribbon = DATA.ribbons[ribbon]
|
|
|
|
|
var order = DATA.order
|
|
|
|
|
|
|
|
|
|
var target = ribbon.indexOf(gid)
|
|
|
|
|
|
|
|
|
|
if(target >= 0){
|
|
|
|
|
return gid
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
target = order.indexOf(gid)
|
|
|
|
|
|
|
|
|
|
var i = ribbon.length
|
|
|
|
|
|
2013-05-06 02:46:48 +04:00
|
|
|
while(i > 0){
|
2013-05-06 02:18:36 +04:00
|
|
|
i = Math.floor(ribbon.length/2)
|
|
|
|
|
|
2013-05-06 02:46:48 +04:00
|
|
|
console.log('>>>', target, i, order.indexOf(ribbon[i]), order.indexOf(ribbon[i+1]))
|
2013-05-06 02:18:36 +04:00
|
|
|
|
|
|
|
|
if(target >= order.indexOf(ribbon[i]) && target < order.indexOf(ribbon[i+1])){
|
|
|
|
|
return ribbon[i]
|
|
|
|
|
|
|
|
|
|
// XXX I do not understand why this works correctly, think I need some sleep...
|
|
|
|
|
} else if(target < order.indexOf(ribbon[i])){
|
|
|
|
|
ribbon = ribbon.slice(0, i)
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
ribbon = ribbon.slice(i)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
function shiftTo(image, ribbon){
|
2013-05-02 23:22:43 +04:00
|
|
|
var target = getImageBefore(image, ribbon, NAV_ALL)
|
2013-05-05 19:53:06 +04:00
|
|
|
var cur_ribbon = getRibbon(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))
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
image.insertAfter(target)
|
|
|
|
|
}
|
|
|
|
|
|
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-05 23:39:35 +04:00
|
|
|
removeRibbon(cur_ribbon)
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return image
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function shiftImage(direction, image, force_create_ribbon){
|
|
|
|
|
if(image == null){
|
|
|
|
|
// XXX need to make this context specific...
|
|
|
|
|
image = $('.current.image')
|
|
|
|
|
} else {
|
|
|
|
|
image = $(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)
|
|
|
|
|
index = direction == 'after' ? index + 1 : index
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// NOTE: to avoid state sync problems this should clone an image if
|
|
|
|
|
// one is available...
|
|
|
|
|
function createImage(n){
|
|
|
|
|
if(n == null){
|
|
|
|
|
if(window._n == null){
|
|
|
|
|
window._n = 0
|
|
|
|
|
}
|
|
|
|
|
n = _n
|
|
|
|
|
_n += 1
|
|
|
|
|
}
|
|
|
|
|
var img = $('.image')
|
|
|
|
|
if(img.length > 0){
|
|
|
|
|
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-05-05 23:39:35 +04:00
|
|
|
return $('<div order="'+n+'" gid="'+n+'" class="image"/>')
|
2013-05-02 22:32:20 +04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This will create a set of new images, reusing a list of existing
|
|
|
|
|
// elements if given.
|
|
|
|
|
// XXX do we need this???
|
2013-05-05 23:39:35 +04:00
|
|
|
// XXX add position...
|
2013-05-02 22:32:20 +04:00
|
|
|
function createImages(need, have){
|
|
|
|
|
have = have == null ? [] : have
|
|
|
|
|
|
|
|
|
|
// 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-05 23:39:35 +04:00
|
|
|
function createRibbon(index){
|
|
|
|
|
// make the ribbon...
|
|
|
|
|
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-05 23:39:35 +04:00
|
|
|
// NOTE: this will pass the index where the ribbon was to the event,
|
|
|
|
|
// rather than an actual ribbon...
|
|
|
|
|
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-05 19:53:06 +04:00
|
|
|
/**********************************************************************
|
2013-05-06 02:18:36 +04:00
|
|
|
* Loaders
|
2013-05-05 19:53:06 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// NOTE: count can be either hegative or positive, this will idicate
|
|
|
|
|
// load direction...
|
|
|
|
|
// NOTE: this will not include the 'from' GID in the resulting list...
|
2013-05-05 23:39:35 +04:00
|
|
|
// NOTE: this can calculate the ribbon number if an image can be only
|
|
|
|
|
// in one ribbon...
|
|
|
|
|
// NOTE: if an image can be in more than one ribbon, one MUST suply the
|
|
|
|
|
// correct ribbon number...
|
|
|
|
|
// XXX do we need more checking???
|
|
|
|
|
function getImageGIDs(from, count, ribbon){
|
2013-05-05 19:53:06 +04:00
|
|
|
if(count == 0){
|
|
|
|
|
return []
|
|
|
|
|
}
|
2013-05-06 02:18:36 +04:00
|
|
|
// ribbon default value...
|
2013-05-05 23:39:35 +04:00
|
|
|
if(ribbon == null){
|
|
|
|
|
$(DATA.ribbons).each(function(i, e){
|
|
|
|
|
if(e.indexOf(from) >= 0){
|
|
|
|
|
ribbon = i
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
// XXX checkif this is empty...
|
|
|
|
|
ribbon = DATA.ribbons[ribbon]
|
|
|
|
|
|
|
|
|
|
if(count > 0){
|
|
|
|
|
var start = ribbon.indexOf(from) + 1
|
|
|
|
|
return ribbon.slice(start, start + count)
|
|
|
|
|
} else {
|
|
|
|
|
var end = ribbon.indexOf(from)
|
2013-05-06 02:18:36 +04:00
|
|
|
return ribbon.slice((Math.abs(count) >= end ? 0 : end + count), end)
|
2013-05-05 23:39:35 +04:00
|
|
|
}
|
2013-05-05 19:53:06 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateImage(image, gid, size){
|
|
|
|
|
image = $(image)
|
|
|
|
|
if(gid == null){
|
2013-05-05 23:39:35 +04:00
|
|
|
gid = JSON.parse(image.attr('gid'))
|
|
|
|
|
} else {
|
|
|
|
|
image.attr('gid', JSON.stringify(gid))
|
2013-05-05 19:53:06 +04:00
|
|
|
}
|
|
|
|
|
size = size == null ? getVisibleImageSize() : size
|
|
|
|
|
|
2013-05-05 23:39:35 +04:00
|
|
|
image.attr({
|
|
|
|
|
//order: JSON.stringify(DATA.order.indexOf(gid)),
|
|
|
|
|
order: JSON.stringify(gid)
|
|
|
|
|
// XXX update attrs
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// XXX STUB
|
|
|
|
|
image.text(gid)
|
|
|
|
|
// XXX slect best previe by size...
|
|
|
|
|
// XXX
|
|
|
|
|
// XXX update classes...
|
2013-05-05 19:53:06 +04:00
|
|
|
// XXX
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NOTE: this is signature-compatible with rollRibbon...
|
|
|
|
|
// NOTE: this will load data ONLY if it is available, otherwise this
|
|
|
|
|
// will have no effect...
|
|
|
|
|
function rollImages(n, ribbon){
|
|
|
|
|
if(n == 0){
|
|
|
|
|
return $([])
|
|
|
|
|
}
|
|
|
|
|
ribbon = ribbon == null ? getRibbon() : $(ribbon)
|
2013-05-06 02:18:36 +04:00
|
|
|
var images = ribbon.find('.image')
|
|
|
|
|
|
2013-05-05 23:39:35 +04:00
|
|
|
var from = n > 0 ? JSON.parse(ribbon.find('.image').last().attr('gid'))
|
|
|
|
|
: JSON.parse(ribbon.find('.image').first().attr('gid'))
|
2013-05-05 19:53:06 +04:00
|
|
|
var gids = getImageGIDs(from, n)
|
|
|
|
|
if(gids.length == 0){
|
|
|
|
|
return $([])
|
|
|
|
|
}
|
2013-05-06 02:18:36 +04:00
|
|
|
// truncate the results to the length of images...
|
|
|
|
|
if(n > images.length){
|
|
|
|
|
gids.reverse().splice(images.length)
|
|
|
|
|
gids.reverse()
|
|
|
|
|
} else if(Math.abs(n) > images.length){
|
|
|
|
|
gids.splice(images.length)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(n < images.length){
|
|
|
|
|
images = rollRibbon(gids.length * (n > 0 ? 1 : -1), ribbon)
|
|
|
|
|
}
|
2013-05-05 19:53:06 +04:00
|
|
|
|
2013-05-06 02:18:36 +04:00
|
|
|
var size = getVisibleImageSize()
|
2013-05-05 19:53:06 +04:00
|
|
|
images.each(function(i, e){
|
|
|
|
|
updateImage($(e), gids[i], size)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return images
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-05-02 22:32:20 +04:00
|
|
|
|
2013-04-26 05:30:56 +04:00
|
|
|
/**********************************************************************
|
2013-05-02 19:47:04 +04:00
|
|
|
* Modes
|
2013-04-26 05:30:56 +04:00
|
|
|
*/
|
|
|
|
|
|
2013-05-03 00:39:29 +04:00
|
|
|
// XXX shifting images and unmarking in this mode do not work correctly...
|
2013-05-02 19:47:04 +04:00
|
|
|
var toggleMarkedOnlyView = createCSSClassToggler('.viewer', 'marked-only',
|
|
|
|
|
function(){
|
|
|
|
|
var cur = $('.current.image')
|
|
|
|
|
// current is marked...
|
|
|
|
|
if(cur.hasClass('marked')){
|
|
|
|
|
centerImage(null, 'css')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
// there is a marked image in this ribbon...
|
2013-05-02 23:22:43 +04:00
|
|
|
var target = getImageBefore(cur, null)
|
2013-05-02 19:47:04 +04:00
|
|
|
if(target.length > 0){
|
|
|
|
|
centerImage(focusImage(target), 'css')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
// get marked image from other ribbons...
|
|
|
|
|
prevRibbon()
|
|
|
|
|
if($('.current.image').hasClass('marked')){
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
nextRibbon()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// XXX add ability to take all marked images and open them in a separate view...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// XXX should we use the createCSSClassToggler for this?
|
|
|
|
|
// XXX revise: does extra stuff...
|
|
|
|
|
function toggleImageProportions(mode){
|
|
|
|
|
var image = $('.image')
|
|
|
|
|
var h = image.outerHeight(true)
|
|
|
|
|
var w = image.outerWidth(true)
|
|
|
|
|
|
|
|
|
|
if(mode == '?'){
|
|
|
|
|
return h != w ? 'viewer' : 'square'
|
|
|
|
|
|
|
|
|
|
// square...
|
|
|
|
|
} else if(h != w || mode == 'square'){
|
|
|
|
|
var size = Math.min(w, h)
|
|
|
|
|
image.css({
|
|
|
|
|
width: size,
|
|
|
|
|
height: size
|
|
|
|
|
})
|
|
|
|
|
centerImage(null, 'css')
|
|
|
|
|
return 'square'
|
|
|
|
|
|
|
|
|
|
// viewer size...
|
|
|
|
|
} else {
|
|
|
|
|
var viewer = $('.viewer')
|
|
|
|
|
var W = viewer.innerWidth()
|
|
|
|
|
var H = viewer.innerHeight()
|
|
|
|
|
|
|
|
|
|
if(W > H){
|
|
|
|
|
image.css('width', W * h/H)
|
|
|
|
|
} else {
|
|
|
|
|
image.css('height', H * w/W)
|
|
|
|
|
}
|
|
|
|
|
centerImage(null, 'css')
|
|
|
|
|
return 'viewer'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
|
* Layout
|
2013-04-26 05:30:56 +04:00
|
|
|
*/
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
function focusImage(image){
|
|
|
|
|
image.closest('.viewer').find('.current.image').removeClass('current')
|
|
|
|
|
return image.addClass('current')
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
|
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
|
|
|
|
|
mode = mode == null ? 'animate' : mode
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
var h = elem.outerHeight()
|
|
|
|
|
target.top = t - dt + (H - h)/2,
|
|
|
|
|
} else if(valign == 'top'){
|
|
|
|
|
target.top = t - dt
|
|
|
|
|
} else if(valign == 'bottom'){
|
|
|
|
|
var h = elem.outerHeight()
|
|
|
|
|
target.top = t - dt - h
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(halign == 'center'){
|
|
|
|
|
var W = container.innerWidth()
|
|
|
|
|
var w = elem.outerWidth()
|
|
|
|
|
target.left = l - dl + (W - w)/2
|
|
|
|
|
} else if(halign == 'left'){
|
|
|
|
|
target.left = l - dl
|
|
|
|
|
} else if(halign == 'right'){
|
|
|
|
|
var w = elem.outerWidth()
|
|
|
|
|
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-02 19:47:04 +04:00
|
|
|
// This appears to work well with scaling...
|
|
|
|
|
// XXX make this more configurable...
|
|
|
|
|
function centerImage(image, mode){
|
|
|
|
|
if(mode == null){
|
|
|
|
|
//mode = 'css'
|
|
|
|
|
mode = 'animate'
|
|
|
|
|
}
|
|
|
|
|
if(image == null || image.length == 0){
|
|
|
|
|
image = $('.current.image')
|
|
|
|
|
}
|
|
|
|
|
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...
|
|
|
|
|
var w = image.outerWidth()*scale
|
|
|
|
|
var h = image.outerHeight()*scale
|
|
|
|
|
|
|
|
|
|
var pos = getRelativeVisualPosition(viewer, image)
|
|
|
|
|
|
|
|
|
|
// 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-05 19:53:06 +04:00
|
|
|
$('.viewer').trigger('centeringRibbon', [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:
|
|
|
|
|
// - ribbon containing the target (given) image
|
|
|
|
|
// center relative to the .viewer via .ribbon-set
|
|
|
|
|
// calls centerImage(...) directly
|
|
|
|
|
// both top and left are used...
|
|
|
|
|
// - any other ribbon
|
|
|
|
|
// center relative to target (given) via the ribbon left
|
|
|
|
|
// only left coordinate is changed...
|
|
|
|
|
//
|
|
|
|
|
// NOTE: image defaults to $('.current.image').
|
|
|
|
|
//
|
|
|
|
|
// 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-03 15:58:22 +04:00
|
|
|
function centerRibbon(ribbon, image, mode){
|
2013-05-03 05:38:40 +04:00
|
|
|
if(mode == null){
|
|
|
|
|
//mode = 'css'
|
|
|
|
|
mode = 'animate'
|
|
|
|
|
}
|
|
|
|
|
ribbon = $(ribbon)
|
2013-05-03 15:58:22 +04:00
|
|
|
image = image == null ? $('.current.image') : $(image)
|
2013-05-03 05:38:40 +04:00
|
|
|
|
|
|
|
|
// if centering current ribbon, just center the image...
|
2013-05-03 15:58:22 +04:00
|
|
|
if(ribbon.find('.image').index(image) >= 0){
|
|
|
|
|
centerImage(image, mode)
|
|
|
|
|
// XXX should this return a ribbon or the target image???
|
2013-05-03 05:38:40 +04:00
|
|
|
return ribbon
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var scale = getElementScale($('.ribbon-set'))
|
2013-05-03 19:01:00 +04:00
|
|
|
var target = getImageBefore(image, ribbon, null)
|
2013-05-03 05:38:40 +04:00
|
|
|
|
|
|
|
|
if(target.length > 0){
|
2013-05-03 15:58:22 +04:00
|
|
|
var dl = getRelativeVisualPosition(target, image).left/scale
|
2013-05-03 05:38:40 +04:00
|
|
|
var l = parseFloat(ribbon.css('left'))
|
|
|
|
|
l = !isNaN(l) ? l : 0
|
|
|
|
|
l = {left: l + dl - ($('.image').outerWidth()/2)}
|
|
|
|
|
|
|
|
|
|
} else {
|
2013-05-03 17:08:59 +04:00
|
|
|
target = ribbon.find('.image').filter(NAV_DEFAULT).first()
|
|
|
|
|
var dl = getRelativeVisualPosition(target, image).left/scale
|
2013-05-03 05:38:40 +04:00
|
|
|
var l = parseFloat(ribbon.css('left'))
|
|
|
|
|
l = !isNaN(l) ? l : 0
|
|
|
|
|
l = {left: l + dl + ($('.image').outerWidth()/2)}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(mode == 'animate'){
|
|
|
|
|
ribbon.stop().animate(l, 100, 'linear')
|
|
|
|
|
} else {
|
|
|
|
|
ribbons.css(res)
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// a shorthand...
|
|
|
|
|
function centerRibbons(mode){
|
2013-05-03 05:47:26 +04:00
|
|
|
return $('.ribbon')
|
|
|
|
|
.filter(':visible')
|
2013-05-03 15:58:22 +04:00
|
|
|
.each(function(){ centerRibbon($(this), null, mode) })
|
2013-05-03 05:38:40 +04:00
|
|
|
}
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
|
* Infinite ribbon machinery
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// XXX need mechanics to populate the images or to connect such
|
|
|
|
|
// functionality...
|
|
|
|
|
// ...this is to be done in the loader...
|
|
|
|
|
|
|
|
|
|
// NOTE: negative left or right will contract the ribbon...
|
|
|
|
|
function extendRibbon(left, right, ribbon){
|
|
|
|
|
ribbon = ribbon == null ?
|
2013-05-05 19:53:06 +04:00
|
|
|
getRibbon()
|
2013-05-02 19:47:04 +04:00
|
|
|
: $(ribbon)
|
|
|
|
|
left = left == null ? 0 : left
|
|
|
|
|
right = right == null ? 0 : right
|
|
|
|
|
var images = ribbon.children('.image')
|
|
|
|
|
var removed = []
|
|
|
|
|
var res = {
|
2013-05-05 19:53:06 +04:00
|
|
|
left: $([]),
|
|
|
|
|
right: $([])
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// truncate...
|
|
|
|
|
// NOTE: we save the detached elements to reuse them on extending,
|
|
|
|
|
// if needed...
|
|
|
|
|
if(left < 0){
|
|
|
|
|
removed = $(images.splice(0, -left)).detach()
|
|
|
|
|
}
|
|
|
|
|
if(right < 0){
|
|
|
|
|
var l = images.length
|
|
|
|
|
removed = $(images.splice(l+right, l)).detach()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// extend...
|
|
|
|
|
if (left > 0){
|
|
|
|
|
res.left = createImages(left, removed).prependTo(ribbon)
|
|
|
|
|
}
|
|
|
|
|
if (right > 0){
|
|
|
|
|
res.right = createImages(right, removed).appendTo(ribbon)
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-03 04:18:47 +04:00
|
|
|
// compensate for the truncation...
|
|
|
|
|
// XXX do we need to split this into a separate function?
|
|
|
|
|
// ...the rest of the function if pretty generic...
|
2013-05-03 04:24:26 +04:00
|
|
|
// XXX for some odd reason this behaves erratically when the page
|
2013-05-03 04:18:47 +04:00
|
|
|
// is zoomed...
|
|
|
|
|
if(left != 0){
|
|
|
|
|
var l = parseFloat(ribbon.css('left'))
|
|
|
|
|
l = isNaN(l) ? 0 : l
|
|
|
|
|
ribbon.css({
|
|
|
|
|
left: l + (-left * parseFloat(images.outerWidth()))
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-02 19:47:04 +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...
|
|
|
|
|
function rollRibbon(n, ribbon){
|
|
|
|
|
var res = extendRibbon(-n, n, ribbon)
|
|
|
|
|
return n > 0 ? res.right : res.left
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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')
|
|
|
|
|
|
|
|
|
|
centerImage(focusImage(img))
|
|
|
|
|
|
|
|
|
|
centerRibbons()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
/**********************************************************************
|
|
|
|
|
* User actions
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// NOTE: NAV_ALL might not be practical...
|
|
|
|
|
var NAV_ALL = '*'
|
|
|
|
|
var NAV_VISIBLE = ':visible'
|
|
|
|
|
var NAV_MARKED = '.marked:visible'
|
|
|
|
|
|
|
|
|
|
var NAV_DEFAULT = NAV_VISIBLE
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// basic navigation actions...
|
2013-05-03 02:27:54 +04:00
|
|
|
function nextImage(n, mode){
|
2013-05-03 17:08:59 +04:00
|
|
|
mode = mode == null ? NAV_DEFAULT : mode
|
2013-05-03 02:27:54 +04:00
|
|
|
n = n == null ? 1 : n
|
2013-05-03 03:43:43 +04:00
|
|
|
var target = $('.current.image').nextAll('.image' + mode)
|
2013-05-03 19:24:06 +04:00
|
|
|
if(target.length < n){
|
|
|
|
|
target = target.last()
|
|
|
|
|
flashIndicator('end')
|
|
|
|
|
} else {
|
|
|
|
|
target = target.eq(n-1)
|
|
|
|
|
}
|
2013-05-03 03:43:43 +04:00
|
|
|
return centerImage(focusImage(target))
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
2013-05-03 02:27:54 +04:00
|
|
|
function prevImage(n, mode){
|
2013-05-03 17:08:59 +04:00
|
|
|
mode = mode == null ? NAV_DEFAULT : mode
|
2013-05-03 02:27:54 +04:00
|
|
|
n = n == null ? 1 : n
|
2013-05-03 03:43:43 +04:00
|
|
|
var target = $('.current.image').prevAll('.image' + mode)
|
2013-05-03 19:24:06 +04:00
|
|
|
if(target.length < n){
|
|
|
|
|
target = target.last()
|
|
|
|
|
flashIndicator('start')
|
|
|
|
|
} else {
|
|
|
|
|
target = target.eq(n-1)
|
|
|
|
|
}
|
2013-05-03 03:43:43 +04:00
|
|
|
return centerImage(focusImage(target))
|
2013-05-03 02:27:54 +04:00
|
|
|
}
|
|
|
|
|
function nextScreenImages(mode){
|
|
|
|
|
return nextImage(Math.round(getScreenWidthInImages()), mode)
|
|
|
|
|
}
|
|
|
|
|
function prevScreenImages(mode){
|
|
|
|
|
return prevImage(Math.round(getScreenWidthInImages()), mode)
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
2013-05-03 19:24:06 +04:00
|
|
|
// XXX revise...
|
2013-05-02 19:47:04 +04:00
|
|
|
function firstImage(mode){
|
2013-05-05 19:53:06 +04:00
|
|
|
$('.viewer').trigger('requestedFirstImage', [getRibbon()])
|
|
|
|
|
|
2013-05-03 17:08:59 +04:00
|
|
|
mode = mode == null ? NAV_DEFAULT : mode
|
2013-05-03 19:24:06 +04:00
|
|
|
if($('.current.image').prevAll('.image' + mode).length == 0){
|
|
|
|
|
flashIndicator('start')
|
|
|
|
|
}
|
2013-05-02 19:47:04 +04:00
|
|
|
return centerImage(
|
|
|
|
|
focusImage(
|
2013-05-05 19:53:06 +04:00
|
|
|
getRibbon().find('.image').filter(mode).first()))
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
2013-05-03 19:24:06 +04:00
|
|
|
// XXX revise...
|
2013-05-02 19:47:04 +04:00
|
|
|
function lastImage(mode){
|
2013-05-05 19:53:06 +04:00
|
|
|
$('.viewer').trigger('requestedLastImage', [getRibbon()])
|
|
|
|
|
|
2013-05-03 17:08:59 +04:00
|
|
|
mode = mode == null ? NAV_DEFAULT : mode
|
2013-05-03 19:24:06 +04:00
|
|
|
if($('.current.image').nextAll('.image' + mode).length == 0){
|
|
|
|
|
flashIndicator('end')
|
|
|
|
|
}
|
2013-05-02 19:47:04 +04:00
|
|
|
return centerImage(
|
|
|
|
|
focusImage(
|
2013-05-05 19:53:06 +04:00
|
|
|
getRibbon().find('.image').filter(mode).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.
|
|
|
|
|
// XXX get move direction...
|
|
|
|
|
function prevRibbon(moving, mode){
|
2013-05-03 17:08:59 +04:00
|
|
|
mode = mode == null ? NAV_DEFAULT : mode
|
2013-05-02 19:47:04 +04:00
|
|
|
var cur = $('.current.image')
|
2013-05-03 19:01:00 +04:00
|
|
|
var target = getImageBefore(cur,
|
2013-05-05 19:53:06 +04:00
|
|
|
getRibbon(cur).prevAll('.ribbon:visible').first())
|
2013-05-03 17:08:59 +04:00
|
|
|
if(target.length == 0){
|
|
|
|
|
// XXX too complex???
|
2013-05-05 19:53:06 +04:00
|
|
|
target = getRibbon(cur)
|
2013-05-03 19:01:00 +04:00
|
|
|
.prevAll('.ribbon:visible').first()
|
|
|
|
|
.find('.image' + mode).first()
|
2013-05-06 02:18:36 +04:00
|
|
|
} else if(moving == 'next' && cur.attr('order') != target.attr('order')){
|
2013-05-02 19:47:04 +04:00
|
|
|
var next = target.nextAll('.image' + mode).first()
|
|
|
|
|
target = next.length > 0 ? next : target
|
|
|
|
|
}
|
|
|
|
|
return centerImage(focusImage(target))
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
2013-05-02 19:47:04 +04:00
|
|
|
// XXX get move direction...
|
|
|
|
|
function nextRibbon(moving, mode){
|
2013-05-03 17:08:59 +04:00
|
|
|
mode = mode == null ? NAV_DEFAULT : mode
|
2013-05-02 19:47:04 +04:00
|
|
|
var cur = $('.current.image')
|
2013-05-03 19:01:00 +04:00
|
|
|
var target = getImageBefore(cur,
|
2013-05-05 19:53:06 +04:00
|
|
|
getRibbon(cur).nextAll('.ribbon:visible').first())
|
2013-05-03 17:08:59 +04:00
|
|
|
if(target.length == 0){
|
|
|
|
|
// XXX too complex???
|
2013-05-05 19:53:06 +04:00
|
|
|
target = getRibbon(cur)
|
2013-05-03 19:01:00 +04:00
|
|
|
.nextAll('.ribbon:visible').first()
|
|
|
|
|
.find('.image' + mode).first()
|
2013-05-06 02:18:36 +04:00
|
|
|
} else if(moving == 'next' && cur.attr('order') != target.attr('order')){
|
|
|
|
|
var next = target.nextAll('.image' + mode).first()
|
|
|
|
|
target = next.length > 0 ? next : target
|
2013-05-02 19:47:04 +04:00
|
|
|
}
|
|
|
|
|
return centerImage(focusImage(target))
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
|
2013-05-05 23:39:35 +04:00
|
|
|
function fitNImages(n){
|
|
|
|
|
var image = $('.current.image')
|
|
|
|
|
var size = image.outerHeight(true)
|
|
|
|
|
|
|
|
|
|
var viewer = $('.viewer')
|
|
|
|
|
var W = viewer.innerWidth()
|
|
|
|
|
var H = viewer.innerHeight()
|
|
|
|
|
|
|
|
|
|
var scale = Math.min(W / (size * n), H / size)
|
|
|
|
|
|
|
|
|
|
// XXX if animating, the next two likes must be animated together...
|
|
|
|
|
setElementScale($('.ribbon-set'), scale)
|
|
|
|
|
centerImage(image, 'css')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************** Editor Actions ***/
|
2013-05-02 19:47:04 +04:00
|
|
|
|
2013-05-05 19:53:06 +04:00
|
|
|
// XXX add a shift event here...
|
2013-05-02 19:47:04 +04:00
|
|
|
// XXX get move direction...
|
2013-05-03 00:57:26 +04:00
|
|
|
function _shiftImageTo(image, direction, moving, force_create_ribbon, mode){
|
2013-05-02 19:47:04 +04:00
|
|
|
if(image == null){
|
|
|
|
|
image = $('.current.image')
|
|
|
|
|
}
|
2013-05-03 17:08:59 +04:00
|
|
|
mode = mode == null ? NAV_DEFAULT : mode
|
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'
|
|
|
|
|
var target = image[a]('.image' + mode).first()
|
2013-05-02 19:47:04 +04:00
|
|
|
|
2013-05-03 04:30:39 +04:00
|
|
|
target = target.length == 0 ? image[b]().first() : target
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
// XXX should this be in here or coupled later via an event???
|
|
|
|
|
flashIndicator(direction)
|
|
|
|
|
|
|
|
|
|
shiftImage(direction, image, force_create_ribbon)
|
|
|
|
|
// XXX does this need to be animated???
|
|
|
|
|
return centerImage(focusImage(target), 'css')
|
|
|
|
|
}
|
2013-05-03 00:57:26 +04:00
|
|
|
function shiftImageUp(image, moving){
|
|
|
|
|
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-02 19:47:04 +04:00
|
|
|
return _shiftImageTo(image, 'next')
|
|
|
|
|
}
|
2013-05-03 00:57:26 +04:00
|
|
|
function shiftImageUpNewRibbon(image, moving){
|
|
|
|
|
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){
|
|
|
|
|
return _shiftImageTo(image, 'prev', moving, false)
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
// TODO manual image ordering (shiftLeft/shiftRight functions)
|
|
|
|
|
// XXX
|
2013-04-26 05:30:56 +04:00
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
|
2013-05-05 23:39:35 +04:00
|
|
|
/*********************************************************** Marks ***/
|
2013-05-02 19:47:04 +04:00
|
|
|
|
2013-05-03 02:11:24 +04:00
|
|
|
// XXX if this unmarks an image in marked-only mode no visible image is
|
|
|
|
|
// going to be current...
|
2013-05-02 19:47:04 +04:00
|
|
|
var toggleImageMark = createCSSClassToggler('.current.image', 'marked')
|
|
|
|
|
|
|
|
|
|
// mode can be:
|
|
|
|
|
// - 'ribbon'
|
|
|
|
|
// - 'all'
|
|
|
|
|
function removeImageMarks(mode){
|
|
|
|
|
// remove marks from current ribbon (default)...
|
|
|
|
|
if(mode == 'ribbon' || mode == null){
|
2013-05-05 19:53:06 +04:00
|
|
|
return getRibbon()
|
|
|
|
|
.find('.marked')
|
|
|
|
|
.removeClass('marked')
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
// remove all marks...
|
|
|
|
|
} else if(mode == 'all'){
|
|
|
|
|
return $('.marked')
|
|
|
|
|
.removeClass('marked')
|
|
|
|
|
}
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
function markAll(mode){
|
|
|
|
|
// remove marks from current ribbon (default)...
|
|
|
|
|
if(mode == 'ribbon' || mode == null){
|
2013-05-05 19:53:06 +04:00
|
|
|
return getRibbon()
|
|
|
|
|
.find('.image:not(.marked)')
|
|
|
|
|
.addClass('marked')
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
// remove all marks...
|
|
|
|
|
} else if(mode == 'all'){
|
|
|
|
|
return $('.image:not(.marked)').addClass('marked')
|
|
|
|
|
}
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
|
|
|
|
|
2013-05-03 00:39:29 +04:00
|
|
|
// NOTE: this only does it's work in the current ribbon...
|
2013-05-02 19:47:04 +04:00
|
|
|
function invertImageMarks(){
|
2013-05-05 19:53:06 +04:00
|
|
|
return getRibbon()
|
|
|
|
|
.find('.image')
|
|
|
|
|
.toggleClass('marked')
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
2013-05-02 19:47:04 +04:00
|
|
|
|
|
|
|
|
// this will toggle marks in the current continuous section of marked
|
|
|
|
|
// or unmarked images...
|
|
|
|
|
function toggleImageMarkBlock(image){
|
|
|
|
|
if(image == null){
|
|
|
|
|
image = $('.current.image')
|
|
|
|
|
}
|
|
|
|
|
// we need to invert this...
|
|
|
|
|
var state = toggleImageMark()
|
|
|
|
|
var _convert = function(){
|
|
|
|
|
if(toggleImageMark(this, '?') == state){
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
toggleImageMark(this, state)
|
|
|
|
|
}
|
|
|
|
|
image.nextAll('.image').each(_convert)
|
|
|
|
|
image.prevAll('.image').each(_convert)
|
|
|
|
|
return state
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-05-02 19:47:04 +04:00
|
|
|
|
2013-04-26 05:30:56 +04:00
|
|
|
/**********************************************************************
|
|
|
|
|
* vim:set sw=4 ts=4 : */
|