@@ -168,20 +168,27 @@ define([
168168
169169 // Shortcut manager class
170170
171- var ShortcutManager = function ( delay , events , actions , env ) {
171+ var ShortcutManager = function ( delay , events , actions , env , config , mode ) {
172172 /**
173173 * A class to deal with keyboard event and shortcut
174174 *
175175 * @class ShortcutManager
176176 * @constructor
177+ *
178+ * :config: configobjet on which to call `update(....)` to persist the config.
179+ * :mode: mode of this shortcut manager where to persist config.
177180 */
181+ mode = mode || 'command' ;
178182 this . _shortcuts = { } ;
183+ this . _defaults_bindings = [ ] ;
179184 this . delay = delay || 800 ; // delay in milliseconds
180185 this . events = events ;
181186 this . actions = actions ;
182187 this . actions . extend_env ( env ) ;
183188 this . _queue = [ ] ;
184189 this . _cleartimeout = null ;
190+ this . _config = config ;
191+ this . _mode = mode ;
185192 Object . seal ( this ) ;
186193 } ;
187194
@@ -334,8 +341,30 @@ define([
334341 }
335342 } ;
336343
344+ ShortcutManager . prototype . is_available_shortcut = function ( shortcut ) {
345+ var shortcut_array = shortcut . split ( ',' ) ;
346+ return this . _is_available_shortcut ( shortcut_array , this . _shortcuts ) ;
347+ } ;
348+
349+ ShortcutManager . prototype . _is_available_shortcut = function ( shortcut_array , tree ) {
350+ var current_node = tree [ shortcut_array [ 0 ] ] ;
351+ if ( ! shortcut_array [ 0 ] ) {
352+ return false ;
353+ }
354+ if ( current_node === undefined ) {
355+ return true ;
356+ } else {
357+ if ( typeof ( current_node ) == 'string' ) {
358+ return false ;
359+ } else { // assume is a sub-shortcut tree
360+ return this . _is_available_shortcut ( shortcut_array . slice ( 1 ) , current_node ) ;
361+ }
362+ }
363+ } ;
364+
337365 ShortcutManager . prototype . _set_leaf = function ( shortcut_array , action_name , tree ) {
338366 var current_node = tree [ shortcut_array [ 0 ] ] ;
367+
339368 if ( shortcut_array . length === 1 ) {
340369 if ( current_node !== undefined && typeof ( current_node ) !== 'string' ) {
341370 console . warn ( '[warning], you are overriting a long shortcut with a shorter one' ) ;
@@ -356,6 +385,51 @@ define([
356385 }
357386 } ;
358387
388+ ShortcutManager . prototype . _persist_shortcut = function ( shortcut , data ) {
389+ /**
390+ * add a shortcut to this manager and persist it to the config file.
391+ **/
392+ shortcut = shortcut . toLowerCase ( ) ;
393+ this . add_shortcut ( shortcut , data ) ;
394+ var patch = { keys :{ } } ;
395+ var b = { bind :{ } } ;
396+ patch . keys [ this . _mode ] = { bind :{ } } ;
397+ patch . keys [ this . _mode ] . bind [ shortcut ] = data ;
398+ this . _config . update ( patch ) ;
399+ } ;
400+
401+ ShortcutManager . prototype . _persist_remove_shortcut = function ( shortcut ) {
402+ /**
403+ * Remove a shortcut from this manager and persist its removal.
404+ */
405+
406+ shortcut = shortcut . toLowerCase ( ) ;
407+ this . remove_shortcut ( shortcut ) ;
408+ var patch = { keys :{ } } ;
409+ var b = { bind :{ } } ;
410+ patch . keys [ this . _mode ] = { bind :{ } } ;
411+ patch . keys [ this . _mode ] . bind [ shortcut ] = null ;
412+ this . _config . update ( patch ) ;
413+ console . info ( patch ) ;
414+
415+ // if the shortcut we unbind is a default one, we add it to the list of
416+ // things to unbind at startup
417+
418+ if ( this . _defaults_bindings . indexOf ( shortcut ) !== - 1 ) {
419+ var cnf = ( this . _config . data . keys || { } ) [ this . _mode ] ;
420+ var unbind_array = cnf . unbind || [ ] ;
421+
422+ // unless it's already there (like if we have remapped a default
423+ // shortcut to another command, and unbind it)
424+ if ( unbind_array . indexOf ( shortcut ) !== - 1 ) {
425+ unbind_array . concat ( shortcut ) ;
426+ var unbind_patch = { keys :{ unbind :unbind_array } } ;
427+ this . _config . _update ( unbind_patch ) ;
428+ }
429+ }
430+ } ;
431+
432+
359433 ShortcutManager . prototype . add_shortcut = function ( shortcut , data , suppress_help_update ) {
360434 /**
361435 * Add a action to be handled by shortcut manager.
@@ -369,8 +443,8 @@ define([
369443 if ( ! action_name ) {
370444 throw new Error ( 'does not know how to deal with : ' + data ) ;
371445 }
372- shortcut = normalize_shortcut ( shortcut ) ;
373- this . set_shortcut ( shortcut , action_name ) ;
446+ var _shortcut = normalize_shortcut ( shortcut ) ;
447+ this . set_shortcut ( _shortcut , action_name ) ;
374448
375449 if ( ! suppress_help_update ) {
376450 // update the keyboard shortcuts notebook help
@@ -391,6 +465,16 @@ define([
391465 this . events . trigger ( 'rebuild.QuickHelp' ) ;
392466 } ;
393467
468+ ShortcutManager . prototype . _add_default_shortcuts = function ( data ) {
469+ /**
470+ * same as add_shortcuts, but register them as "default" that if persistently unbound, with
471+ * persist_remove_shortcut, need to be on the "unbind" list.
472+ **/
473+ this . _defaults_bindings = this . _defaults_bindings . concat ( Object . keys ( data ) ) ;
474+ this . add_shortcuts ( data ) ;
475+
476+ } ;
477+
394478 ShortcutManager . prototype . remove_shortcut = function ( shortcut , suppress_help_update ) {
395479 /**
396480 * Remove the binding of shortcut `sortcut` with its action.
@@ -415,7 +499,7 @@ define([
415499 this . events . trigger ( 'rebuild.QuickHelp' ) ;
416500 }
417501 } catch ( ex ) {
418- throw new Error ( 'trying to remove a non-existent shortcut' , shortcut ) ;
502+ throw new Error ( 'trying to remove a non-existent shortcut' , shortcut , typeof shortcut ) ;
419503 }
420504 } ;
421505
0 commit comments