diff --git a/ui/data.js b/ui/data.js
index d7f876ca..a6407670 100755
--- a/ui/data.js
+++ b/ui/data.js
@@ -943,7 +943,7 @@ function loadFileImages(path, no_load_diffs, callback){
}).sort().reverse()[0]
path = path == null ? 'images.json' : path
- console.log('Loading:', path)
+ updateStatus('Loading: ' + path)
path = base +'/'+ path
@@ -972,7 +972,7 @@ function loadFileImages(path, no_load_diffs, callback){
// whether we have one or more deffereds here...
.done(function(data){
diff_data[i+1] = data
- console.log('Loaded:', e)
+ updateStatus('Loaded:', e)
})
}))
.then(function(){
@@ -988,12 +988,12 @@ function loadFileImages(path, no_load_diffs, callback){
$.extend(json, diff_data)
IMAGES = json
- console.log('Loaded IMAGES...')
+ updateStatus('Loaded images...')
callback != null && callback()
})
.fail(function(){
- console.error('ERROR LOADING:', path)
+ updateErrorStatus('Loading: ' + path)
})
}
@@ -1009,7 +1009,7 @@ function saveFileImages(name){
name = name == null ? normalizePath(CACHE_DIR +'/'+ Date.timeStamp()) : name
if(window.dumpJSON == null){
- console.error('Can\'t save to file.')
+ updateErrorStatus('Can\'t save to file.')
return
}
@@ -1018,7 +1018,7 @@ function saveFileImages(name){
$.each($.map(listDir(normalizePath(CACHE_DIR)), function(e){
return /.*-images-diff.json$/.test(e) ? e : null
}), function(i, e){
- console.log('removeing:', e)
+ updateStatus('removeing:', e)
removeFile(normalizePath(CACHE_DIR +'/'+ e))
})
IMAGES_UPDATED = []
@@ -1060,12 +1060,12 @@ function loadFileState(data_path, callback){
// unknown format...
} else {
- console.error('unknown format.')
+ updateStatus('Unknown format.')
return
}
})
.fail(function(){
- console.error('ERROR LOADING:', data_path)
+ updateErrorStatus('Loading:', data_path)
})
return res
@@ -1114,10 +1114,12 @@ function loadDir(path, raw_load){
var orig_path = path
var data
+ updateStatus('Loading...').show()
+
var files = listDir(path)
if(files == null){
- console.error('Path error:', path)
+ updateErrorStatus('Path: ' + path)
return
}
@@ -1143,11 +1145,14 @@ function loadDir(path, raw_load){
// load the found data file...
if(data != null){
- console.log('Loading:', data)
+ updateStatus('Loading: ', data)
data = path + '/' + data
return loadFileState(data)
+ .always(function(){
+ showStatus('Done.')
+ })
// load the dir as-is...
} else {
@@ -1157,7 +1162,7 @@ function loadDir(path, raw_load){
})
if(image_paths.length == 0){
- console.error('No images in:', orig_path)
+ updateErrorStatus('No images in:', orig_path)
return
}
@@ -1168,6 +1173,7 @@ function loadDir(path, raw_load){
MARKED = []
loadData()
+ showStatus('Done.')
}
}
@@ -1183,7 +1189,7 @@ function updateRibbonsFromFavDirs(){
// NOTE: this will open the default editor/viewer.
function openImage(){
if(window.runSystem == null){
- console.error('Can\'t run external programs.')
+ updateErrorStatus('Can\'t run external programs.')
return
}
// XXX if path is not present try and open the biggest preview...
@@ -1193,13 +1199,61 @@ function openImage(){
/**********************************************************************
-* Actions
+* Info & status...
*/
+// NOTE: if message is null, then just return the status element...
+function updateStatus(message){
+
+ var elem = $('.global-status')
+ if(elem.length == 0){
+ elem = $('
')
+ }
+ if(message == null){
+ return elem
+ }
+
+ if(arguments.length > 1){
+ message = Array.apply(Array, arguments).join(' ')
+ }
+
+ if(typeof(message) == typeof('s') && /^error.*/i.test(message)){
+ console.error.apply(console, arguments)
+ } else {
+ console.log.apply(console, arguments)
+ }
+
+ return updateInfo(elem, message)
+}
+function showStatus(message){
+ return updateStatus(message)
+ .stop()
+ .show()
+ .delay(500)
+ .fadeOut(800)
+}
+function showErrorStatus(message){
+ return updateStatus('Error:' + message)
+ .stop()
+ .show()
+}
+
+
// XXX do we need a full rewrite here, or will it be better to just fill
// the slots...
function updateGlobalImageInfo(image){
image = image == null ? getImage() : $(image)
+ image = image.length == 0 ? getImage() : image
+
+ var elem = $('.global-image-info')
+ if(elem.length == 0){
+ elem = $('')
+ }
+
+ // no image no update...
+ if(image.length == 0){
+ return elem
+ }
var gid = getImageGID(image)
var r = getRibbonIndex(getRibbon(image))
@@ -1222,11 +1276,6 @@ function updateGlobalImageInfo(image){
meta = meta.join(', ')
meta = meta != '' ? '( '+ meta +' )' : ''
- var elem = $('.global-image-info')
- if(elem.length == 0){
- elem = $('')
- }
-
return updateInfo(elem,
// path...
''+
@@ -1268,6 +1317,18 @@ function updateGlobalImageInfo(image){
function updateInlineImageInfo(image){
image = image == null ? getImage() : $(image)
+ image = image.length == 0 ? getImage() : image
+
+ var elem = $('.inline-image-info')
+ if(elem.length == 0){
+ elem = $('')
+ }
+
+ // no image no update...
+ if(image.length == 0){
+ return elem
+ }
+
var gid = getImageGID(image)
var r = getRibbonIndex(getRibbon(image))
@@ -1277,11 +1338,6 @@ function updateInlineImageInfo(image){
var orientation = data.orientation
orientation = orientation == null ? 0 : orientation
- var elem = $('.inline-image-info')
- if(elem.length == 0){
- elem = $('')
- }
-
return updateInfo(elem,
// name...
data.path.split('/').pop() +'
'+
@@ -1297,6 +1353,16 @@ function updateInlineImageInfo(image){
}
+function inlineImageInfoHoverHandler(evt){
+ var img = $(evt.target).closest('.image')
+ if(img.length > 0){
+ if(img.find('.inline-image-info:visible').length == 0){
+ updateInlineImageInfo(img)
+ }
+ }
+}
+
+
/**********************************************************************
* Setup
diff --git a/ui/index.html b/ui/index.html
index 8700b7ae..c36c4cfb 100755
--- a/ui/index.html
+++ b/ui/index.html
@@ -254,7 +254,8 @@ body {
width: 100%;
background: black;
opacity: 0.7;
-
+}
+.image .inline-image-info:hover {
-moz-user-select: auto;
-webkit-user-select: auto;
-o-user-select: auto;
@@ -328,7 +329,8 @@ body {
color: white;
opacity: 0.6;
-
+}
+.overlay-info:hover {
-moz-user-select: auto;
-webkit-user-select: auto;
-o-user-select: auto;
@@ -526,6 +528,11 @@ body {
display: inline;
}
+.global-status {
+ opacity: 1;
+ z-index: 1000;
+}
+
@@ -578,18 +585,6 @@ $(function(){
function(k){
window.DEBUG && console.log(k)
}))
- .on('mouseover', function(evt){
- var img = $(evt.target).closest('.image')
- if(img.length > 0){
- if(IMAGE_INFO){
- if(img.find('.inline-image-info:visible').length == 0){
- updateInlineImageInfo(img)
- }
- } else {
- img.find('.inline-image-info').remove()
- }
- }
- })
setupDataBindings()
diff --git a/ui/keybindings.js b/ui/keybindings.js
index 1f29894b..a5f922b8 100755
--- a/ui/keybindings.js
+++ b/ui/keybindings.js
@@ -16,7 +16,32 @@ var DIRECTION = 'next'
/*********************************************************************/
var KEYBOARD_CONFIG = {
+ // info overlay...
+ //
+ // NOTE: this is here to prevent selecting images while trying to
+ // select info text...
+ '.overlay-info:hover': {
+ title: 'Info overlay',
+ doc: 'NOTE: when the cursor is over the info overlay one can use '+
+ 'Ctrl-A and Ctrl-D for info text selection, without affecting '+
+ 'image selection/marks.',
+ ignore: [ 'A' ],
+ A: {
+ // NOTE: this is here only for documentation...
+ ctrl: doc('Select all'),
+ },
+ D: {
+ ctrl: doc('Clear selection',
+ function(){
+ document.getSelection().empty()
+ return false
+ })
+ }
+ },
+
+
// help mode...
+ //
// NOTE: need to keep all info modes before the rest so as to give
// their bindings priority...
'.help-mode': {
@@ -40,6 +65,7 @@ var KEYBOARD_CONFIG = {
// single image mode only...
+ //
'.single-image-mode': {
title: 'Single image mode',
@@ -59,6 +85,7 @@ var KEYBOARD_CONFIG = {
// single image mode only...
+ //
'.marked-only-view:not(.single-image-mode)': {
title: 'Marked only view',
@@ -72,6 +99,7 @@ var KEYBOARD_CONFIG = {
// general setup...
+ //
'.viewer:not(.overlay)': {
title: 'Global',
@@ -285,7 +313,7 @@ var KEYBOARD_CONFIG = {
},
I: {
// XXX group this with other info stuff into a single on/off toggle...
- default: doc('Toggle image info visibility (on hover)',
+ default: doc('Toggle image info display',
function(){ toggleImageInfo() }),
// XXX STUB -- replace with a real info window...
shift: doc('Show current image info',
@@ -307,14 +335,30 @@ var KEYBOARD_CONFIG = {
'Position (global): '+ order +'/'+ DATA.order.length +'\n'+
'')
}),
+ alt: doc('Toggle inline image info display',
+ function(){
+ toggleInlineImageInfo()
+ }),
+
+ // marking...
ctrl: doc('Invert image marks',
function(){ invertImageMarks() }),
},
A: {
- shift: doc('Toggle marks in current contagious block',
- function(){ toggleImageMarkBlock() }),
+ // XXX does not yet work with DATA (???)
+ //shift: doc('Toggle marks in current contagious block',
+ // function(){ toggleImageMarkBlock() }),
+
ctrl: doc('Mark current ribbon',
function(){ markAll('ribbon') }),
+ 'ctrl+shift': doc('Mark all images',
+ function(){ markAll('all') }),
+ },
+ D: {
+ ctrl: doc('Unmark current ribbon',
+ function(){ removeImageMarks('ribbon') }),
+ 'ctrl+shift': doc('Unmark all images',
+ function(){ removeImageMarks('all') }),
},
U: {
ctrl: doc('Unmark current ribbon',
diff --git a/ui/lib/keyboard.js b/ui/lib/keyboard.js
index b54ba418..63530c22 100755
--- a/ui/lib/keyboard.js
+++ b/ui/lib/keyboard.js
@@ -62,6 +62,17 @@ var _SPECIAL_KEYS = {
188: ',', 190: '.', 191: '/',
}
+var _SHIFT_KEYS = {
+ '`': '~', '-': '_', '=':'+',
+
+ 1: '!', 2: '@', 3: '#', 4: '$', 5: '%',
+ 6:'^', 7:'&', 8: '*', 9: '(', 0: ')',
+
+ '[': '{', ']': '}i', '\\': '|',
+ ';': ':', '\'': '"',
+ ',': '<', '.': '>', '/': '?'
+}
+
var _KEY_CODES = {}
for(var k in _SPECIAL_KEYS){
_KEY_CODES[_SPECIAL_KEYS[k]] = k
@@ -93,6 +104,7 @@ function toKeyCode(c){
// documentation wrapper...
function doc(text, func){
+ func = func == null ? function(){return true}: func
func.doc = text
return func
}
@@ -135,11 +147,12 @@ function doc(text, func){
* XXX BUG explicitly given modes do not yield results if the pattern
* does not match...
*/
-function getKeyHandlers(key, modifiers, keybindings, modes){
+function getKeyHandlers(key, modifiers, keybindings, modes, shifted_keys){
var chr = null
var did_handling = false
modifiers = modifiers == null ? '' : modifiers
modes = modes == null ? 'any' : modes
+ shifted_keys = shifted_keys == null ? _SHIFT_KEYS : shifted_keys
if(typeof(key) == typeof(123)){
key = key
@@ -149,6 +162,12 @@ function getKeyHandlers(key, modifiers, keybindings, modes){
key = toKeyCode(key)
}
+ /* XXX this is not done yet...
+ if(shifted_keys != false && key in shifted_keys){
+ key = shifted_keys[key]
+ }
+ */
+
res = {}
for(var mode in keybindings){
@@ -400,7 +419,8 @@ function makeKeyboardHandler(keybindings, unhandled){
* - list of key names.
*
*/
-function buildKeybindingsHelp(keybindings){
+function buildKeybindingsHelp(keybindings, shifted_keys){
+ shifted_keys = shifted_keys == null ? _SHIFT_KEYS : shifted_keys
var res = {}
var mode, title
@@ -455,6 +475,13 @@ function buildKeybindingsHelp(keybindings){
var keys = []
section[doc] = keys
}
+
+ // translate shifted keys...
+ if(shifted_keys != false && mod == 'shift' && key in shifted_keys){
+ mod = ''
+ key = shifted_keys[key]
+ }
+
keys.push((mod == '' || mod == 'default') ? key : (mod +'+'+ key))
}
diff --git a/ui/modes.js b/ui/modes.js
index 64e17c08..014aec23 100755
--- a/ui/modes.js
+++ b/ui/modes.js
@@ -69,6 +69,20 @@ var toggleTheme = createCSSClassToggler('.viewer',
var toggleImageInfo = createCSSClassToggler('.viewer', '.image-info-visible')
+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()
+ }
+ })
+
+
// NOTE: this confirmsto the css toggler protocol, but is not implemented
// via createCSSClassToggler as we do not need to set any classes,
// al least at this point...