##// END OF EJS Templates
Merge pull request #7981 from Carreau/focus-after-save...
Thomas Kluyver -
r20656:49d378b4 merge
parent child Browse files
Show More
@@ -1,520 +1,521 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define(function(require){
5 5 "use strict";
6 6
7 7 var ActionHandler = function (env) {
8 8 this.env = env || {};
9 9 Object.seal(this);
10 10 };
11 11
12 12 /**
13 13 * A bunch of predefined `Simple Actions` used by IPython.
14 14 * `Simple Actions` have the following keys:
15 15 * help (optional): a short string the describe the action.
16 16 * will be used in various context, like as menu name, tool tips on buttons,
17 17 * and short description in help menu.
18 18 * help_index (optional): a string used to sort action in help menu.
19 19 * icon (optional): a short string that represent the icon that have to be used with this
20 20 * action. this should mainly correspond to a Font_awesome class.
21 21 * handler : a function which is called when the action is activated. It will receive at first parameter
22 22 * a dictionary containing various handle to element of the notebook.
23 23 *
24 24 * action need to be registered with a **name** that can be use to refer to this action.
25 25 *
26 26 *
27 27 * if `help` is not provided it will be derived by replacing any dash by space
28 28 * in the **name** of the action. It is advised to provide a prefix to action name to
29 29 * avoid conflict the prefix should be all lowercase and end with a dot `.`
30 30 * in the absence of a prefix the behavior of the action is undefined.
31 31 *
32 32 * All action provided by IPython are prefixed with `ipython.`.
33 33 *
34 34 * One can register extra actions or replace an existing action with another one is possible
35 35 * but is considered undefined behavior.
36 36 *
37 37 **/
38 38 var _actions = {
39 39 'run-select-next': {
40 40 icon: 'fa-play',
41 41 help : 'run cell, select below',
42 42 help_index : 'ba',
43 43 handler : function (env) {
44 44 env.notebook.execute_cell_and_select_below();
45 45 }
46 46 },
47 47 'execute-in-place':{
48 48 help : 'run cell',
49 49 help_index : 'bb',
50 50 handler : function (env) {
51 51 env.notebook.execute_cell();
52 52 }
53 53 },
54 54 'execute-and-insert-after':{
55 55 help : 'run cell, insert below',
56 56 help_index : 'bc',
57 57 handler : function (env) {
58 58 env.notebook.execute_cell_and_insert_below();
59 59 }
60 60 },
61 61 'go-to-command-mode': {
62 62 help : 'command mode',
63 63 help_index : 'aa',
64 64 handler : function (env) {
65 65 env.notebook.command_mode();
66 66 }
67 67 },
68 68 'split-cell-at-cursor': {
69 69 help : 'split cell',
70 70 help_index : 'ea',
71 71 handler : function (env) {
72 72 env.notebook.split_cell();
73 73 }
74 74 },
75 75 'enter-edit-mode' : {
76 76 help_index : 'aa',
77 77 handler : function (env) {
78 78 env.notebook.edit_mode();
79 79 }
80 80 },
81 81 'select-previous-cell' : {
82 82 help: 'select cell above',
83 83 help_index : 'da',
84 84 handler : function (env) {
85 85 var index = env.notebook.get_selected_index();
86 86 if (index !== 0 && index !== null) {
87 87 env.notebook.select_prev();
88 88 env.notebook.focus_cell();
89 89 }
90 90 }
91 91 },
92 92 'select-next-cell' : {
93 93 help: 'select cell below',
94 94 help_index : 'db',
95 95 handler : function (env) {
96 96 var index = env.notebook.get_selected_index();
97 97 if (index !== (env.notebook.ncells()-1) && index !== null) {
98 98 env.notebook.select_next();
99 99 env.notebook.focus_cell();
100 100 }
101 101 }
102 102 },
103 103 'cut-selected-cell' : {
104 104 icon: 'fa-cut',
105 105 help_index : 'ee',
106 106 handler : function (env) {
107 107 var index = env.notebook.get_selected_index();
108 108 env.notebook.cut_cell();
109 109 env.notebook.select(index);
110 110 env.notebook.focus_cell();
111 111 }
112 112 },
113 113 'copy-selected-cell' : {
114 114 icon: 'fa-copy',
115 115 help_index : 'ef',
116 116 handler : function (env) {
117 117 env.notebook.copy_cell();
118 118 env.notebook.focus_cell();
119 119 }
120 120 },
121 121 'paste-cell-before' : {
122 122 help: 'paste cell above',
123 123 help_index : 'eg',
124 124 handler : function (env) {
125 125 env.notebook.paste_cell_above();
126 126 }
127 127 },
128 128 'paste-cell-after' : {
129 129 help: 'paste cell below',
130 130 icon: 'fa-paste',
131 131 help_index : 'eh',
132 132 handler : function (env) {
133 133 env.notebook.paste_cell_below();
134 134 }
135 135 },
136 136 'insert-cell-before' : {
137 137 help: 'insert cell above',
138 138 help_index : 'ec',
139 139 handler : function (env) {
140 140 env.notebook.insert_cell_above();
141 141 env.notebook.select_prev();
142 142 env.notebook.focus_cell();
143 143 }
144 144 },
145 145 'insert-cell-after' : {
146 146 help: 'insert cell below',
147 147 icon : 'fa-plus',
148 148 help_index : 'ed',
149 149 handler : function (env) {
150 150 env.notebook.insert_cell_below();
151 151 env.notebook.select_next();
152 152 env.notebook.focus_cell();
153 153 }
154 154 },
155 155 'change-selected-cell-to-code-cell' : {
156 156 help : 'to code',
157 157 help_index : 'ca',
158 158 handler : function (env) {
159 159 env.notebook.to_code();
160 160 }
161 161 },
162 162 'change-selected-cell-to-markdown-cell' : {
163 163 help : 'to markdown',
164 164 help_index : 'cb',
165 165 handler : function (env) {
166 166 env.notebook.to_markdown();
167 167 }
168 168 },
169 169 'change-selected-cell-to-raw-cell' : {
170 170 help : 'to raw',
171 171 help_index : 'cc',
172 172 handler : function (env) {
173 173 env.notebook.to_raw();
174 174 }
175 175 },
176 176 'change-selected-cell-to-heading-1' : {
177 177 help : 'to heading 1',
178 178 help_index : 'cd',
179 179 handler : function (env) {
180 180 env.notebook.to_heading(undefined, 1);
181 181 }
182 182 },
183 183 'change-selected-cell-to-heading-2' : {
184 184 help : 'to heading 2',
185 185 help_index : 'ce',
186 186 handler : function (env) {
187 187 env.notebook.to_heading(undefined, 2);
188 188 }
189 189 },
190 190 'change-selected-cell-to-heading-3' : {
191 191 help : 'to heading 3',
192 192 help_index : 'cf',
193 193 handler : function (env) {
194 194 env.notebook.to_heading(undefined, 3);
195 195 }
196 196 },
197 197 'change-selected-cell-to-heading-4' : {
198 198 help : 'to heading 4',
199 199 help_index : 'cg',
200 200 handler : function (env) {
201 201 env.notebook.to_heading(undefined, 4);
202 202 }
203 203 },
204 204 'change-selected-cell-to-heading-5' : {
205 205 help : 'to heading 5',
206 206 help_index : 'ch',
207 207 handler : function (env) {
208 208 env.notebook.to_heading(undefined, 5);
209 209 }
210 210 },
211 211 'change-selected-cell-to-heading-6' : {
212 212 help : 'to heading 6',
213 213 help_index : 'ci',
214 214 handler : function (env) {
215 215 env.notebook.to_heading(undefined, 6);
216 216 }
217 217 },
218 218 'toggle-output-visibility-selected-cell' : {
219 219 help : 'toggle output',
220 220 help_index : 'gb',
221 221 handler : function (env) {
222 222 env.notebook.toggle_output();
223 223 }
224 224 },
225 225 'toggle-output-scrolling-selected-cell' : {
226 226 help : 'toggle output scrolling',
227 227 help_index : 'gc',
228 228 handler : function (env) {
229 229 env.notebook.toggle_output_scroll();
230 230 }
231 231 },
232 232 'move-selected-cell-down' : {
233 233 icon: 'fa-arrow-down',
234 234 help_index : 'eb',
235 235 handler : function (env) {
236 236 env.notebook.move_cell_down();
237 237 }
238 238 },
239 239 'move-selected-cell-up' : {
240 240 icon: 'fa-arrow-up',
241 241 help_index : 'ea',
242 242 handler : function (env) {
243 243 env.notebook.move_cell_up();
244 244 }
245 245 },
246 246 'toggle-line-number-selected-cell' : {
247 247 help : 'toggle line numbers',
248 248 help_index : 'ga',
249 249 handler : function (env) {
250 250 env.notebook.cell_toggle_line_numbers();
251 251 }
252 252 },
253 253 'show-keyboard-shortcut-help-dialog' : {
254 254 help_index : 'ge',
255 255 handler : function (env) {
256 256 env.quick_help.show_keyboard_shortcuts();
257 257 }
258 258 },
259 259 'delete-cell': {
260 260 help: 'delete selected cell',
261 261 help_index : 'ej',
262 262 handler : function (env) {
263 263 env.notebook.delete_cell();
264 264 }
265 265 },
266 266 'interrupt-kernel':{
267 267 icon: 'fa-stop',
268 268 help_index : 'ha',
269 269 handler : function (env) {
270 270 env.notebook.kernel.interrupt();
271 271 env.notebook.focus_cell();
272 272 }
273 273 },
274 274 'restart-kernel':{
275 275 icon: 'fa-repeat',
276 276 help_index : 'hb',
277 277 handler : function (env) {
278 278 env.notebook.restart_kernel();
279 279 env.notebook.focus_cell();
280 280 }
281 281 },
282 282 'undo-last-cell-deletion' : {
283 283 help_index : 'ei',
284 284 handler : function (env) {
285 285 env.notebook.undelete_cell();
286 286 }
287 287 },
288 288 'merge-selected-cell-with-cell-after' : {
289 289 help : 'merge cell below',
290 290 help_index : 'ek',
291 291 handler : function (env) {
292 292 env.notebook.merge_cell_below();
293 293 }
294 294 },
295 295 'close-pager' : {
296 296 help_index : 'gd',
297 297 handler : function (env) {
298 298 env.pager.collapse();
299 299 }
300 300 }
301 301
302 302 };
303 303
304 304 /**
305 305 * A bunch of `Advance actions` for IPython.
306 306 * Cf `Simple Action` plus the following properties.
307 307 *
308 308 * handler: first argument of the handler is the event that triggerd the action
309 309 * (typically keypress). The handler is responsible for any modification of the
310 310 * event and event propagation.
311 311 * Is also responsible for returning false if the event have to be further ignored,
312 312 * true, to tell keyboard manager that it ignored the event.
313 313 *
314 314 * the second parameter of the handler is the environemnt passed to Simple Actions
315 315 *
316 316 **/
317 317 var custom_ignore = {
318 318 'ignore':{
319 319 handler : function () {
320 320 return true;
321 321 }
322 322 },
323 323 'move-cursor-up-or-previous-cell':{
324 324 handler : function (env, event) {
325 325 var index = env.notebook.get_selected_index();
326 326 var cell = env.notebook.get_cell(index);
327 327 var cm = env.notebook.get_selected_cell().code_mirror;
328 328 var cur = cm.getCursor();
329 329 if (cell && cell.at_top() && index !== 0 && cur.ch === 0) {
330 330 if(event){
331 331 event.preventDefault();
332 332 }
333 333 env.notebook.command_mode();
334 334 env.notebook.select_prev();
335 335 env.notebook.edit_mode();
336 336 cm = env.notebook.get_selected_cell().code_mirror;
337 337 cm.setCursor(cm.lastLine(), 0);
338 338 }
339 339 return false;
340 340 }
341 341 },
342 342 'move-cursor-down-or-next-cell':{
343 343 handler : function (env, event) {
344 344 var index = env.notebook.get_selected_index();
345 345 var cell = env.notebook.get_cell(index);
346 346 if (cell.at_bottom() && index !== (env.notebook.ncells()-1)) {
347 347 if(event){
348 348 event.preventDefault();
349 349 }
350 350 env.notebook.command_mode();
351 351 env.notebook.select_next();
352 352 env.notebook.edit_mode();
353 353 var cm = env.notebook.get_selected_cell().code_mirror;
354 354 cm.setCursor(0, 0);
355 355 }
356 356 return false;
357 357 }
358 358 },
359 359 'scroll-down': {
360 360 handler: function(env, event) {
361 361 if(event){
362 362 event.preventDefault();
363 363 }
364 364 return env.notebook.scroll_manager.scroll(1);
365 365 },
366 366 },
367 367 'scroll-up': {
368 368 handler: function(env, event) {
369 369 if(event){
370 370 event.preventDefault();
371 371 }
372 372 return env.notebook.scroll_manager.scroll(-1);
373 373 },
374 374 },
375 375 'save-notebook':{
376 376 help: "Save and Checkpoint",
377 377 help_index : 'fb',
378 378 icon: 'fa-save',
379 379 handler : function (env, event) {
380 380 env.notebook.save_checkpoint();
381 381 if(event){
382 382 event.preventDefault();
383 383 }
384 env.notebook.focus_cell();
384 385 return false;
385 386 }
386 387 },
387 388 };
388 389
389 390 // private stuff that prepend `.ipython` to actions names
390 391 // and uniformize/fill in missing pieces in of an action.
391 392 var _prepare_handler = function(registry, subkey, source){
392 393 registry['ipython.'+subkey] = {};
393 394 registry['ipython.'+subkey].help = source[subkey].help||subkey.replace(/-/g,' ');
394 395 registry['ipython.'+subkey].help_index = source[subkey].help_index;
395 396 registry['ipython.'+subkey].icon = source[subkey].icon;
396 397 return source[subkey].handler;
397 398 };
398 399
399 400 // Will actually generate/register all the IPython actions
400 401 var fun = function(){
401 402 var final_actions = {};
402 403 var k;
403 404 for(k in _actions){
404 405 if(_actions.hasOwnProperty(k)){
405 406 // Js closure are function level not block level need to wrap in a IIFE
406 407 // and append ipython to event name these things do intercept event so are wrapped
407 408 // in a function that return false.
408 409 var handler = _prepare_handler(final_actions, k, _actions);
409 410 (function(key, handler){
410 411 final_actions['ipython.'+key].handler = function(env, event){
411 412 handler(env);
412 413 if(event){
413 414 event.preventDefault();
414 415 }
415 416 return false;
416 417 };
417 418 })(k, handler);
418 419 }
419 420 }
420 421
421 422 for(k in custom_ignore){
422 423 // Js closure are function level not block level need to wrap in a IIFE
423 424 // same as above, but decide for themselves wether or not they intercept events.
424 425 if(custom_ignore.hasOwnProperty(k)){
425 426 var handler = _prepare_handler(final_actions, k, custom_ignore);
426 427 (function(key, handler){
427 428 final_actions['ipython.'+key].handler = function(env, event){
428 429 return handler(env, event);
429 430 };
430 431 })(k, handler);
431 432 }
432 433 }
433 434
434 435 return final_actions;
435 436 };
436 437 ActionHandler.prototype._actions = fun();
437 438
438 439
439 440 /**
440 441 * extend the environment variable that will be pass to handlers
441 442 **/
442 443 ActionHandler.prototype.extend_env = function(env){
443 444 for(var k in env){
444 445 this.env[k] = env[k];
445 446 }
446 447 };
447 448
448 449 ActionHandler.prototype.register = function(action, name, prefix){
449 450 /**
450 451 * Register an `action` with an optional name and prefix.
451 452 *
452 453 * if name and prefix are not given they will be determined automatically.
453 454 * if action if just a `function` it will be wrapped in an anonymous action.
454 455 *
455 456 * @return the full name to access this action .
456 457 **/
457 458 action = this.normalise(action);
458 459 if( !name ){
459 460 name = 'autogenerated-'+String(action.handler);
460 461 }
461 462 prefix = prefix || 'auto';
462 463 var full_name = prefix+'.'+name;
463 464 this._actions[full_name] = action;
464 465 return full_name;
465 466
466 467 };
467 468
468 469
469 470 ActionHandler.prototype.normalise = function(data){
470 471 /**
471 472 * given an `action` or `function`, return a normalised `action`
472 473 * by setting all known attributes and removing unknown attributes;
473 474 **/
474 475 if(typeof(data) === 'function'){
475 476 data = {handler:data};
476 477 }
477 478 if(typeof(data.handler) !== 'function'){
478 479 throw('unknown datatype, cannot register');
479 480 }
480 481 var _data = data;
481 482 data = {};
482 483 data.handler = _data.handler;
483 484 data.help = _data.help || '';
484 485 data.icon = _data.icon || '';
485 486 data.help_index = _data.help_index || '';
486 487 return data;
487 488 };
488 489
489 490 ActionHandler.prototype.get_name = function(name_or_data){
490 491 /**
491 492 * given an `action` or `name` of a action, return the name attached to this action.
492 493 * if given the name of and corresponding actions does not exist in registry, return `null`.
493 494 **/
494 495
495 496 if(typeof(name_or_data) === 'string'){
496 497 if(this.exists(name_or_data)){
497 498 return name_or_data;
498 499 } else {
499 500 return null;
500 501 }
501 502 } else {
502 503 return this.register(name_or_data);
503 504 }
504 505 };
505 506
506 507 ActionHandler.prototype.get = function(name){
507 508 return this._actions[name];
508 509 };
509 510
510 511 ActionHandler.prototype.call = function(name, event, env){
511 512 return this._actions[name].handler(env|| this.env, event);
512 513 };
513 514
514 515 ActionHandler.prototype.exists = function(name){
515 516 return (typeof(this._actions[name]) !== 'undefined');
516 517 };
517 518
518 519 return {init:ActionHandler};
519 520
520 521 });
General Comments 0
You need to be logged in to leave comments. Login now