##// END OF EJS Templates
Merge pull request #5844 from jdfreder/scrollmanager...
Matthias Bussonnier -
r17935:f3f0886e merge
parent child Browse files
Show More
@@ -0,0 +1,193 b''
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
3 define(['jquery'], function($){
4 "use strict";
5
6 var ScrollManager = function(notebook, options) {
7 // Public constructor.
8 this.notebook = notebook;
9 options = options || {};
10 this.animation_speed = options.animation_speed || 250; //ms
11 };
12
13 ScrollManager.prototype.scroll = function (delta) {
14 // Scroll the document.
15 //
16 // Parameters
17 // ----------
18 // delta: integer
19 // direction to scroll the document. Positive is downwards.
20 // Unit is one page length.
21 this.scroll_some(delta);
22 return false;
23 };
24
25 ScrollManager.prototype.scroll_to = function(selector) {
26 // Scroll to an element in the notebook.
27 $('#notebook').animate({'scrollTop': $(selector).offset().top + $('#notebook').scrollTop() - $('#notebook').offset().top}, this.animation_speed);
28 };
29
30 ScrollManager.prototype.scroll_some = function(pages) {
31 // Scroll up or down a given number of pages.
32 //
33 // Parameters
34 // ----------
35 // pages: integer
36 // number of pages to scroll the document, may be positive or negative.
37 $('#notebook').animate({'scrollTop': $('#notebook').scrollTop() + pages * $('#notebook').height()}, this.animation_speed);
38 };
39
40 ScrollManager.prototype.get_first_visible_cell = function() {
41 // Gets the index of the first visible cell in the document.
42
43 // First, attempt to be smart by guessing the index of the cell we are
44 // scrolled to. Then, walk from there up or down until the right cell
45 // is found. To guess the index, get the top of the last cell, and
46 // divide that by the number of cells to get an average cell height.
47 // Then divide the scroll height by the average cell height.
48 var cell_count = this.notebook.ncells();
49 var first_cell_top = this.notebook.get_cell(0).element.offset().top;
50 var last_cell_top = this.notebook.get_cell(cell_count-1).element.offset().top;
51 var avg_cell_height = (last_cell_top - first_cell_top) / cell_count;
52 var notebook = $('#notebook');
53 var i = Math.ceil(notebook.scrollTop() / avg_cell_height);
54 i = Math.min(Math.max(i , 0), cell_count - 1);
55
56 while (this.notebook.get_cell(i).element.offset().top - first_cell_top < notebook.scrollTop() && i < cell_count - 1) {
57 i += 1;
58 }
59
60 while (this.notebook.get_cell(i).element.offset().top - first_cell_top > notebook.scrollTop() - 50 && i >= 0) {
61 i -= 1;
62 }
63 return Math.min(i + 1, cell_count - 1);
64 };
65
66
67 var TargetScrollManager = function(notebook, options) {
68 // Public constructor.
69 ScrollManager.apply(this, [notebook, options]);
70 };
71 TargetScrollManager.prototype = new ScrollManager();
72
73 TargetScrollManager.prototype.is_target = function (index) {
74 // Check if a cell should be a scroll stop.
75 //
76 // Returns `true` if the cell is a cell that the scroll manager
77 // should scroll to. Otherwise, false is returned.
78 //
79 // Parameters
80 // ----------
81 // index: integer
82 // index of the cell to test.
83 return false;
84 };
85
86 TargetScrollManager.prototype.scroll = function (delta) {
87 // Scroll the document.
88 //
89 // Parameters
90 // ----------
91 // delta: integer
92 // direction to scroll the document. Positive is downwards.
93 // Units are targets.
94
95 // Try to scroll to the next slide.
96 var cell_count = this.notebook.ncells();
97 var selected_index = this.get_first_visible_cell() + delta;
98 while (0 <= selected_index && selected_index < cell_count && !this.is_target(selected_index)) {
99 selected_index += delta;
100 }
101
102 if (selected_index < 0 || cell_count <= selected_index) {
103 return ScrollManager.prototype.scroll.apply(this, [delta]);
104 } else {
105 this.scroll_to(this.notebook.get_cell(selected_index).element);
106
107 // Cancel browser keyboard scroll.
108 return false;
109 }
110 };
111
112
113 var SlideScrollManager = function(notebook, options) {
114 // Public constructor.
115 TargetScrollManager.apply(this, [notebook, options]);
116 };
117 SlideScrollManager.prototype = new TargetScrollManager();
118
119 SlideScrollManager.prototype.is_target = function (index) {
120 var cell = this.notebook.get_cell(index);
121 return cell.metadata && cell.metadata.slideshow &&
122 cell.metadata.slideshow.slide_type &&
123 (cell.metadata.slideshow.slide_type === "slide" ||
124 cell.metadata.slideshow.slide_type === "subslide");
125 };
126
127
128 var HeadingScrollManager = function(notebook, options) {
129 // Public constructor.
130 ScrollManager.apply(this, [notebook, options]);
131 options = options || {};
132 this._level = options.heading_level || 1;
133 };
134 HeadingScrollManager.prototype = new ScrollManager();
135
136 HeadingScrollManager.prototype.scroll = function (delta) {
137 // Scroll the document.
138 //
139 // Parameters
140 // ----------
141 // delta: integer
142 // direction to scroll the document. Positive is downwards.
143 // Units are headers.
144
145 // Get all of the header elements that match the heading level or are of
146 // greater magnitude (a smaller header number).
147 var headers = $();
148 var i;
149 for (i = 1; i <= this._level; i++) {
150 headers = headers.add('#notebook-container h' + i);
151 }
152
153 // Find the header the user is on or below.
154 var first_cell_top = this.notebook.get_cell(0).element.offset().top;
155 var notebook = $('#notebook');
156 var current_scroll = notebook.scrollTop();
157 var header_scroll = 0;
158 i = -1;
159 while (current_scroll >= header_scroll && i < headers.length) {
160 if (++i < headers.length) {
161 header_scroll = $(headers[i]).offset().top - first_cell_top;
162 }
163 }
164 i--;
165
166 // Check if the user is below the header.
167 if (i < 0 || current_scroll > $(headers[i]).offset().top - first_cell_top + 30) {
168 // Below the header, count the header as a target.
169 if (delta < 0) {
170 delta += 1;
171 }
172 }
173 i += delta;
174
175 // Scroll!
176 if (0 <= i && i < headers.length) {
177 this.scroll_to(headers[i]);
178 return false;
179 } else {
180 // Default to the base's scroll behavior when target header doesn't
181 // exist.
182 return ScrollManager.prototype.scroll.apply(this, [delta]);
183 }
184 };
185
186 // Return naemspace for require.js loads
187 return {
188 'ScrollManager': ScrollManager,
189 'SlideScrollManager': SlideScrollManager,
190 'HeadingScrollManager': HeadingScrollManager,
191 'TargetScrollManager': TargetScrollManager
192 };
193 });
@@ -0,0 +1,1 b''
1 * A ScrollManager was added to the notebook. The ScrollManager controls how the notebook document is scrolled using keyboard. Users can inherit from the ScrollManager or TargetScrollManager to customize how their notebook scrolls. The default ScrollManager is the SlideScrollManager, which tries to scroll to the nearest slide or sub-slide cell.
@@ -183,6 +183,18 b' define(['
183 183 KeyboardManager.prototype.get_default_command_shortcuts = function() {
184 184 var that = this;
185 185 return {
186 'space': {
187 help: "Scroll down",
188 handler: function(event) {
189 return that.notebook.scroll_manager.scroll(1);
190 },
191 },
192 'shift-space': {
193 help: "Scroll up",
194 handler: function(event) {
195 return that.notebook.scroll_manager.scroll(-1);
196 },
197 },
186 198 'enter' : {
187 199 help : 'edit mode',
188 200 help_index : 'aa',
@@ -148,7 +148,6 b' define(['
148 148 );
149 149 };
150 150
151
152 151 MainToolBar.prototype.add_celltoolbar_list = function () {
153 152 var label = $('<span/>').addClass("navbar-text").text('Cell Toolbar:');
154 153 var select = $('<select/>')
@@ -186,7 +185,6 b' define(['
186 185 });
187 186 };
188 187
189
190 188 MainToolBar.prototype.bind_events = function () {
191 189 var that = this;
192 190
@@ -18,6 +18,7 b' define(['
18 18 'notebook/js/celltoolbarpresets/default',
19 19 'notebook/js/celltoolbarpresets/rawcell',
20 20 'notebook/js/celltoolbarpresets/slideshow',
21 'notebook/js/scrollmanager'
21 22 ], function (
22 23 IPython,
23 24 $,
@@ -34,7 +35,8 b' define(['
34 35 tooltip,
35 36 default_celltoolbar,
36 37 rawcell_celltoolbar,
37 slideshow_celltoolbar
38 slideshow_celltoolbar,
39 scrollmanager
38 40 ) {
39 41
40 42 var Notebook = function (selector, options) {
@@ -64,6 +66,10 b' define(['
64 66 this.ws_url = options.ws_url;
65 67 this._session_starting = false;
66 68 this.default_cell_type = this.config.default_cell_type || 'code';
69
70 // Create default scroll manager.
71 this.scroll_manager = new scrollmanager.ScrollManager(this);
72
67 73 // default_kernel_name is a temporary measure while we implement proper
68 74 // kernel selection and delayed start. Do not rely on it.
69 75 this.default_kernel_name = 'python';
@@ -135,7 +141,7 b' define(['
135 141 rawcell_celltoolbar.register(this);
136 142 slideshow_celltoolbar.register(this);
137 143 };
138
144
139 145 Notebook.options_default = {
140 146 // can be any cell type, or the special values of
141 147 // 'above', 'below', or 'selected' to get the value from another cell.
@@ -1620,7 +1626,7 b' define(['
1620 1626 this._session_starting = false;
1621 1627 utils.log_ajax_error(jqxhr, status, error);
1622 1628 };
1623
1629
1624 1630 /**
1625 1631 * Prompt the user to restart the IPython kernel.
1626 1632 *
General Comments 0
You need to be logged in to leave comments. Login now