From 7297474b2e683f6e6e382891b2ec36e7f22c0764 Mon Sep 17 00:00:00 2001 From: Greg Denehy Date: Sun, 30 Apr 2017 15:23:04 +0930 Subject: [PATCH 1/6] Added programatic support for custom key bindings with optional descriptions to be added to the help screen --- js/reveal.js | 71 +++++++++++++++++++++++++++++++++++++++++-- plugin/notes/notes.js | 14 +-------- 2 files changed, 70 insertions(+), 15 deletions(-) diff --git a/js/reveal.js b/js/reveal.js index e25337e0..e8833c49 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -232,7 +232,10 @@ 'B , .': 'Pause', 'F': 'Fullscreen', 'ESC, O': 'Slide overview' - }; + }, + + // Holds custom key code mappings + registeredKeyBindings = {}; /** * Starts up the presentation if the client is capable. @@ -1091,6 +1094,33 @@ } + /** + * Add a custom key binding with optional description to be added to the help screen + */ + function addKeyBinding(binding, callback) { + if (typeof binding === 'object' && binding.code) { + registeredKeyBindings[binding.code] = { + callback: callback, + key: binding.key, + description: binding.description + } + } + else { + registeredKeyBindings[binding] = { + callback: callback, + key: null, + description: null + } + } + } + + /** + * Removes the specified custom key binding + */ + function removeKeyBinding(binding) { + delete registeredKeyBindings[binding]; + } + /** * Extend object a with the properties of object b. * If there's a conflict, object b takes precedence. @@ -1518,6 +1548,13 @@ html += '' + key + '' + keyboardShortcuts[ key ] + ''; } + // add custom key bindings that have associated descriptions + for( var binding in registeredKeyBindings ) { + if (registeredKeyBindings[binding].key && registeredKeyBindings[binding].description) { + html += '' + registeredKeyBindings[binding].key + '' + registeredKeyBindings[binding].description + ''; + } + } + html += ''; dom.overlay.innerHTML = [ @@ -3967,7 +4004,31 @@ } - // 2. System defined key bindings + // 2. Registered custom key bindings + if( triggered === false ) { + + for( key in registeredKeyBindings ) { + + // Check if this binding matches the pressed key + if( parseInt( key, 10 ) === event.keyCode ) { + + var value = registeredKeyBindings[ key ].callback; + + // Callback function + if( typeof value === 'function' ) { + value.apply( null, [ event ] ); + } + // String shortcuts to reveal.js API + else if( typeof value === 'string' && typeof Reveal[ value ] === 'function' ) { + Reveal[ value ].call(); + } + + triggered = true; + } + } + } + + // 3. System defined key bindings if( triggered === false ) { // Assume true and try to prove false @@ -4676,6 +4737,12 @@ } }, + // Adds a custom key binding + addKeyBinding: addKeyBinding, + + // Removes a custom key binding + removeKeyBinding: removeKeyBinding, + // Programatically triggers a keyboard event triggerKey: function( keyCode ) { onDocumentKeyDown( { keyCode: keyCode } ); diff --git a/plugin/notes/notes.js b/plugin/notes/notes.js index 202e73b9..8980fb41 100644 --- a/plugin/notes/notes.js +++ b/plugin/notes/notes.js @@ -106,19 +106,7 @@ var RevealNotes = (function() { } // Open the notes when the 's' key is hit - document.addEventListener( 'keydown', function( event ) { - // Disregard the event if the target is editable or a - // modifier is present - if ( document.querySelector( ':focus' ) !== null || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) return; - - // Disregard the event if keyboard is disabled - if ( Reveal.getConfig().keyboard === false ) return; - - if( event.keyCode === 83 ) { - event.preventDefault(); - openNotes(); - } - }, false ); + Reveal.addKeyBinding({code: 83, key: 'S', description: 'Speaker notes'}, openNotes); } From 8bf9986fa21c89b9b38145b43e6fe572c3acebd5 Mon Sep 17 00:00:00 2001 From: Greg Denehy Date: Sun, 30 Apr 2017 15:24:42 +0930 Subject: [PATCH 2/6] Pass through key event when calling keyboardCondition() to allow conditional function to filter on key codes --- js/reveal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/reveal.js b/js/reveal.js index e8833c49..9d4444f5 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -3940,7 +3940,7 @@ // If there's a condition specified and it returns false, // ignore this event - if( typeof config.keyboardCondition === 'function' && config.keyboardCondition() === false ) { + if( typeof config.keyboardCondition === 'function' && config.keyboardCondition(event) === false ) { return true; } From e48e1e19b97d99de107966dd3f8c431a89457972 Mon Sep 17 00:00:00 2001 From: Greg Denehy Date: Sun, 30 Apr 2017 16:35:35 +0930 Subject: [PATCH 3/6] Changed custom key binding config properties to use 'keyCode' instead of 'code' --- js/reveal.js | 4 ++-- plugin/notes/notes.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/js/reveal.js b/js/reveal.js index 9d4444f5..328edb08 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -1098,8 +1098,8 @@ * Add a custom key binding with optional description to be added to the help screen */ function addKeyBinding(binding, callback) { - if (typeof binding === 'object' && binding.code) { - registeredKeyBindings[binding.code] = { + if (typeof binding === 'object' && binding.keyCode) { + registeredKeyBindings[binding.keyCode] = { callback: callback, key: binding.key, description: binding.description diff --git a/plugin/notes/notes.js b/plugin/notes/notes.js index 8980fb41..6373d976 100644 --- a/plugin/notes/notes.js +++ b/plugin/notes/notes.js @@ -106,7 +106,7 @@ var RevealNotes = (function() { } // Open the notes when the 's' key is hit - Reveal.addKeyBinding({code: 83, key: 'S', description: 'Speaker notes'}, openNotes); + Reveal.addKeyBinding({keyCode: 83, key: 'S', description: 'Speaker notes'}, openNotes); } From 40a46e1c0c7836bdc26d25993a5c785be82e9973 Mon Sep 17 00:00:00 2001 From: Greg Denehy Date: Sun, 30 Apr 2017 17:19:01 +0930 Subject: [PATCH 4/6] Added description of custom key binding API to readme --- README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/README.md b/README.md index c52a492d..04550893 100644 --- a/README.md +++ b/README.md @@ -393,6 +393,37 @@ Reveal.isPaused(); Reveal.isAutoSliding(); ``` +### Custom Key Bindings + +Custom key bindings can be added and removed using the following Javascript API. Custom key bindings will override the default keyboard bindings, but will in turn be overridden by the user defined bindings in the ``keyboard`` config option. + +```javascript +Reveal.addKeyBinding( binding, callback ); +Reveal.removeKeyBinding( keyCode ); +``` + +For example + +```javascript +// The binding parameter provides the following properties +// keyCode: the keycode for binding to the callback +// key: the key label to show in the help overlay +// description: the description of the action to show in the help overlay +Reveal.addKeyBinding( { keyCode: 84, key: 'T', description: 'Start timer' }, function() { + // start timer +} ) + +// The binding parameter can also be a direct keycode without providing the help description +Reveal.addKeyBinding( 82, function() { + // reset timer +} ) +``` + +This allows plugins to add key bindings directly to Reveal so they can + +* make use of Reveal's pre-processing logic for key handling (for example, ignoring key presses when paused); and +* be included in the help overlay (optional) + ### Slide Changed Event A 'slidechanged' event is fired each time the slide is changed (regardless of state). The event object holds the index values of the current slide as well as a reference to the previous and current slide HTML nodes. From e16508477ab541314452997d20aa6bdb5a8b0862 Mon Sep 17 00:00:00 2001 From: Greg Denehy Date: Sun, 30 Apr 2017 17:51:38 +0930 Subject: [PATCH 5/6] Fixed notes.js to account for upstream updates --- plugin/notes/notes.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plugin/notes/notes.js b/plugin/notes/notes.js index 1a35110d..3f00eb6b 100644 --- a/plugin/notes/notes.js +++ b/plugin/notes/notes.js @@ -131,10 +131,9 @@ var RevealNotes = (function() { } // Open the notes when the 's' key is hit - Reveal.addKeyBinding({keyCode: 83, key: 'S', description: 'Speaker notes'}, openNotes); - - // Show our keyboard shortcut in the reveal.js help overlay - if( window.Reveal ) Reveal.registerKeyboardShortcut( 'S', 'Speaker notes view' ); + Reveal.addKeyBinding({keyCode: 83, key: 'S', description: 'Speaker notes view'}, function() { + openNotes(); + } ); } From b86b667d2552b32dd0a6d52a210fcf6bbb132867 Mon Sep 17 00:00:00 2001 From: Greg Denehy Date: Sun, 30 Apr 2017 19:42:45 +0930 Subject: [PATCH 6/6] Changes to fix failed jshint test related to Key Binding API --- js/reveal.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/js/reveal.js b/js/reveal.js index 4e44b017..0bdcd121 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -1234,14 +1234,14 @@ callback: callback, key: binding.key, description: binding.description - } + }; } else { registeredKeyBindings[binding] = { callback: callback, key: null, description: null - } + }; } } @@ -4386,15 +4386,15 @@ // Check if this binding matches the pressed key if( parseInt( key, 10 ) === event.keyCode ) { - var value = registeredKeyBindings[ key ].callback; + var action = registeredKeyBindings[ key ].callback; // Callback function - if( typeof value === 'function' ) { - value.apply( null, [ event ] ); + if( typeof action === 'function' ) { + action.apply( null, [ event ] ); } // String shortcuts to reveal.js API - else if( typeof value === 'string' && typeof Reveal[ value ] === 'function' ) { - Reveal[ value ].call(); + else if( typeof action === 'string' && typeof Reveal[ action ] === 'function' ) { + Reveal[ action ].call(); } triggered = true;