ImageGrid/ui/setup.js
Alex A. Naanou f690308b4c cleanup, minor refactoring and commenting...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2013-12-07 05:05:43 +04:00

459 lines
12 KiB
JavaScript
Executable File

/**********************************************************************
*
*
**********************************************************************/
// A threshold after which the image block ratio will be changed to
// 'fit-viewer' in single image mode...
//
// NOTE: if null this feature will be disabled.
var PROPORTIONS_RATIO_THRESHOLD = 1.5
/**********************************************************************
* Setup
*/
function setupIndicators(){
showGlobalIndicator(
'single-ribbon-mode',
'Single ribbon mode (F3)')
.css('cursor', 'hand')
.click(function(){ toggleSingleRibbonMode() })
showGlobalIndicator(
'marks-visible',
'Marks visible (F2)')
.css('cursor', 'hand')
.click(function(){ toggleMarkesView() })
showGlobalIndicator(
'marked-only-visible',
'Marked only images visible (shift-F2)')
.css('cursor', 'hand')
.click(function(){ toggleMarkedOnlyView() })
showContextIndicator(
'current-image-marked',
'Image is marked (Ins)')
.css('cursor', 'hand')
.click(function(){ toggleImageMark() })
}
function updateContextIndicators(image){
image = image == null ? getImage() : $(image)
// marked...
var indicator = $('.context-mode-indicators .current-image-marked')
if(image.hasClass('marked')){
indicator.addClass('shown')
} else {
indicator.removeClass('shown')
}
}
// Setup event handlers for data bindings...
//
// This does two jobs:
// - maintain DATA state
// - editor actions
// - focus
// - marking
// - maintain view consistency
// - centering/moving (roll)
// - shifting (expand/contract)
// - zooming (expand/contract)
//
function setupDataBindings(viewer){
viewer = viewer == null ? $('.viewer') : viewer
viewer
.click(function(){
if($('.ribbon').length == 0){
loadDirectoryDialog()
}
})
.on([
'focusingImage',
'fittingImages'
].join(' '),
function(){
updateCurrentMarker()
})
// NOTE: we do not need to worry about explicit centering the ribbon
// here, just ball-park-load the correct batch...
// NOTE: if we decide to hide ribbons, uncomment the visibility
// test down in the code...
.on('preCenteringRibbon', function(evt, ribbon, image){
var r = getRibbonIndex(ribbon)
// skip all but the curent ribbon in single image view...
if(toggleSingleImageMode('?') == 'on' && r != getRibbonIndex()){
return
}
// skip the whole thing if the ribbon is not visible, i.e. outside
// of viewer area...
// NOTE: we are accounting for position relative to image...
// NOTE: we do not need to account for image height because
// of origin and vertical-align... (check)
var R = $('.viewer').height()/2
var d = Math.abs(getRelativeVisualPosition(image, ribbon).top)
if( d >= R ){
return
}
/* 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
}
*/
// prepare for loading...
var gid = getImageGID(image)
var gr = DATA.ribbons[r]
// NOTE: this can return null in certain cases (see docs)
var gid_before = getGIDBefore(gid, r)
// we'll set the image to the first if the align target is
// before it...
var img_before = gid_before == null
? ribbon.find('.image').first()
: getImageBefore(image, ribbon)
gid_before = gid_before == null ? gr[0] : gid_before
var screen_size = getScreenWidthInImages()
screen_size = screen_size < 1 ? 1 : screen_size
var load_frame_size = Math.round(screen_size * LOAD_SCREENS)
// target image is loaded...
if(gid_before == getImageGID(img_before)){
var roll_frame_size = Math.ceil(load_frame_size * ROLL_FRAME)
var threshold = Math.floor(load_frame_size * LOAD_THRESHOLD)
threshold = threshold < 1 ? 1 : threshold
var head = img_before.prevAll('.image').length
var tail = img_before.nextAll('.image').length
var l = ribbon.find('.image').length
var index = gr.indexOf(gid_before)
var at_start = index < threshold
var at_end = (gr.length-1 - index) < threshold
// less images than expected - extend ribbon...
if(l < load_frame_size){
// NOTE: we are forcing the count of images...
loadImagesAround(load_frame_size, gid, ribbon, null, true)
// tail at threshold - roll ->
} else if(!at_end && tail < threshold){
var rolled = rollImages(roll_frame_size, ribbon)
// head at threshold - roll <-
} else if(!at_start && head < threshold){
var rolled = rollImages(-roll_frame_size, ribbon)
} else {
console.log('>>> skipping:', r)
}
// we jumped, load new set...
} else {
// NOTE: we are forcing the count of images...
loadImagesAround(load_frame_size, gid, ribbon, null, true)
}
})
.on('shiftedImage', function(evt, image, from, to){
from = getRibbonIndex(from)
//var ribbon = to
to = getRibbonIndex(to)
var gid = getImageGID(image)
var after = getGIDBefore(gid, to)
// remove the elem from the from ribbon...
var index = DATA.ribbons[from].indexOf(gid)
var img = DATA.ribbons[from].splice(index, 1)
// put the elem in the to ribbon...
index = after == null ? 0 : DATA.ribbons[to].indexOf(after) + 1
DATA.ribbons[to].splice(index, 0, gid)
// indicators...
flashIndicator(from < to ? 'next' : 'prev')
})
.on('createdRibbon', function(evt, index){
index = getRibbonIndex(index)
DATA.ribbons.splice(index, 0, [])
})
.on('removedRibbon', function(evt, index){
DATA.ribbons.splice(index, 1)
})
.on('requestedFirstImage', function(evt, ribbon){
var r = getRibbonIndex(ribbon)
var gr = DATA.ribbons[r]
rollImages(-gr.length, ribbon)
})
.on('requestedLastImage', function(evt, ribbon){
var r = getRibbonIndex(ribbon)
var gr = DATA.ribbons[r]
rollImages(gr.length, ribbon)
})
.on('fittingImages', function(evt, n){
console.log('!!!! fittingImages')
// load correct amount of images in each ribbon!!!
var screen_size = getScreenWidthInImages()
var gid = getImageGID()
/* XXX used to skip ribbons that are not visible... (see bellow)
var viewer = $('.viewer')
var H = viewer.height()
var h = getImage().height()
*/
// update and align ribbons...
$('.ribbon').each(function(){
var r = $(this)
/* XXX skip ribbons that are not visible...
* causes misaligns and misloads on zoom-in...
// NOTE: we factor in the scale difference to predict
// ribbon position in the new view...
var t = getRelativeVisualPosition(viewer, r).top * (n/screen_size)
if( t+h <= 0 || t >= H ){
console.log('#### skipping align of ribbon:', getRibbonIndex(r))
return
}
*/
loadImagesAround(Math.round(screen_size * LOAD_SCREENS), gid, r, null, true)
})
centerView(null, 'css')
// update settings...
if(toggleSingleImageMode('?') == 'on'){
SETTINGS['single-image-mode-screen-images'] = n
} else {
SETTINGS['ribbon-mode-screen-images'] = n
}
// update proportions...
if(window.PROPORTIONS_RATIO_THRESHOLD != null
&& toggleSingleImageMode('?') == 'on'){
var h = getVisibleImageSize('height')
var w = getVisibleImageSize('width')
var H = $('.viewer').innerHeight()
var W = $('.viewer').innerWidth()
var m = Math.min(W/w, H/h)
if(m < PROPORTIONS_RATIO_THRESHOLD){
toggleImageProportions('fit-viewer')
} else {
toggleImageProportions('none')
}
}
// update size classes...
// XXX make thresholds global...
if(n <= 2.5){
$('.viewer')
.removeClass('small')
.addClass('large')
} else if (n >= 6) {
$('.viewer')
.addClass('small')
.removeClass('large')
} else {
$('.viewer')
.removeClass('small')
.removeClass('large')
}
// update previews...
updateImages()
})
.on('focusingImage', function(evt, image){
image = $(image)
DATA.current = getImageGID(image)
if(window.setWindowTitle != null){
// XXX do we need to hide the extension...
setWindowTitle(getImageFileName())
//.split(/\.(jpg|jpeg|png|gif)$/)[0])
}
})
// basic image manipulation...
.on('rotatingLeft rotatingRight', function(evt, image){
$(image).each(function(i, e){
var img = $(this)
var gid = getImageGID(img)
var orientation = img.attr('orientation')
// change the image orientation status and add to
// updated list...
IMAGES[gid].orientation = orientation
if(IMAGES_UPDATED.indexOf(gid) == -1){
IMAGES_UPDATED.push(gid)
}
})
})
.on('flippingVertical flippingHorizontal', function(evt, image){
$(image).each(function(i, e){
var img = $(this)
var gid = getImageGID(img)
var flip = getImageFlipState(img)
IMAGES[gid].flipped = flip
if(IMAGES_UPDATED.indexOf(gid) == -1){
IMAGES_UPDATED.push(gid)
}
})
})
.on('resetToOriginalImage', function(evt, image){
$(image).each(function(i, e){
var img = $(this)
var gid = getImageGID(img)
IMAGES[gid].flipped = null
IMAGES[gid].orientation = 0
if(IMAGES_UPDATED.indexOf(gid) == -1){
IMAGES_UPDATED.push(gid)
}
})
})
// marks...
// XXX toggle marking a block is not yet supported...
.on('togglingMark', function(evt, img, action){
var gid = getImageGID(img)
// add marked image to list...
if(action == 'on'){
MARKED.indexOf(gid) == -1 && MARKED.push(gid)
// remove marked image from list...
} else {
MARKED.splice(MARKED.indexOf(gid), 1)
}
})
.on('removeingRibbonMarks', function(evt, ribbon){
$.each(DATA.ribbons[getRibbonIndex(ribbon)], function(_, e){
var i = MARKED.indexOf(e)
if(i != -1){
MARKED.splice(i, 1)
}
})
})
.on('removeingAllMarks', function(evt){
MARKED.splice(0, MARKED.length)
})
.on('markingRibbon', function(evt, ribbon){
$.each(DATA.ribbons[getRibbonIndex(ribbon)], function(_, e){
var i = MARKED.indexOf(e)
if(i == -1){
MARKED.push(e)
}
})
})
.on('markingAll', function(evt){
MARKED.splice(0, MARKED.length)
MARKED.concat(DATA.order)
})
.on('invertingMarks', function(evt, ribbon){
$.each(DATA.ribbons[getRibbonIndex(ribbon)], function(_, e){
var i = MARKED.indexOf(e)
if(i == -1){
MARKED.push(e)
} else {
MARKED.splice(i, 1)
}
})
})
// caching...
.on('reloadedRibbon updatedRibbon', function(evt, ribbon){
window.DEBUG && console.log('>>> (ribbon:', getRibbonIndex(ribbon), ') Updating cache...')
preCacheRibbonImages(ribbon)
})
// info...
.on('focusingImage',
function(){
showRibbonIndicator()
})
.on([
'focusedNextRibbon',
'focusedPrevRibbon'
].join(' '),
function(){
if(toggleSingleImageMode('?') == 'on'){
flashRibbonIndicator()
}
})
.on([
'focusingImage',
'togglingMark'
].join(' '),
function(evt, image){
image = $(image)
updateGlobalImageInfo(image)
updateContextIndicators(image)
})
.on([
'rotatingLeft',
'rotateingRight',
'flippingVertical',
'flippingHorizontal'
].join(' '),
function(evt, image){
updateGlobalImageInfo($(image))
})
.on([
'removeingAllMarks',
'removeingRibbonMarks',
'markingAll',
'markingRibbon',
'invertingMarks'
].join(' '),
function(){
updateGlobalImageInfo()
updateContextIndicators()
})
.on('baseURLChanged', function(evt, url){
saveLocalStorageBaseURL()
saveLocalStorageBaseURLHistory()
})
}
/**********************************************************************
* vim:set ts=4 sw=4 : */