Commit 4a44482d authored by Sven Franck's avatar Sven Franck

started integrating dispatch and external code into prototype

parent 734051d3
...@@ -373,39 +373,22 @@ ...@@ -373,39 +373,22 @@
} }
}; };
// => mapping URL query-string (configuration // => map internal browser:// urls
priv.mapUrlString = function (spec) { // API browser://{command}/{method}/{scope}/{interaction}/
var key, obj, parsedJSON, config = {}; priv.mapBrowserURL = function (url) {
if (spec !== undefined && spec !== "") { var api = ['command', 'method', 'scope', 'interaction'], internalRequest;
obj = spec.slice(1).split("="); try {
key = obj[0]; internalRequest = url.split("/")
switch (key) { .filter( String )
case "string": .splice(1)
case "url": .reduce( function( previous, current, index ){
config.root = priv.decodeURI(obj[1]); previous[ api[index] ] = current;
break; return previous;
case "json": },{});
parsedJSON = JSON.parse(priv.decodeURI(obj[1])); } catch(e) {
config.root = parsedJSON.root || window.location.pathname; console.log("internal URL could not be mapped");
config.src = priv.decodeURIArray(parsedJSON.src) || [];
break;
case "hal":
parsedJSON = JSON.parse(priv.decodeURI(obj[1]));
config.root = parsedJSON._links.self || window.location.pathname;
config.src = priv.decodeURIArray(parsedJSON.src) || [];
break;
case "data":
break;
default:
// no allowable-type - ignore config-parameter!
config.root = window.location.href;
config.src = [];
break;
}
} else {
config = {"root": window.location.href};
} }
return config; return internalRequest;
}; };
// => create Index of gadgets on page (excluding gadgets in iFrame/Sandbox) // => create Index of gadgets on page (excluding gadgets in iFrame/Sandbox)
...@@ -439,7 +422,7 @@ ...@@ -439,7 +422,7 @@
if (options.parentFrame === undefined) { if (options.parentFrame === undefined) {
treeNode.children.unshift({ treeNode.children.unshift({
"id": options.id, "id": options.id,
"src": options.src, "src": priv.makeUrlAbsolute(priv.decodeURI(options.src)),
"foreign" : priv.isForeignUrl(options.src), "foreign" : priv.isForeignUrl(options.src),
"children": [] "children": []
}); });
...@@ -482,6 +465,8 @@ ...@@ -482,6 +465,8 @@
priv.constructSelectorForService = function (src, node, selector) { priv.constructSelectorForService = function (src, node, selector) {
var i, result; var i, result;
selector = selector || []; selector = selector || [];
// the error is in the gadgetTree!
// we must not push "root" into the array to make reduce work // we must not push "root" into the array to make reduce work
if (node.id !== "root") { if (node.id !== "root") {
selector.push([node.id, node.foreign]); selector.push([node.id, node.foreign]);
...@@ -489,6 +474,7 @@ ...@@ -489,6 +474,7 @@
if (node.src === src) { if (node.src === src) {
return selector; return selector;
} }
for (i = 0; i < node.children.length; i += 1) { for (i = 0; i < node.children.length; i += 1) {
result = priv.constructSelectorForService( result = priv.constructSelectorForService(
src, src,
...@@ -522,9 +508,9 @@ ...@@ -522,9 +508,9 @@
}; };
// => manages all interactions (listens to incoming postMessages) // => manages all interactions (listens to incoming postMessages)
// need a switch, because only one "message" listener can be set
priv.serviceHandler = function (event) { priv.serviceHandler = function (event) {
var type = event.data.type, route, trackingId;
var type = event.data.type, route;
if (type) { if (type) {
route = event.data.type.split("/"); route = event.data.type.split("/");
...@@ -535,20 +521,11 @@ ...@@ -535,20 +521,11 @@
// route // route
switch (route[0]) { switch (route[0]) {
case "service": case "register":
priv.registerNewService(event); priv.registerNewService(event);
break; break;
case "request": case "request":
trackingId = priv.generateUuid(); priv.requestServiceFromGadget(event);
// track this request, so we know where to send the response
priv.trackRequest(trackingId, event.originalTarget);
// request the service
priv.requestServiceFromGadget(event, trackingId);
break;
case "tree":
if (route[1] === "update") {
priv.addGadgetToTree(event.data.options, that.gadgetTree);
}
break; break;
case "run": case "run":
priv.runService(event); priv.runService(event);
...@@ -559,9 +536,48 @@ ...@@ -559,9 +536,48 @@
case "reply": case "reply":
priv.returnResult(event); priv.returnResult(event);
break; break;
// not part of the request-response cylce, but if the gadgetTree
// is global at the top, we need to inform the top about gadgets to add
case "tree":
if (route[1] === "update") {
priv.addGadgetToTree(event.data.options, that.gadgetTree);
}
break;
} }
} else { } else {
// no matching type! // switch to using URLs here
// global get!
$.ajax({
method: "GET",
url: event.data,
error: function (jqXHR, textStatus, errorThrown) {
console.log("request failed: " + errorThrown);
},
success: function (value, textStatus, jqXHR) {
// switch here!
var scope = value._links.self.href.split("/").slice(0,-1).pop(),
service = {
"service" : value._links.self.href.split(/[/]+/).pop(),
"parameters" : [value._links.request.href],
"scope" : scope
},
request = 'browser://request/' + scope + '/';
$.ajax({
method: "POST",
url: request,
context: $(this),
data: JSON.stringify(service),
error: function (jqXHR, textStatus, errorThrown) {
console.log("request for service failed");
},
// success: function () {
// console.log("service requested from renderJS");
// }
});
}
});
} }
}; };
...@@ -660,14 +676,18 @@ ...@@ -660,14 +676,18 @@
}; };
// => request a service provided by a gadget // => request a service provided by a gadget
priv.requestServiceFromGadget = function (event, trackingId) { priv.requestServiceFromGadget = function (event) {
var callService = priv.findServiceInMap( var callService = priv.findServiceInMap(
event.data.service, event.data.service,
event.data.type.split("/")[1] event.data.type.split("/")[1]
), ),
selector, selector,
targetWindow, targetWindow,
options; options,
trackingId = priv.generateUuid();
// track this request, so we know where to send the response
priv.trackRequest(trackingId, event.originalTarget);
if (callService) { if (callService) {
// services are stored by URL (not id), because if inside an iFrame // services are stored by URL (not id), because if inside an iFrame
...@@ -677,7 +697,7 @@ ...@@ -677,7 +697,7 @@
// in our gadget tree by using the URL provided by the service... // in our gadget tree by using the URL provided by the service...
// and return an id path, so we can create a selector // and return an id path, so we can create a selector
selector = priv.constructSelectorForService( selector = priv.constructSelectorForService(
callService.src, priv.decodeURI(callService.src),
that.gadgetTree, that.gadgetTree,
[] []
); );
...@@ -750,6 +770,7 @@ ...@@ -750,6 +770,7 @@
} }
} }
if (addInteraction) { if (addInteraction) {
delete event.data.type;
that.gadgetService.map.push(event.data); that.gadgetService.map.push(event.data);
} }
}; };
...@@ -769,6 +790,7 @@ ...@@ -769,6 +790,7 @@
services, services,
service, service,
options, options,
src,
i, i,
j; j;
...@@ -778,10 +800,11 @@ ...@@ -778,10 +800,11 @@
for (i = 0; i < services.length; i += 1) { for (i = 0; i < services.length; i += 1) {
service = JSON.parse(priv.getAttribute(services[i], 'service')); service = JSON.parse(priv.getAttribute(services[i], 'service'));
for (j = 0; j < service.length; j += 1) { for (j = 0; j < service.length; j += 1) {
src = service[j].src || window.location.href.split("?")[0];
options = { options = {
"rel": service[j].rel, "rel": service[j].rel,
"type": service[j].type, "type": service[j].type || "register/any",
"src": service[j].src || window.location.href.split("?")[0], "src": priv.makeUrlAbsolute(priv.decodeURI(src)),
"url": "" "url": ""
}; };
$(root).addService(options); $(root).addService(options);
...@@ -837,7 +860,8 @@ ...@@ -837,7 +860,8 @@
cleanedString, cleanedString,
content, content,
i, i,
element; element,
src;
// update gadgetIndex // update gadgetIndex
priv.registerGadget(gadgetData, options); priv.registerGadget(gadgetData, options);
...@@ -863,10 +887,12 @@ ...@@ -863,10 +887,12 @@
element = content[i]; element = content[i];
switch (element.tagName) { switch (element.tagName) {
case "LINK": case "LINK":
if (element.getAttribute("type").split("/")[0] === "service") { if (element.getAttribute("type").split("/")[0] === "register") {
// need to make sure we store absolute URLs for services, too!
src = element.getAttribute("src") ||
window.location.href.split("?")[0];
$(element).addService({ $(element).addService({
"src": element.getAttribute("src") || "src": priv.makeUrlAbsolute(priv.decodeURI(src)),
window.location.href.split("?")[0],
"type": element.getAttribute("type"), "type": element.getAttribute("type"),
"rel": element.getAttribute("rel"), "rel": element.getAttribute("rel"),
"url": "" "url": ""
...@@ -960,7 +986,7 @@ ...@@ -960,7 +986,7 @@
// both root and iFrame try to map location.search, either for initial // both root and iFrame try to map location.search, either for initial
// configuration or to retrieve the root when inside an iFrame // configuration or to retrieve the root when inside an iFrame
var spec = priv.mapUrlString(window.location.search); var spec = that.mapUrl(window.location.search);
// create index // create index
priv.createGadgetIndex(); priv.createGadgetIndex();
...@@ -982,11 +1008,69 @@ ...@@ -982,11 +1008,69 @@
}; };
// ================ public API (call on renderJs and $(elem) =========== // ================ public API (call on renderJs and $(elem) ===========
// => mapURL searchstring
that.mapUrl = function (spec, internal) {
var key,
obj,
parsedJSON,
configuration = {};
if (spec !== undefined && spec !== "") {
obj = spec.slice(1).split("=");
key = obj[0];
switch (key) {
case "string":
case "url":
configuration.root = priv.decodeURI(obj[1]);
break;
case "json":
parsedJSON = JSON.parse(priv.decodeURI(obj[1]));
configuration.root = parsedJSON.root || window.location.pathname;
configuration.src = priv.decodeURIArray(parsedJSON.src) || [];
break;
case "hal":
parsedJSON = JSON.parse(priv.decodeURI(obj[1]));
configuration.root = parsedJSON._links.self || window.location.pathname;
configuration.src = priv.decodeURIArray(parsedJSON.src) || [];
break;
case "file":
$.ajax({
method: 'GET',
url: obj[1],
context: $('body'),
fail: function (jqXHR, textStatus, errorThrown) {
configuration = {
"errorThrown":errorThrown,
"textStatus": textStatus,
"jqXHR": jqXHR
}
},
done: function (value, textStatus, jqXHR) {
configuration = {
"value":value,
"textStatus": textStatus,
"jqXHR": jqXHR
}
}
});
break;
default:
// no allowable-type - ignore configuration-parameter!
configuration.root = window.location.href;
configuration.src = [];
break;
}
} else {
configuration = {"root": window.location.href};
}
return configuration;
};
// => publish a service to this instance (and root instance) // => publish a service to this instance (and root instance)
that.addService = $.fn.addService = function (options) { that.addService = $.fn.addService = function (options) {
var addressArray = window.location.href.split("?"), targetUrl; var addressArray = window.location.href.split("?"), targetUrl;
options.src = options.src || addressArray[0]; options.src = priv.makeUrlAbsolute(priv.decodeURI(options.src)) || addressArray[0];
// posts to URL passed (need for CORS?) // posts to URL passed (need for CORS?)
// otherwise window.top.location.href) would also work // otherwise window.top.location.href) would also work
...@@ -995,6 +1079,7 @@ ...@@ -995,6 +1079,7 @@
} else { } else {
targetUrl = priv.decodeURI(addressArray[1].split("=")[1]); targetUrl = priv.decodeURI(addressArray[1].split("=")[1]);
} }
// TODO: this should be a URL link
window.top.postMessage(options, targetUrl); window.top.postMessage(options, targetUrl);
}; };
...@@ -1152,16 +1237,41 @@ ...@@ -1152,16 +1237,41 @@
browse_ss_file_regexp = /^browser:\/\/browse\/ss\/([\w\W]+)/, browse_ss_file_regexp = /^browser:\/\/browse\/ss\/([\w\W]+)/,
browse_ss_directory_regexp = /^browser:\/\/browse\/ss\//, browse_ss_directory_regexp = /^browser:\/\/browse\/ss\//,
// internal API (scope, interaction are optional)
// child > parent = call/{method}/{scope}/{interaction}/
// parent > child = delegate/{method}/{scope}/{interaction}/
// gadget > global = request/{method}/{scope}/{interaction}/
call_regexp = /^browser:\/\/call\/([\w\W]+)\//, call_regexp = /^browser:\/\/call\/([\w\W]+)\//,
delegate_regexp = /^browser:\/\/delegate\/([\w\W]+)\//, delegate_regexp = /^browser:\/\/delegate\/([\w\W]+)\//,
request_regexp = /^browser:\/\/request\/([\w\W]+)\//, request_regexp = /^browser:\/\/request\/([\w\W]+)\//,
// vars
key, config, provider, param, value, targetWindow; key, config, provider, param, value, targetWindow;
// =================== cleanup ====================
// internal API
// {command}/{method}/{scope}/{interaction}/
var internalRequest = priv.mapBrowserURL(this.url);
if (internalRequest.command === "call") {
// if (this.method === "POST") {
//
// } else {
// this.respond(405, {}, "");
// }
} else if (internalRequest.command === "delegate") {
// if (this.method === "POST") {
//
// } else {
// this.respond(405, {}, "");
// }
} else if (internalRequest.command === "request") {
// if (this.method === "POST") {
//
// } else {
// this.respond(405, {}, "");
// }
} else {
// this.respond(404, {}, "");
}
// =================== previous ====================
// localStorage handler // localStorage handler
if (ls_regexp.test(this.url)) { if (ls_regexp.test(this.url)) {
key = ls_regexp.exec(this.url)[1]; key = ls_regexp.exec(this.url)[1];
...@@ -1280,14 +1390,17 @@ ...@@ -1280,14 +1390,17 @@
// still inside child frame // still inside child frame
// add to tree, so lookup is possible when service is requested // add to tree, so lookup is possible when service is requested
config = JSON.parse(this.requestBody); config = JSON.parse(this.requestBody);
window.parent.postMessage({ // // we don't need this here!
"type": "tree/update", // // but first get the internal router to work, so we only
"options": { // // handle data-uris
"id": config.self, // window.parent.postMessage({
"src": config.src, // "type": "tree/update",
"children": [] // "options": {
} // "id": config.self,
}, "*"); // "src": config.src,
// "children": []
// }
// }, "*");
// generate a url to be called once the service is requested // generate a url to be called once the service is requested
// this is a parent > child URL, so we delegate // this is a parent > child URL, so we delegate
...@@ -1300,11 +1413,11 @@ ...@@ -1300,11 +1413,11 @@
config.scope = value || "any"; config.scope = value || "any";
// register service // register service
window.parent.postMessage(config, "*"); window.top.postMessage(config, "*");
this.respond(204, {}, ""); this.respond(204, {}, "");
} else if (key === "service") { } else if (key === "request") {
// inside child frame, request service to be run // inside child frame, request service to be run
var sendToParent = "data://application/hal+json;base64," + var sendToParent = "data://application/hal+json;base64," +
window.btoa(JSON.stringify({ window.btoa(JSON.stringify({
...@@ -1313,7 +1426,7 @@ ...@@ -1313,7 +1426,7 @@
request: {href: this.requestBody} request: {href: this.requestBody}
}})); }}));
window.parent.postMessage(sendToParent, "*"); window.top.postMessage(sendToParent, "*");
} else { } else {
this.respond(404, {}, ""); this.respond(404, {}, "");
} }
......
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