# publicipython/ipython

### Subversion checkout URL

You can clone with HTTPS or Subversion.

# Notebook usability fixes#884

Merged
merged 16 commits into from over 2 years ago
 +149 33

### 3 participants

Owner

A number of small fixes for notebook usability, based on intensive 'in anger' use and feedback from @jdh2358 and others.

Note: it's NOT ready for merge, b/c I need help with one thing. I added a 'quick help' button that should at least be visible at the top and for the moment show the keybindings (later we can make a better quick help page). But right now that button:

• doesn't get the right jquery styling
• is too close to the left, it should be at the right, just left of the kernel status area
• when clicked doesn't do anything.

I tried fixing all three of these and failed, a bit of JS help would be very welcome here. @ellisonbg and @minrk, if you guys can give me some pointers if you know, I'd be grateful and I can finish the job.

Once the quick help button thing is fixed, it's otherwise ready for review/discussion for merge. I'll be happy to take feedback on anything besides that button issue in the meantime.

Summary of changes that work (i.e., other than the broken quickhelp button):

• add kernel restart dialog confirmation (it destroys the user session)
• change language from 'terminal mode' to 'in-place execution' which is more descriptive
• add line numbering toggle to code cells. Triggered with C-m-l.
• show keybindings in monospaced font.
added some commits October 13, 2011
 fperez Add Ctrl-L as a way to toggle line-numbers for any individual code cell e6ec9bc fperez Padding adjustments to better use vertical and horizontal whitespace. Verified that all prompts align correctly on linux/chrome + ffox, and that input prompts up to 4 digits long still fit. 7160056 fperez Add C-m-{'i', '.'} as keybindings for kernel interrupt/restart. e4e174d fperez Use monospaced font for keybinding display. 0be16e0 fperez Refactor line num. toggle into proper function, access via C-m-l. This makes the keybinding consistent with the rest, updated help dialog. b12c675 fperez Add confirmation dialog to kernel restart action. 566748a fperez Change button labels in restart dialog to action words. 6c90928 fperez Add quick help button: broken ATM, style and binding aren't working. Help needed here, will discuss during pull request before merging. 6492aa9 fperez Fix text cell color, was too light to be seen on certain monitors/bro… …wsers. 249093d
Owner

One code note: You seem to have inserted a number of tabs, rather than soft-tabs into the js, so the diff on GH looks a bit funky.

Owner

Argh! Thanks for catching that... I guess emacs in javascript mode will insert tabs. I'll clean it up in a bit.

 fperez Clean up accidentally introduced hard tabs in JS code. 0f5ba50
Owner

OK, fixed and pushed the tab cleanup (and obviously configured emacs so it wouldn't happen again!).

 fperez Keep kernel-related bindings together in code. 2b62313
Owner

Note: GH seems to be updating slowly. I've pushed the changes but they're not appearing on the branch yet, so perhaps give it a few minutes. The last commit should be:

2b62313 Keep kernel-related bindings together in code.

 IPython/frontend/html/notebook/static/css/notebook.css 
 ... ... @@ -200,7 +206,7 @@ div.input_area { 200 206  color: black; 201 207  border: 1px solid #ddd; 202 208  border-radius: 3px; 203 - background: #fafafa; 209 + background: #f4f4f4;
 5 Owner minrk added a note October 17, 2011 Can I ask why you darkened the code background? I actually like the lighter color better. The dark background doesn't feel editable to me. Owner fperez added a note October 17, 2011 I tested it on several systems, with various combinations of ffox, chrome, chromium and monitors. Onn some of them the previous gray was barely distinguishable from the background. Can you let me know which is the darkest gray that seems OK to you? Ultimately we may want to make this user-configurable... I also tried by using yellows, with things like fafaea and similar (basically B
Owner

@fperez the reason the changes aren't showing up here is you pushed to ipython/nb-usablility instead of fperez/nb-usability

Owner

Argh, I'm an idiot! Don't know how I managed to do that, I was obvoiusly too tired yesterday sorting several branches at the same time. Fixing it now.

Owner

OK, done. I did a forced push b/c I'd rebased locally, so do a clean reset.

Owner

Deleting nb-usability branch from main repo, that was never meant to be there.

 fperez Adjust cell background and number color after review with @minrk. fc0d8b1
Owner

@ellisonbg, we split the difference on the gray after review with @minrk at f7. One thing to note is that to see the full effect, it's worth loading a notebook with very long cells, like the display_protocol one in our examples. We also adjusted the number color to be a subdued blue, that would stand out better against a non-white background.

We also played with the idea of using a yellow like #f8f4e8 for the bg. I kind of like it, but it may stand out too much for other's taste.

Ultimately, we'll probably want to allow people to load their custom CSS, because in the end there isn't really a 'right' answer to this: to a good extent this depends on variables beyond our control like people's monitor brightness, lighting environment, visual system and simple personal taste. We can only find a sensible rough solution, not the ultimate perfect one for everybody.

Let us know if this looks reasonable to you. With @minrk's help, I'm fixing up the help button too...

and others added some commits October 17, 2011
 minrk fix quickhelp widget Move header.js -> quickhelp.js, as it not longer acts on whole header. feffa59 minrk show_keyboard_shortcuts -> toggle_keyboard_shortcuts Now multiple calls no longer show multiple instances of the shortcut dialog. Rather, clicking the quick help, or invoking C-m h will hide the dialog if shown. d8d1752 fperez Underline quick help button key accelerator (h). b80a26b fperez Adjust title area sizes to improve alignment. 89110cb
merged commit 4cc4dc8 into from October 17, 2011
closed this October 17, 2011
Owner

OK, I've merged this one after the feedback and @minrk's help. We'll keep fine-tuning UI things for a long time, but I think this gets us close to something fairly solid for new users. Thanks for all the help/review!

referenced this pull request from a commit January 10, 2012
 Commit has since been removed from the repository and is no longer available.

Showing 16 unique commits by 2 authors.

Oct 16, 2011
Add Ctrl-L as a way to toggle line-numbers for any individual code cell e6ec9bc
Padding adjustments to better use vertical and horizontal whitespace.
Verified that all prompts align correctly on linux/chrome + ffox, and
that input prompts up to 4 digits long still fit.
7160056
Add C-m-{'i', '.'} as keybindings for kernel interrupt/restart. e4e174d
Use monospaced font for keybinding display. 0be16e0
Refactor line num. toggle into proper function, access via C-m-l.
This makes the keybinding consistent with the rest, updated help dialog.
b12c675
Add confirmation dialog to kernel restart action. 566748a
Change button labels in restart dialog to action words. 6c90928
Add quick help button: broken ATM, style and binding aren't working.
Help needed here, will discuss during pull request before merging.
6492aa9
Fix text cell color, was too light to be seen on certain monitors/bro…
…wsers.
249093d
Oct 17, 2011
Clean up accidentally introduced hard tabs in JS code. 0f5ba50
Keep kernel-related bindings together in code. 2b62313
Adjust cell background and number color after review with @minrk. fc0d8b1
fix quickhelp widget
Move header.js -> quickhelp.js, as it not longer acts on whole header.
feffa59
show_keyboard_shortcuts -> toggle_keyboard_shortcuts
Now multiple calls no longer show multiple instances of the shortcut dialog.  Rather, clicking the quick help, or invoking C-m h will hide
the dialog if shown.
d8d1752
Underline quick help button key accelerator (h). b80a26b
Adjust title area sizes to improve alignment. 89110cb
2  IPython/frontend/html/notebook/static/codemirror/theme/ipython.css
 ... ... @@ -1,7 +1,7 @@ 1 1   2 2   3 3  .cm-s-ipython span.cm-keyword {color: #008000; font-weight: bold;} 4 -.cm-s-ipython span.cm-number {color: #666666;} 4 +.cm-s-ipython span.cm-number {color: #0A32C8;} 5 5  .cm-s-ipython span.cm-operator {color: #AA22FF; font-weight: bold;} 6 6  .cm-s-ipython span.cm-meta {color: #AA22FF;} 7 7  .cm-s-ipython span.cm-comment {color: #408080; font-style: italic;}
4  IPython/frontend/html/notebook/static/css/base.css
 @@ -22,7 +22,7 @@ div#header { 22 22  /* Initially hidden to prevent FLOUC */ 23 23  display: none; 24 24  position: relative; 25 - height: 45px; 25 + height: 40px; 26 26  padding: 5px; 27 27  margin: 0px; 28 28  width: 100%; @@ -35,7 +35,7 @@ span#ipython_notebook { 35 35   36 36  span#ipython_notebook h1 { 37 37  font-family: Verdana, "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif; 38 - font-size: 197%; 38 + font-size: 150%; 39 39  display: inline; 40 40  color: black; 41 41  }
25  IPython/frontend/html/notebook/static/css/notebook.css
 ... ... @@ -1,4 +1,3 @@ 1 - 2 1  /** 3 2  * Primary styles 4 3  * @@ -19,12 +18,18 @@ body { 19 18  } 20 19   21 20  span#save_widget { 22 - position: absolute; 21 + position: static; 23 22  left: 0px; 24 23  padding: 5px 0px; 25 24  margin: 0px 0px 0px 0px; 26 25  } 27 26   27 +span#quick_help_area { 28 + position: static; 29 + padding: 5px 0px; 30 + margin: 0px 0px 0px 0px; 31 +} 32 + 28 33  input#notebook_name { 29 34  height: 1em; 30 35  line-height: 1em; @@ -35,9 +40,10 @@ span#kernel_status { 35 40  position: absolute; 36 41  padding: 8px 5px 5px 5px; 37 42  right: 10px; 38 - font-weight: bold; 43 + font-weight: bold; 39 44  } 40 45   46 + 41 47  .status_idle { 42 48  color: gray; 43 49  } @@ -156,7 +162,7 @@ div#notebook { 156 162  overflow-x: auto; 157 163  width: 100%; 158 164  /* This spaces the cell away from the edge of the notebook area */ 159 - padding: 15px 15px 15px 15px; 165 + padding: 5px 5px 15px 5px; 160 166  margin: 0px 161 167  background-color: white; 162 168  } @@ -172,9 +178,9 @@ div#pager { 172 178   173 179  div.cell { 174 180  width: 100%; 175 - padding: 5px; 181 + padding: 5px 5px 5px 0px; 176 182  /* This acts as a spacer between cells, that is outside the border */ 177 - margin: 5px 0px 5px 0px; 183 + margin: 2px 0px 2px 0px; 178 184  } 179 185   180 186  div.code_cell { @@ -200,7 +206,7 @@ div.input_area { 200 206  color: black; 201 207  border: 1px solid #ddd; 202 208  border-radius: 3px; 203 - background: #fafafa; 209 + background: #f7f7f7; 204 210  } 205 211   206 212  div.input_prompt { @@ -330,9 +336,10 @@ div.text_cell_render { 330 336   331 337  .shortcut_key { 332 338  display: inline-block; 333 - width: 10ex; 339 + width: 13ex; 334 340  text-align: right; 341 + font-family: monospace; 335 342  } 336 343   337 344  .shortcut_descr { 338 -} 345 +}
31  IPython/frontend/html/notebook/static/js/codecell.js
 @@ -48,9 +48,10 @@ var IPython = (function (IPython) { 48 48   49 49   50 50  CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) { 51 - // This method gets called in CodeMirror's onKeyDown/onKeyPress handlers and 52 - // is used to provide custom key handling. Its return value is used to determine 53 - // if CodeMirror should ignore the event: true = ignore, false = don't ignore. 51 + // This method gets called in CodeMirror's onKeyDown/onKeyPress 52 + // handlers and is used to provide custom key handling. Its return 53 + // value is used to determine if CodeMirror should ignore the event: 54 + // true = ignore, false = don't ignore. 54 55  if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) { 55 56  // Always ignore shift-enter in CodeMirror as we handle it. 56 57  return true; @@ -59,8 +60,8 @@ var IPython = (function (IPython) { 59 60  var cur = editor.getCursor(); 60 61  var pre_cursor = editor.getRange({line:cur.line,ch:0},cur).trim(); 61 62  if (pre_cursor === "") { 62 - // Don't autocomplete if the part of the line before the cursor is empty. 63 - // In this case, let CodeMirror handle indentation. 63 + // Don't autocomplete if the part of the line before the cursor 64 + // is empty. In this case, let CodeMirror handle indentation. 64 65  return false; 65 66  } else { 66 67  // Autocomplete the current line. @@ -86,9 +87,14 @@ var IPython = (function (IPython) { 86 87  } else { 87 88  return false; 88 89  }; 89 - } else { 90 - // keypress/keyup also trigger on TAB press, and we don't want to use those 91 - // to disable tab completion. 90 + } else if (event.keyCode === 76 && event.ctrlKey && event.shiftKey 91 + && event.type == 'keydown') { 92 + // toggle line numbers with Ctrl-Shift-L 93 + this.toggle_line_numbers(); 94 + } 95 + else { 96 + // keypress/keyup also trigger on TAB press, and we don't want to 97 + // use those to disable tab completion. 92 98  if (this.is_completing && event.keyCode !== 9) { 93 99  var ed_cur = editor.getCursor(); 94 100  var cc_cur = this.completion_cursor; @@ -177,6 +183,14 @@ var IPython = (function (IPython) { 177 183  select.focus(); 178 184  }; 179 185   186 + CodeCell.prototype.toggle_line_numbers = function () { 187 + if (this.code_mirror.getOption('lineNumbers') == false) { 188 + this.code_mirror.setOption('lineNumbers', true); 189 + } else { 190 + this.code_mirror.setOption('lineNumbers', false); 191 + } 192 + this.code_mirror.refresh() 193 + }; 180 194   181 195  CodeCell.prototype.select = function () { 182 196  IPython.Cell.prototype.select.apply(this); @@ -470,4 +484,3 @@ var IPython = (function (IPython) { 470 484   471 485  return IPython; 472 486  }(IPython)); 473 -
68  IPython/frontend/html/notebook/static/js/notebook.js
 @@ -130,9 +130,24 @@ var IPython = (function (IPython) { 130 130  that.select_next(); 131 131  that.control_key_active = false; 132 132  return false; 133 + } else if (event.which === 76 && that.control_key_active) { 134 + // Toggle line numbers = l 135 + that.cell_toggle_line_numbers(); 136 + that.control_key_active = false; 137 + return false; 138 + } else if (event.which === 73 && that.control_key_active) { 139 + // Interrupt kernel = i 140 + IPython.notebook.kernel.interrupt(); 141 + that.control_key_active = false; 142 + return false; 143 + } else if (event.which === 190 && that.control_key_active) { 144 + // Restart kernel = . # matches qt console 145 + IPython.notebook.restart_kernel(); 146 + that.control_key_active = false; 147 + return false; 133 148  } else if (event.which === 72 && that.control_key_active) { 134 149  // Show keyboard shortcuts = h 135 - that.show_keyboard_shortcuts(); 150 + that.toggle_keyboard_shortcuts(); 136 151  that.control_key_active = false; 137 152  return false; 138 153  } else if (that.control_key_active) { @@ -181,15 +196,25 @@ var IPython = (function (IPython) { 181 196  }; 182 197   183 198   184 - Notebook.prototype.show_keyboard_shortcuts = function () { 199 + Notebook.prototype.toggle_keyboard_shortcuts = function () { 200 + // toggles display of keyboard shortcut dialog 201 + var that = this; 202 + if ( this.shortcut_dialog ){ 203 + // if dialog is already shown, close it 204 + this.shortcut_dialog.dialog("close"); 205 + this.shortcut_dialog = null; 206 + return; 207 + } 185 208  var dialog = $(' '); 209 + this.shortcut_dialog = dialog; 186 210  var shortcuts = [ 187 211  {key: 'Shift-Enter', help: 'run cell'}, 188 - {key: 'Ctrl-Enter', help: 'run cell in terminal mode'}, 212 + {key: 'Ctrl-Enter', help: 'run cell in-place'}, 189 213  {key: 'Ctrl-m d', help: 'delete cell'}, 190 214  {key: 'Ctrl-m a', help: 'insert cell above'}, 191 215  {key: 'Ctrl-m b', help: 'insert cell below'}, 192 216  {key: 'Ctrl-m t', help: 'toggle output'}, 217 + {key: 'Ctrl-m l', help: 'toggle line numbers'}, 193 218  {key: 'Ctrl-m s', help: 'save notebook'}, 194 219  {key: 'Ctrl-m j', help: 'move cell down'}, 195 220  {key: 'Ctrl-m k', help: 'move cell up'}, @@ -197,7 +222,9 @@ var IPython = (function (IPython) { 197 222  {key: 'Ctrl-m m', help: 'markdown cell'}, 198 223  {key: 'Ctrl-m p', help: 'select previous'}, 199 224  {key: 'Ctrl-m n', help: 'select next'}, 200 - {key: 'Ctrl-m h', help: 'display keyboard shortcuts'} 225 + {key: 'Ctrl-m i', help: 'interrupt kernel'}, 226 + {key: 'Ctrl-m .', help: 'restart kernel'}, 227 + {key: 'Ctrl-m h', help: 'show keyboard shortcuts'} 201 228  ]; 202 229  for (var i=0; i'). @@ -205,6 +232,10 @@ var IPython = (function (IPython) { 205 232  append($('').addClass('shortcut_descr').html(' : ' + shortcuts[i].help)) 206 233  ); 207 234  }; 235 + dialog.bind('dialogclose', function(event) { 236 + // dialog has been closed, allow it to be drawn again. 237 + that.shortcut_dialog = null; 238 + }); 208 239  dialog.dialog({title: 'Keyboard shortcuts'}); 209 240  }; 210 241   @@ -602,6 +633,11 @@ var IPython = (function (IPython) { 602 633  this.dirty = true; 603 634  }; 604 635   636 + // Other cell functions: line numbers, ... 637 + 638 + Notebook.prototype.cell_toggle_line_numbers = function() { 639 + this.selected_cell().toggle_line_numbers() 640 + }; 605 641   606 642  // Kernel related things 607 643   @@ -613,8 +649,26 @@ var IPython = (function (IPython) { 613 649   614 650   615 651  Notebook.prototype.restart_kernel = function () { 652 + var that = this; 616 653  var notebook_id = IPython.save_widget.get_notebook_id(); 617 - this.kernel.restart($.proxy(this.kernel_started, this)); 654 + 655 + var dialog =$('
'); 656 + dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.'); 657 + $(document).append(dialog); 658 + dialog.dialog({ 659 + resizable: false, 660 + modal: true, 661 + title: "Restart kernel or continue running?", 662 + buttons : { 663 + "Restart": function () { 664 + that.kernel.restart($.proxy(that.kernel_started, that)); 665 + $(this).dialog('close'); 666 + }, 667 + "Continue running": function () { 668 +$(this).dialog('close'); 669 + } 670 + } 671 + }); 618 672  }; 619 673   620 674   @@ -694,11 +748,11 @@ var IPython = (function (IPython) { 694 748  modal: true, 695 749  title: "Dead kernel", 696 750  buttons : { 697 - "Yes": function () { 751 + "Restart": function () { 698 752  that.start_kernel(); 699 753  $(this).dialog('close'); 700 754  }, 701 - "No": function () { 755 + "Continue running": function () { 702 756 $(this).dialog('close'); 703 757  } 704 758  }
1  IPython/frontend/html/notebook/static/js/notebook_main.js
 @@ -32,6 +32,7 @@ $(document).ready(function () { 32 32  IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter'); 33 33  IPython.left_panel = new IPython.LeftPanel('div#left_panel', 'div#left_panel_splitter'); 34 34  IPython.save_widget = new IPython.SaveWidget('span#save_widget'); 35 + IPython.quick_help = new IPython.QuickHelp('span#quick_help_area'); 35 36  IPython.print_widget = new IPython.PrintWidget('span#print_widget'); 36 37  IPython.notebook = new IPython.Notebook('div#notebook'); 37 38  IPython.kernel_status_widget = new IPython.KernelStatusWidget('#kernel_status'); 39  IPython/frontend/html/notebook/static/js/quickhelp.js  ... ... @@ -0,0 +1,39 @@ 1 +//---------------------------------------------------------------------------- 2 +// Copyright (C) 2008-2011 The IPython Development Team 3 +// 4 +// Distributed under the terms of the BSD License. The full license is in 5 +// the file COPYING, distributed as part of this software. 6 +//---------------------------------------------------------------------------- 7 + 8 +//============================================================================ 9 +// QuickHelp button 10 +//============================================================================ 11 + 12 +var IPython = (function (IPython) { 13 + 14 + var QuickHelp = function (selector) { 15 + this.selector = selector; 16 + if (this.selector !== undefined) { 17 + this.element =$(selector); 18 + this.style(); 19 + this.bind_events(); 20 + } 21 + }; 22 + 23 + QuickHelp.prototype.style = function () { 24 + this.element.find('button#quick_help').button(); 25 + }; 26 + 27 + QuickHelp.prototype.bind_events = function () { 28 + var that = this; 29 + this.element.find("button#quick_help").click(function () { 30 + IPython.notebook.toggle_keyboard_shortcuts(); 31 + }); 32 + }; 33 + 34 + // Set module variables 35 + IPython.QuickHelp = QuickHelp; 36 + 37 + return IPython; 38 + 39 +}(IPython));
12  IPython/frontend/html/notebook/templates/notebook.html
 @@ -56,13 +56,16 @@ 56 56   57 57   58 58   59 +  60 +  61 +  59 62  Idle 60 63   61 64   62 65 `

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.