From ef57f6e272f55619d12addfe2918a3d43d5ef880 2012-06-18 03:36:16 From: Min RK Date: 2012-06-18 03:36:16 Subject: [PATCH] Merge pull request #1825 from minrk/elide2 second attempt at scrolled long output Some amount of CSS tweaking will probably want to be done before 0.13 final, but this is good enough for beta. closes #1553 --- diff --git a/IPython/frontend/html/notebook/static/css/notebook.css b/IPython/frontend/html/notebook/static/css/notebook.css index a9f2862..dc2b0ac 100644 --- a/IPython/frontend/html/notebook/static/css/notebook.css +++ b/IPython/frontend/html/notebook/static/css/notebook.css @@ -104,7 +104,7 @@ div#notebook { width: 100%; /* This spaces the cell away from the edge of the notebook area */ padding: 5px 5px 15px 5px; - margin: 0px + margin: 0px; background-color: white; } @@ -137,6 +137,7 @@ div.cell { div.code_cell { background-color: white; } + /* any special styling for code cells that are currently running goes here */ div.code_cell.running { } @@ -168,13 +169,50 @@ div.input_prompt { border-top: 1px solid transparent; } -div.output { +div.output_wrapper { /* This is a spacer between the input and output of each cell */ margin-top: 5px; + margin-left: 5px; + /* FF needs explicit width to stretch */ + width: 100%; + /* this position must be relative to enable descendents to be absolute within it */ + position: relative; +} + +/* class for the output area when it should be height-limited */ +div.output_scroll { + /* ideally, this would be max-height, but FF barfs all over that */ + height: 24em; + /* FF needs this *and the wrapper* to specify full width, or it will shrinkwrap */ + width: 100%; + + overflow: auto; + border-radius: 3px; + box-shadow: inset 0 2px 8px rgba(0, 0, 0, .8); +} + +/* output div while it is collapsed */ +div.output_collapsed { + margin-right: 5px; +} + +div.out_prompt_overlay { + height: 100%; + padding: 0px; + position: absolute; + border-radius: 3px; +} + +div.out_prompt_overlay:hover { + /* use inner shadow to get border that is computed the same on WebKit/FF */ + box-shadow: inset 0 0 1px #000; + background: rgba(240, 240, 240, 0.5); } div.output_prompt { color: darkred; + /* 5px right shift to account for margin in parent container */ + margin: 0 5px 0 -5px; } /* This class is the outer container of all output sections. */ diff --git a/IPython/frontend/html/notebook/static/js/codecell.js b/IPython/frontend/html/notebook/static/js/codecell.js index 5c5ead2..c4a1884 100644 --- a/IPython/frontend/html/notebook/static/js/codecell.js +++ b/IPython/frontend/html/notebook/static/js/codecell.js @@ -218,6 +218,11 @@ var IPython = (function (IPython) { }; + CodeCell.prototype.toggle_output_scroll = function () { + this.output_area.toggle_scroll(); + }; + + CodeCell.prototype.set_input_prompt = function (number) { this.input_prompt_number = number; var ns = number || " "; diff --git a/IPython/frontend/html/notebook/static/js/menubar.js b/IPython/frontend/html/notebook/static/js/menubar.js index a809cfd..e2e6c61 100644 --- a/IPython/frontend/html/notebook/static/js/menubar.js +++ b/IPython/frontend/html/notebook/static/js/menubar.js @@ -158,6 +158,15 @@ var IPython = (function (IPython) { this.element.find('#toggle_output').click(function () { IPython.notebook.toggle_output(); }); + this.element.find('#collapse_all_output').click(function () { + IPython.notebook.collapse_all_output(); + }); + this.element.find('#scroll_all_output').click(function () { + IPython.notebook.scroll_all_output(); + }); + this.element.find('#expand_all_output').click(function () { + IPython.notebook.expand_all_output(); + }); this.element.find('#clear_all_output').click(function () { IPython.notebook.clear_all_output(); }); diff --git a/IPython/frontend/html/notebook/static/js/notebook.js b/IPython/frontend/html/notebook/static/js/notebook.js index 7c02bf7..2978047 100644 --- a/IPython/frontend/html/notebook/static/js/notebook.js +++ b/IPython/frontend/html/notebook/static/js/notebook.js @@ -194,7 +194,11 @@ var IPython = (function (IPython) { return false; } else if (event.which === 79 && that.control_key_active) { // Toggle output = o - that.toggle_output(); + if (event.shiftKey){ + that.toggle_output_scroll(); + } else { + that.toggle_output(); + } that.control_key_active = false; return false; } else if (event.which === 83 && that.control_key_active) { @@ -883,6 +887,53 @@ var IPython = (function (IPython) { }; + Notebook.prototype.toggle_output_scroll = function (index) { + var i = this.index_or_selected(index); + this.get_cell(i).toggle_output_scroll(); + }; + + + Notebook.prototype.collapse_all_output = function () { + var ncells = this.ncells(); + var cells = this.get_cells(); + for (var i=0; i"); + this.collapse_button = $("
"); + this.prompt_overlay = $("
"); + this.wrapper.append(this.prompt_overlay); + this.wrapper.append(this.element); + this.wrapper.append(this.collapse_button); }; OutputArea.prototype.style = function () { + this.collapse_button.hide(); + this.prompt_overlay.hide(); + + this.wrapper.addClass('output_wrapper'); this.element.addClass('output vbox'); + + this.collapse_button.button(); + this.collapse_button.addClass('output_collapsed vbox'); + this.collapse_button.attr('title', 'click to expand outout'); + this.collapse_button.html('. . .'); + + this.prompt_overlay.addClass('out_prompt_overlay prompt'); + this.prompt_overlay.attr('title', 'click to expand outout; double click to hide output'); + this.collapse(); }; + OutputArea.prototype._should_scroll = function (lines) { + if (!lines) { + lines = 50; + } + // line-height from http://stackoverflow.com/questions/1185151 + var fontSize = this.element.css('font-size'); + var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5); + + return (this.element.height() > lines * lineHeight); + }; + + + OutputArea.prototype.bind_events = function () { + var that = this; + this.prompt_overlay.dblclick(function () { that.toggle_output(); }); + this.prompt_overlay.click(function () { that.toggle_scroll(); }); + + this.element.resize(function () { + // maybe scroll output, + // if it's grown large enough and hasn't already been scrolled. + if ( !that.scrolled && that._should_scroll()) { + that.scroll_area(); + } + }); + this.collapse_button.click(function () { + that.expand(); + }); + this.collapse_button.hover(function () { + $(this).addClass("ui-state-hover"); + }, function () { + $(this).removeClass("ui-state-hover"); + }); + }; + + OutputArea.prototype.collapse = function () { if (!this.collapsed) { this.element.hide(); + this.prompt_overlay.hide(); + if (this.element.html()){ + this.collapse_button.show(); + } this.collapsed = true; }; }; @@ -45,7 +109,9 @@ var IPython = (function (IPython) { OutputArea.prototype.expand = function () { if (this.collapsed) { + this.collapse_button.hide(); this.element.show(); + this.prompt_overlay.show(); this.collapsed = false; }; }; @@ -60,6 +126,38 @@ var IPython = (function (IPython) { }; + OutputArea.prototype.scroll_area = function () { + this.element.addClass('output_scroll'); + this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide'); + this.scrolled = true; + }; + + + OutputArea.prototype.unscroll_area = function () { + this.element.removeClass('output_scroll'); + this.prompt_overlay.attr('title', 'click to scroll output; double click to hide'); + this.scrolled = false; + }; + + + OutputArea.prototype.scroll_if_long = function (lines) { + if (this._should_scroll(lines)) { + // only allow scrolling long-enough output + this.scroll_area(); + }; + }; + + + OutputArea.prototype.toggle_scroll = function () { + if (this.scrolled) { + this.unscroll_area(); + } else { + // only allow scrolling long-enough output + this.scroll_if_long(20); + }; + }; + + // typeset with MathJax if MathJax is available OutputArea.prototype.typeset = function () { if (window.MathJax){ @@ -132,6 +230,8 @@ var IPython = (function (IPython) { this.append_stream(json); }; this.outputs.push(json); + var that = this; + setTimeout(function(){that.element.trigger('resize');}, 100); }; @@ -346,6 +446,7 @@ var IPython = (function (IPython) { // clear all, no need for logic output_div.html(""); this.outputs = []; + this.unscroll_area(); return; } // remove html output @@ -360,7 +461,8 @@ var IPython = (function (IPython) { if (other) { output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove(); } - + this.unscroll_area(); + // remove cleared outputs from JSON list: for (var i = this.outputs.length - 1; i >= 0; i--) { var out = this.outputs[i]; diff --git a/IPython/frontend/html/notebook/static/js/quickhelp.js b/IPython/frontend/html/notebook/static/js/quickhelp.js index 3376883..d609e70 100644 --- a/IPython/frontend/html/notebook/static/js/quickhelp.js +++ b/IPython/frontend/html/notebook/static/js/quickhelp.js @@ -35,6 +35,7 @@ var IPython = (function (IPython) { {key: 'Ctrl-m a', help: 'insert cell above'}, {key: 'Ctrl-m b', help: 'insert cell below'}, {key: 'Ctrl-m o', help: 'toggle output'}, + {key: 'Ctrl-m O', help: 'toggle output scroll'}, {key: 'Ctrl-m l', help: 'toggle line numbers'}, {key: 'Ctrl-m s', help: 'save notebook'}, {key: 'Ctrl-m j', help: 'move cell down'}, diff --git a/IPython/frontend/html/notebook/templates/notebook.html b/IPython/frontend/html/notebook/templates/notebook.html index 64da27c..26eb12f 100644 --- a/IPython/frontend/html/notebook/templates/notebook.html +++ b/IPython/frontend/html/notebook/templates/notebook.html @@ -117,8 +117,15 @@ data-notebook-id={{notebook_id}}
  • Heading 5
  • Heading 6

  • -
  • Toggle Output
  • -
  • Clear All Output
  • +
  • Toggle Current Output
  • +
  • All Output + +
  • Kernel