-
Notifications
You must be signed in to change notification settings - Fork 5
Development Notes
-
Abstract all of the storage code out of the notebook classes
-
Check out how IPython handles this.
-
Consolidate storage code on the back-end so that creating a new storage implementation is as easy as extending the
DataStoreclass
-
-
With storage code abstracted out of the notebook classes, store all worksheet metadata in a database.
-
Use sockets in place of AJAX
-
Implement the ability to embed cells from a published worksheet in a web page much the same way that YouTube allows videos to be embedded in other sites.
-
Drag-and-drop uploading of worksheets
-
Include option for soft/real tabs and tab size
-
Don't enable webassets minification when in development mode
-
Support back and forward button in single cell mode
- Use http://benalman.com/projects/jquery-hashchange-plugin/ and set button event handlers to just change the hash
-
Add some better styling to
?and??introspections- See cell.less
-
flask_server/ - backend stuff
-
admin.py - routes for the user and general management pages of the notebook
-
authentication.py - routes for login, logout, user registration, and forgotten password handling
-
base.py - home to the
SageNBFlaskclass -
decorators.py - contains route decorators, which enforce security on notebook and worksheet routes
-
doc.py - routes for the notebook documentation
-
settings.py - the user settings route
-
worksheet.py - contains all of the routes for the worksheet commands
-
worksheet_listing.py - contains routes for worksheet listing commands
-
-
sagenb/
-
data/ - all of the html/css/js goes here
-
sage/ - all of the sage data
-
html/ - html templates
-
accounts/ - templates for account recovery and registration
-
alerts/ - html alert snippets which are included in other pages
-
modals/ - html modal snippets which are included in other pages
-
settings/ - templates for user and notebook settings
-
base.html - base template for all pages
-
docs.html - template for the help page
-
error_message.html - template for error pages
-
history.html - template for worksheet history
-
jmol_popup.html - template for Jmol popups
-
login.html - template for the login page
-
worksheet.html - the worksheet page
-
worksheet_edit.html - the worksheet edit page
-
worksheet_list.html - the worksheet list page
-
worksheet_text.html - the worksheet text page
-
-
js/
-
cell.js - contains the
sagenb.worksheetapp.cellfunction -
jmol.js - functions which handle jmol creation and use
-
load_mathjax.js - a script which dynamically loads the MathJax library either from the CDN or from the notebook.
-
localization.js - contains the
gettextjavascript function -
misc.js - contains helper functions including
encode_responseanddecode_response -
sagenb.js - contains the
sagenbjavascript object used as a sort of namespace as well as essential functions used throughout the notebook includingsagenb.init,sagenb.async_request, andsagenb.generic_callback -
settings.js - javascript for the user management page
-
username.js - a simple script template which sets the
sagenb.usernamevariable -
worksheet.js - contains the
sagenb.worksheetapp.worksheetfunction for theworksheet.htmlpage -
worksheet_list.js - contains the
sagenb.worksheetlistapp.list_rowandsagenb.worksheetlistapp.worksheet_listfunctions for theworksheet_list.htmlpage
-
-
less/ - stylesheets; if you are interested in adjusting the design of the notebook, start here
-
cell.less - stylesheet for cells
-
dialogs.less - stylesheet for various dialogs/modals
-
jmol.less - stylesheet for Jmol inline instances and popups
-
main.less - stylesheet for the base template
-
print.less - stylesheet for printing
-
settings.less - stylesheet for the settings pages
-
worksheet.less - stylesheet for the worksheet page
-
worksheet_list.less - stylesheet for the worksheet_list page
-
-
webassets_generated/ - minified/combined files generated by webassets are outputted here
-
-
-
notebook/ - main pieces of the actual notebook back-end
-
The frontend of the Sage Notebook is built on Twitter's Bootstrap framework, MathJax, LESS, TinyMCE, and CodeMirror.
Content is loaded dynamically -- no more sending HTML back-and-forth in AJAX requests/responses. All communication is done with JSON using the async_request, encode_response and decode_response functions. All of the worksheet commands and worksheet list content is handled this way. By keeping data on the wire, browsers can cache static pages, there is a cleaner distinction between the front- and back-ends of the application, and other non-HTML front-end implementations are possible (mobile?).
Bootstrap is just a bunch of CSS and javascript which makes just about anything on the web look good. You can find everything there is to know on Bootstrap here: http://twitter.github.com/bootstrap/.
CSS preprocessing is very similar to CSS and significantly speeds up development. The choice between LESS and SASS/SCSS is tough. The Notebook is written in LESS for the time being primarily because the Bootstrap framework is built on LESS. I would certainly not be offended, however, if someone was interested in rewriting the stylesheet in SASS/SCSS.
All of the JavaScript was re-designed and re-written from scratch. Whereas the old notebook (notebook_lib.js) kept everything in the global scope, the newest version takes an object-oriented approach. Where the old notebook may implement cells with code like this
function get_cell_input(cell_id) { /* ... */ }
function get_cell_output(cell_id) { /* ... */ }
function render_cell(cell_id, container) {
get_cell_input(cell_id)
get_cell_output(cell_id)
// ...
}
the new notebook implements cells like this
var sagenb = { worksheetapp: {} };
sagenb.worksheetapp.cell = function(id) {
// provide an unchanging reference to this cell
var _this = this;
_this.id = id;
_this.input = "";
_this.output = "";
_this.render = function(container) {
_this.id;
_this.input;
_this.output;
// etc...
};
};
var c = new sagenb.worksheetapp.cell(/* ... */);
c.render(/* ... */);
Besides avoiding pollution of the global scope, this approach gives us all of the sanity that comes with object-oriented programming.
JavaScript of course does not provide us built-in support for classes or methods in the same way that traditional object-oriented programming languages like Java and C++ do. However, through some functional programming magic we can achieve the same thing. Because functions are Objects in JavaScript and calling a function with the new keyword returns an instance of that Object, we can use functions as pseudo classes. Methods are simulated by attaching functions to the object as properties. In the example above, the render function shares the scope of the cell, which gives it access to all of the cells properties. Because the this keyword in JavaScript is a little tricky, we create a variable called _this which refers to the outermost Object.
All of the JavaScript for cells is contained in data/sage/js/cell.js. Each cell has a unique id. Both text and evaluate cells are handled with the same object. Important functions include
-
update- makes a request for the properties of this cell (specified by id) and updates all of the cells properties accordingly. Optionally, a container can be given for the cell to be rendered into once all of the properties are fetch. Ifauto_evaluateis true and this cell has the %auto percent directive,evaluatewill be called. -
render- builds the DOM structure for this cell and inserts it into the given container. This will initialize the CodeMirror or TinyMCE instance for evaluate and text cells, respectively and setup event handlers. If you are interested in adjusting the settings of these text editors look in this function. -
render_output- renders the given string into the output of the cell. If the cell detects and interact here, it will carefully start or update the interact. If the cell detects mathematical expressions and typesetting is on, it will call on MathJax to render the output. -
send_input- sends the current cell input to the notebook server to be saved (not evaluated) -
evaluate- evaluates the current input and callscheck_for_outputon the request callback -
check_for_output- sets up an interval which automatically checks for new output. Once new output is received, the output property of the cell is updated and rendered to the DOM. In addition and because introspection is evaluated in the same way, thecheck_for_outputfunction also checks for introspect output and handles it properly by either presenting a dropdown selection of completions, filling a completion, or showing a docstring popover. -
introspect- Attempts to begin an introspection. First, it splits the input according to the cursor position. Then it matches the text before the cursor to some regex expression to check which type of introspection we are doing. Once it determines the type of introspection, it stores some properties in theintrospect_statevariable. If there is nothing to introspect, it returns false. Otherwise, it executes the introspection and returns true. Handling of the introspection result is done in thecheck_for_outputfunction.
All of the JavaScript for cells is contained in data/sage/js/cell.js. Each worksheet has a unique id. Important properties include
-
cells- a JavaScript Object which maps cell id's to the cell instances. -
worksheet_command- formats a request url and updates the state number of the worksheet -
worksheet_update- requests all of the properties of the worksheet (not including the list of cells) and updates all of the user interface appropriately. -
cell_list_update- requests all of the cells in this worksheet, instantiates them, puts them in thecellsObject, and renders them to the DOM. -
init- the most important function.initcalls onworksheet_updateandcell_list_update, sets up all of the user interface event handlers, and begins an interval that checks when the worksheet and all of its cells are done loading. Once fully loaded, calls onon_load_done, which scrolls to a specific cell if the URL contains something like #cell_5 and enters single-cell mode if the URL contains #single_cell.
The JavaScript worksheet lists is contained in data/sage/js/worksheet_list.js, which contains sagenb.worksheetlistapp.list_row and sagenb.worksheetlistapp.worksheet_list. sagenb.worksheetlistapp.list_row is fairly straightforward. Important properties of sagenb.worksheetlistapp.worksheet_list include
-
rows- a JavaScript Object which maps worksheet filenames to their corresponding rows. -
init- sets up user interface event handlers -
load- requests a listing of worksheets from the notebook server, instantiates list_row's, and renders them to the DOM -
show_...- functions which call onloadto filter worksheets -
do_search- gets the search query and calls onloadto perform the search