Commit 45d87016 authored by Cédric Le Ninivin's avatar Cédric Le Ninivin

Applications: Add the possibility to deploy apps on another CribJS

* By default Apps are now deployed to a Crib with a different domain
* App JSON has been updated to have necessary parameters for this
* App list redirect to url list, editor, and export pages with the
crib_enable parameter of the applications to have these pages work
 with the crib of the application
* URL List, Editor and Export pages set crib enable url when the
parameter is provided
parent ed667023
...@@ -36,3 +36,24 @@ iframe { ...@@ -36,3 +36,24 @@ iframe {
0% { transform: rotate(0deg); } 0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); } 100% { transform: rotate(360deg); }
} }
details {
border: 1px solid #aaa;
border-radius: 4px;
padding: .5em .5em 0;
}
summary {
font-weight: bold;
margin: -.5em -.5em 0;
padding: .5em;
}
details[open] {
padding: .5em;
}
details[open] summary {
border-bottom: 1px solid #aaa;
margin-bottom: .5em;
}
\ No newline at end of file
...@@ -30,12 +30,12 @@ ...@@ -30,12 +30,12 @@
</label> </label>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>Application Path: <label>Application ID:
<input name="load-zip-to-path" <input name="load-zip-to-subdomain"
class="load-zip-to-path form-control" type="text" class="load-zip-to-subdomain form-control" type="text"
size="30" value="" pattern="[a-zA-Z0-9]+" size="30" value="" pattern="[a-zA-Z0-9]+"
title="Alphanumeric Characters" required title="Alphanumeric Characters" required
placeholder="my-app-path/"> placeholder="myappid">
</label> </label>
</div> </div>
<div class="form-group"> <div class="form-group">
...@@ -45,25 +45,50 @@ ...@@ -45,25 +45,50 @@
<input name="load-zip-url" class="load-zip-url form-control" type="text" size="60" <input name="load-zip-url" class="load-zip-url form-control" type="text" size="60"
value="apps/hello-world-template.zip"></label> value="apps/hello-world-template.zip"></label>
</div> </div>
<details>
<summary>Advanced Parameters</summary>
<div class="form-group"> <div class="form-group">
<label> Path in Zip: <label> Path in Zip:
<input name="load-zip-path" <input name="load-zip-path"
class="load-from-zip-path form-control" type="text" class="load-from-zip-path form-control" type="text"
size="50" value="" size="50" value=""
placeholder="Use if index.html is not at the root of the zip. e.g.: cribjs-editor-master/" placeholder="Use if you want to only select part of the Zip"
title="Use if index.html is not at the root of the zip. e.g.: cribjs-editor-master/"> title="Use if you want to only select part of the Zip">
</label> </label>
</div> </div>
<div class="form-group"> <div class="form-group">
<label> And redirect to: <label> Defaut home page for the App:
<input name="redirect-url" class="redirect-url form-control" <input name="redirect-url" class="redirect-url form-control"
type="text" size="30" value="index.html" type="text" size="30" value="index.html"
title="Will be used as home page"> title="Will be used as home page">
</label> </label>
</div> </div>
<div class="form-group">
<label>Crib URL to Deploy to:
<input name="load-zip-to-crib-url"
class="load-zip-to-crib-url form-control" type="text"
size="55" value=""
placeholder="https://${myappid}.cribjs.nexedi.net/crib-enable.html">
</label>
</div>
<div class="form-group">
<label>Path to Deploy to:
<input name="load-zip-to-path"
class="load-zip-to-path form-control" type="text"
size="30" value="" pattern="[a-zA-Z0-9]+"
title="Alphanumeric Characters"
placeholder="myapppath">
</label>
</div>
</details>
<div class="form-group"> <div class="form-group">
<button name="load-zip-contents" class="load-zip-contents btn btn-primary" type="submit">Import Application</button> <button name="load-zip-contents" class="load-zip-contents btn btn-primary" type="submit">Import Application</button>
</div> </div>
<div class="crib_enable_validator" style="display:none;">
<div data-gadget-url="./crib_enable_validator.html"
data-gadget-scope="crib_enable_validator"
data-gadget-sandbox="public"></div>
</div>
</form> </form>
</div> </div>
......
...@@ -4,19 +4,8 @@ ...@@ -4,19 +4,8 @@
(function (window, rJS, jIO) { (function (window, rJS, jIO) {
"use strict"; "use strict";
var DEFAULT_APP_LIST_DOC = "app-list.json", var DEFAULT_APP_LIST_DOC = "app-list.json",
SAMPLE_APP_LIST_DOC = "sample-app-list.json"; SAMPLE_APP_LIST_DOC = "sample-app-list.json",
BASE_CRIB_WILDCARD = ".cribjs.nexedi.net/crib-enable.html";
function getParameterDict() {
var hash = window.location.hash.substring(1),
params = {};
/*
hash.split('&').map(hk => {
let temp = hk.split('=');
params[temp[0]] = temp[1];
});
*/
return params;
}
function log(gadget, str, klass) { function log(gadget, str, klass) {
var p = document.createElement('p'), var p = document.createElement('p'),
...@@ -78,12 +67,66 @@ ...@@ -78,12 +67,66 @@
}); });
} }
/*
* This function validate the Crib URL to use, set it if correct and return
* the scope.
*/
function validateAndSetCribEnableGadget(gadget, crib_url, logAddApp) {
return RSVP.Queue()
.push(function () {
logAddApp(gadget, "Testing Crib URL: " + crib_url);
gadget.props.element.querySelector(".crib_enable_validator")
.style = "display:none;";
return gadget.getDeclaredGadget("crib_enable_validator");
})
.push(function (validator_gadget) {
return validator_gadget.validateCribEnableGadgetUrl(crib_url);
})
.push(function (result) {
if (!result) {
gadget.props.element.querySelector(".crib_enable_validator")
.style = "";
logAddApp(gadget, "Could not Validate CribJS Gadget URL: " +
crib_url);
throw "Could not Validate CribJS Gadget URL: " + crib_url;
}
logAddApp(gadget, "Validated Crib URL: " + crib_url);
return gadget.crib_sw_setCribEnableGadgetUrl(crib_url);
})
.push(function () {
return gadget.crib_sw_getScope();
});
}
/*
* This is the Core Function that will "install" the Application
*/
function loadCribJSFromZip(gadget, event) { function loadCribJSFromZip(gadget, event) {
var app_list = [], var app_list = [],
to_path = gadget.props
.element.querySelector("form.crib-load-from-zip .load-zip-to-path").value + "/", // Define the list of elements for the app
redirect_to = to_path + options = {
gadget.props.element.querySelector("form.crib-load-from-zip .redirect-url").value; name: gadget.props.element.querySelector(".app-name").value,
subdomain: gadget.props.element
.querySelector(".load-zip-to-subdomain").value,
from_path: gadget.props.element
.querySelector("form.crib-load-from-zip .load-from-zip-path").value,
redirect_url: gadget.props.element
.querySelector("form.crib-load-from-zip .redirect-url").value,
crib_url: gadget.props.element
.querySelector("form.crib-load-from-zip .load-zip-to-crib-url").value,
to_path: gadget.props.element
.querySelector("form.crib-load-from-zip .load-zip-to-path").value
};
// If no Crib URL is provided construct one from the App ID
if (!options.crib_url) {
options.crib_url = "https://" + options.subdomain + BASE_CRIB_WILDCARD;
}
// If no Zip is provided no need to continue
if (gadget.props.element if (gadget.props.element
.querySelector("form.crib-load-from-zip .load-zip-file").files.length === 0 && .querySelector("form.crib-load-from-zip .load-zip-file").files.length === 0 &&
gadget.props.element gadget.props.element
...@@ -91,8 +134,20 @@ ...@@ -91,8 +134,20 @@
logAddApp(gadget, "Please set a Zip File or Zip Url"); logAddApp(gadget, "Please set a Zip File or Zip Url");
return; return;
} }
// Start the process to add the application
return RSVP.Queue() return RSVP.Queue()
.push(function () { .push(function () {
// Check the Crib Enable Gadget and return the Scope
return validateAndSetCribEnableGadget(gadget, options.crib_url, logAddApp);
})
.push(function (scope) {
/*
* Effectively push the App in browser
*/
options.to_path = options.to_path ? options.to_path + "/" : options.to_path;
options.default_page = options.to_path + options.redirect_url;
options.redirect_to = scope + options.default_page;
var promise_list = []; var promise_list = [];
if (gadget.props.element if (gadget.props.element
.querySelector("form.crib-load-from-zip .load-zip-file").files.length !== 0) { .querySelector("form.crib-load-from-zip .load-zip-file").files.length !== 0) {
...@@ -106,6 +161,9 @@ ...@@ -106,6 +161,9 @@
return RSVP.all(promise_list); return RSVP.all(promise_list);
}) })
.push(function (result_list) { .push(function (result_list) {
/*
* The app has been pushed, we add it to the app list
*/
app_list = result_list[1]; app_list = result_list[1];
app_list.splice( app_list.splice(
0, 0, { 0, 0, {
...@@ -113,19 +171,26 @@ ...@@ -113,19 +171,26 @@
application_image_type: undefined, application_image_type: undefined,
application_image_url: undefined, application_image_url: undefined,
application_description: undefined, application_description: undefined,
application_url: redirect_to, application_url: options.redirect_to,
application_path: to_path, application_path: options.to_path,
application_edit_page: redirect_to, application_edit_page: options.redirect_to,
application_title: gadget.props.element.querySelector(".app-name").value, application_crib: options.crib_url,
application_title: options.name,
application_category: undefined application_category: undefined
} }
); );
logAddApp(gadget, "Adding App to App list"); logAddApp(gadget, "Adding App to App list");
return putNewAppList(gadget, app_list); return RSVP.all([
putNewAppList(gadget, app_list),
gadget.setSetting("editor-pattern", options.to_path)
]);
}) })
.push(function () { .push(function () {
logAddApp(gadget, "Redirecting to Editor"); logAddApp(gadget, "Redirecting to Editor");
return gadget.redirect({page: "editor", url: redirect_to}); return gadget.redirect({page: "editor", url: options.default_page});
})
.push(undefined, function (error) {
logAddApp(gadget, error);
}); });
} }
...@@ -192,14 +257,21 @@ ...@@ -192,14 +257,21 @@
////////////////////////////////////////////// //////////////////////////////////////////////
.declareAcquiredMethod("redirect", "redirect") .declareAcquiredMethod("redirect", "redirect")
.declareAcquiredMethod("crib_sw_get", "crib_sw_get") .declareAcquiredMethod("crib_sw_get", "crib_sw_get")
.declareAcquiredMethod("crib_sw_getScope", "crib_sw_getScope")
.declareAcquiredMethod( .declareAcquiredMethod(
"crib_sw_setCribEnableGadgetUrl", "crib_sw_setCribEnableGadgetUrl",
"crib_sw_setCribEnableGadgetUrl" "crib_sw_setCribEnableGadgetUrl"
) )
.allowPublicAcquisition("crib_sw_setCribEnableGadgetUrl", function (argument_list) {
return this.crib_sw_setCribEnableGadgetUrl(argument_list[0]);
})
.declareAcquiredMethod( .declareAcquiredMethod(
"crib_sw_getCribEnableGadgetUrl", "crib_sw_getCribEnableGadgetUrl",
"crib_sw_getCribEnableGadgetUrl" "crib_sw_getCribEnableGadgetUrl"
) )
.allowPublicAcquisition("crib_sw_getCribEnableGadgetUrl", function (argument_list) {
return this.crib_sw_getCribEnableGadgetUrl();
})
.allowPublicAcquisition("crib_sw_get", function (argument_list) { .allowPublicAcquisition("crib_sw_get", function (argument_list) {
return this.crib_sw_get(argument_list[0]); return this.crib_sw_get(argument_list[0]);
}) })
...@@ -207,22 +279,22 @@ ...@@ -207,22 +279,22 @@
.allowPublicAcquisition("crib_sw_put", function (argument_list) { .allowPublicAcquisition("crib_sw_put", function (argument_list) {
return this.crib_sw_put(argument_list[0], argument_list[1]); return this.crib_sw_put(argument_list[0], argument_list[1]);
}) })
.declareAcquiredMethod("setSetting", "setSetting")
.declareMethod('render', function (options) { .declareMethod('render', function (options) {
var gadget = this, var gadget = this,
getURL = window.location, getURL = window.location,
site = getURL.protocol + "//" + getURL.host, site = getURL.protocol + "//" + getURL.host;
params = getParameterDict(); if (options.hasOwnProperty("from_path")) {
if (params.hasOwnProperty("from_path")) { gadget.props.element.querySelector("form.crib-load-from-zip .load-from-zip-path").value = options.from_path;
gadget.props.element.querySelector("form.crib-load-from-zip .load-from-zip-path").value = params.from_path;
} }
if (params.hasOwnProperty("to_path")) { if (options.hasOwnProperty("to_path")) {
gadget.props.element.querySelector("form.crib-load-from-zip .load-zip-to-path").value = params.to_path; gadget.props.element.querySelector("form.crib-load-from-zip .load-zip-to-path").value = options.to_path;
} }
if (params.hasOwnProperty("zip_url")) { if (options.hasOwnProperty("zip_url")) {
gadget.props.element.querySelector("form.crib-load-from-zip .load-zip-url").value = params.zip_url; gadget.props.element.querySelector("form.crib-load-from-zip .load-zip-url").value = options.zip_url;
} }
if (params.hasOwnProperty("redirect_url")) { if (options.hasOwnProperty("redirect_url")) {
gadget.props.element.querySelector("form.crib-load-from-zip .redirect-url").value = params.redirect_url; gadget.props.element.querySelector("form.crib-load-from-zip .redirect-url").value = options.redirect_url;
} }
return gadget.props.start_deferred.resolve(); return gadget.props.start_deferred.resolve();
}) })
......
...@@ -5,6 +5,15 @@ ...@@ -5,6 +5,15 @@
var DEFAULT_APP_LIST_DOC = "app-list.json", var DEFAULT_APP_LIST_DOC = "app-list.json",
SAMPLE_APP_LIST_DOC = "sample-app-list.json"; SAMPLE_APP_LIST_DOC = "sample-app-list.json";
function isValidUrl(string) {
try {
new URL(string);
} catch (_) {
return false;
}
return true;
}
function displayAppList(gadget) { function displayAppList(gadget) {
var app_list = []; var app_list = [];
return gadget.fetch(DEFAULT_APP_LIST_DOC) return gadget.fetch(DEFAULT_APP_LIST_DOC)
...@@ -18,10 +27,12 @@ ...@@ -18,10 +27,12 @@
promise_list.push(RSVP.all([ promise_list.push(RSVP.all([
gadget.getUrlFor({ gadget.getUrlFor({
page: "url_list", page: "url_list",
crib_enable_url: app_list[i].application_crib,
pattern: app_list[i].application_path pattern: app_list[i].application_path
}), }),
gadget.getUrlFor({ gadget.getUrlFor({
page: "save_load", page: "save_load",
crib_enable_url: app_list[i].application_crib,
zip_download_path: app_list[i].application_path, zip_download_path: app_list[i].application_path,
zip_name: app_list[i].application_title + ".zip", zip_name: app_list[i].application_title + ".zip",
start_zip_download: true start_zip_download: true
...@@ -35,14 +46,12 @@ ...@@ -35,14 +46,12 @@
}) })
.push(function (url_list) { .push(function (url_list) {
var app_list_html = [], var app_list_html = [],
base_url = window.location.origin,
current_path = window.location.pathname, current_path = window.location.pathname,
tmp_url; tmp_url;
for (var i = 0; i < app_list.length; i += 1) { for (var i = 0; i < app_list.length; i += 1) {
// XXX Ugly Hack tmp_url = app_list[i].application_url;
tmp_url = window.location.pathname + "/" + app_list[i].application_url; if (!isValidUrl(tmp_url)) {
while (tmp_url.indexOf("//") !== -1) { tmp_url = new URL(tmp_url, window.location.href).href;
tmp_url = tmp_url.replace("//", "/");
} }
app_list_html.push(domsugar("div", {class: "col-sm-4 col-md-4"}, [ app_list_html.push(domsugar("div", {class: "col-sm-4 col-md-4"}, [
domsugar("div", {class: "thumbnail"}, [ domsugar("div", {class: "thumbnail"}, [
...@@ -52,7 +61,7 @@ ...@@ -52,7 +61,7 @@
domsugar("a", {href: url_list[i][1], class:"btn btn-default", domsugar("a", {href: url_list[i][1], class:"btn btn-default",
role:"button", text:"", title: "Download"}), role:"button", text:"", title: "Download"}),
domsugar("a", {href: url_list[i][0], class:"btn btn-default", role:"button", text:"Edit"}), domsugar("a", {href: url_list[i][0], class:"btn btn-default", role:"button", text:"Edit"}),
domsugar("a", {href: base_url + tmp_url , class:"btn btn-primary", role:"button", text:"GO", target: "_blank"}) domsugar("a", {href: tmp_url , class:"btn btn-primary", role:"button", text:"GO", target: "_blank"})
]) ])
]) ])
...@@ -90,8 +99,6 @@ ...@@ -90,8 +99,6 @@
// acquired methods // acquired methods
////////////////////////////////////////////// //////////////////////////////////////////////
.declareAcquiredMethod("getUrlFor", "getUrlFor") .declareAcquiredMethod("getUrlFor", "getUrlFor")
.declareAcquiredMethod("crib_sw_get", "crib_sw_get")
.declareAcquiredMethod("crib_sw_put", "crib_sw_put")
.declareMethod('render', function (options) { .declareMethod('render', function (options) {
return displayAppList(this); return displayAppList(this);
}) })
......
...@@ -156,6 +156,10 @@ ...@@ -156,6 +156,10 @@
.declareAcquiredMethod("crib_sw_getScope", "crib_sw_getScope") .declareAcquiredMethod("crib_sw_getScope", "crib_sw_getScope")
.declareAcquiredMethod("crib_sw_get", "crib_sw_get") .declareAcquiredMethod("crib_sw_get", "crib_sw_get")
.declareAcquiredMethod("crib_sw_put", "crib_sw_put") .declareAcquiredMethod("crib_sw_put", "crib_sw_put")
.declareAcquiredMethod(
"crib_sw_setCribEnableGadgetUrl",
"crib_sw_setCribEnableGadgetUrl"
)
.declareAcquiredMethod("setSetting", "setSetting") .declareAcquiredMethod("setSetting", "setSetting")
.declareAcquiredMethod("getUrlFor", "getUrlFor") .declareAcquiredMethod("getUrlFor", "getUrlFor")
.declareAcquiredMethod("redirect", "redirect") .declareAcquiredMethod("redirect", "redirect")
...@@ -171,7 +175,9 @@ ...@@ -171,7 +175,9 @@
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
if (gadget.props.options.crib_enable_url !== undefined) { if (gadget.props.options.crib_enable_url !== undefined) {
return gadget.setSetting("site_editor_gadget_url", gadget.props.options.crib_enable_url); return gadget.crib_sw_setCribEnableGadgetUrl(
gadget.props.options.crib_enable_url
);
} }
return; return;
}) })
......
...@@ -289,12 +289,24 @@ ...@@ -289,12 +289,24 @@
.declareAcquiredMethod("crib_sw_get", "crib_sw_get") .declareAcquiredMethod("crib_sw_get", "crib_sw_get")
.declareAcquiredMethod("crib_sw_put", "crib_sw_put") .declareAcquiredMethod("crib_sw_put", "crib_sw_put")
.declareAcquiredMethod("getUrlFor", "getUrlFor") .declareAcquiredMethod("getUrlFor", "getUrlFor")
.declareAcquiredMethod(
"crib_sw_setCribEnableGadgetUrl",
"crib_sw_setCribEnableGadgetUrl"
)
.declareMethod('render', function (options) { .declareMethod('render', function (options) {
var gadget = this; var gadget = this;
if (options === undefined) if (options === undefined)
options = {}; options = {};
gadget.props.options = options; gadget.props.options = options;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () {
if (gadget.props.options.crib_enable_url !== undefined) {
return gadget.crib_sw_setCribEnableGadgetUrl(
gadget.props.options.crib_enable_url
);
}
return;
})
.push(function () { .push(function () {
return gadget.props.start_deferred.resolve(); return gadget.props.start_deferred.resolve();
}); });
......
...@@ -113,6 +113,10 @@ ...@@ -113,6 +113,10 @@
}) })
.declareAcquiredMethod("crib_sw_allDocs", "crib_sw_allDocs") .declareAcquiredMethod("crib_sw_allDocs", "crib_sw_allDocs")
.declareAcquiredMethod("crib_sw_getScope", "crib_sw_getScope") .declareAcquiredMethod("crib_sw_getScope", "crib_sw_getScope")
.declareAcquiredMethod(
"crib_sw_setCribEnableGadgetUrl",
"crib_sw_setCribEnableGadgetUrl"
)
.declareAcquiredMethod("getUrlFor", "getUrlFor") .declareAcquiredMethod("getUrlFor", "getUrlFor")
.declareAcquiredMethod("redirect", "redirect") .declareAcquiredMethod("redirect", "redirect")
.declareAcquiredMethod("setSetting", "setSetting") .declareAcquiredMethod("setSetting", "setSetting")
...@@ -123,6 +127,14 @@ ...@@ -123,6 +127,14 @@
options = {}; options = {};
gadget.props.options = options; gadget.props.options = options;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () {
if (gadget.props.options.crib_enable_url !== undefined) {
return gadget.crib_sw_setCribEnableGadgetUrl(
gadget.props.options.crib_enable_url
);
}
return;
})
.push(function () { .push(function () {
if (options.pattern !== undefined) { if (options.pattern !== undefined) {
return gadget.setSetting("editor-pattern", options.pattern) return gadget.setSetting("editor-pattern", options.pattern)
......
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
"application_image_url": "img/vifib-logo.png", "application_image_url": "img/vifib-logo.png",
"application_toc_accept": false, "application_toc_accept": false,
"application_description":"Hello World", "application_description":"Hello World",
"application_url":"hello-world/", "application_url":"./hello-world/",
"application_crib":"./crib-enable.html",
"application_path":"hello-world/", "application_path":"hello-world/",
"application_edit_page":"hello-world/index.html", "application_edit_page":"hello-world/index.html",
"application_title":"Hello World", "application_title":"Hello World",
...@@ -16,7 +17,8 @@ ...@@ -16,7 +17,8 @@
"application_image_type": "image", "application_image_type": "image",
"application_image_url": "pdf_viewer_app_logo.svg", "application_image_url": "pdf_viewer_app_logo.svg",
"application_description":"Read and manage you PDF Offline", "application_description":"Read and manage you PDF Offline",
"application_url":"", "application_url":"./",
"application_crib":"./crib-enable.html",
"application_path":"", "application_path":"",
"application_edit_page":"gadget/gadget_cribjs_page_cribjs_home.html", "application_edit_page":"gadget/gadget_cribjs_page_cribjs_home.html",
"application_title":"CribJS", "application_title":"CribJS",
......
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