Commit ff372f17 authored by Roque's avatar Roque

erp5_notebook: JSMD viewer refactoring

- sub gadget eval is now a full RJS gadget
- it is created in iframe scope
- this fixes Firefox 401 bug to access local data within the notebook iframe
parent c510cfd6
...@@ -11,8 +11,10 @@ ...@@ -11,8 +11,10 @@
<link rel="stylesheet" type="text/css" href="gadget_jsmd_eval.css" /> <link rel="stylesheet" type="text/css" href="gadget_jsmd_eval.css" />
<script src="rsvp.js" type="text/javascript"></script> <script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<script src="marked.js" type="text/javascript"></script> <script src="marked.js" type="text/javascript"></script>
<script src="iodide_utils.js" type="text/javascript"></script> <script src="iodide_utils.js" type="text/javascript"></script>
<script src="gadget_global.js" type="text/javascript"></script>
<script src="gadget_jsmd_eval.js" type="text/javascript"></script> <script src="gadget_jsmd_eval.js" type="text/javascript"></script>
</head> </head>
......
/*global window, console, RSVP, document, URL, eval, XMLHttpRequest, marked, WebAssembly, loadSharedlib */ /*global window, document, rJS, RSVP, XMLHttpRequest, WebAssembly, loadSharedlib, marked, console */
/*jslint nomen: true, indent: 2, maxerr: 3 */ /*jslint nomen: true, indent: 2, maxerr: 3 */
(function (window) { (function (window, document, rJS, RSVP, XMLHttpRequest, WebAssembly, loadSharedlib, marked, console) {
"use strict"; "use strict";
var IODide = function createIODide() { var IODide = function createIODide() {
...@@ -532,31 +532,31 @@ ...@@ -532,31 +532,31 @@
}; };
} }
rJS(window)
.declareMethod("render", function (options) {
return this.changeState(options);
})
.onStateChange(function (options) {
var gadget = this,
jsmd = options.jsmd_code,
cell_list = parseJSMDCellList(jsmd),
len = cell_list.length,
i,
queue = new RSVP.Queue();
for (i = 0; i < len; i += 1) {
queue.push(deferCellExecution(cell_list[i]));
}
return queue
.push(function () {
console.info('JSMD executed.');
}, function (error) {
console.error(error);
var pre = document.createElement('pre');
pre.textContent = error;
document.body.appendChild(pre);
});
});
document.addEventListener('DOMContentLoaded', function () { }(window, document, rJS, RSVP, XMLHttpRequest, WebAssembly, loadSharedlib, marked, console));
\ No newline at end of file
var jsmd = document.querySelector('[type="text/x-jsmd"]').textContent,
cell_list = parseJSMDCellList(jsmd),
len = cell_list.length,
i,
queue = new RSVP.Queue();
for (i = 0; i < len; i += 1) {
queue.push(deferCellExecution(cell_list[i]));
}
return queue
.push(function () {
console.info('JSMD executed.');
}, function (error) {
console.error(error);
var pre = document.createElement('pre');
pre.textContent = error;
document.body.appendChild(pre);
})
.push(function () {
window.parent.postMessage("jsmd_eval_done", window.origin);
});
}, false);
}(window));
\ No newline at end of file
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
</head> </head>
<body> <body>
<div></div> <div data-gadget-url="gadget_jsmd_eval.html"
data-gadget-scope="jsmd_eval"
data-gadget-sandbox="iframe">
</div>
</body> </body>
</html> </html>
/*global window, rJS, console, RSVP, jIO, DOMParser, Blob, document, /*global window, rJS, RSVP, document, loopEventListener, console */
URL, loopEventListener */ /*jslint nomen: true, indent: 2, maxerr: 30 */
/*jslint nomen: true, indent: 2, maxerr: 3 */ (function (window, rJS, RSVP, document, loopEventListener, console) {
(function (window, rJS, RSVP, jIO, DOMParser, document, URL,
loopEventListener) {
"use strict"; "use strict";
function fetchHTML(url, base_url) {
url = new URL(url, base_url).href;
return new RSVP.Queue()
.push(function () {
return jIO.util.ajax({url: url});
})
.push(function (evt) {
// Insert a "base" element, in order to resolve all relative links
// which could get broken with a data url
var doc = (new DOMParser()).parseFromString(evt.target.responseText,
'text/html'),
base = doc.createElement('base');
base.href = url;
doc.head.insertBefore(base, doc.head.firstChild);
return doc;
});
}
rJS(window) rJS(window)
.ready(function (gadget) { .ready(function (gadget) {
gadget.property_dict = {}; gadget.property_dict = {};
}) })
/////////////////////////////////////////////////////////////////
// declared methods
/////////////////////////////////////////////////////////////////
.declareMethod("render", function (options) { .declareMethod("render", function (options) {
return this.changeState(options); return this.changeState(options);
}) })
.onStateChange(function () { .onStateChange(function () {
// Reset everything if something change var gadget = this;
var gadget = this,
base_url = document.location.toString(),
doc;
gadget.property_dict.deferred = RSVP.defer(); gadget.property_dict.deferred = RSVP.defer();
return fetchHTML("gadget_jsmd_eval.html", base_url) return gadget.getDeclaredGadget('jsmd_eval')
.push(function (result) { .push(function (eval_gadget) {
doc = result; var loading_spinner = document.createElement("div");
// Insert text
doc.body.textContent = '';
// Insert the JSMD value inside the HTML
var script = document.createElement('script'),
iframe = document.createElement("iframe"),
loading_spinner = document.createElement("div");
script.setAttribute('type', 'text/x-jsmd');
script.setAttribute('id', 'jsmd-source');
script.textContent = gadget.state.value;
doc.head.appendChild(script);
loading_spinner.setAttribute('id', 'js-spinner'); loading_spinner.setAttribute('id', 'js-spinner');
loading_spinner.classList.add("nb-ui-icon-spinner"); loading_spinner.classList.add("nb-ui-icon-spinner");
loading_spinner.classList.add("nb-ui-btn-icon-notext"); loading_spinner.classList.add("nb-ui-btn-icon-notext");
loading_spinner.classList.add("nb-loader"); loading_spinner.classList.add("nb-loader");
loading_spinner.innerHTML = "Loading notebook..."; loading_spinner.innerHTML = "Loading notebook...";
/*
blob = new Blob([doc.documentElement.outerHTML],
{type: "text/html;charset=UTF-8"});
return jIO.util.readBlobAsDataURL(blob);
})
.push(function (evt) {
*/
// XXX Insecure
iframe.setAttribute("sandbox", "allow-scripts allow-same-origin");
// iframe.setAttribute("csp", "default-src *; script-src * 'unsafe-inline';");
// iframe.setAttribute("src", evt.target.result);
iframe.setAttribute('id', 'jsmd_eval_notebook');
iframe.setAttribute('name', 'jsmd_eval_notebook');
iframe.setAttribute("srcdoc", doc.documentElement.outerHTML);
gadget.element.innerHTML = iframe.outerHTML;
gadget.element.prepend(loading_spinner); gadget.element.prepend(loading_spinner);
return eval_gadget.render({'jsmd_code' : gadget.state.value});
})
.push(function () {
gadget.listenResize(); gadget.listenResize();
gadget.listenMessage(); console.log("JSMD Eval Done.");
document.querySelector('[id="js-spinner"]').remove();
return gadget.property_dict.deferred.resolve();
}); });
}) })
...@@ -102,20 +51,6 @@ ...@@ -102,20 +51,6 @@
}); });
}) })
.declareJob('listenMessage', function () {
var gadget = this,
dict = gadget.property_dict;
return loopEventListener(window, 'message', false, function (event) {
//only handle jsmd eval child messages
if ((event.origin !== window.origin) || (event.data !== "jsmd_eval_done"))
return;
console.log("JSMD Eval Done.");
document.querySelector('[id="js-spinner"]').remove();
return dict.deferred.resolve();
}
);
})
.declareJob('listenResize', function () { .declareJob('listenResize', function () {
var gadget = this; var gadget = this;
function resize() { function resize() {
...@@ -127,4 +62,4 @@ ...@@ -127,4 +62,4 @@
return loopEventListener(window, 'resize', false, resize); return loopEventListener(window, 'resize', false, resize);
}); });
}(window, rJS, RSVP, jIO, DOMParser, document, URL, loopEventListener)); }(window, rJS, RSVP, document, loopEventListener, console));
\ No newline at end of file \ No newline at end of file
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