mirror of
https://github.com/flynx/PortableMag.git
synced 2025-10-28 10:40:07 +00:00
started project revival -- updated keyboard.js and split out the bindings...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
2b8081ce9d
commit
95301411e4
141
index.html
141
index.html
@ -110,6 +110,9 @@ CKEDITOR.disableAutoInline = true
|
||||
|
||||
<script src="platform.js"></script>
|
||||
|
||||
<!-- XXX load this as early as possible... -->
|
||||
<script src="keybindings.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
function showInOverlay(text){
|
||||
@ -237,144 +240,6 @@ function handleFileSelect(evt) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
var KEYBOARD_CONFIG = {
|
||||
'.overlay': {
|
||||
title: 'Overlay mode.',
|
||||
doc: '',
|
||||
|
||||
ignore: '*',
|
||||
|
||||
Esc: function(){
|
||||
removeOverlay()
|
||||
return false
|
||||
},
|
||||
},
|
||||
|
||||
'.editor:not(.inline-editor-mode)': {
|
||||
title: 'Editor mode.',
|
||||
doc: '',
|
||||
|
||||
'0': function(){
|
||||
var n = getPageNumber()
|
||||
if(togglePageView('?') == 'on'){
|
||||
setMagazineScale(getPageTargetScale(1))
|
||||
} else {
|
||||
setMagazineScale(getPageTargetScale(PAGES_IN_RIBBON))
|
||||
}
|
||||
setCurrentPage(n)
|
||||
},
|
||||
Esc: '0',
|
||||
|
||||
'=': function(){
|
||||
var n = getPageNumber()
|
||||
setMagazineScale(Math.min(
|
||||
getMagazineScale() * 1.2,
|
||||
getPageTargetScale(1)))
|
||||
setCurrentPage(n)
|
||||
},
|
||||
'-': function(){
|
||||
var n = getPageNumber()
|
||||
setMagazineScale(Math.max(
|
||||
getMagazineScale() * 0.8,
|
||||
getPageTargetScale(PAGES_IN_RIBBON*2)))
|
||||
setCurrentPage(n)
|
||||
},
|
||||
|
||||
'O': {
|
||||
// load...
|
||||
// XXX needs testing...
|
||||
'ctrl': function(){
|
||||
showInOverlay('<h1>Open Issue</h1>'+
|
||||
'<input type="file" id="upload" name="file" multiple onchange="handleFileSelect(event)"/>')
|
||||
},
|
||||
},
|
||||
'S': {
|
||||
// save...
|
||||
// XXX needs testing...
|
||||
'ctrl': function(){
|
||||
showInOverlay('<h1>Save Issue</h1>'+
|
||||
'<p>NOTE: this download will not include the actual '+
|
||||
'images. at this point, images should be added manually.</p>'+
|
||||
'<p><a id="data_download" href="#">Download</a></p>')
|
||||
|
||||
// setup the data...
|
||||
$(generateMagazineDownload)
|
||||
},
|
||||
},
|
||||
|
||||
// ?
|
||||
'/': function(){
|
||||
showInOverlay('<h1>Controls</h1>'+
|
||||
'<p>NOTE: this section is a stub.<p>'+
|
||||
'<table width="100%">'+
|
||||
'<tr><td align="right" width="45%"><b> C-O </b></td><td> Load issue from file. </td></tr>'+
|
||||
'<tr><td align="right"><b> C-S </b></td><td> Save issue to file. </td></tr>'+
|
||||
'<tr><td align="right"><b> - / + </b></td><td> Zoom out/in. </td></tr>'+
|
||||
'<tr><td align="right"><b> 0 </b></td><td> Set default zoom level. </td></tr>'+
|
||||
'</table>')
|
||||
},
|
||||
},
|
||||
|
||||
// ignore all keys except Esc here...
|
||||
'.inline-editor-mode': {
|
||||
title: 'Inline editor mode.',
|
||||
doc: '',
|
||||
|
||||
//ignore: '*'
|
||||
Esc: function(){
|
||||
$(':focus').blur()
|
||||
return false
|
||||
},
|
||||
},
|
||||
|
||||
'.chrome:not(.inline-editor-mode)': {
|
||||
title: 'Global bindings.',
|
||||
doc: '',
|
||||
|
||||
Esc: function(){
|
||||
if(toggleEditor('?') == 'on'){
|
||||
toggleEditor('off')
|
||||
} else {
|
||||
togglePageView('off')
|
||||
}
|
||||
},
|
||||
|
||||
Home: firstPage,
|
||||
End: lastPage,
|
||||
Left: {
|
||||
default: function(){ prevPage() },
|
||||
shift: prevBookmark,
|
||||
ctrl: prevArticle,
|
||||
},
|
||||
Right: {
|
||||
default: function(){ nextPage() },
|
||||
shift: nextBookmark,
|
||||
ctrl: nextArticle,
|
||||
},
|
||||
Space: {
|
||||
default: 'Right',
|
||||
shift: 'Left'
|
||||
},
|
||||
//Tab: 'Space',
|
||||
Tab: function(){ return false },
|
||||
Enter: function(){ togglePageView('on') },
|
||||
// combined navigation with actions..
|
||||
Up: function(){ togglePageView() },
|
||||
Down: function(){ togglePageView() },
|
||||
|
||||
F: function(){ togglePageFitMode() },
|
||||
B: {
|
||||
default: function(){ toggleBookmark() },
|
||||
ctrl: function(){ toggleThemes() },
|
||||
},
|
||||
|
||||
// XXX this should not be in the production viewer...
|
||||
E: function(){ toggleEditor() },
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
// this is to fix some sort of bug baking things align in a wrong
|
||||
|
||||
223
keybindings.js
223
keybindings.js
@ -1,94 +1,173 @@
|
||||
/*********************************************************************/
|
||||
// NOTE: use String.fromCharCode(code)...
|
||||
// list of keys to be ignored by handler but still handled by the browser...
|
||||
|
||||
var keybindings = {
|
||||
/*
|
||||
// global bindings...
|
||||
'*': {
|
||||
title: 'Global',
|
||||
var KEYBOARD_CONFIG = {
|
||||
'Global bindings': {
|
||||
doc: 'NOTE: binding priority is the same as the order of sections '+
|
||||
'on this page.',
|
||||
pattern: '*',
|
||||
|
||||
F4: {
|
||||
alt: doc('Close viewer',
|
||||
function(){
|
||||
if(window.require != null){
|
||||
require('nw.gui')
|
||||
.Window.get().close()
|
||||
return false
|
||||
}
|
||||
}),
|
||||
},
|
||||
F5: doc('Full reload viewer',
|
||||
function(){
|
||||
if(window.require != null){
|
||||
require('nw.gui')
|
||||
.Window.get().reload()
|
||||
return false
|
||||
}
|
||||
}),
|
||||
F12: doc('Show devTools',
|
||||
function(){
|
||||
if(window.require != null){
|
||||
require('nw.gui')
|
||||
.Window.get().showDevTools()
|
||||
return false
|
||||
}
|
||||
}),
|
||||
},
|
||||
|
||||
'.overlay': {
|
||||
title: 'Overlay mode.',
|
||||
doc: '',
|
||||
|
||||
ignore: [
|
||||
116, // F5
|
||||
122, // F11
|
||||
123, // F12
|
||||
8 // BkSp
|
||||
],
|
||||
ignore: '*',
|
||||
|
||||
// ignore the modifiers (shift, alt, ctrl, caps)...
|
||||
16: function(){},
|
||||
17: 16,
|
||||
18: 16,
|
||||
20: 16, // Caps Lock
|
||||
Esc: function(){
|
||||
removeOverlay()
|
||||
return false
|
||||
},
|
||||
},
|
||||
|
||||
'.editor:not(.inline-editor-mode)': {
|
||||
title: 'Editor mode.',
|
||||
doc: '',
|
||||
|
||||
// overlay...
|
||||
'.overlay-mode': {
|
||||
title: 'Overlay mode',
|
||||
doc: 'Overlay mode key bindings.',
|
||||
'0': function(){
|
||||
var n = getPageNumber()
|
||||
if(togglePageView('?') == 'on'){
|
||||
setMagazineScale(getPageTargetScale(1))
|
||||
} else {
|
||||
setMagazineScale(getPageTargetScale(PAGES_IN_RIBBON))
|
||||
}
|
||||
setCurrentPage(n)
|
||||
},
|
||||
Esc: '0',
|
||||
|
||||
ignore: [
|
||||
33, // PgUp
|
||||
34, // PgDown
|
||||
37, // Left
|
||||
39, // Right
|
||||
36, // Home
|
||||
32, // Space
|
||||
35, // End
|
||||
38, // Up
|
||||
40, // Down
|
||||
],
|
||||
'=': function(){
|
||||
var n = getPageNumber()
|
||||
setMagazineScale(Math.min(
|
||||
getMagazineScale() * 1.2,
|
||||
getPageTargetScale(1)))
|
||||
setCurrentPage(n)
|
||||
},
|
||||
'-': function(){
|
||||
var n = getPageNumber()
|
||||
setMagazineScale(Math.max(
|
||||
getMagazineScale() * 0.8,
|
||||
getPageTargetScale(PAGES_IN_RIBBON*2)))
|
||||
setCurrentPage(n)
|
||||
},
|
||||
|
||||
'O': {
|
||||
// load...
|
||||
// XXX needs testing...
|
||||
'ctrl': function(){
|
||||
showInOverlay('<h1>Open Issue</h1>'+
|
||||
'<input type="file" id="upload" name="file" multiple onchange="handleFileSelect(event)"/>')
|
||||
},
|
||||
},
|
||||
'S': {
|
||||
// save...
|
||||
// XXX needs testing...
|
||||
'ctrl': function(){
|
||||
showInOverlay('<h1>Save Issue</h1>'+
|
||||
'<p>NOTE: this download will not include the actual '+
|
||||
'images. at this point, images should be added manually.</p>'+
|
||||
'<p><a id="data_download" href="#">Download</a></p>')
|
||||
|
||||
// setup the data...
|
||||
$(generateMagazineDownload)
|
||||
},
|
||||
},
|
||||
|
||||
// ?
|
||||
'/': function(){
|
||||
showInOverlay('<h1>Controls</h1>'+
|
||||
'<p>NOTE: this section is a stub.<p>'+
|
||||
'<table width="100%">'+
|
||||
'<tr><td align="right" width="45%"><b> C-O </b></td><td> Load issue from file. </td></tr>'+
|
||||
'<tr><td align="right"><b> C-S </b></td><td> Save issue to file. </td></tr>'+
|
||||
'<tr><td align="right"><b> - / + </b></td><td> Zoom out/in. </td></tr>'+
|
||||
'<tr><td align="right"><b> 0 </b></td><td> Set default zoom level. </td></tr>'+
|
||||
'</table>')
|
||||
},
|
||||
},
|
||||
*/
|
||||
|
||||
// ignore all keys here...
|
||||
// ignore all keys except Esc here...
|
||||
'.inline-editor-mode': {
|
||||
ignore: '*'
|
||||
},
|
||||
|
||||
// everything except overlays...
|
||||
'.viewer:not(.inline-editor-mode)': {
|
||||
title: 'Ribbon and Viewer',
|
||||
title: 'Inline editor mode.',
|
||||
doc: '',
|
||||
|
||||
// navigation...
|
||||
36: goToMagazineCover, // Home
|
||||
219: 36, // [
|
||||
35: goToMagazineEnd, // End
|
||||
221: 35, // ]
|
||||
37: {
|
||||
'default': prevPage, // Right
|
||||
'ctrl': prevArticle, // ctrl-Right
|
||||
'shift': prevBookmark // shift-Right
|
||||
},
|
||||
188: 37, // <
|
||||
39: {
|
||||
'default': nextPage, // Left
|
||||
'ctrl': nextArticle, // ctrl-Left
|
||||
'shift': nextBookmark // shift-Left
|
||||
},
|
||||
32: {
|
||||
'default': nextPage, // Space
|
||||
'shift': prevPage // shift-Space
|
||||
},
|
||||
190: 39, // >
|
||||
//ignore: '*'
|
||||
Esc: function(){
|
||||
$(':focus').blur()
|
||||
return false
|
||||
},
|
||||
},
|
||||
|
||||
66: {
|
||||
'default': toggleBookmark, // B
|
||||
'ctrl': function(){toggleThemes()}, // ctrl-B
|
||||
},
|
||||
'.chrome:not(.inline-editor-mode)': {
|
||||
title: 'Global bindings.',
|
||||
doc: '',
|
||||
|
||||
Esc: function(){
|
||||
if(toggleEditor('?') == 'on'){
|
||||
toggleEditor('off')
|
||||
} else {
|
||||
togglePageView('off')
|
||||
}
|
||||
},
|
||||
|
||||
Home: firstPage,
|
||||
End: lastPage,
|
||||
Left: {
|
||||
default: function(){ prevPage() },
|
||||
shift: prevBookmark,
|
||||
ctrl: prevArticle,
|
||||
},
|
||||
Right: {
|
||||
default: function(){ nextPage() },
|
||||
shift: nextBookmark,
|
||||
ctrl: nextArticle,
|
||||
},
|
||||
Space: {
|
||||
default: 'Right',
|
||||
shift: 'Left'
|
||||
},
|
||||
//Tab: 'Space',
|
||||
Tab: function(){ return false },
|
||||
Enter: function(){ togglePageView('on') },
|
||||
// combined navigation with actions..
|
||||
38: function(){togglePageView()}, // Up
|
||||
40: function(){togglePageView()}, // Down
|
||||
Up: function(){ togglePageView() },
|
||||
Down: function(){ togglePageView() },
|
||||
|
||||
13: function(){togglePageView('on')}, // Enter
|
||||
27: function(){togglePageView('off')}, // Esc
|
||||
}
|
||||
}
|
||||
F: function(){ togglePageFitMode() },
|
||||
B: {
|
||||
default: function(){ toggleBookmark() },
|
||||
ctrl: function(){ toggleThemes() },
|
||||
},
|
||||
|
||||
// XXX this should not be in the production viewer...
|
||||
E: function(){ toggleEditor() },
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
298
lib/keyboard.js
298
lib/keyboard.js
@ -10,6 +10,17 @@
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
// Attributes to be ignored my the key handler...
|
||||
//
|
||||
// These are used for system tasks.
|
||||
var KEYBOARD_SYSTEM_ATTRS = [
|
||||
'doc',
|
||||
'title',
|
||||
'ignore',
|
||||
'pattern'
|
||||
]
|
||||
|
||||
|
||||
// Neither _SPECIAL_KEYS nor _KEY_CODES are meant for direct access, use
|
||||
// toKeyName(<code>) and toKeyCode(<name>) for a more uniform access.
|
||||
//
|
||||
@ -109,22 +120,49 @@ function toKeyCode(c){
|
||||
|
||||
// documentation wrapper...
|
||||
function doc(text, func){
|
||||
func = func == null ? function(){return true}: func
|
||||
func = !func ? function(){return true}: func
|
||||
func.doc = text
|
||||
return func
|
||||
}
|
||||
|
||||
|
||||
// Build or normalize a modifier string.
|
||||
//
|
||||
// Acceptable argument sets:
|
||||
// - none -> ""
|
||||
// - true, false, true -> "ctrl+shift"
|
||||
// - true, false -> "ctrl"
|
||||
// - [true, false] -> "ctrl"
|
||||
// - 'alt+shift' -> "alt+shift"
|
||||
// - 'shift - alt' -> "alt+shift"
|
||||
//
|
||||
function normalizeModifiers(c, a, s){
|
||||
if(c != null && c.constructor.name == 'Array'){
|
||||
a = c[1]
|
||||
s = c[2]
|
||||
c = c[0]
|
||||
}
|
||||
if(typeof(c) == typeof('str')){
|
||||
var modifiers = c
|
||||
} else {
|
||||
var modifiers = (c ? 'ctrl' : '')
|
||||
+ (a ? ' alt' : '')
|
||||
+ (s ? ' shift' : '')
|
||||
}
|
||||
|
||||
// build the dormalized modifier string...
|
||||
var res = /ctrl/i.test(modifiers) ? 'ctrl' : ''
|
||||
res += /alt/i.test(modifiers) ? (res != '' ? '+alt' : 'alt') : ''
|
||||
res += /shift/i.test(modifiers) ? (res != '' ? '+shift' : 'shift') : ''
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
/* Key handler getter
|
||||
*
|
||||
* For doc on format see makeKeyboardHandler(...)
|
||||
*
|
||||
* modes can be:
|
||||
* - 'any' (default) - Get list of all applicable handlers up until
|
||||
* the first applicable ignore.
|
||||
* - 'all' - Get ALL handlers, including ignores
|
||||
* - <mode> - Get handlers for an explicit mode
|
||||
*
|
||||
* modifiers can be:
|
||||
* - '' (default) - No modifiers
|
||||
* - '?' - Return list of applicable modifiers per mode
|
||||
@ -135,6 +173,15 @@ function doc(text, func){
|
||||
* Ex:
|
||||
* 'ctrl+shift'
|
||||
* NOTE: 'shift+ctrl' is wrong.
|
||||
* NOTE: normalizeModifiers(...) can be used as
|
||||
* a reference, if in doubt.
|
||||
*
|
||||
* modes can be:
|
||||
* - 'any' (default) - Get list of all applicable handlers up until
|
||||
* the first applicable ignore.
|
||||
* - 'all' - Get ALL handlers, including ignores
|
||||
* - <mode> - Get handlers for an explicit mode
|
||||
*
|
||||
*
|
||||
* This will also resolve several shifted keys by name, for example:
|
||||
* 'shift-/' is the same as '?', and either can be used, but the shorter
|
||||
@ -148,24 +195,41 @@ function doc(text, func){
|
||||
* }
|
||||
*
|
||||
*
|
||||
* <handler> can be:
|
||||
* - <function> - handler
|
||||
* - [<doc>, <function>]
|
||||
* - lisp-style handler
|
||||
* - 'IGNORE' - if mode is 'all' and key is in .ignore
|
||||
* - [<function>, 'IGNORE NEXT']
|
||||
* - if mode is 'all' and the key is both in .ignore
|
||||
* and a handler is defined in the current section
|
||||
* NOTE: in this case if this mode matches, all
|
||||
* the subsequent handlers will get ignored
|
||||
* in normal modes...
|
||||
*
|
||||
*
|
||||
* NOTE: adding a key to the ignore list has the same effect as returning
|
||||
* false form it's handler in the same context.
|
||||
* NOTE: it is not possible to do a shift-? as it is already shifted.
|
||||
* NOTE: if a key is not handled in a mode, that mode will not be
|
||||
* present in the resulting object.
|
||||
* NOTE: this will not unwrap lisp-style (see below) handlers.
|
||||
* NOTE: modes are prioritized by order of occurrence.
|
||||
* NOTE: modifiers can be a list of three bools...
|
||||
* (see: normalizeModifiers(...) for further information)
|
||||
*
|
||||
* XXX need an explicit way to prioritize modes, avoiding object attr
|
||||
* ordering...
|
||||
* XXX check do we need did_handling here...
|
||||
*
|
||||
* XXX BUG explicitly given modes do not yield results if the pattern
|
||||
* does not match...
|
||||
*/
|
||||
function getKeyHandlers(key, modifiers, keybindings, modes, shifted_keys){
|
||||
var chr = null
|
||||
var s_chr = null
|
||||
// XXX I do not understand why this is here...
|
||||
var did_handling = false
|
||||
var did_ignore = false
|
||||
modifiers = modifiers == null ? '' : modifiers
|
||||
modifiers = modifiers != '?' ? normalizeModifiers(modifiers) : modifiers
|
||||
modes = modes == null ? 'any' : modes
|
||||
shifted_keys = shifted_keys == null ? _SHIFT_KEYS : shifted_keys
|
||||
|
||||
@ -184,18 +248,41 @@ function getKeyHandlers(key, modifiers, keybindings, modes, shifted_keys){
|
||||
|
||||
res = {}
|
||||
|
||||
for(var mode in keybindings){
|
||||
for(var title in keybindings){
|
||||
|
||||
// test for mode compatibility...
|
||||
// XXX this fails for explicitly given mode...
|
||||
if(modes != 'all'
|
||||
&& (modes != 'any'
|
||||
&& modes != mode
|
||||
|| $(mode).length == 0)){
|
||||
// If a key is ignored then look no further...
|
||||
if(did_ignore){
|
||||
if(modes != 'all'){
|
||||
break
|
||||
} else {
|
||||
did_ignore = false
|
||||
if(modifiers != '?' && res[mode] != 'IGNORE'){
|
||||
res[mode] = [ res[mode], 'IGNORE NEXT']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// older version compatibility...
|
||||
if(keybindings[title].pattern != null){
|
||||
var mode = keybindings[title].pattern
|
||||
} else {
|
||||
var mode = title
|
||||
}
|
||||
|
||||
// check if we need to skip this mode...
|
||||
if( !(modes == 'all'
|
||||
// explicit mode match...
|
||||
|| modes == mode
|
||||
// 'any' means we need to check the mode...
|
||||
|| (modes == 'any'
|
||||
// '*' always matches...
|
||||
&& mode == '*'
|
||||
// match the mode...
|
||||
|| $(mode).length != 0))){
|
||||
continue
|
||||
}
|
||||
|
||||
var bindings = keybindings[mode]
|
||||
var bindings = keybindings[title]
|
||||
|
||||
if(s_chr != null && s_chr in bindings){
|
||||
var handler = bindings[s_chr]
|
||||
@ -208,6 +295,7 @@ function getKeyHandlers(key, modifiers, keybindings, modes, shifted_keys){
|
||||
}
|
||||
|
||||
// alias...
|
||||
// XXX should this be before after or combined with ignore handling...
|
||||
while( handler != null
|
||||
&& (typeof(handler) == typeof(123)
|
||||
|| typeof(handler) == typeof('str')
|
||||
@ -244,21 +332,24 @@ function getKeyHandlers(key, modifiers, keybindings, modes, shifted_keys){
|
||||
}
|
||||
}
|
||||
|
||||
// if something is ignored then just breakout and stop handling...
|
||||
if(bindings.ignore == '*'
|
||||
|| bindings.ignore != null
|
||||
&& (bindings.ignore.indexOf(key) != -1
|
||||
|| bindings.ignore.indexOf(chr) != -1)){
|
||||
did_handling = true
|
||||
// ignoring a key will stop processing it...
|
||||
if(modes == 'all' || mode == modes){
|
||||
// NOTE: if a handler is defined in this section, this
|
||||
// will be overwritten...
|
||||
// XXX need to add the handler to this if it's defined...
|
||||
res[mode] = 'IGNORE'
|
||||
}
|
||||
did_ignore = true
|
||||
}
|
||||
|
||||
// no handler...
|
||||
if(handler == null){
|
||||
// if something is ignored then just breakout and stop handling...
|
||||
if(bindings.ignore == '*'
|
||||
|| bindings.ignore != null
|
||||
&& (bindings.ignore.indexOf(key) != -1
|
||||
|| bindings.ignore.indexOf(chr) != -1)){
|
||||
did_handling = true
|
||||
// ignoring a key will stop processing it...
|
||||
if(modes == 'all' || mode == modes){
|
||||
res[mode] = 'IGNORE'
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@ -308,10 +399,9 @@ function getKeyHandlers(key, modifiers, keybindings, modes, shifted_keys){
|
||||
/* Basic key binding format:
|
||||
*
|
||||
* {
|
||||
* <css-selector>: {
|
||||
* // meta-data used to generate user docs/help/config
|
||||
* title: <text>,
|
||||
* <title>: {
|
||||
* doc: <text>,
|
||||
* pattern: <css-selector>,
|
||||
*
|
||||
* // this defines the list of keys to ignore by the handler.
|
||||
* // NOTE: use "*" to ignore all keys other than explicitly
|
||||
@ -338,12 +428,14 @@ function getKeyHandlers(key, modifiers, keybindings, modes, shifted_keys){
|
||||
* default: <callback> | <key-def-x>,
|
||||
*
|
||||
* // a modifier can be any single modifier, like shift or a
|
||||
* // combination of modifiers like 'ctrl+shift', given in order
|
||||
* // combination of modifiers like 'ctrl+shift', in order
|
||||
* // of priority.
|
||||
* // supported modifiers are (in order of priority):
|
||||
* // supported modifiers, ordered by priority, are:
|
||||
* // - ctrl
|
||||
* // - alt
|
||||
* // - shift
|
||||
* // NOTE: if in doubt use normalizeModifiers(..) as a
|
||||
* // reference...
|
||||
* <modifer>: [...],
|
||||
* ...
|
||||
* },
|
||||
@ -354,6 +446,13 @@ function getKeyHandlers(key, modifiers, keybindings, modes, shifted_keys){
|
||||
* ...
|
||||
* },
|
||||
*
|
||||
* // legacy format, still supported... (deprecated)
|
||||
* <css-selector>: {
|
||||
* // meta-data used to generate user docs/help/config
|
||||
* title: <text>,
|
||||
* ...
|
||||
* },
|
||||
*
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
@ -365,6 +464,8 @@ function getKeyHandlers(key, modifiers, keybindings, modes, shifted_keys){
|
||||
* - action -- any arbitrary string that is not in the above categories.
|
||||
*
|
||||
*
|
||||
* NOTE: adding a key to the ignore list has the same effect as returning
|
||||
* false form it's handler in the same context.
|
||||
* NOTE: actions,the last case, are used for alias referencing, they will
|
||||
* never match a real key, but will get resolved in alias searches.
|
||||
* NOTE: to test what to use as <key-def> use toKeyCode(..) / toKeyName(..).
|
||||
@ -380,8 +481,8 @@ function getKeyHandlers(key, modifiers, keybindings, modes, shifted_keys){
|
||||
* NOTE: the number keys are named with a leading hash '#' (e.g. '#8')
|
||||
* to avoid conflicsts with keys that have the code with the same
|
||||
* value (e.g. 'backspace' (8)).
|
||||
* NOTE: one can use a doc(<doc-string>, <callback>) as a shorthand to assign
|
||||
* a docstring to a handler.
|
||||
* NOTE: one can use a doc(<doc-string>, <callback>) as a shorthand to
|
||||
* assign a docstring to a handler.
|
||||
* it will only assign .doc attr and return the original function.
|
||||
*
|
||||
* XXX need an explicit way to prioritize modes...
|
||||
@ -398,10 +499,8 @@ function makeKeyboardHandler(keybindings, unhandled){
|
||||
// key data...
|
||||
var key = evt.keyCode
|
||||
|
||||
// normalize the modifiers...
|
||||
var modifiers = evt.ctrlKey ? 'ctrl' : ''
|
||||
modifiers += evt.altKey ? (modifiers != '' ? '+alt' : 'alt') : ''
|
||||
modifiers += evt.shiftKey ? (modifiers != '' ? '+shift' : 'shift') : ''
|
||||
// get modifiers...
|
||||
var modifiers = [evt.ctrlKey, evt.altKey, evt.shiftKey]
|
||||
|
||||
//window.DEBUG && console.log('KEY:', key, chr, modifiers)
|
||||
|
||||
@ -450,16 +549,25 @@ function makeKeyboardHandler(keybindings, unhandled){
|
||||
*
|
||||
* NOTE: this will not add keys (key names) that are not explicit key names.
|
||||
*/
|
||||
// XXX do we need to normalize/pre-process keybindings???
|
||||
// - might be a good idea to normalize the <modifiers>...
|
||||
function buildKeybindingsHelp(keybindings, shifted_keys){
|
||||
shifted_keys = shifted_keys == null ? _SHIFT_KEYS : shifted_keys
|
||||
var res = {}
|
||||
var mode, title
|
||||
|
||||
for(var pattern in keybindings){
|
||||
mode = keybindings[pattern]
|
||||
for(var title in keybindings){
|
||||
mode = keybindings[title]
|
||||
|
||||
// older version compatibility...
|
||||
if(keybindings[title].pattern != null){
|
||||
var pattern = keybindings[title].pattern
|
||||
} else {
|
||||
var pattern = title
|
||||
// titles and docs...
|
||||
var title = mode.title == null ? pattern : mode.title
|
||||
}
|
||||
|
||||
// titles and docs...
|
||||
title = mode.title == null ? pattern : mode.title
|
||||
res[title] = {
|
||||
doc: mode.doc == null ? '' : mode.doc
|
||||
}
|
||||
@ -467,25 +575,27 @@ function buildKeybindingsHelp(keybindings, shifted_keys){
|
||||
|
||||
// handlers...
|
||||
for(var key in mode){
|
||||
if(key == 'doc' || key == 'title' || key == 'ignore'){
|
||||
if(KEYBOARD_SYSTEM_ATTRS.indexOf(key) >= 0){
|
||||
continue
|
||||
}
|
||||
//var modifiers = getKeyHandlers(key, '?', keybindings, pattern)[pattern]
|
||||
var modifiers = getKeyHandlers(key, '?', keybindings, 'all')[pattern]
|
||||
modifiers = modifiers == 'none' || modifiers == undefined ? [''] : modifiers
|
||||
|
||||
for(var i=0; i < modifiers.length; i++){
|
||||
var mod = modifiers[i]
|
||||
|
||||
//var handler = getKeyHandlers(key, mod, keybindings, pattern)[pattern]
|
||||
var handler = getKeyHandlers(key, mod, keybindings, 'all')[pattern]
|
||||
|
||||
if(handler.constructor.name == 'Array' && handler[1] == 'IGNORE NEXT'){
|
||||
handler = handler[0]
|
||||
}
|
||||
|
||||
// standard object doc...
|
||||
if('doc' in handler){
|
||||
var doc = handler.doc
|
||||
|
||||
// lisp style...
|
||||
} else if(typeof(handler) == typeof([]) && handler.constructor.name == 'Array'){
|
||||
} else if(handler.constructor.name == 'Array'){
|
||||
var doc = handler[1]
|
||||
|
||||
// no doc...
|
||||
@ -528,6 +638,31 @@ function buildKeybindingsHelp(keybindings, shifted_keys){
|
||||
}
|
||||
|
||||
|
||||
// Get a list of keys associated with a given doc...
|
||||
//
|
||||
// The second argument must be a structure formated as returned by
|
||||
// buildKeybindingsHelp(...)
|
||||
//
|
||||
// Returned format:
|
||||
// {
|
||||
// <section-name> : <key-spec>
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// NOTE: <key-spec> is the same as generated by buildKeybindingsHelp(..)
|
||||
function getKeysByDoc(doc, help){
|
||||
var res = {}
|
||||
for(var mode in help){
|
||||
var name = mode
|
||||
var section = help[mode]
|
||||
if(doc in section){
|
||||
res[mode] = section[doc]
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
// Build a basic HTML table with keyboard help...
|
||||
//
|
||||
// The table will look like this:
|
||||
@ -584,6 +719,69 @@ function buildKeybindingsHelpHTML(keybindings){
|
||||
}
|
||||
|
||||
|
||||
// Build HTML for a single key definition...
|
||||
//
|
||||
// Format if combining sections (default):
|
||||
// <span class="key-doc">
|
||||
// <span class="doc"> DOC </span>
|
||||
// <span class="keys"> KEYS </span>
|
||||
// </span>
|
||||
//
|
||||
// Format if not combining sections:
|
||||
// <span class="key-doc">
|
||||
// <span class="doc"> DOC </span>
|
||||
// <span class="section">
|
||||
// <span class="name"> MODE NAME </span>
|
||||
// <span class="keys"> KEYS </span>
|
||||
// </span>
|
||||
// ...
|
||||
// </span>
|
||||
//
|
||||
// XXX not yet sure if we are handling the sections correctly...
|
||||
function getKeysByDocHTML(doc, help, combine_sections){
|
||||
combine_sections = combine_sections == null ? true : combine_sections
|
||||
|
||||
var spec = getKeysByDoc(doc, help)
|
||||
var res = '<span class="key-doc">'
|
||||
|
||||
res += '<span class="doc">'+ doc +'</span>'
|
||||
|
||||
var keys = []
|
||||
|
||||
for(var section in spec){
|
||||
if(!combine_sections){
|
||||
keys = spec[section].join(', ')
|
||||
res += '<span class="section">'
|
||||
+'<span class="name">'+ section +'</span>'
|
||||
+'<span class="keys">'+ keys +'</span>'
|
||||
+'</span>'
|
||||
} else {
|
||||
keys = keys.concat(spec[section])
|
||||
}
|
||||
}
|
||||
|
||||
if(combine_sections){
|
||||
res += '<span class="keys">'+ keys.join(', ') +'</span>'
|
||||
}
|
||||
|
||||
return res + '</span>'
|
||||
}
|
||||
|
||||
|
||||
// Update key definitions...
|
||||
//
|
||||
// NOTE: this does not support multiple sections...
|
||||
function updateHTMLKeyDoc(help, root){
|
||||
root = root == null ? $('body') : root
|
||||
return root.find('.key-doc').each(function(i, e){
|
||||
e = $(e)
|
||||
var doc = e.find('.doc')
|
||||
var keys = $(getKeysByDocHTML(doc.html(), help)).find('.keys')
|
||||
e.find('.keys').html(keys.html())
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* Key binding editor...
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user