scrollmanager.js
214 lines
| 7.3 KiB
| application/javascript
|
JavascriptLexer
Jonathan Frederic
|
r17864 | // Copyright (c) IPython Development Team. | ||
// Distributed under the terms of the Modified BSD License. | ||||
Jonathan Frederic
|
r17869 | define(['jquery'], function($){ | ||
Jonathan Frederic
|
r17864 | "use strict"; | ||
Jonathan Frederic
|
r17873 | var ScrollManager = function(notebook, options) { | ||
Jonathan Frederic
|
r19176 | /** | ||
* Public constructor. | ||||
*/ | ||||
Jonathan Frederic
|
r17864 | this.notebook = notebook; | ||
Min RK
|
r19733 | this.element = $('body'); | ||
Jonathan Frederic
|
r17895 | options = options || {}; | ||
Jonathan Frederic
|
r17873 | this.animation_speed = options.animation_speed || 250; //ms | ||
Jonathan Frederic
|
r17864 | }; | ||
ScrollManager.prototype.scroll = function (delta) { | ||||
Jonathan Frederic
|
r19176 | /** | ||
* Scroll the document. | ||||
* | ||||
* Parameters | ||||
* ---------- | ||||
* delta: integer | ||||
* direction to scroll the document. Positive is downwards. | ||||
* Unit is one page length. | ||||
*/ | ||||
Jonathan Frederic
|
r17869 | this.scroll_some(delta); | ||
return false; | ||||
}; | ||||
Jonathan Frederic
|
r17873 | ScrollManager.prototype.scroll_to = function(selector) { | ||
Jonathan Frederic
|
r19176 | /** | ||
* Scroll to an element in the notebook. | ||||
*/ | ||||
Min RK
|
r19733 | this.element.animate({'scrollTop': $(selector).offset().top + this.element.scrollTop() - this.element.offset().top}, this.animation_speed); | ||
Jonathan Frederic
|
r17869 | }; | ||
ScrollManager.prototype.scroll_some = function(pages) { | ||||
Jonathan Frederic
|
r19176 | /** | ||
* Scroll up or down a given number of pages. | ||||
* | ||||
* Parameters | ||||
* ---------- | ||||
* pages: integer | ||||
* number of pages to scroll the document, may be positive or negative. | ||||
*/ | ||||
Min RK
|
r19733 | this.element.animate({'scrollTop': this.element.scrollTop() + pages * this.element.height()}, this.animation_speed); | ||
Jonathan Frederic
|
r17869 | }; | ||
ScrollManager.prototype.get_first_visible_cell = function() { | ||||
Jonathan Frederic
|
r19176 | /** | ||
* Gets the index of the first visible cell in the document. | ||||
* | ||||
* First, attempt to be smart by guessing the index of the cell we are | ||||
* scrolled to. Then, walk from there up or down until the right cell | ||||
* is found. To guess the index, get the top of the last cell, and | ||||
* divide that by the number of cells to get an average cell height. | ||||
* Then divide the scroll height by the average cell height. | ||||
*/ | ||||
Jonathan Frederic
|
r17870 | var cell_count = this.notebook.ncells(); | ||
var first_cell_top = this.notebook.get_cell(0).element.offset().top; | ||||
var last_cell_top = this.notebook.get_cell(cell_count-1).element.offset().top; | ||||
Jonathan Frederic
|
r17869 | var avg_cell_height = (last_cell_top - first_cell_top) / cell_count; | ||
Min RK
|
r19733 | var i = Math.ceil(this.element.scrollTop() / avg_cell_height); | ||
Jonathan Frederic
|
r17870 | i = Math.min(Math.max(i , 0), cell_count - 1); | ||
Jonathan Frederic
|
r17869 | |||
Min RK
|
r19733 | while (this.notebook.get_cell(i).element.offset().top - first_cell_top < this.element.scrollTop() && i < cell_count - 1) { | ||
Jonathan Frederic
|
r17869 | i += 1; | ||
} | ||||
Min RK
|
r19733 | while (this.notebook.get_cell(i).element.offset().top - first_cell_top > this.element.scrollTop() - 50 && i >= 0) { | ||
Jonathan Frederic
|
r17869 | i -= 1; | ||
} | ||||
Jonathan Frederic
|
r17870 | return Math.min(i + 1, cell_count - 1); | ||
Jonathan Frederic
|
r17869 | }; | ||
Jonathan Frederic
|
r17873 | var TargetScrollManager = function(notebook, options) { | ||
Jonathan Frederic
|
r19176 | /** | ||
* Public constructor. | ||||
*/ | ||||
Jonathan Frederic
|
r17873 | ScrollManager.apply(this, [notebook, options]); | ||
Jonathan Frederic
|
r17869 | }; | ||
Matthias Bussonnier
|
r18377 | TargetScrollManager.prototype = Object.create(ScrollManager.prototype); | ||
Jonathan Frederic
|
r17869 | |||
Jonathan Frederic
|
r17870 | TargetScrollManager.prototype.is_target = function (index) { | ||
Jonathan Frederic
|
r19176 | /** | ||
* Check if a cell should be a scroll stop. | ||||
* | ||||
* Returns `true` if the cell is a cell that the scroll manager | ||||
* should scroll to. Otherwise, false is returned. | ||||
* | ||||
* Parameters | ||||
* ---------- | ||||
* index: integer | ||||
* index of the cell to test. | ||||
*/ | ||||
Jonathan Frederic
|
r17870 | return false; | ||
Jonathan Frederic
|
r17869 | }; | ||
Jonathan Frederic
|
r17870 | TargetScrollManager.prototype.scroll = function (delta) { | ||
Jonathan Frederic
|
r19176 | /** | ||
* Scroll the document. | ||||
* | ||||
* Parameters | ||||
* ---------- | ||||
* delta: integer | ||||
* direction to scroll the document. Positive is downwards. | ||||
* Units are targets. | ||||
* | ||||
* Try to scroll to the next slide. | ||||
*/ | ||||
Jonathan Frederic
|
r17870 | var cell_count = this.notebook.ncells(); | ||
var selected_index = this.get_first_visible_cell() + delta; | ||||
while (0 <= selected_index && selected_index < cell_count && !this.is_target(selected_index)) { | ||||
selected_index += delta; | ||||
} | ||||
Jonathan Frederic
|
r17864 | |||
Jonathan Frederic
|
r17870 | if (selected_index < 0 || cell_count <= selected_index) { | ||
return ScrollManager.prototype.scroll.apply(this, [delta]); | ||||
Jonathan Frederic
|
r17864 | } else { | ||
Jonathan Frederic
|
r17870 | this.scroll_to(this.notebook.get_cell(selected_index).element); | ||
// Cancel browser keyboard scroll. | ||||
Jonathan Frederic
|
r17867 | return false; | ||
Jonathan Frederic
|
r17870 | } | ||
}; | ||||
Jonathan Frederic
|
r17873 | var SlideScrollManager = function(notebook, options) { | ||
Jonathan Frederic
|
r19176 | /** | ||
* Public constructor. | ||||
*/ | ||||
Jonathan Frederic
|
r17873 | TargetScrollManager.apply(this, [notebook, options]); | ||
Jonathan Frederic
|
r17870 | }; | ||
Matthias Bussonnier
|
r18377 | SlideScrollManager.prototype = Object.create(TargetScrollManager.prototype); | ||
Jonathan Frederic
|
r17870 | |||
SlideScrollManager.prototype.is_target = function (index) { | ||||
var cell = this.notebook.get_cell(index); | ||||
return cell.metadata && cell.metadata.slideshow && | ||||
cell.metadata.slideshow.slide_type && | ||||
Jonathan Frederic
|
r17873 | (cell.metadata.slideshow.slide_type === "slide" || | ||
cell.metadata.slideshow.slide_type === "subslide"); | ||||
Jonathan Frederic
|
r17870 | }; | ||
Jonathan Frederic
|
r17873 | var HeadingScrollManager = function(notebook, options) { | ||
Jonathan Frederic
|
r19176 | /** | ||
* Public constructor. | ||||
*/ | ||||
Jonathan Frederic
|
r17895 | ScrollManager.apply(this, [notebook, options]); | ||
options = options || {}; | ||||
Jonathan Frederic
|
r17873 | this._level = options.heading_level || 1; | ||
Jonathan Frederic
|
r17870 | }; | ||
Min RK
|
r19733 | HeadingScrollManager.prototype = Object.create(ScrollManager.prototype); | ||
Jonathan Frederic
|
r17870 | |||
Jonathan Frederic
|
r17895 | HeadingScrollManager.prototype.scroll = function (delta) { | ||
Jonathan Frederic
|
r19176 | /** | ||
* Scroll the document. | ||||
* | ||||
* Parameters | ||||
* ---------- | ||||
* delta: integer | ||||
* direction to scroll the document. Positive is downwards. | ||||
* Units are headers. | ||||
* | ||||
* Get all of the header elements that match the heading level or are of | ||||
* greater magnitude (a smaller header number). | ||||
*/ | ||||
Jonathan Frederic
|
r17895 | var headers = $(); | ||
var i; | ||||
for (i = 1; i <= this._level; i++) { | ||||
headers = headers.add('#notebook-container h' + i); | ||||
} | ||||
Jonathan Frederic
|
r17870 | |||
Jonathan Frederic
|
r17895 | // Find the header the user is on or below. | ||
var first_cell_top = this.notebook.get_cell(0).element.offset().top; | ||||
Min RK
|
r19733 | var current_scroll = this.element.scrollTop(); | ||
Jonathan Frederic
|
r17895 | var header_scroll = 0; | ||
i = -1; | ||||
while (current_scroll >= header_scroll && i < headers.length) { | ||||
if (++i < headers.length) { | ||||
header_scroll = $(headers[i]).offset().top - first_cell_top; | ||||
} | ||||
} | ||||
i--; | ||||
// Check if the user is below the header. | ||||
if (i < 0 || current_scroll > $(headers[i]).offset().top - first_cell_top + 30) { | ||||
// Below the header, count the header as a target. | ||||
if (delta < 0) { | ||||
delta += 1; | ||||
} | ||||
} | ||||
i += delta; | ||||
// Scroll! | ||||
if (0 <= i && i < headers.length) { | ||||
this.scroll_to(headers[i]); | ||||
return false; | ||||
} else { | ||||
// Default to the base's scroll behavior when target header doesn't | ||||
// exist. | ||||
return ScrollManager.prototype.scroll.apply(this, [delta]); | ||||
} | ||||
}; | ||||
Jonathan Frederic
|
r17864 | |||
// Return naemspace for require.js loads | ||||
Jonathan Frederic
|
r17869 | return { | ||
'ScrollManager': ScrollManager, | ||||
'SlideScrollManager': SlideScrollManager, | ||||
Jonathan Frederic
|
r17870 | 'HeadingScrollManager': HeadingScrollManager, | ||
'TargetScrollManager': TargetScrollManager | ||||
Jonathan Frederic
|
r17869 | }; | ||
Jonathan Frederic
|
r17864 | }); | ||