diff --git a/ui/gallery-prototype.js b/ui/gallery-prototype.js
index 2ae86c7e..da9f0903 100755
--- a/ui/gallery-prototype.js
+++ b/ui/gallery-prototype.js
@@ -13,15 +13,23 @@
var ImageGrid = {
// this can be serialized...
// NOTE: to load a serialized set of options use ImageGrid.set(options)...
+ actions: {},
option: {},
option_props: {},
+ option_groups: [],
// define an action...
// the two values that are obligatory are:
// title - name of the action
// call - callable
// XXX revise...
- ACTION: function(obj){
+ ACTION: function(obj, func){
+ if(func != null){
+ obj = $.extend(obj, {
+ id: func.name != '' ? func.name : obj.id,
+ call: func
+ })
+ }
// add all the attrs to the function...
if(this._type_handler[obj.type] != null){
this._type_handler[obj.type](obj)
@@ -34,8 +42,24 @@ var ImageGrid = {
call[i] = obj[i]
}
this[obj.id] = call
+ this.actions[obj.id] = call
return call
},
+ // shorthand: each argument is an action, the group of each will be set the same...
+ GROUP: function(group){
+ for(var i=1; i')
- // build options...
- for(var n in opt_ps){
- var disabled = false
- var opt = opt_ps[n]
- var group = opt.group
- // handle disabled opts...
- if(opt.display == false){
- if(!DEBUG){
- continue
- }
- disabled = true
+
+ // build an action indexed dict (effectively reverse keybindings)...
+ var res = {}
+ for(var k in keybindings){
+ var n = [toKeyName(k)]
+ // get the action name...
+ // XXX need a name here...
+ var v = keybindings[k]
+ // alias...
+ while(typeof(v) == typeof(3)){
+ // XXX skip for now...
+ // ...later we will need to accumolate all the keys in a list...
+ continue
}
- // build an option...
- var option = $('
').append($([
- $('').text(opt.title != null ? opt.title : n)[0],
- $('').html(opt['doc'].replace(/\n/g, '
'))[0],
- $('').text(opts[n])[0]
- ]))
- // group things correctly...
- if(group == null){
- group = 'Other'
- }
- if(groups[group] == null){
- groups[group] = $('')
- .append($('').text(group))
- .append(option)
+ // function...
+ if(typeof(v) == typeof(function(){})){
+ // XXX title...
+ // XXX name...
+ // XXX ???
+ // Array...
+ } else if(typeof(v) == typeof([]) && v.constructor.name == 'Array'){
+ // XXX get the second arg...
+ // object...
+ } else if(typeof(v) == typeof({})){
+ // XXX get all the handlers and accumolate the keys...
+ // XXX unknown...
} else {
- groups[group].append(option)
+ // XXX err...
}
- // event handlers...
- var handler = opt_ps[n].click_handler
- if(disabled){
- option.addClass('disabled')
- } else if(handler != null){
- option.click(handler)
- }
-
}
- // build groups...
- for(var i = 0; i < ImageGrid.option_groups.length; i++){
- var group_name = ImageGrid.option_groups[i]
- opts_container.append(groups[group_name])
- }
- opts_container.append(groups['Other'])
- opts_container.click(function(e){
- // update the view...
- // XXX do we need to redraw the whole thing on each click???
- showSetup()
- e.preventDefault()
- return false
- })
- showInOverlay(opts_container)
+ var res = {}
}
@@ -206,76 +241,74 @@ var DEBUG = true
//var DEBUG = false
-ImageGrid.OPTION({
- name: 'BACKGROUND_MODES',
- doc: 'list of available background styles.\n'+
- 'NOTE: there is also a null mode that is what is set in the '+
- 'main CSS.',
- display: false,
- value: [
- 'dark',
- 'black',
- // this can be removed but when given it must be last.
- null
- ]
-})
+ImageGrid.GROUP('State',
+ ImageGrid.OPTION({
+ name: 'BACKGROUND_MODES',
+ doc: 'list of available background styles.\n'+
+ 'NOTE: there is also a null mode that is what is set in the '+
+ 'main CSS.',
+ display: false,
+ value: [
+ 'dark',
+ 'black',
+ // this can be removed but when given it must be last.
+ null
+ ]
+ }),
+ ImageGrid.OPTION({
+ name: 'NORMAL_MODE_BG',
+ display: false,
+ value: null,
+ doc: 'Background style in normal (ribbon) mode.\n'+
+ 'NOTE: This will get updated on background change in tuntime.\n'+
+ 'NOTE: null represents the default style.',
+ callback: function(){
+ if(ImageGrid.toggleSingleImageMode('?') == 'off'){
+ setBackgroundMode(ImageGrid.option.NORMAL_MODE_BG)
+ }
+ }
+ }),
+ ImageGrid.OPTION({
+ name: 'SINGLE_IMAGE_MODE_BG',
+ display: false,
+ value: 'black',
+ doc: 'Background style in single image mode.\n'+
+ 'NOTE: This will get updated on background change in tuntime.\n'+
+ 'NOTE: null represents the default style.',
+ callback: function(){
+ if(ImageGrid.toggleSingleImageMode('?') == 'on'){
+ setBackgroundMode(ImageGrid.option.SINGLE_IMAGE_MODE_BG)
+ }
+ }
+ }),
+ ImageGrid.OPTION({
+ name: 'ORIGINAL_FIELD_SCALE',
+ display: false,
+ value: 1.0,
+ doc: 'Scale of view in image mode.\n'+
+ 'NOTE: this will change if changed at runtime.',
+ callback: function(){
+ if(ImageGrid.toggleSingleImageMode('?') == 'off'){
+ setContainerScale(ImageGrid.option.ORIGINAL_FIELD_SCALE)
+ }
+ }
+ }))
-ImageGrid.OPTION({
- name: 'NORMAL_MODE_BG',
- display: false,
- value: null,
- doc: 'Background style in normal (ribbon) mode.\n'+
- 'NOTE: This will get updated on background change in tuntime.\n'+
- 'NOTE: null represents the default style.',
- callback: function(){
- if(ImageGrid.toggleSingleImageMode('?') == 'off'){
- setBackgroundMode(ImageGrid.option.NORMAL_MODE_BG)
- }
- }
-})
-ImageGrid.OPTION({
- name: 'SINGLE_IMAGE_MODE_BG',
- display: false,
- value: 'black',
- doc: 'Background style in single image mode.\n'+
- 'NOTE: This will get updated on background change in tuntime.\n'+
- 'NOTE: null represents the default style.',
- callback: function(){
- if(ImageGrid.toggleSingleImageMode('?') == 'on'){
- setBackgroundMode(ImageGrid.option.SINGLE_IMAGE_MODE_BG)
- }
- }
-})
+ImageGrid.GROUP('Mode: All',
+ ImageGrid.OPTION({
+ name: 'ZOOM_FACTOR',
+ title: 'Zooming factor',
+ value: 2,
+ doc: 'Sets the zoom factor used for a manual zooming step.'
+ }),
+ ImageGrid.OPTION({
+ name: 'MOVE_DELTA',
+ title: 'Move step',
+ value: 50,
+ doc: 'Sets the move delta in pixels for keyboard view moving.'
+ }))
-ImageGrid.OPTION({
- name: 'ORIGINAL_FIELD_SCALE',
- display: false,
- value: 1.0,
- doc: 'Scale of view in image mode.\n'+
- 'NOTE: this will change if changed at runtime.',
- callback: function(){
- if(ImageGrid.toggleSingleImageMode('?') == 'off'){
- setContainerScale(ImageGrid.option.ORIGINAL_FIELD_SCALE)
- }
- }
-})
-
-ImageGrid.OPTION({
- name: 'ZOOM_FACTOR',
- title: 'Zooming factor',
- group: 'Mode: All',
- value: 2,
- doc: 'Sets the zoom factor used for a manual zooming step.'
-})
-
-ImageGrid.OPTION({
- name: 'MOVE_DELTA',
- title: 'Move step',
- group: 'Mode: All',
- value: 50,
- doc: 'Sets the move delta in pixels for keyboard view moving.'
-})
@@ -320,6 +353,28 @@ function cmpImageOrder(a, b){
+// show a jQuary opject in viewer overlay...
+function showInOverlay(obj){
+ // clean things up...
+ $('.overlay .content').children().remove()
+ // put it in the overlay...
+ $('.overlay .content').append(obj)
+ // prepare the overlay...
+ $('.overlay')
+ .one('click', function(){
+ $('.overlay')
+ .fadeOut(function(){
+ $('.overlay .content')
+ .children()
+ .remove()
+ })
+ })
+ .fadeIn()
+ return obj
+}
+
+
+
// this will create a function that will add/remove a css_class to elem
// calling the optional callbacks before and/or after.
//
@@ -396,6 +451,21 @@ function doWithoutTransitions(obj, func){
}
+
+function clickAfterTransitionsDone(img){
+ if(img == null){
+ img = $('.current.image')
+ }
+ $('.viewer')
+ .one("webkitTransitionEnd oTransitionEnd msTransitionEnd transitionend", function(){
+ img.click()
+ return true
+ })
+}
+
+
+
+
// find an image object after which to position image ID...
// used for two main tasks:
// - positioning promoted/demoted images
@@ -495,6 +565,161 @@ var getImageBefore = getImageBefore_bin
+/*
+ * The folowing two functions will get the vertical and horizontal
+ * distance components between the points a and A, centers of the small
+ * and large squares respectively.
+ * One of the squares is .field and the other is .container,
+ * which is small or big is not important.
+ *
+ * +---------------+-------+
+ * | | |
+ * | | |
+ * | + a . . | . . . | . +
+ * | . | | +- getCurrentVerticalOffset(...)
+ * | . + A | . . . | . +
+ * +---------------+ |
+ * | . . |
+ * | . . |
+ * | . . |
+ * +-----------------------+
+ * . .
+ * +-+-+
+ * +------------------- getCurrentHorizontalOffset(...)
+ *
+ *
+ * Adding this distance to margins of one of the sqares will effectively
+ * allign the two points.
+ *
+ * NOTE: neither function accunts for field margins.
+ *
+ */
+
+// get the vertical offset of the center of square from center of container
+// NOTE: this does not account for field margins
+function getCurrentVerticalOffset(image){
+ if(image == null){
+ image = $('.image.current')
+ }
+
+ var scale = getElementScale($('.field'))
+
+ var ribbons = $('.ribbon')
+ var ribbon = image.parents('.ribbon')
+ var images = ribbon.children('.image')
+
+ // vertical...
+ var H = $('.container').height()
+ var h = ribbons.outerHeight(true)
+ // margin...
+ var mh = h - ribbons.outerHeight()
+ // current ribbon position (1-based)
+ var rn = ribbons.index(ribbon) + 1
+ // relative position to field...
+ // XXX is there a better way to get this?
+ var t = rn * (h - mh/2)
+
+ return -t + H/2 + h/2
+}
+
+// get the horizontal offset of the center of square from center of container
+// NOTE: this does not account for field margins
+function getCurrentHorizontalOffset(image){
+ if(image == null){
+ image = $('.image.current')
+ }
+
+ var ribbon = image.parents('.ribbon')
+ var images = ribbon.children('.image')
+
+ var W = $('.container').width()
+ var w = images.outerWidth(true)
+ // margin...
+ var mw = w - images.outerWidth()
+ // current square position (1-based)
+ var sn = images.index(image) + 1
+ var l = sn * (w - mw/2)
+
+ return -l + W/2 + w/2
+}
+
+
+
+function centerSquare(){
+ $('.field').css({
+ 'margin-top': getCurrentVerticalOffset()
+ })
+ // horizontal...
+ alignRibbon()
+ ImageGrid.centerCurrentImage()
+}
+
+
+
+function alignRibbon(image, position){
+ // default values...
+ if(image == null){
+ image = $('.image.current')
+ }
+ if(position == null){
+ position = 'center'
+ }
+
+ var ribbon = image.parents('.ribbon')
+
+ // account for margined field...
+ // NOTE: this enables us to cheat and shift all the ribbons just
+ // by changing field margin-left...
+ var cml = parseFloat($('.field').css('margin-left'))
+ if(!cml){
+ cml = 0
+ }
+ var h_offset = getCurrentHorizontalOffset(image) - cml
+ var w = $('.image').outerWidth(true)
+
+ switch(position){
+ case 'before':
+ ribbon.css({'margin-left': h_offset - w/2})
+ return true
+ case 'center':
+ ribbon.css({'margin-left': h_offset})
+ return true
+ case 'after':
+ ribbon.css({'margin-left': h_offset + w/2})
+ return true
+ }
+ return false
+}
+
+
+
+// center other ribbons relative to current image...
+// NOTE: only two ribbons are positioned at this point...
+function alignRibbons(get_order){
+ if(get_order == null){
+ get_order = getImageOrder
+ }
+ // XXX might be good to move this to a more generic location...
+ var id = get_order($('.current.image'))
+ var directions = ['prev', 'next']
+ for(var i in directions){
+ var ribbon = $('.current.ribbon')[directions[i]]('.ribbon')
+ if(ribbon.length == 1){
+ var img = getImageBefore(id, ribbon)
+ if(img != null){
+ alignRibbon(img, 'before')
+ } else {
+ // there are no images before...
+ alignRibbon(ribbon.children('.image').first(), 'after')
+ }
+ }
+ }
+}
+
+
+
+
+
/************************************************** Setup Functions **/
// XXX is this a correct place for these?
@@ -526,8 +751,8 @@ function setupEvents(){
// swipe...
$('.viewer')
.swipe({
- swipeLeft: nextImage,
- swipeRight: prevImage,
+ swipeLeft: ImageGrid.nextImage,
+ swipeRight: ImageGrid.prevImage,
swipeUp: shiftImageUp,
swipeDown: shiftImageDown
})
@@ -545,8 +770,8 @@ function setupControlElements(){
$(".image").click(handleImageClick)
// buttons...
- $('.screen-button.next-image').click(nextImage)
- $('.screen-button.prev-image').click(prevImage)
+ $('.screen-button.next-image').click(ImageGrid.nextImage)
+ $('.screen-button.prev-image').click(ImageGrid.prevImage)
// XXX rename classes to "shift-image-up" and "shift-image-down"...
$('.screen-button.demote').click(shiftImageUp)
$('.screen-button.promote').click(shiftImageDown)
@@ -557,7 +782,7 @@ function setupControlElements(){
$('.screen-button.toggle-single').click(ImageGrid.toggleSingleImageMode)
$('.screen-button.fit-three').click(fitThreeImages)
$('.screen-button.show-controls').click(function(){ImageGrid.toggleControls('on')})
- $('.screen-button.settings').click(showSetup)
+ $('.screen-button.settings').click(ImageGrid.showSetup)
}
@@ -653,133 +878,7 @@ function loadJSON(data, set_order){
-/*
- * The folowing two functions will get the vertical and horizontal
- * distance components between the points a and A, centers of the small
- * and large squares respectively.
- * One of the squares is .field and the other is .container,
- * which is small or big is not important.
- *
- * +---------------+-------+
- * | | |
- * | | |
- * | + a . . | . . . | . +
- * | . | | +- getCurrentVerticalOffset(...)
- * | . + A | . . . | . +
- * +---------------+ |
- * | . . |
- * | . . |
- * | . . |
- * +-----------------------+
- * . .
- * +-+-+
- * +------------------- getCurrentHorizontalOffset(...)
- *
- *
- * Adding this distance to margins of one of the sqares will effectively
- * allign the two points.
- *
- * NOTE: neither function accunts for field margins.
- *
- */
-
-// get the vertical offset of the center of square from center of container
-// NOTE: this does not account for field margins
-function getCurrentVerticalOffset(image){
- if(image == null){
- image = $('.image.current')
- }
-
- var scale = getElementScale($('.field'))
-
- var ribbons = $('.ribbon')
- var ribbon = image.parents('.ribbon')
- var images = ribbon.children('.image')
-
- // vertical...
- var H = $('.container').height()
- var h = ribbons.outerHeight(true)
- // margin...
- var mh = h - ribbons.outerHeight()
- // current ribbon position (1-based)
- var rn = ribbons.index(ribbon) + 1
- // relative position to field...
- // XXX is there a better way to get this?
- var t = rn * (h - mh/2)
-
- return -t + H/2 + h/2
-}
-
-// get the horizontal offset of the center of square from center of container
-// NOTE: this does not account for field margins
-function getCurrentHorizontalOffset(image){
- if(image == null){
- image = $('.image.current')
- }
-
- var ribbon = image.parents('.ribbon')
- var images = ribbon.children('.image')
-
- var W = $('.container').width()
- var w = images.outerWidth(true)
- // margin...
- var mw = w - images.outerWidth()
- // current square position (1-based)
- var sn = images.index(image) + 1
- var l = sn * (w - mw/2)
-
- return -l + W/2 + w/2
-}
-
-
-
-function centerSquare(){
- $('.field').css({
- 'margin-top': getCurrentVerticalOffset()
- })
- // horizontal...
- alignRibbon()
- centerCurrentImage()
-}
-
-
-
-function alignRibbon(image, position){
- // default values...
- if(image == null){
- image = $('.image.current')
- }
- if(position == null){
- position = 'center'
- }
-
- var ribbon = image.parents('.ribbon')
-
- // account for margined field...
- // NOTE: this enables us to cheat and shift all the ribbons just
- // by changing field margin-left...
- var cml = parseFloat($('.field').css('margin-left'))
- if(!cml){
- cml = 0
- }
- var h_offset = getCurrentHorizontalOffset(image) - cml
- var w = $('.image').outerWidth(true)
-
- switch(position){
- case 'before':
- ribbon.css({'margin-left': h_offset - w/2})
- return true
- case 'center':
- ribbon.css({'margin-left': h_offset})
- return true
- case 'after':
- ribbon.css({'margin-left': h_offset + w/2})
- return true
- }
- return false
-}
-
-
+/*********************************************************************/
/*************************************************** Event Handlers **/
@@ -799,44 +898,6 @@ function handleImageClick(){
-function clickAfterTransitionsDone(img){
- if(img == null){
- img = $('.current.image')
- }
- $('.viewer')
- .one("webkitTransitionEnd oTransitionEnd msTransitionEnd transitionend", function(){
- img.click()
- return true
- })
-}
-
-
-
-// center other ribbons relative to current image...
-// NOTE: only two ribbons are positioned at this point...
-function alignRibbons(get_order){
- if(get_order == null){
- get_order = getImageOrder
- }
- // XXX might be good to move this to a more generic location...
- var id = get_order($('.current.image'))
- var directions = ['prev', 'next']
- for(var i in directions){
- var ribbon = $('.current.ribbon')[directions[i]]('.ribbon')
- if(ribbon.length == 1){
- var img = getImageBefore(id, ribbon)
- if(img != null){
- alignRibbon(img, 'before')
- } else {
- // there are no images before...
- alignRibbon(ribbon.children('.image').first(), 'after')
- }
- }
- }
-}
-
-
-
/*
* Basic key format:
* : ,
@@ -851,6 +912,11 @@ function alignRibbons(get_order){
* // - shift
* : [...]
* },
+ * : [
+ * // this can be any type of handler except for an alias...
+ * ,
+ *
+ * ],
* // alias...
* : ,
*
@@ -877,6 +943,12 @@ function makeKeyboardHandler(keybindings, unhandled){
if(handler == null){
return unhandled(key)
}
+ // Array, lisp style with docs...
+ // XXX for some odd reason in chrome typeof([]) == typeof({})!!!
+ if(typeof(handler) == typeof([]) && handler.constructor.name == 'Array'){
+ // we do not care about docs here, so just get the handler...
+ handler = handler[0]
+ }
// complex handler...
if(typeof(handler) == typeof({})){
var callback = handler[modifers]
@@ -900,68 +972,7 @@ function makeKeyboardHandler(keybindings, unhandled){
-/************************************************************ Modes **/
-
-ImageGrid.ACTION({
- id: 'toggleSingleImageMode',
- title: 'Single image mode',
- doc: 'Toggle single image mode.',
- group: 'Mode: Single Image',
- type: 'toggle',
- display: false,
- call: createCSSClassToggler('.viewer', 'single-image-mode',
- // pre...
- function(action){
- if(action == 'on'){
- ImageGrid.option.NORMAL_MODE_BG = getBackgroundMode()
- ImageGrid.option.ORIGINAL_FIELD_SCALE = getElementScale($('.field'))
- // do this only when coming out of single image mode...
- } else if(ImageGrid.toggleSingleImageMode('?') == 'on'){
- ImageGrid.option.SINGLE_IMAGE_MODE_BG = getBackgroundMode()
- }
- },
- // post...
- function(action){
- if(action == 'on'){
- fitImage()
- setBackgroundMode(ImageGrid.option.SINGLE_IMAGE_MODE_BG)
- } else {
- setContainerScale(ImageGrid.option.ORIGINAL_FIELD_SCALE)
- setBackgroundMode(ImageGrid.option.NORMAL_MODE_BG)
- }
- clickAfterTransitionsDone()
- })
-})
-
-
-ImageGrid.ACTION({
- id: 'toggleSingleRibbonMode',
- title: 'Single ribbon mode',
- doc: 'Show/hide other ribbons.',
- group: 'Mode: Ribbon',
- type: 'toggle',
- call: createCSSClassToggler('.viewer', 'single-ribbon-mode')
-})
-
-
-// XXX this can be done in two ways:
-// - keep all images when promoting, just add a class to them that
-// will hide them until we enable their display...
-// + very fast to show/hide
-// - will complicate reversing ribbons allot
-// - add/remove these images on demand
-// + a tad complicated...
-ImageGrid.ACTION({
- id: 'toggleDisplayShiftedUpImages',
- title: 'Display shifted up images',
- doc: 'Toggle display of shifted images.',
- group: 'Mode: Ribbon',
- display: false,
- type: 'toggle',
- call: createCSSClassToggler('.viewer', 'show-shifted-up-images')
-})
-
-
+/************************************************ Mode & UI Actions **/
function getBackgroundMode(){
var mode = null
@@ -1022,174 +1033,344 @@ function toggleBackgroundModes(){
-// XXX for some reason this is backwords... (says 'on' when it's off ans 'off' when on)
+// XXX use order and priority of options...
+// XXX make history work for this...
+// XXX should this be a toggle??
ImageGrid.ACTION({
- id: 'toggleSingleImageModeTransitions',
- title: 'Disable single image mode transitions',
- doc: 'Toggle transitions in single image mode.',
- group: 'Mode: Single Image',
- type: 'toggle',
- call: createCSSClassToggler('.viewer', 'no-single-image-transitions')
+ title: 'Settings',
+ doc: 'Show setup interface.',
+},
+function showSetup(){
+ var opts = ImageGrid.option
+ var opt_ps = ImageGrid.option_props
+ var groups = {}
+
+ var opts_container = $('')
+ // build options...
+ for(var n in opt_ps){
+ var disabled = false
+ var opt = opt_ps[n]
+ var group = opt.group
+ // handle disabled opts...
+ if(opt.display == false){
+ if(!DEBUG){
+ continue
+ }
+ disabled = true
+ }
+ // build an option...
+ var option = $('').append($([
+ $('').text(opt.title != null ? opt.title : n)[0],
+ $('').html(opt['doc'].replace(/\n/g, '
'))[0],
+ $('').text(opts[n])[0]
+ ]))
+ // group things correctly...
+ if(group == null){
+ group = 'Other'
+ }
+ if(groups[group] == null){
+ groups[group] = $('')
+ .append($('').text(group))
+ .append(option)
+ } else {
+ groups[group].append(option)
+ }
+ // event handlers...
+ var handler = opt_ps[n].click_handler
+ if(disabled){
+ option.addClass('disabled')
+ } else if(handler != null){
+ option.click(handler)
+ }
+ }
+ // build groups...
+ for(var i = 0; i < ImageGrid.option_groups.length; i++){
+ var group_name = ImageGrid.option_groups[i]
+ opts_container.append(groups[group_name])
+ }
+ opts_container.append(groups['Other'])
+ opts_container.click(function(e){
+ // update the view...
+ // XXX do we need to redraw the whole thing on each click???
+ ImageGrid.showSetup()
+ e.preventDefault()
+ return false
+ })
+ showInOverlay(opts_container)
})
-ImageGrid.ACTION({
- id: 'toggleControls',
- title: 'Keyboard-oriented interface',
- doc: 'Toggle Touch/Keyboard UI controls.',
- group: 'Mode: All',
- type: 'toggle',
- call: createCSSClassToggler('.viewer', 'hidden-controls')
-})
-ImageGrid.ACTION({
- id: 'toggleTransitions',
- title: 'Global transitions',
- doc: 'Toggle global transitions.',
- group: 'Mode: All',
- type: 'toggle',
- call: createCSSClassToggler('.viewer', 'transitions-enabled')
-})
+ImageGrid.GROUP('Mode: All',
+ ImageGrid.ACTION({
+ id: 'toggleControls',
+ title: 'Keyboard-oriented interface',
+ doc: 'Toggle Touch/Keyboard UI controls.',
+ type: 'toggle',
+ },
+ createCSSClassToggler('.viewer', 'hidden-controls')),
+ ImageGrid.ACTION({
+ id: 'toggleTransitions',
+ title: 'Global transitions',
+ doc: 'Toggle global transitions.',
+ type: 'toggle',
+ },
+ createCSSClassToggler('.viewer', 'transitions-enabled')))
+
+
+
+
+ImageGrid.GROUP('Mode: Single Image',
+ ImageGrid.ACTION({
+ id: 'toggleSingleImageMode',
+ title: 'Single image mode',
+ doc: 'Toggle single image mode.',
+ type: 'toggle',
+ display: false,
+ },
+ createCSSClassToggler('.viewer', 'single-image-mode',
+ // pre...
+ function(action){
+ if(action == 'on'){
+ ImageGrid.option.NORMAL_MODE_BG = getBackgroundMode()
+ ImageGrid.option.ORIGINAL_FIELD_SCALE = getElementScale($('.field'))
+ // do this only when coming out of single image mode...
+ } else if(ImageGrid.toggleSingleImageMode('?') == 'on'){
+ ImageGrid.option.SINGLE_IMAGE_MODE_BG = getBackgroundMode()
+ }
+ },
+ // post...
+ function(action){
+ if(action == 'on'){
+ fitImage()
+ setBackgroundMode(ImageGrid.option.SINGLE_IMAGE_MODE_BG)
+ } else {
+ setContainerScale(ImageGrid.option.ORIGINAL_FIELD_SCALE)
+ setBackgroundMode(ImageGrid.option.NORMAL_MODE_BG)
+ }
+ clickAfterTransitionsDone()
+ })),
+ // XXX for some reason this is backwords... (says 'on' when it's off ans 'off' when on)
+ // ...and needs an extra click to sync with state...
+ ImageGrid.ACTION({
+ id: 'toggleSingleImageModeTransitions',
+ title: 'Disable single image mode transitions',
+ doc: 'Toggle transitions in single image mode.',
+ type: 'toggle',
+ },
+ createCSSClassToggler('.viewer', 'no-single-image-transitions')))
+
+
+
+ImageGrid.GROUP('Mode: Ribbon',
+ ImageGrid.ACTION({
+ id: 'toggleSingleRibbonMode',
+ title: 'Single ribbon mode',
+ doc: 'Show/hide other ribbons.',
+ type: 'toggle',
+ },
+ createCSSClassToggler('.viewer', 'single-ribbon-mode')),
+
+ // XXX this can be done in two ways:
+ // - keep all images when promoting, just add a class to them that
+ // will hide them until we enable their display...
+ // + very fast to show/hide
+ // - will complicate reversing ribbons allot
+ // - add/remove these images on demand
+ // + a tad complicated...
+ ImageGrid.ACTION({
+ id: 'toggleDisplayShiftedUpImages',
+ title: 'Display shifted up images',
+ doc: 'Toggle display of shifted images.',
+ display: false,
+ type: 'toggle',
+ },
+ createCSSClassToggler('.viewer', 'show-shifted-up-images')))
+
+
/********************************************************* Movement **/
-/* Set the transform-origin to the center of the current view...
- */
-function centerOrigin(){
- var mt = parseFloat($('.field').css('margin-top'))
- var ml = parseFloat($('.field').css('margin-left'))
- var cml = parseFloat($('.current.ribbon').css('margin-left'))
+ImageGrid.GROUP('Movement',
+ ImageGrid.ACTION({
+ title: 'Center origin',
+ doc: 'Set the transform-origin to the center of the current view.',
+ display: false,
+ },
+ function centerOrigin(){
+ var mt = parseFloat($('.field').css('margin-top'))
+ var ml = parseFloat($('.field').css('margin-left'))
+ var cml = parseFloat($('.current.ribbon').css('margin-left'))
- var t = parseFloat($('.field').css('top'))
- var l = parseFloat($('.field').css('left'))
- var w = $('.field').width()
- var h = $('.field').height()
- var W = $('.container').width()
- var H = $('.container').height()
+ var t = parseFloat($('.field').css('top'))
+ var l = parseFloat($('.field').css('left'))
+ var w = $('.field').width()
+ var h = $('.field').height()
+ var W = $('.container').width()
+ var H = $('.container').height()
- var ot = -getCurrentVerticalOffset() + H/2 - t
- var ol = -ml + W/2 - l
+ var ot = -getCurrentVerticalOffset() + H/2 - t
+ var ol = -ml + W/2 - l
- $('.field').css({
- 'transform-origin': ol + 'px ' + ot + 'px',
- '-o-transform-origin': ol + 'px ' + ot + 'px',
- '-moz-transform-origin': ol + 'px ' + ot + 'px',
- '-webkit-transform-origin': ol + 'px ' + ot + 'px',
- '-ms-transform-origin': ol + 'px ' + ot + 'px'
- })
-
- // XXX for debugging...
- $('.origin-marker').css({
- 'top': ot,
- 'left': ol
- })
-}
-
-
-
-// XXX these work oddly when page is scaled in maxthon...
-// XXX virtually identical, see of can be merged...
-function moveViewUp(){
- var t = parseInt($('.field').css('top'))
- $('.field').css({'top': t-(ImageGrid.option.MOVE_DELTA)})
-}
-function moveViewDown(){
- var t = parseInt($('.field').css('top'))
- $('.field').css({'top': t+(ImageGrid.option.MOVE_DELTA)})
-}
-function moveViewLeft(){
- var l = parseInt($('.field').css('left'))
- $('.field').css({'left': l-(ImageGrid.option.MOVE_DELTA)})
-}
-function moveViewRight(){
- var l = parseInt($('.field').css('left'))
- $('.field').css({'left': l+(ImageGrid.option.MOVE_DELTA)})
-}
-
-
-
-function centerCurrentImage(){
- $('.field')
- .css({
- 'top': 0,
- 'left': 0
- })
- // do this after animations are done...
- .one("webkitTransitionEnd oTransitionEnd msTransitionEnd transitionend", centerOrigin)
- // this is repeated intentionally...
- // ...needed for small shifts, while the after-animation event
- // is for large moves.
- centerOrigin()
-}
+ $('.field').css({
+ 'transform-origin': ol + 'px ' + ot + 'px',
+ '-o-transform-origin': ol + 'px ' + ot + 'px',
+ '-moz-transform-origin': ol + 'px ' + ot + 'px',
+ '-webkit-transform-origin': ol + 'px ' + ot + 'px',
+ '-ms-transform-origin': ol + 'px ' + ot + 'px'
+ })
+ // XXX for debugging...
+ $('.origin-marker').css({
+ 'top': ot,
+ 'left': ol
+ })
+ }),
+ // XXX these work oddly when page is scaled in maxthon...
+ // XXX virtually identical, see of can be merged...
+ ImageGrid.ACTION({
+ title: 'Move view up',
+ },
+ function moveViewUp(){
+ var t = parseInt($('.field').css('top'))
+ $('.field').css({'top': t-(ImageGrid.option.MOVE_DELTA)})
+ }),
+ ImageGrid.ACTION({
+ title: 'Move view down',
+ },
+ function moveViewDown(){
+ var t = parseInt($('.field').css('top'))
+ $('.field').css({'top': t+(ImageGrid.option.MOVE_DELTA)})
+ }),
+ ImageGrid.ACTION({
+ title: 'Move view left',
+ },
+ function moveViewLeft(){
+ var l = parseInt($('.field').css('left'))
+ $('.field').css({'left': l-(ImageGrid.option.MOVE_DELTA)})
+ }),
+ ImageGrid.ACTION({
+ title: 'Move view right',
+ },
+ function moveViewRight(){
+ var l = parseInt($('.field').css('left'))
+ $('.field').css({'left': l+(ImageGrid.option.MOVE_DELTA)})
+ }),
+ ImageGrid.ACTION({
+ title: 'Center current image',
+ },
+ function centerCurrentImage(){
+ $('.field')
+ .css({
+ 'top': 0,
+ 'left': 0
+ })
+ // do this after animations are done...
+ .one("webkitTransitionEnd oTransitionEnd msTransitionEnd transitionend", ImageGrid.centerOrigin)
+ // this is repeated intentionally...
+ // ...needed for small shifts, while the after-animation event
+ // is for large moves.
+ ImageGrid.centerOrigin()
+ }))
/******************************************************* Navigation **/
-// basic navigation...
-function firstImage(){
- return $('.current.ribbon').children('.image').first().click()
-}
-function prevImage(){
- return $('.current.image').prev('.image').click()
-}
-function nextImage(){
- return $('.current.image').next('.image').click()
-}
-function lastImage(){
- return $('.current.ribbon').children('.image').last().click()
-}
+ImageGrid.GROUP('Navigation',
+ // basic navigation...
+ ImageGrid.ACTION({
+ title: 'Go to first image',
+ },
+ function firstImage(){
+ return $('.current.ribbon').children('.image').first().click()
+ }),
+ ImageGrid.ACTION({
+ title: 'Go to previous image',
+ },
+ function prevImage(){
+ return $('.current.image').prev('.image').click()
+ }),
+ ImageGrid.ACTION({
+ title: 'Go to next image',
+ },
+ function nextImage(){
+ return $('.current.image').next('.image').click()
+ }),
+ ImageGrid.ACTION({
+ title: 'Go to last image',
+ },
+ function lastImage(){
+ return $('.current.ribbon').children('.image').last().click()
+ }),
+ ImageGrid.ACTION({
+ title: 'Skip screen images',
+ doc: 'Skip screen-width images in specified direction',
+ display: false,
+ },
+ function skipScreenImages(direction){
+ // calculate screen width in images...
+ var W = $('.viewer').width()
+ var w = $('.current.image').width()
+ var scale = getElementScale($('.field'))
+ var n = Math.max(Math.floor(W/(w*scale))-1, 0)
+ var img = $('.current.image')[direction + 'All']('.image').eq(n)
+ if(img.length > 0){
+ return img.click()
+ } else if(direction == 'next'){
+ return ImageGrid.lastImage()
+ } else if(direction == 'prev'){
+ return ImageGrid.firstImage()
+ }
+ }),
+ ImageGrid.ACTION({
+ title: 'Skip next screen images',
+ },
+ function nextScreenImages(){ return ImageGrid.skipScreenImages('next') }),
+ ImageGrid.ACTION({
+ title: 'Skip screen images backwards',
+ },
+ function prevScreenImages(){ return ImageGrid.skipScreenImages('prev') }),
-// add skip screen images in direction...
-function skipScreenImages(direction){
- // calculate screen width in images...
- var W = $('.viewer').width()
- var w = $('.current.image').width()
- var scale = getElementScale($('.field'))
- var n = Math.max(Math.floor(W/(w*scale))-1, 0)
+ ImageGrid.ACTION({
+ title: 'Focus ribbon',
+ doc: 'Focus ribbon in specified direction',
+ display: false,
+ },
+ function focusRibbon(direction, get_order){
+ if(get_order == null){
+ get_order = getImageOrder
+ }
+ var id = get_order($('.current.image'))
+ var prev = getImageBefore(id, $('.current.ribbon')[direction]('.ribbon'))
+ if(prev){
+ var next = prev.next()
+ // NOTE: direction is accounted for to make the up/down shifts
+ // symmetrical in the general case...
+ if(next.length == 0 || direction == 'next'){
+ return prev.click()
+ } else {
+ return next.click()
+ }
+ } else {
+ return $('.current.ribbon')[direction]('.ribbon').children('.image').first().click()
+ }
+ }),
+ ImageGrid.ACTION({
+ title: 'Focus ribbon above',
+ },
+ function focusAboveRibbon(){ return ImageGrid.focusRibbon('prev') }),
+ ImageGrid.ACTION({
+ title: 'Focus ribbon below',
+ },
+ function focusBelowRibbon(){ return ImageGrid.focusRibbon('next') }))
- var img = $('.current.image')[direction + 'All']('.image').eq(n)
- if(img.length > 0){
- return img.click()
- } else if(direction == 'next'){
- return lastImage()
- } else if(direction == 'prev'){
- return firstImage()
- }
-}
-var nextScreenImages = function(){ return skipScreenImages('next') }
-var prevScreenImages = function(){ return skipScreenImages('prev') }
-
-
-
-function focusRibbon(direction, get_order){
- if(get_order == null){
- get_order = getImageOrder
- }
- var id = get_order($('.current.image'))
- var prev = getImageBefore(id, $('.current.ribbon')[direction]('.ribbon'))
- if(prev){
- var next = prev.next()
- // NOTE: direction is accounted for to make the up/down shifts
- // symmetrical in the general case...
- if(next.length == 0 || direction == 'next'){
- return prev.click()
- } else {
- return next.click()
- }
- } else {
- return $('.current.ribbon')[direction]('.ribbon').children('.image').first().click()
- }
-}
-var focusAboveRibbon = function(){ return focusRibbon('prev') }
-var focusBelowRibbon = function(){ return focusRibbon('next') }
@@ -1246,27 +1427,13 @@ function setContainerScale(scale){
-function fitImage(){
- var H = $('.container').height()
- var W = $('.container').width()
-
- var h = $('.image.current').height()
- var w = $('.image.current').width()
-
- var f = Math.min(H/h, W/w)
-
- setContainerScale(f)
-}
-
-
-
-function fitThreeImages(){
+function fitNImages(n){
var H = $('.container').height()
var W = $('.container').width()
var h = $('.image.current').height()
// NOTE: this is cheating, need to get actual three widths...
- var w = $('.image.current').width()*3
+ var w = $('.image.current').width()*n
var f = Math.min(H/h, W/w)
@@ -1274,6 +1441,17 @@ function fitThreeImages(){
}
+function fitImage(){fitNImages(1)}
+function fitTwoImages(){fitNImages(2)}
+function fitThreeImages(){fitNImages(3)}
+function fitFourImages(){fitNImages(4)}
+function fitFiveImages(){fitNImages(5)}
+function fitSixImages(){fitNImages(6)}
+function fitSevenImages(){fitNImages(7)}
+function fitEightImages(){fitNImages(8)}
+function fitNineImages(){fitNImages(9)}
+
+
/********************************************************** Actions **/
@@ -1376,9 +1554,9 @@ function shiftImage(direction, get_order){
} else {
img = $('.current.image')
if(img.next('.image').length == 0){
- prevImage()
+ ImageGrid.prevImage()
} else {
- nextImage()
+ ImageGrid.nextImage()
}
// do the actual move...
if(prev_elem){
diff --git a/ui/keybindings.js b/ui/keybindings.js
index 180adaa1..fea0c66f 100755
--- a/ui/keybindings.js
+++ b/ui/keybindings.js
@@ -2,7 +2,7 @@
// NOTE: use String.fromCharCode(code)...
var keybindings = {
// togglable modes and options...
- 191: showSetup, // ?
+ 191: ImageGrid.showSetup, // ?
70: ImageGrid.toggleSingleImageMode, // f
83: ImageGrid.toggleSingleRibbonMode, // s
13: 70, // Enter
@@ -13,59 +13,76 @@ var keybindings = {
77: toggleMarkers, // m
- 27: function(){$('.overlay').click()}, // Esc
+ 27: [
+ // XXX make this into a real action...
+ function(){$('.overlay').click()}, // Esc
+ 'Hide overlay'
+ ],
// zooming...
+ // XXX make this into a real action...
187: function(){scaleContainerBy(ImageGrid.option.ZOOM_FACTOR)}, // +
+ // XXX make this into a real action...
189: function(){scaleContainerBy(1/ImageGrid.option.ZOOM_FACTOR)}, // -
// zoom presets...
48: {
'default': fitImage, // 0
+ // XXX make this into a real action...
'ctrl': function(){setContainerScale(1)}, // ctrl+0
},
+ 49: fitImage, // 1
+ 50: fitTwoImages, // 2
51: fitThreeImages, // 3
+ 52: fitFourImages, // 4
+ 53: fitFiveImages, // 5
+ 54: fitSixImages, // 6
+ 55: fitSevenImages, // 7
+ 56: fitEightImages, // 8
+ 57: fitNineImages, // 9
// navigation...
- 36: firstImage, // Home
- 35: lastImage, // End
+ 36: ImageGrid.firstImage, // Home
+ 35: ImageGrid.lastImage, // End
37: {
- 'default': prevImage, // Right
- 'ctrl': prevScreenImages, // ctrl-Right
- 'alt': prevScreenImages, // alt-Right
+ 'default': ImageGrid.prevImage, // Right
+ 'ctrl': ImageGrid.prevScreenImages, // ctrl-Right
+ 'alt': ImageGrid.prevScreenImages, // alt-Right
},
80: 37, // BkSp
188: 37, // p
8: 37, // <
39: {
- 'default': nextImage, // Left
- 'ctrl': nextScreenImages, // ctrl-Left
- 'alt': nextScreenImages, // alt-Left
+ 'default': ImageGrid.nextImage, // Left
+ 'ctrl': ImageGrid.nextScreenImages, // ctrl-Left
+ 'alt': ImageGrid.nextScreenImages, // alt-Left
},
32: 39, // Space
190: 39, // m
78: 39, // >
// move view...
// XXX should these be s-up, s-down, ... ??
- 75: moveViewUp, // k
- 74: moveViewDown, // j
- 72: moveViewLeft, // h
- 76: moveViewRight, // l
- 79: centerCurrentImage, // o
+ 75: ImageGrid.moveViewUp, // k
+ 74: ImageGrid.moveViewDown, // j
+ 72: ImageGrid.moveViewLeft, // h
+ 76: ImageGrid.moveViewRight, // l
+ 79: ImageGrid.centerCurrentImage, // o
// combined navigation with actions..
40: {
- 'default': focusBelowRibbon, // Down
+ 'default': ImageGrid.focusBelowRibbon, // Down
'shift': shiftImageDown, // shift-Down
+ // XXX make this into a real action...
'ctrl+shift': function(){ // ctrl-shift-Down
createRibbon('next')
shiftImageDown()
}
},
38: {
- 'default': focusAboveRibbon, // Up
+ 'default': ImageGrid.focusAboveRibbon, // Up
'shift': shiftImageUp, // shift-Up
+ // XXX make this into a real action...
'ctrl+shift': function(){ // ctrl-shift-Up
createRibbon('prev')
shiftImageUp()
@@ -80,6 +97,7 @@ var keybindings = {
20: 16, // Caps Lock
// refresh...
+ // XXX make this into a real action...
116: function(){ return DEBUG?true:false } // F5
}