reworked keyboard to support better searching for keys + added capslock state support...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2017-04-22 06:20:12 +03:00
parent c64fe92afe
commit b2c9a5cb34
5 changed files with 211 additions and 32 deletions

View File

@ -1482,6 +1482,23 @@ stretching in width... */
opacity: 1;
}
/* Capslock indicator.. */
.overlay-info .capslock-state {
font-size: small;
font-style: italic;
margin: 0px 10pt;
}
.overlay-info .capslock-state:not(.on) {
opacity: 0.2;
}
.overlay-info .capslock-state.on {
color: yellow;
opacity: 0.6;
}
.overlay-info .capslock-state:hover {
opacity: 1
}
/*************************************************** Global status ***/

View File

@ -271,16 +271,20 @@ module.GLOBAL_KEYBOARD = {
shift_End: 'lastRibbon',
Up: 'prevRibbon',
caps_shift_Up: 'prevRibbon',
Down: 'nextRibbon',
caps_shift_Down: 'nextRibbon',
// shifting...
shift_Up: 'shiftImageUp',
caps_Up: 'shiftImageUp',
alt_shift_Up: 'travelImageUp',
ctrl_shift_Up: 'shiftImageUpNewRibbon',
ctrl_Up: 'shiftMarkedUp',
shift_Down: 'shiftImageDown',
caps_Down: 'shiftImageDown',
alt_shift_Down: 'travelImageDown',
ctrl_shift_Down: 'shiftImageDownNewRibbon',
ctrl_Down: 'shiftMarkedDown',

View File

@ -64,7 +64,6 @@ core.ImageGridFeatures.Feature('viewer-testing', [
'ui-single-image',
//'ui-partial-ribbons',
// XXX this is still experimental but seems to already work faster...
'ui-partial-ribbons-2',
'marks',

View File

@ -62,6 +62,7 @@ var StatusBarActions = actions.Actions({
// separates left/right aligned elements...
'---',
'edit-mode',
'mark',
'bookmark',
],
@ -90,7 +91,39 @@ var StatusBarActions = actions.Actions({
},
__statusbar_elements__: {
/* item template...
item: function(item){
// cleanup...
if(item == null){
// XXX
return
}
// setup the item DOM...
if(typeof(item) == typeof('str')){
var type = item
item = $('<span>')
.addClass('item-example')
.attr('type', item)
.text('example')
// get stuff from the item...
} else {
var type = item.attr('type')
}
// update the item...
// XXX
return item
},
*/
index: function(item, gid, img){
// cleanup...
if(item == null){
return
}
var that = this
gid = gid || this.current
@ -188,6 +221,11 @@ var StatusBarActions = actions.Actions({
return item
},
ribbon: function(item, gid, img){
// cleanup...
if(item == null){
return
}
var that = this
// get ribbon number...
@ -248,6 +286,11 @@ var StatusBarActions = actions.Actions({
return item
},
changes: function(item, gid, img){
// cleanup...
if(item == null){
return
}
if(typeof(item) == typeof('str')){
item = $('<span>')
.addClass('changes')
@ -260,6 +303,11 @@ var StatusBarActions = actions.Actions({
},
// XXX handle path correctly...
gid: function(item, gid, img){
// cleanup...
if(item == null){
return
}
var that = this
gid = gid || this.current
img = img || (this.images && gid in this.images && this.images[gid])
@ -309,8 +357,54 @@ var StatusBarActions = actions.Actions({
return item
},
path: 'gid',
'edit-mode': function(item){
// cleanup...
if(item == null){
this.__edit_mode_indicator_update
&& this.off('keyPress', this.__edit_mode_indicator_update)
delete this.__edit_mode_indicator_update
return
}
var update = this.__edit_mode_indicator_update = this.__edit_mode_indicator_update
|| (function(){
var caps = this.keyboard.capslock
caps = typeof(event) != 'undefined' && event.getModifierState ?
event.getModifierState('CapsLock')
: caps
item
.attr('info', 'Edit mode '
+ (caps ? 'on' : 'off')
+ ' (Click to update / Press CapsLock to toggle)')
[caps ? 'addClass' : 'removeClass']('on')
}).bind(this)
if(typeof(item) == typeof('str')){
var type = item
item = $('<span>')
.addClass('capslock-state expanding-text')
.append($('<span class="shown">')
.text('E'))
.append($('<span class="hidden">')
.text('Edit mode'))
.click(update)
// XXX need a way to cleanly unhandle this...
this.on('keyPress', update)
}
update()
return item
},
// XXX show menu in the appropriate corner...
mark: function(item, gid, img){
// cleanup...
if(item == null){
return
}
gid = gid || this.current
var that = this
@ -398,8 +492,50 @@ var StatusBarActions = actions.Actions({
var that = this
this.config['status-bar-mode'] = state
var _getHandler = function(key){
var elems = that.__statusbar_elements__ || {}
var base_elems = StatusBarActions.__statusbar_elements__ || {}
var handler = elems[key] || base_elems[key]
if(handler == null){
return
}
// handle aliases...
var seen = []
while(typeof(handler) == typeof('str')){
seen.push(handler)
var handler = elems[handler] || base_elems[handler]
// check for loops...
if(seen.indexOf(handler) >= 0){
console.error('state indicator alias loop detected at:', key)
handler = null
break
}
}
return handler
}
// destroy...
if(state == 'none'){
// notify items that they are removed...
bar.children()
.each(function(i, item){
item = $(item)
var type = item.attr('type')
if(type == null){
return
}
var handler = _getHandler(type)
if(handler != null){
handler.call(that, null)
}
})
bar.empty()
// build/update...
@ -407,32 +543,6 @@ var StatusBarActions = actions.Actions({
gid = gid || this.current
var img = this.images && this.images[gid]
var _getHandler = function(key){
var elems = that.__statusbar_elements__ || {}
var base_elems = StatusBarActions.__statusbar_elements__ || {}
var handler = elems[key] || base_elems[key]
if(handler == null){
return
}
// handle aliases...
var seen = []
while(typeof(handler) == typeof('str')){
seen.push(handler)
var handler = elems[handler] || base_elems[handler]
// check for loops...
if(seen.indexOf(handler) >= 0){
console.error('state indicator alias loop detected at:', key)
handler = null
break
}
}
return handler
}
// build...
if(bar.children().length <= 0){
var items = this.config['status-bar-items'].slice()

View File

@ -14,7 +14,8 @@ var object = require('lib/object')
/*********************************************************************/
var MODIFIERS =
module.MODIFIERS = [ 'ctrl', 'meta', 'alt', 'shift' ]
//module.MODIFIERS = [ 'ctrl', 'meta', 'alt', 'shift' ]
module.MODIFIERS = [ 'caps', 'ctrl', 'meta', 'alt', 'shift' ]
var KEY_SEPARATORS =
@ -204,12 +205,17 @@ var event2key =
module.event2key =
function event2key(evt){
evt = evt || event
// NOTE: we do not care about the jQuery wrapper here...
evt = evt.originalEvent || evt
var key = []
evt.ctrlKey && key.push('ctrl')
evt.altKey && key.push('alt')
evt.metaKey && key.push('meta')
evt.shiftKey && key.push('shift')
evt.getModifierState
&& evt.getModifierState('CapsLock')
&& key.push('caps')
var k = code2key(evt.keyCode)
@ -760,8 +766,7 @@ var KeyboardPrototype = {
mode = '*'
}
var genKeys = function(key, shift_key){
var joinKeys = function(key, shift_key){
// match candidates...
return key_separators
// full key...
@ -772,6 +777,40 @@ var KeyboardPrototype = {
.map(function(s){ return shift_key.join(s) })
: [])
.unique() }
var normalize = this.normalizeKey
var keyCombinations = function(key, shift_key){
if(key.length <= 1){
return key
}
var _combinations = function(level, res){
var next = []
level
.map(function(elem){
var c = normalize(elem)
c = typeof(c) == typeof('str') ? c : c.join('+++')
res.indexOf(c) < 0
&& res.push(c)
&& elem
//.reverse()
.slice(0, -1)
.map(function(_, i){
var s = elem.slice()
s.splice(i, 1)
s.length > 0
//&& next.push(s.reverse())
&& next.push(s)
})
})
next.length > 0
&& _combinations(next, res)
return res
}
return _combinations(shift_key ? [key, shift_key] : [key], [])
// XXX is there a better way???
//.map(function(e){ return e.split(/\+\+\+/g).concat(key.slice(-1)) })
.map(function(e){ return joinKeys(e.split(/\+\+\+/g)) })
.reduce(function(a, b){ return a.concat(b) }, [])
}
var walkAliases = function(bindings, handler, modifiers){
var seen = []
var modifiers = modifiers || []
@ -803,7 +842,8 @@ var KeyboardPrototype = {
var shift_key = this.shifted(key)
// match candidates...
var keys = genKeys(key, shift_key).unique()
//var keys = joinKeys(key, shift_key).unique()
var keys = keyCombinations(key, shift_key)
// get modes...
var modes = mode == '*' ? Object.keys(keyboard)
@ -817,7 +857,8 @@ var KeyboardPrototype = {
var k = key.slice(-1)[0]
var c = this.key2code(k)
var mod = genKeys(key.slice(0, -1).concat(''))
//var mod = joinKeys(key.slice(0, -1).concat(''))
var mod = keyCombinations(key.slice(0, -1).concat(''))
var drop = mode == 'test' || mode == '?'
for(var i=0; i < modes.length; i++){
@ -983,6 +1024,11 @@ KeyboardWithCSSModes.prototype.__proto__ = Keyboard.prototype
// // used directly...
// handler('ctrl_C', function(k){ console.log('Not bound:', k) })
//
// NOTE: the handler will also set the .capslock attribute on the
// keyboard object and update it on each key press...
// NOTE: if .capslock is false means that either it is not on or
// undetectable...
// NOTE: before any key is pressed the .capslock is set to undefined
var makeKeyboardHandler =
module.makeKeyboardHandler =
function makeKeyboardHandler(keyboard, unhandled, actions){
@ -991,6 +1037,7 @@ function makeKeyboardHandler(keyboard, unhandled, actions){
keyboard
//: Keyboard(keyboard, checkGlobalMode)
: Keyboard(keyboard)
kb.capslock = undefined
return function(key, no_match){
no_match = no_match || unhandled
@ -1002,6 +1049,8 @@ function makeKeyboardHandler(keyboard, unhandled, actions){
if(typeof(key) != typeof('str')){
evt = key
key = kb.event2key(evt)
kb.capslock = key.indexOf('caps') >= 0
}
var handlers = kb.handler('test', key)