/********************************************************************** * * * **********************************************************************/ //var DEBUG = DEBUG != null ? DEBUG : true var SLIDESHOW_INTERVAL = 3000 var SLIDESHOW_LOOP = true var SLIDESHOW_DIRECTION = 'next' /********************************************************************** * Utils... */ // NOTE: this expects a certain structure, this it is not generic... //function makeDrawerToggler(contentRenderer, root, element_class, mode_class){ function makeDrawerToggler(contentRenderer, root){ var element_class = '.drawer-block' var toggler = createCSSClassToggler( root, 'drawer-mode overlay', function(action){ // XXX var body = $(document.body) var win = $(window) // on... if(action == 'on'){ // remove helo when we scroll to the top... var scroll_handler = function(){ if(body.scrollTop() <= 0){ toggler('off') } } // prepare and cleanup... $(element_class).remove() showInOverlay($(root)) // build the help... var doc = contentRenderer() .addClass(element_class.replace('.', ' ')) .on('click', function(){ event.stopImmediatePropagation() return false }) .css({ cursor: 'auto', }) // XXX depends on body... .appendTo(body) // add exit by click... // XXX depends on body... body .one('click', function(){ toggler('off') }) .css({ cursor: 'hand', }) // scroll to the help... // NOTE: need to set the scroll handler AFTER we // scroll down, or it will be more of a // tease than a help... var t = getRelativeVisualPosition($(root), doc).top body .animate({ scrollTop: Math.abs(t) - 40, }, function(){ // XXX depends on window... win .on('scroll', scroll_handler) }) // off... } else { // things to cleanup... var _cleanup = function(){ $(element_class).remove() hideOverlay($(root)) // XXX depends on body... body.click() win.off('scroll', scroll_handler) } // animate things if we are not at the top... if(body.scrollTop() > 0){ // XXX depends on body... body .css({ cursor: '', }) .animate({ scrollTop: 0, }, _cleanup) // if we are at the top do things fast... } else { _cleanup() } } }) return toggler } /********************************************************************** * Modes */ // XXX make this save and restore settings... var toggleSingleImageMode = createCSSClassToggler( '.viewer', 'single-image-mode', function(action){ // prevent reentering... if(action == toggleSingleImageMode('?')){ return false } }, function(action){ var w = getScreenWidthInImages() // single image mode... if(action == 'on'){ TRANSITION_MODE_DEFAULT = 'css' // save things... UI_STATE['ribbon-mode-screen-images'] = w UI_STATE['ribbon-mode-image-info'] = toggleImageInfo('?') // load things... w = UI_STATE['single-image-mode-screen-images'] w = w == null ? 1 : w // set stuff... fitNImages(w) toggleImageInfo('off') // ribbon mode... } else { TRANSITION_MODE_DEFAULT = 'animate' // save things... UI_STATE['single-image-mode-screen-images'] = w // load things... w = UI_STATE['ribbon-mode-screen-images'] w = w == null ? getScreenWidthInImages(CONFIG.default_image_size) : w fitNImages(w) var i = UI_STATE['ribbon-mode-image-info'] == 'on' ? 'on' : 'off' toggleImageInfo(i) UI_STATE['ribbon-mode-image-info'] = i centerRibbons() } }) // TODO transitions... // TODO a real setup UI (instead of prompt) // // XXX avoid using globals: // _pre_slideshow_marks_view // _slideshow_timer var toggleSlideShowMode = createCSSClassToggler( '.viewer', '.slideshow-mode', function(action){ if(action == 'on'){ updateStatus('Slideshow...').show() // XXX hackish... _pre_slideshow_marks_view = toggleMarksView('?') // interval from user... //var interval = prompt('Slideshow interval (sec):', SLIDESHOW_INTERVAL/1000) formDialog($('.viewer'), 'Slideshow', { 'Interval': (SLIDESHOW_INTERVAL/1000) + 'sec', 'Looping': SLIDESHOW_LOOP ? true : false, 'Reverse direction': SLIDESHOW_DIRECTION == 'prev' ? true : false }, 'Start') .done(function(data){ var looping = data['Looping'] var reverse = data['Reverse direction'] SLIDESHOW_LOOP = looping SLIDESHOW_DIRECTION = reverse == true ? 'prev' : 'next' // parse interval... var interval_raw = data['Interval'] // units... var M = 1000 if(/ms|msec|milsec|millisecond[s]/i.test(interval_raw)){ M = 1 } else if(/(s|sec|second[s])/i.test(interval_raw)){ M = 1000 } else if(/m|min|minute[s]/i.test(interval_raw)){ M = 1000*60 } // fractions... if(/[0-9]+\/[0-9]+/.test(interval_raw)){ var parts = interval_raw.split('/') var interval = parseFloat(parts[0]) / parseFloat(parts[1]) } else { var interval = parseFloat(interval_raw) } SLIDESHOW_INTERVAL = isNaN(interval) ? 3000 : interval*M showStatus('Slideshow: starting:', SLIDESHOW_INTERVAL/1000 +'sec,', SLIDESHOW_LOOP ? 'looped...' : 'unlooped...') // XXX is this the correct way to go??? hideOverlay($('.viewer')) toggleSingleImageMode('on') toggleMarksView('off') _slideshow_timer = setInterval(function(){ var cur = getImage() // advance the image... var next = SLIDESHOW_DIRECTION == 'next' ? nextImage() : prevImage() // handle slideshow end... if(getImageGID(cur) == getImageGID(next)){ if(SLIDESHOW_LOOP){ SLIDESHOW_DIRECTION == 'next' ? firstImage() : lastImage() } else { toggleSlideShowMode('off') toggleMarksView(window._pre_slideshow_marks_view == null ? 'on' : window._pre_slideshow_marks_view) return } } // center and trigger load events... centerRibbon() }, SLIDESHOW_INTERVAL) }) // user cancelled... .fail(function(){ toggleSlideShowMode('off') toggleMarksView(window._pre_slideshow_marks_view == null ? 'on' : window._pre_slideshow_marks_view) }) } else { window._slideshow_timer != null && clearInterval(_slideshow_timer) showStatus('Slideshow: canceled.') toggleMarksView(window._pre_slideshow_marks_view == null ? 'on' : window._pre_slideshow_marks_view) hideOverlay($('.viewer')) } }) var toggleTheme = createCSSClassToggler( '.viewer', [ 'gray', 'dark', 'light' ], // XXX does this get called for default state (gray)??? function(action){ UI_STATE['global-theme'] = action }) var toggleImageInfo = createCSSClassToggler( '.viewer', '.image-info-visible', function(action){ if(toggleSingleImageMode('?') == 'off'){ UI_STATE['ribbon-mode-image-info'] = action } }) var toggleInlineImageInfo = createCSSClassToggler( '.viewer', '.image-info-inline-visible', function(action){ if(action == 'on'){ $(document) .on('mouseover', inlineImageInfoHoverHandler) } else { $(document) .off('mouseover', inlineImageInfoHoverHandler) $('.inline-image-info').remove() } }) // Toggle image container proportions mode // // Available modes: // - none : square proportions // - fit-viewer : calculate proportions // // If CONFIG.proportions_ratio_threshold is null or if ignore_thresholds, // is set, this willsimply switch between square and viewer proportions. // // If CONFIG.proportions_ratio_threshold is set to a list of two values, // this will use the screen width in images (S) to calculate the // proportions: // S < min : viewer proportions // S > max : square proportions // min > S < max : transitional, proportions between // square and viewer... // // NOTE: if n is not passed, getScreenWidthInImages() will be used... // NOTE: if ignore_thresholds is set or the threshold is not a list, this // will ignore the threshold... // // XXX is this the right place to calculate proportions??? (revise) var toggleImageProportions = createCSSClassToggler( '.viewer', [ 'none', 'fit-viewer' ], function(action, viewer, n, ignore_thresholds){ var image = $('.image') // viewer proportions... if(action == 'fit-viewer'){ // NOTE: we care about n only in fit-viewer mode... n = n == null ? getScreenWidthInImages() : n var threshold = CONFIG.proportions_ratio_threshold // image proportions between square and viewer indicator... // // must be between 0 and 1: // - 1 is square proportions // - 0 is viewer proportions var c = 0 // calculate c... if(!ignore_thresholds && (threshold != null || threshold.length == 2)){ var min = Math.min.apply(null, threshold) var max = Math.max.apply(null, threshold) var c = (n - min) / (max - min) c = c < 0 ? 0 : c > 1 ? 1 : c } var W = viewer.innerWidth() var H = viewer.innerHeight() // landscape viewer... if(W > H){ var h = image.outerHeight(true) var scale = h/H var tw = W * scale var d = tw - h image.css({ //width: W * scale, width: tw - (d * c), height: '', }) // portrait viewer... } else { var w = image.outerWidth(true) var scale = w/W var th = H * scale var d = th - w image.css({ width: '', //height: H * scale, height: th - d * c, }) } // square proportions... // NOTE: this will reset the size to default (defined in CSS) } else { image.css({ width: '', height: '' }) } // account for rotation... correctImageProportionsForRotation(image) centerView(null, 'css') viewer.trigger('updatingImageProportions') }) var toggleHelp = makeDrawerToggler( function(){ // XXX populate... // ...load from file. return $('

Help

') }, '.viewer') var toggleKeyboardHelp = makeDrawerToggler( function(){ return buildKeybindingsHelpHTML(KEYBOARD_CONFIG) }, '.viewer') var toggleOptionsUI = makeDrawerToggler( function(){ // XXX populate... return $('

Options

') }, '.viewer') // XXX needs styling and cleanup... // XXX add a preview... var toggleImageInfoDrawer = makeDrawerToggler( function(){ var gid = getImageGID(getImage()) var r = getRibbonIndex(getRibbon()) var data = IMAGES[gid] var orientation = data.orientation orientation = orientation == null ? 0 : orientation var order = DATA.order.indexOf(gid) var name = getImageFileName(gid) return $('
'+ '

"'+ name +'"

'+ 'Orientation: '+ orientation +'deg
'+ 'GID: '+ gid +'
'+ 'Path: "'+ data.path +'"
'+ 'Order: '+ order +'
'+ 'Position (ribbon): '+ (DATA.ribbons[r].indexOf(gid)+1) + '/'+ DATA.ribbons[r].length +'
'+ 'Position (global): '+ (order+1) +'/'+ DATA.order.length +'
'+ '
') }, '.viewer') /********************************************************************** * Experimental... */ function getImageProportions(gid){ gid = gid == null ? getImageGID() : gid var o = IMAGES[gid].orientation o = o == null ? 0 : o var res = $.Deferred() var i = new Image() i.onload = function(){ if(o == 0 || o == 180){ var w = i.width/i.height } else { var w = i.height/i.width } res.resolve(w) } i.src = getBestPreview(gid).url return res } function _fitImageToRibbonHeight(gid, image){ setTimeout(function(){ getImageProportions(gid).done(function(r){ var h = image.height() image.css({ width: h * r, }) correctImageProportionsForRotation(image, image) }) }, 0) return image } // XXX this does not work yet + I'm not sure if we need it... var toggleRibbonImageProportions = createCSSClassToggler( '.viewer', [ 'none', 'ribbon-image-proportions' ], function(action){ var image = $('.image') if(action == 'ribbon-image-proportions'){ // register the updater... IMAGE_UPDATERS.push(_fitImageToRibbonHeight) updateImages() } else { // unregister the updater... IMAGE_UPDATERS.splice(IMAGE_UPDATERS.indexOf(_fitImageToRibbonHeight), 1) image.css({ width: '', height: '' }) // account for rotation... correctImageProportionsForRotation(image) } centerView(null, 'css') }) /********************************************************************** * vim:set ts=4 sw=4 : */