Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Notebook usability fixes #884

Merged
merged 16 commits into from

3 participants

Fernando Perez Min RK Brian E. Granger
Fernando Perez
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)
  • add missing keybindings
  • change language from 'terminal mode' to 'in-place execution' which is more descriptive
  • adjust spacing/padding and colors slightly for readability and better use of space in small screens.
  • add line numbering toggle to code cells. Triggered with C-m-l.
  • show keybindings in monospaced font.
Min RK
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.

Fernando Perez
Owner

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

Fernando Perez
Owner

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

Fernando Perez
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 {
color: black;
border: 1px solid #ddd;
border-radius: 3px;
- background: #fafafa;
+ background: #f4f4f4;
Min RK Owner
minrk added a note

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.

Fernando Perez Owner
fperez added a note

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<R=G), but wasn't quite happy with any of the results.

Brian E. Granger Owner
Fernando Perez Owner
fperez added a note

@ellisonbg, can you try with the chrome debug console or firebug (or just by saving and reloading the css) intermediate grays between fa and f4? Perhaps we can move a few notches darker so on linux/chrome it's readable (it really isn't right now) without looking too dark on osx.

Another option would be to darken the outline around every cell a little. That currently is ddd but perhaps we could make it darker. It would higlight each cell a little more without messing with the editing area.

Min RK Owner
minrk added a note

On my linux machines as well, I think it's much too dark, and I even find f9f9f9 to be darker than ideal. I think the outline is the more significant thing for delineating the code area.

If we darken the border, it can't be much darker, as it should definitely be lighter than the cell border which is only #a8, so #bbb is as dark as it could reasonably go, and I probably wouldn't go lower than #ccc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Min RK
Owner

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

Fernando Perez
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.

Fernando Perez
Owner

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

Fernando Perez
Owner

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

Fernando Perez
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...

minrk and others added some commits
Min RK minrk fix quickhelp widget
Move header.js -> quickhelp.js, as it not longer acts on whole header.
feffa59
Min RK 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
Fernando Perez fperez Underline quick help button key accelerator (h). b80a26b
Fernando Perez fperez Adjust title area sizes to improve alignment. 89110cb
Fernando Perez fperez merged commit 4cc4dc8 into from
Fernando Perez
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!

Fernando Perez fperez referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 17, 2011
  1. Fernando Perez
  2. Fernando Perez

    Padding adjustments to better use vertical and horizontal whitespace.

    fperez authored
    Verified that all prompts align correctly on linux/chrome + ffox, and
    that input prompts up to 4 digits long still fit.
  3. Fernando Perez
  4. Fernando Perez
  5. Fernando Perez

    Refactor line num. toggle into proper function, access via C-m-l.

    fperez authored
    This makes the keybinding consistent with the rest, updated help dialog.
  6. Fernando Perez
  7. Fernando Perez
  8. Fernando Perez

    Add quick help button: broken ATM, style and binding aren't working.

    fperez authored
    Help needed here, will discuss during pull request before merging.
  9. Fernando Perez
  10. Fernando Perez
  11. Fernando Perez
  12. Fernando Perez
  13. Min RK

    fix quickhelp widget

    minrk authored
    Move header.js -> quickhelp.js, as it not longer acts on whole header.
  14. Min RK

    show_keyboard_shortcuts -> toggle_keyboard_shortcuts

    minrk authored
    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.
  15. Fernando Perez
  16. Fernando Perez
This page is out of date. Refresh to see the latest.
2  IPython/frontend/html/notebook/static/codemirror/theme/ipython.css
View
@@ -1,7 +1,7 @@
.cm-s-ipython span.cm-keyword {color: #008000; font-weight: bold;}
-.cm-s-ipython span.cm-number {color: #666666;}
+.cm-s-ipython span.cm-number {color: #0A32C8;}
.cm-s-ipython span.cm-operator {color: #AA22FF; font-weight: bold;}
.cm-s-ipython span.cm-meta {color: #AA22FF;}
.cm-s-ipython span.cm-comment {color: #408080; font-style: italic;}
4 IPython/frontend/html/notebook/static/css/base.css
View
@@ -22,7 +22,7 @@ div#header {
/* Initially hidden to prevent FLOUC */
display: none;
position: relative;
- height: 45px;
+ height: 40px;
padding: 5px;
margin: 0px;
width: 100%;
@@ -35,7 +35,7 @@ span#ipython_notebook {
span#ipython_notebook h1 {
font-family: Verdana, "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
- font-size: 197%;
+ font-size: 150%;
display: inline;
color: black;
}
25 IPython/frontend/html/notebook/static/css/notebook.css
View
@@ -1,4 +1,3 @@
-
/**
* Primary styles
*
@@ -19,12 +18,18 @@ body {
}
span#save_widget {
- position: absolute;
+ position: static;
left: 0px;
padding: 5px 0px;
margin: 0px 0px 0px 0px;
}
+span#quick_help_area {
+ position: static;
+ padding: 5px 0px;
+ margin: 0px 0px 0px 0px;
+}
+
input#notebook_name {
height: 1em;
line-height: 1em;
@@ -35,9 +40,10 @@ span#kernel_status {
position: absolute;
padding: 8px 5px 5px 5px;
right: 10px;
- font-weight: bold;
+ font-weight: bold;
}
+
.status_idle {
color: gray;
}
@@ -156,7 +162,7 @@ div#notebook {
overflow-x: auto;
width: 100%;
/* This spaces the cell away from the edge of the notebook area */
- padding: 15px 15px 15px 15px;
+ padding: 5px 5px 15px 5px;
margin: 0px
background-color: white;
}
@@ -172,9 +178,9 @@ div#pager {
div.cell {
width: 100%;
- padding: 5px;
+ padding: 5px 5px 5px 0px;
/* This acts as a spacer between cells, that is outside the border */
- margin: 5px 0px 5px 0px;
+ margin: 2px 0px 2px 0px;
}
div.code_cell {
@@ -200,7 +206,7 @@ div.input_area {
color: black;
border: 1px solid #ddd;
border-radius: 3px;
- background: #fafafa;
+ background: #f7f7f7;
}
div.input_prompt {
@@ -330,9 +336,10 @@ div.text_cell_render {
.shortcut_key {
display: inline-block;
- width: 10ex;
+ width: 13ex;
text-align: right;
+ font-family: monospace;
}
.shortcut_descr {
-}
+}
31 IPython/frontend/html/notebook/static/js/codecell.js
View
@@ -48,9 +48,10 @@ var IPython = (function (IPython) {
CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
- // This method gets called in CodeMirror's onKeyDown/onKeyPress handlers and
- // is used to provide custom key handling. Its return value is used to determine
- // if CodeMirror should ignore the event: true = ignore, false = don't ignore.
+ // This method gets called in CodeMirror's onKeyDown/onKeyPress
+ // handlers and is used to provide custom key handling. Its return
+ // value is used to determine if CodeMirror should ignore the event:
+ // true = ignore, false = don't ignore.
if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
// Always ignore shift-enter in CodeMirror as we handle it.
return true;
@@ -59,8 +60,8 @@ var IPython = (function (IPython) {
var cur = editor.getCursor();
var pre_cursor = editor.getRange({line:cur.line,ch:0},cur).trim();
if (pre_cursor === "") {
- // Don't autocomplete if the part of the line before the cursor is empty.
- // In this case, let CodeMirror handle indentation.
+ // Don't autocomplete if the part of the line before the cursor
+ // is empty. In this case, let CodeMirror handle indentation.
return false;
} else {
// Autocomplete the current line.
@@ -86,9 +87,14 @@ var IPython = (function (IPython) {
} else {
return false;
};
- } else {
- // keypress/keyup also trigger on TAB press, and we don't want to use those
- // to disable tab completion.
+ } else if (event.keyCode === 76 && event.ctrlKey && event.shiftKey
+ && event.type == 'keydown') {
+ // toggle line numbers with Ctrl-Shift-L
+ this.toggle_line_numbers();
+ }
+ else {
+ // keypress/keyup also trigger on TAB press, and we don't want to
+ // use those to disable tab completion.
if (this.is_completing && event.keyCode !== 9) {
var ed_cur = editor.getCursor();
var cc_cur = this.completion_cursor;
@@ -177,6 +183,14 @@ var IPython = (function (IPython) {
select.focus();
};
+ CodeCell.prototype.toggle_line_numbers = function () {
+ if (this.code_mirror.getOption('lineNumbers') == false) {
+ this.code_mirror.setOption('lineNumbers', true);
+ } else {
+ this.code_mirror.setOption('lineNumbers', false);
+ }
+ this.code_mirror.refresh()
+ };
CodeCell.prototype.select = function () {
IPython.Cell.prototype.select.apply(this);
@@ -470,4 +484,3 @@ var IPython = (function (IPython) {
return IPython;
}(IPython));
-
68 IPython/frontend/html/notebook/static/js/notebook.js
View
@@ -130,9 +130,24 @@ var IPython = (function (IPython) {
that.select_next();
that.control_key_active = false;
return false;
+ } else if (event.which === 76 && that.control_key_active) {
+ // Toggle line numbers = l
+ that.cell_toggle_line_numbers();
+ that.control_key_active = false;
+ return false;
+ } else if (event.which === 73 && that.control_key_active) {
+ // Interrupt kernel = i
+ IPython.notebook.kernel.interrupt();
+ that.control_key_active = false;
+ return false;
+ } else if (event.which === 190 && that.control_key_active) {
+ // Restart kernel = . # matches qt console
+ IPython.notebook.restart_kernel();
+ that.control_key_active = false;
+ return false;
} else if (event.which === 72 && that.control_key_active) {
// Show keyboard shortcuts = h
- that.show_keyboard_shortcuts();
+ that.toggle_keyboard_shortcuts();
that.control_key_active = false;
return false;
} else if (that.control_key_active) {
@@ -181,15 +196,25 @@ var IPython = (function (IPython) {
};
- Notebook.prototype.show_keyboard_shortcuts = function () {
+ Notebook.prototype.toggle_keyboard_shortcuts = function () {
+ // toggles display of keyboard shortcut dialog
+ var that = this;
+ if ( this.shortcut_dialog ){
+ // if dialog is already shown, close it
+ this.shortcut_dialog.dialog("close");
+ this.shortcut_dialog = null;
+ return;
+ }
var dialog = $('<div/>');
+ this.shortcut_dialog = dialog;
var shortcuts = [
{key: 'Shift-Enter', help: 'run cell'},
- {key: 'Ctrl-Enter', help: 'run cell in terminal mode'},
+ {key: 'Ctrl-Enter', help: 'run cell in-place'},
{key: 'Ctrl-m d', help: 'delete cell'},
{key: 'Ctrl-m a', help: 'insert cell above'},
{key: 'Ctrl-m b', help: 'insert cell below'},
{key: 'Ctrl-m t', help: 'toggle output'},
+ {key: 'Ctrl-m l', help: 'toggle line numbers'},
{key: 'Ctrl-m s', help: 'save notebook'},
{key: 'Ctrl-m j', help: 'move cell down'},
{key: 'Ctrl-m k', help: 'move cell up'},
@@ -197,7 +222,9 @@ var IPython = (function (IPython) {
{key: 'Ctrl-m m', help: 'markdown cell'},
{key: 'Ctrl-m p', help: 'select previous'},
{key: 'Ctrl-m n', help: 'select next'},
- {key: 'Ctrl-m h', help: 'display keyboard shortcuts'}
+ {key: 'Ctrl-m i', help: 'interrupt kernel'},
+ {key: 'Ctrl-m .', help: 'restart kernel'},
+ {key: 'Ctrl-m h', help: 'show keyboard shortcuts'}
];
for (var i=0; i<shortcuts.length; i++) {
dialog.append($('<div>').
@@ -205,6 +232,10 @@ var IPython = (function (IPython) {
append($('<span/>').addClass('shortcut_descr').html(' : ' + shortcuts[i].help))
);
};
+ dialog.bind('dialogclose', function(event) {
+ // dialog has been closed, allow it to be drawn again.
+ that.shortcut_dialog = null;
+ });
dialog.dialog({title: 'Keyboard shortcuts'});
};
@@ -602,6 +633,11 @@ var IPython = (function (IPython) {
this.dirty = true;
};
+ // Other cell functions: line numbers, ...
+
+ Notebook.prototype.cell_toggle_line_numbers = function() {
+ this.selected_cell().toggle_line_numbers()
+ };
// Kernel related things
@@ -613,8 +649,26 @@ var IPython = (function (IPython) {
Notebook.prototype.restart_kernel = function () {
+ var that = this;
var notebook_id = IPython.save_widget.get_notebook_id();
- this.kernel.restart($.proxy(this.kernel_started, this));
+
+ var dialog = $('<div/>');
+ dialog.html('Do you want to restart the current kernel? You will lose all variables defined in it.');
+ $(document).append(dialog);
+ dialog.dialog({
+ resizable: false,
+ modal: true,
+ title: "Restart kernel or continue running?",
+ buttons : {
+ "Restart": function () {
+ that.kernel.restart($.proxy(that.kernel_started, that));
+ $(this).dialog('close');
+ },
+ "Continue running": function () {
+ $(this).dialog('close');
+ }
+ }
+ });
};
@@ -694,11 +748,11 @@ var IPython = (function (IPython) {
modal: true,
title: "Dead kernel",
buttons : {
- "Yes": function () {
+ "Restart": function () {
that.start_kernel();
$(this).dialog('close');
},
- "No": function () {
+ "Continue running": function () {
$(this).dialog('close');
}
}
1  IPython/frontend/html/notebook/static/js/notebook_main.js
View
@@ -32,6 +32,7 @@ $(document).ready(function () {
IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter');
IPython.left_panel = new IPython.LeftPanel('div#left_panel', 'div#left_panel_splitter');
IPython.save_widget = new IPython.SaveWidget('span#save_widget');
+ IPython.quick_help = new IPython.QuickHelp('span#quick_help_area');
IPython.print_widget = new IPython.PrintWidget('span#print_widget');
IPython.notebook = new IPython.Notebook('div#notebook');
IPython.kernel_status_widget = new IPython.KernelStatusWidget('#kernel_status');
39 IPython/frontend/html/notebook/static/js/quickhelp.js
View
@@ -0,0 +1,39 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2008-2011 The IPython Development Team
+//
+// Distributed under the terms of the BSD License. The full license is in
+// the file COPYING, distributed as part of this software.
+//----------------------------------------------------------------------------
+
+//============================================================================
+// QuickHelp button
+//============================================================================
+
+var IPython = (function (IPython) {
+
+ var QuickHelp = function (selector) {
+ this.selector = selector;
+ if (this.selector !== undefined) {
+ this.element = $(selector);
+ this.style();
+ this.bind_events();
+ }
+ };
+
+ QuickHelp.prototype.style = function () {
+ this.element.find('button#quick_help').button();
+ };
+
+ QuickHelp.prototype.bind_events = function () {
+ var that = this;
+ this.element.find("button#quick_help").click(function () {
+ IPython.notebook.toggle_keyboard_shortcuts();
+ });
+ };
+
+ // Set module variables
+ IPython.QuickHelp = QuickHelp;
+
+ return IPython;
+
+}(IPython));
12 IPython/frontend/html/notebook/templates/notebook.html
View
@@ -56,13 +56,16 @@
<span id="notebook_id" style="display:none">{{notebook_id}}</span>
<button id="save_notebook"><u>S</u>ave</button>
</span>
+ <span id="quick_help_area">
+ <button id="quick_help">Quick<u>H</u>elp</button>
+ </span>
<span id="kernel_status">Idle</span>
</div>
<div id="MathJaxFetchingWarning"
style="width:80%; margin:auto;padding-top:20%;text-align: justify; display:none">
<p style="font-size:26px;">There was an issue trying to fetch MathJax.js
- from the internet.</p>
+ from the internet.</p>
<p style="padding:0.2em"> With a working internet connection, you can run
the following at a Python or IPython prompt, which will install a local
@@ -176,7 +179,7 @@ <h3 class="section_header">Kernel</h3>
<div class="section_content">
<div class="section_row">
<span id="int_restart" class="section_row_buttons">
- <button id="int_kernel">Interrupt</button>
+ <button id="int_kernel"><u>I</u>nterrupt</button>
<button id="restart_kernel">Restart</button>
</span>
<span class="section_row_header">Actions</span>
@@ -217,7 +220,7 @@ <h3 class="section_header">Help</h3>
<span class="help_string_label">Shift-Enter :</span>
</div>
<div class="section_row">
- <span class="help_string">run in terminal mode</span>
+ <span class="help_string">run selected cell in-place</span>
<span class="help_string_label">Ctrl-Enter :</span>
</div>
<div class="section_row">
@@ -263,6 +266,7 @@ <h3 class="section_header">Help</h3>
<script src="static/js/kernelstatus.js" type="text/javascript" charset="utf-8"></script>
<script src="static/js/layout.js" type="text/javascript" charset="utf-8"></script>
<script src="static/js/savewidget.js" type="text/javascript" charset="utf-8"></script>
+<script src="static/js/quickhelp.js" type="text/javascript" charset="utf-8"></script>
<script src="static/js/pager.js" type="text/javascript" charset="utf-8"></script>
<script src="static/js/panelsection.js" type="text/javascript" charset="utf-8"></script>
<script src="static/js/printwidget.js" type="text/javascript" charset="utf-8"></script>
@@ -274,5 +278,3 @@ <h3 class="section_header">Help</h3>
</body>
</html>
-
-
Something went wrong with that request. Please try again.