Commit 83b4c91b authored by Sebastian's avatar Sebastian

Update: README and add many comments to the source code

parent 0689d482
# Notes
# Concept:
It is required to overwrite NotebookApp.contents_manager_class to avoid a
* Inject rsvp, renderJS and jIO into the default jupyter page (after it is rendered) and manually bootstrap renderJS. Entrypoint is jiocontents.js which is loaded by jupyter as part of the nbextension
* This injection is done with the mother-gadget gadget_jupyter_page which has the subgadget gadget_jiocontents responsible for handling the API calls which come from jupyter to the jiocontentsmanager
## Exmaple of API call processing:
1. User presses "Create New Notebook Button" and fills in the form
2. Jupyter internally calls the contents API which is rerouted to this javascript nbextension "jiocontents"
3. The function `Contents.prototype.new_untitled` is called
4. We wait for the waitForReadyPromise resolve (resolves once renderJS injection is complete) or reject after a timeout of 3s
5. A custom event is dispatched to the gadget_jiocontents gadget which has access to JIO containing the information jupyter provides (here only the path of the directory from which the new notebook was created).
Additionally we supply handles to the resolve / reject functions of the wrapping promise so gadget_jiocontents can resolve the wrapping promise after the information was exchanged with JIO
6. In gadget_jiocontents we create an empty notebook json and jio.post it to ERP5
7. If this JIO action succeedes, we resolve the wrapping promise with the notebook json which is then further processed internally by jupyter
All jupyter-actions are processed in this way. We create a wrapping promise and pass the work on to gadget_jiocontents, which communicates via JIO and resolves/rejects
this promise based on the communication with the ERP5.
# Important Notes
* It is required to overwrite NotebookApp.contents_manager_class to avoid a
immediate redirect to 404 page upon notebook-loading. Currently this is done
inline in jupyter_notebook_config.py, but should better be moved to a seperate
python file and imported in the config. However, I was unable to get the include
paths right with slapos.
A lot of weirdness comes with loading notebooks into the page. de-stringyfied
* A lot of weirdness comes with loading notebooks into the page. de-stringyfied
JSONs must be further processed because of unlined-strings. See
https://github.com/jupyter/jupyter-drive/blob/master/jupyterdrive/gdrive/notebook_model.js#L45
https://github.com/jupyter/jupyter-drive/pull/124
\ No newline at end of file
/*global window, rJS, jIO, FormData */
/*jslint indent: 2, maxerr: 3 */
(function (window, rJS) {
"use strict";
/*
Next two functions deal with a weird issue of unlin-ed strings, ie. list
of strings instead a single joined string. Adpoted from
https://github.com/jupyter/jupyter-drive/blob/master/jupyterdrive/gdrive/notebook_model.js#L45
with adjustment to match updates in jupyter's data model.
*/
function createBlankNotebook(kernel_type) {
return {
"cells": [
{ "cell_type": "code",
"execution_count": null,
"metadata": { "collapsed": true },
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
}
},
"nbformat": 4,
"nbformat_minor": 2
};
}
/**
* Next two functions deal with a weird issue of unlin-ed strings, ie. list
* of strings instead a single joined string. Adpoted from
* https://github.com/jupyter/jupyter-drive/blob/master/jupyterdrive/gdrive/notebook_model.js#L45
* with adjustment to match updates in jupyter's data model.
*/
function unsplit_lines(multiline_string) {
if (Array.isArray(multiline_string)) {
return multiline_string.join('');
......@@ -40,8 +63,8 @@
});
}
// Convert what we get from ERP5 to the internal jupyter representation
function toNotebookModel(id, obj, isRootDir) {
//console.log(obj.value.text_content);
var cont = null;
var title = obj.title;
if(isRootDir) {
......@@ -65,10 +88,13 @@
return nbobj;
}
/*
/**
*
*
* Event handlers API <-> JIO connection points
*
*
*/
function handleGet(e) {
......@@ -79,7 +105,7 @@
query: 'portal_type: "Web JSON"',
select_list : ["text_content", "title", "reference", "creation_date", "modification_date"],
sort_on: [["modification_date", "descending"]],
limit: [0, 20]
limit: [0, 200]
})
.push(function(result) {
var nbs = [];
......@@ -134,7 +160,7 @@
portal_type: "Web JSON",
parent_relative_url: "web_page_module",
title: "untitled_notebook",
reference: "ut_nb_from_" + now.getTime(),
reference: "ut_nb_from_" + now.getTime(), // this is an arbitrary choice and should be unique
text_content: JSON.stringify(createBlankNotebook())
};
var gadget = this;
......@@ -172,10 +198,12 @@
});
}
/*
/**
*
* RJS Stuffs
*
* RJS Functions
*
*
*/
rJS(window)
......@@ -196,28 +224,6 @@
document.jiocontentsReady = true;
return this;
});
function createBlankNotebook(kernel_type) {
return {
"cells": [
{ "cell_type": "code",
"execution_count": null,
"metadata": { "collapsed": true },
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
}
},
"nbformat": 4,
"nbformat_minor": 2
};
}
}(window, rJS));
/*global window, rJS, RSVP, Handlebars, URI */
/*jslint nomen: true, indent: 2, maxerr: 3 */
/**
*
*
* This is an adaption of the erp5_launcher_nojqm.js in which all UI components
* are removed and a custom hateoas URL calculation based on the instance-parameter
* configuration is added.
*
* Currently it is hardcoded that web_site_module/renderjs_runner is used
* for the hateoas URL. This should be changed and configurable.
*
*
*
*/
(function (window, rJS, RSVP) {
"use strict";
var gadget_klass = rJS(window);
// SNIP
function callJioGadget(gadget, method, param_list) {
var called = false;
......@@ -65,12 +79,15 @@
setting[key] = value;
}
// Original:
// Calculate erp5 hateoas url
//setting.hateoas_url = (new URI(gadget.props.hateoas_url))
// .absoluteTo(location.href)
// .toString();
// Read erp5 URL
/**
* Set the hateoas URL! XXX Remove the hardcoded hateoas suffix XXX
*/
setting.hateoas_url = _erp5_hateoas_url + "web_site_module/renderjs_runner/hateoas/";
if (setting.hasOwnProperty('service_worker_url') &&
......
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*
/**
* For reference see https://github.com/ipython/ipython/wiki/IPEP-27%3A-Contents-Service
*/
......@@ -11,16 +11,27 @@ define(function(require) {
var $ = require('jquery');
var utils = require('base/js/utils');
/**
*
*
* Setup for RenderJS
*
*
*/
var baseUrl = "/nbextensions/jiocontents/";
var gadget_main_div = document.createElement("div");
gadget_main_div.setAttribute("data-gadget-url", baseUrl + "src/gadget_jupyter_page.html");
gadget_main_div.setAttribute("class", "gadget-jupyter-page-container");
document.body.append(gadget_main_div);
// create and append the div element which contains the bootstrap renderjs gadget
var gadgetMainDiv = document.createElement("div");
gadgetMainDiv.setAttribute("data-gadget-url", baseUrl + "src/gadget_jupyter_page.html");
gadgetMainDiv.setAttribute("class", "gadget-jupyter-page-container");
document.body.append(gadgetMainDiv);
// this flag is needed to have an indicator to when all scripts are (asych)
// injected and all gadgets ready. This flag is set to true in render
// function of gadget_jiocontents.js
document.jiocontentsReady = false;
// inject the scripts into the default jupyter page
var s1 = document.createElement("script"); s1.type = "text/javascript";
s1.onload = function() {
console.log("loaded rsvp");
......@@ -32,6 +43,8 @@ define(function(require) {
console.log("loaded erp5 config");
rJS.manualBootstrap();
};
// this file comes from the slapos build system and is defined via
// an instance parameter
s3.src = baseUrl + "jiocontents_erp5_config.js";
document.head.append(s3);
};
......@@ -41,10 +54,9 @@ define(function(require) {
s1.src = baseUrl + "src/rsvp.js";
document.head.append(s1);
/*
.then on this method to be sure the rjs-setup was completed and
.onEvent are available to receive events
*/
// .then on this method to be sure the rjs-setup was completed and
// all the ".onEvent" are available to receive events
function waitForReadyPromise() {
if(document.jiocontentsReady) {
return Promise.resolve(); // rjs-setup is already complete
......@@ -53,58 +65,31 @@ define(function(require) {
var timerId = window.setInterval(function() {
if(document.jiocontentsReady) {
resolve();
clearInterval(timerId);
clearInterval(timerId); // clear the timeout reject timer
}
}, 100); // Check every 100ms to see if rjs-setup is complete and eventlistener available
}, 100); // Check every 100ms to see if rjs-setup is complete
window.setTimeout(function() {
if(!document.jiocontentsReady) {
reject();
}
}, 3000) // Reject after 3sec
}, 3000) // timeout reject after 3sec
});
}
function getJiocontentsDiv() {
return document.querySelector(".jiocontents_gadget");
}
var Contents = function(options) {
this.base_url = options.base_url;
};
/** Error type */
Contents.DIRECTORY_NOT_EMPTY_ERROR = 'DirectoryNotEmptyError';
Contents.DirectoryNotEmptyError = function() {
this.message = 'A directory must be empty before being deleted.';
};
Contents.DirectoryNotEmptyError.prototype =
Object.create(Error.prototype);
Contents.DirectoryNotEmptyError.prototype.name =
Contents.DIRECTORY_NOT_EMPTY_ERROR;
Contents.prototype.api_url = function() {
var url_parts = [
this.base_url, 'api/contents',
utils.url_join_encode.apply(null, arguments),
];
return utils.url_path_join.apply(null, url_parts);
};
Contents.prototype.create_basic_error_handler = function(callback) {
if (!callback) {
return utils.log_ajax_error;
}
return function(xhr, status, error) {
callback(utils.wrap_ajax_error(xhr, status, error));
};
};
/**
* File Functions (including notebook operations)
*
*
* Implementation of contents API functions
*
*
*/
// Is called when a notebook should be displayed, either in the list of notebooks
// or the notebook itself
Contents.prototype.get = function (path, options) {
return waitForReadyPromise()
.then(function() {
......@@ -141,6 +126,7 @@ define(function(require) {
});
};
// Currently the jIO Erp5 Storage does not support delete
Contents.prototype.delete = function(path) {
return Promise.reject("Delete is currently not supported!");
};
......@@ -152,7 +138,7 @@ define(function(require) {
var ev = new CustomEvent("rename_event", {
detail: {
path: path,
// get rid of path-prefix web_page_module. Not used in titles!
// get rid of path-prefix "web_page_module". Not used in titles!
new_title: new_path.split("/")[1],
resolve: resolve,
reject: reject
......@@ -180,14 +166,13 @@ define(function(require) {
});
};
// TODO: implement copy
Contents.prototype.copy = function(from_file, to_dir) {
return Promise.reject("Copy is currently not supported!");
};
/**
* Checkpointing Functions
*/
// Checkpoints are not used in this implementation of the contents API
// Instead only the save-action is executed
Contents.prototype.create_checkpoint = function(path) {
return Promise.resolve({
id: "dummy-id",
......@@ -207,10 +192,8 @@ define(function(require) {
return Promise.resolve();
};
/**
* File management functions
*/
// Get a list of all notebooks in the given diretory. In this implementation
// we do not support directories other than "" which menas root
Contents.prototype.list_contents = function(path) {
return this.get(path, {type: 'directory'});
};
......
  • Hi guys are you looking for a website where you can download the latest video for Raksha Bandhan video status download this is the best website because they daily post new video for their visitors

Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment