Commit 8a1e595d authored by Sven Franck's avatar Sven Franck

reworked 2nd instance in example to only using ajax links

parent 77fdb96b
/*global document, jQuery */ /*global document, jQuery */
// filebrowser.html?file=browser%3A%2F%2Fbrowse%2Fls%2F
"use strict";
(function (document, $) { (function (document, $) {
"use strict";
var getParameter = function(searchString, paramName) { var getParameter = function(searchString, paramName) {
var i, val, params = searchString.split("&"); var i, val, params = searchString.split("&");
...@@ -15,76 +14,108 @@ ...@@ -15,76 +14,108 @@
return null; return null;
}; };
var mapUrl = function (url) { var mapUrl = function (searchString) {
var searchString = url.href.split("?")[1], var fileToDisplay = getParameter(searchString, "file"),
fileToDisplay; scope,
register,
service;
if (searchString) { if (fileToDisplay) {
fileToDisplay = getParameter(searchString, "file"); $.ajax({
if (fileToDisplay) { method: 'GET',
url: fileToDisplay,
context: $('body'),
error: function (jqXHR, textStatus, errorThrown) {
$(this).text(errorThrown);
},
success: function (value, textStatus, jqXHR) {
$.ajax({ scope = value._links.scope.href.slice(0,-1).split(/[/]+/).pop();
method: 'GET', register = value._links.call.href
// XXX Hardcoded .replace("{method}", "register")
url: fileToDisplay, .replace("{scope}", scope )
context: $('body'), .replace("{interaction}", "");
error: function (jqXHR, textStatus, errorThrown) { service = {
$(this).text(errorThrown); "type": "service/test",
}, "src": encodeURIComponent(window.location.href),
success: function (value, textStatus, jqXHR) { "rel": "browse",
$.ajax({ "self": window.frameElement.id
method: 'GET', };
// XXX Hardcoded
url: value._links.storage.href,
context: $('body'),
error: function (jqXHR, textStatus, errorThrown) {
$(this).text(errorThrown);
},
success: function (value2, textStatus, jqXHR) {
var content_type = jqXHR.getResponseHeader("Content-Type") || "";
// XXX Hardcoded mime type
if (content_type.split(';')[0] === "application/hal+json") {
// XXX Will fail if response does not send expected links...
$(this).html("<ul>");
for (var i in value2._links.contents){
$(this).append("<li><button id='" + i + "'>" +
value2._links.contents[i].href + "</button></li>");
$(this).find("#" + i.toString()).on('click', function(e, target) {
$.ajax({
// XXX Hardcoded post and url
// Why using postMessage?
method: "POST",
url: value._links.display.href,
context: $(this),
data: $(this).text(),
error: function (jqXHR, textStatus, errorThrown) {
console.log("Plumbing failed: " + errorThrown);
},
// success: function (value, textStatus, jqXHR) {
// console.log(value);
// },
});
});
}
$(this).append("</ul>");
} else {
$(this).text("Unsupported content type " + content_type);
};
},
});
},
});
} else { $.ajax({
$("body").text("No parameter found in url"); method: 'POST',
} url: register,
context: $(this),
data: JSON.stringify(service),
error: function (jqXHR, textStatus, errorThrown) {
console.log("registration failed: " + errorThrown);
},
success: function (value, textStatus, jqXHR) {
// console.log("registration successful");
}
});
// HACK: this is hacking the functionality provided by the
// filebrowser!
// 'browser://call/browse/' should be called by the interactor
// instead of hardcoding it here
$.ajax({
method: 'GET',
url: value._links.scope.href,
context: $('body'),
error: function (jqXHR, textStatus, errorThrown) {
$(this).text(errorThrown);
},
success: function (value2, textStatus, jqXHR) {
var content_type = jqXHR.getResponseHeader("Content-Type") || "",
request = value._links.call.href
.replace("{method}", "service")
.replace("{scope}", scope )
.replace("{interaction}", "preview");
// XXX Hardcoded mime type
if (content_type.split(';')[0] === "application/hal+json") {
// XXX Will fail if response does not send expected links...
$(this).html("<ul>");
for (var i in value2._links.contents){
$(this).append("<li><button id='" + i + "'>" +
value2._links.contents[i].href + "</button></li>");
$(this).find("#" + i.toString()).on('click', function(e, target) {
$.ajax({
method: "POST",
url: request,
context: $(this),
data: $(this).text(),
error: function (jqXHR, textStatus, errorThrown) {
console.log("request failed: " + errorThrown);
},
// success: function (value, textStatus, jqXHR) {
// console.log("request sent");
// }
});
});
}
$(this).append("</ul>");
} else {
$(this).text("Unsupported content type " + content_type);
};
}
});
},
});
} else { } else {
$("body").text("No parameter found in url (2)"); $("body").text("No parameter found in url");
} }
}; };
$(document).ready(function () { $(document).ready(function () {
mapUrl(window.location); var search = window.location.search;
if (search) {
mapUrl(search.slice(1));
} else {
$("body").text("No parameter found in url");
}
}); });
}(document, jQuery)); }(document, jQuery));
/*global document, jQuery */ /*global document, jQuery */
// filebrowser.html?file=browser%3A%2F%2Fbrowse%2Fls%2F
"use strict"; "use strict";
(function (document, $) { (function (document, $) {
...@@ -20,6 +19,20 @@ ...@@ -20,6 +19,20 @@
return -1; return -1;
}; };
var generateUuid = function () {
var S4 = function () {
/* 65536 */
var i, string = Math.floor(
Math.random() * 0x10000
).toString(16);
for (i = string.length; i < 4; i += 1) {
string = "0" + string;
}
return string;
};
return S4() + S4();
};
var getParameter = function(searchString, paramName) { var getParameter = function(searchString, paramName) {
var i, val, params = searchString.split("&"); var i, val, params = searchString.split("&");
...@@ -32,29 +45,69 @@ ...@@ -32,29 +45,69 @@
return null; return null;
}; };
// this is our "interactor", it only knows one other iFrame
// so we post to this one!
var handler = function (event) { var handler = function (event) {
var frames = document.getElementsByTagName("iframe"), frame, i; // prevent registrations to renderJs from triggering here
for (i = 0; i < frames.length; i += 1) { var type = event.data.type,
frame = frames[i]; service,
if (myIndexOf( scope,
event.source.location.pathname, request;
frame.getAttribute("src").split("?")[0]
) < 0) { if (type === undefined) {
frame.contentWindow.postMessage(event.data, "*"); $.ajax({
// frame.contentWindow.postMessage(event.data, window.location.href); method: "GET",
} url: event.data,
error: function (jqXHR, textStatus, errorThrown) {
console.log("request failed: " + errorThrown);
},
success: function (value, textStatus, jqXHR) {
// we now have the URL to handle and the method
// to request. We need to POST this, because
// we can't access renderJS.gadgetService from here...
// when optimizing all the secondary ajax calls should be removed
// question also is, whether we need POST at all, if we could
// pass everything through the URL?
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");
// }
});
}
});
// var frames = document.getElementsByTagName("iframe"), frame, i;
// for (i = 0; i < frames.length; i += 1) {
// frame = frames[i];
// if (myIndexOf(
// event.source.location.pathname,
// frame.getAttribute("src").split("?")[0]
// ) < 0) {
// frame.contentWindow.postMessage(event.data, "*");
// }
// }
} }
}; };
var mapUrl = function (url) { var mapUrl = function (searchString) {
var searchString = url.href.split("?")[1], var fileToDisplay = getParameter(searchString, "file"),
fileToDisplay, fileToDisplayData; browserAPI,
previewAPI;
if (searchString) {
fileToDisplay = getParameter(searchString, "file");
if (fileToDisplay) {
$.ajax({ $.ajax({
method: 'GET', method: 'GET',
// XXX Hardcoded // XXX Hardcoded
...@@ -64,45 +117,65 @@ ...@@ -64,45 +117,65 @@
$(this).text(errorThrown); $(this).text(errorThrown);
}, },
success: function (value, textStatus, jqXHR) { success: function (value, textStatus, jqXHR) {
fileToDisplayData = "data://application/hal+json;base64," + var access;
// detour to request, while working on the 2nd preview window
if (value._links.target.href === "preview_by_postmessage.html") {
access = "request";
} else {
access = "plumb";
}
// merge again once working!
browserAPI = "data://application/hal+json;base64," +
window.btoa(JSON.stringify({ window.btoa(JSON.stringify({
_links: { _links: {
self: {href: value._links.storage.href}, self: {href: value._links.scope.href},
storage: {href: value._links.storage.href}, scope: {href: value._links.scope.href},
display: {href: 'browser://plumb/parentwindow/'}, display: {href: 'browser://' + access + '/parentwindow/'},
// pass API-url so child can call parent
call: {href:'browser://call/{method}/{scope}/{interaction}'}
}})); }}));
if (fileToDisplay) { previewAPI = "data://application/hal+json;base64," +
window.btoa(JSON.stringify({
$("body").html( _links: {
'<iframe src="' + self: {href:''},
// XXX Hardcoded gadget to load scope: {href: value._links.scope.href},
'filebrowser.html?file=' + fileToDisplayData + display: {href: ''},
'">' + call: {href:'browser://call/{method}/{scope}/{interaction}'}
'<p>Your browser does not support iframes.</p>' + }}));
'</iframe">');
$("body").append( $("body").html(
'<iframe src="' + '<iframe src="' +
// XXX Hardcoded gadget to load // XXX Hardcoded gadget to load
value._links.preview.href + 'filebrowser.html?file=' + browserAPI +
'">' + '" id="' + generateUuid() +
'<p>Your browser does not support iframes.</p>' + '">' +
'</iframe">'); '<p>Your browser does not support iframes.</p>' +
'</iframe">');
} else { $("body").append(
$("body").text("No parameter found in url"); '<iframe src="' +
} // XXX Hardcoded gadget to load
}, value._links.target.href + '?file=' + previewAPI +
'" id="' + generateUuid() +
'">' +
'<p>Your browser does not support iframes.</p>' +
'</iframe">');
}
}); });
} else { } else {
$("body").text("No parameter found in url (2)"); $("body").text("No parameter found in url");
} }
}; };
$(document).ready(function () { $(document).ready(function () {
mapUrl(window.location); var search = window.location.search;
if (search) {
mapUrl(search.slice(1));
} else {
$("body").text("No parameter found in url");
}
if (window.addEventListener){ if (window.addEventListener){
window.addEventListener("message", handler, false) window.addEventListener("message", handler, false)
......
/*global document, jQuery */ /*global document, jQuery */
// filebrowser.html?file=browser%3A%2F%2Fbrowse%2Fls%2F
// filebrowser_and_preview.html?file=browser%3A%2F%2Fbrowse%2Fls%2F
"use strict"; "use strict";
(function (document, $) { (function (document, $) {
// sample contents
localStorage.setItem("foo", "bar");
localStorage.setItem("baz", "bam");
sessionStorage.setItem("cous", "cous");
sessionStorage.setItem("schnick", "schnack");
// contents var generateUuid = function () {
localStorage.setItem("foo", "bar"); var S4 = function () {
localStorage.setItem("baz", "bam"); var i, string = Math.floor(
sessionStorage.setItem("cous", "cous"); Math.random() * 0x10000
sessionStorage.setItem("schnick", "schnack"); ).toString(16);
// var myIndexOf = function (path, contains) { for (i = string.length; i < 4; i += 1) {
// var len = path.length; string = "0" + string;
// var wordLen = contains.length; }
// for(var i = 0; i < len; i++) { return string;
// var j = 0; };
// for(j = 0; j < wordLen; j++) { return S4() + S4();
// if(path[i+j] != contains[j]) { };
// break;
// }
// }
// if(j == wordLen) {
// return i;
// }
// }
// return -1;
// };
//
// var getParameter = function(searchString, paramName) {
// var i, val, params = searchString.split("&");
//
// for (i=0;i<params.length;i++) {
// val = params[i].split("=");
// if (val[0] == paramName) {
// return decodeURIComponent(val[1]);
// }
// }
// return null;
// };
//
// // this is our "interactor", it only knows one other iFrame
// // so we post to this one!
// var handler = function (event) {
// var frames = document.getElementsByTagName("iframe"), frame, i;
// for (i = 0; i < frames.length; i += 1) {
// frame = frames[i];
// if (myIndexOf(
// event.source.location.pathname,
// frame.getAttribute("src").split("?")[0]
// ) < 0) {
// frame.contentWindow.postMessage(event.data, "*");
// }
// }
// };
//
var mapUrl = function (url) {
// var searchString = url.href.split("?")[1],
// fileToDisplay;
//
// if (searchString) {
// fileToDisplay = getParameter(searchString, "file");
//
// if (fileToDisplay) {
var param1 = "data://application/hal+json;base64," +
window.btoa(JSON.stringify({
_links: {
self: {href: ""},
storage: {href: 'browser://browse/ls/'},
preview: {href: 'preview_by_hash_change.html'},
}}));
var param2 = "data://application/hal+json;base64," + var setup = function () {
window.btoa(JSON.stringify({ // this will have to run automatically should renderJs have an easy API
_links: { var instance1 = "data://application/hal+json;base64," +
self: {href: ""}, window.btoa(JSON.stringify({
storage: {href: 'browser://browse/ss/'}, _links: {
preview: {href: 'preview_by_postmessage.html'}, self: {href: ''},
}})); // not sure if scope should be passed as a link or JSON parameter
scope: {href: 'browser://browse/ls/'},
target: {href: 'preview_by_hash_change.html'},
call: {href: ''}
}}));
$("body").append( var instance2 = "data://application/hal+json;base64," +
'<iframe src="' + window.btoa(JSON.stringify({
// XXX Hardcoded gadget to load _links: {
'filebrowser_and_preview.html' + "?file=" + param1 + self: {href: ''},
'">' + scope: {href: 'browser://browse/ss/'},
'<p>Your browser does not support iframes.</p>' + target: {href: 'preview_by_postmessage.html'},
'</iframe">'); call: {href: ''}
}}));
$("body").append( $("body").append(
'<iframe src="' + '<iframe src="' +
// XXX Hardcoded gadget to load // XXX Hardcoded gadget to load
'filebrowser_and_preview.html' + "?file=" + param2 + 'filebrowser_and_preview.html' + "?file=" + instance1 +
'">' + '" id="' + generateUuid() +
'<p>Your browser does not support iframes.</p>' + '">' +
'</iframe">'); '<p>Your browser does not support iframes.</p>' +
'</iframe">');
// } else { $("body").append(
// $("body").text("No parameter found in url"); '<iframe src="' +
// } // XXX Hardcoded gadget to load
// } else { 'filebrowser_and_preview.html' + "?file=" + instance2 +
// $("body").text("No parameter found in url (2)"); '" id="' + generateUuid() +
// } '">' +
'<p>Your browser does not support iframes.</p>' +
'</iframe">');
}; };
$(document).ready(function () { $(document).ready(function () {
mapUrl(window.location); setup();
// if (window.addEventListener){
// window.addEventListener("message", handler, false)
// } else {
// window.attachEvent("onmessage", handler)
// }
}); });
}(document, jQuery)); }(document, jQuery));
<!DOCTYPE html>
<html>
<head>
<title>Preview</title>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript"
src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="../hyperbrowser.js"></script>
<script type="text/javascript" src="../renderjs.js"></script>
<script type="text/javascript" src="preview.js"></script>
</head>
<body>
<noscript>
Please enable Javascript
</noscript>
</body>
</html>
\ No newline at end of file
// > grab URL with parameters of file to open
// > call addGadget with those parameters?
// > display a file from some storage (local/session)
// > storage type will also be a parameter in the url?
// return "browser://localstorage/foo"
// file=browser%3A%2F%2Flocalstorage%2Ffoo
/*global document, jQuery */
"use strict";
(function (document, $) {
var ajaxGet = function (src, cb) {
$.ajax({
method: 'GET',
url: src,
context: $('body'),
error: function (jqXHR, textStatus, errorThrown) {
$(this).text(errorThrown);
},
success: function (value, textStatus, jqXHR) {
cb(value, textStatus, jqXHR);
}
});
};
var handler = function (event) {
ajaxGet(event.data, function(value, status, jqXHR) {
ajaxGet(value._links.enclosure.href, function(value, status, jqXHR) {
if (value === "") {
window.document.body.innerHTML = "file not found";
} else {
window.document.body.innerHTML = value;
}
});
});
}
var mapUrl = function (url) {
var searchString = url.href.split("?")[1],
fileToDisplay;
if (searchString) {
fileToDisplay = getParameter(searchString, "file");
if (fileToDisplay) {
$.ajax({
method: 'GET',
url: fileToDisplay,
context: $('body'),
error: function (jqXHR, textStatus, errorThrown) {
$(this).text(errorThrown);
},
success: function (value, textStatus, jqXHR) {
if (value === "") {
$(this).text("file not found");
} else {
$(this).text(value);
}
},
});
}
} else {
$(this).text("no file to display");
}
};
var getParameter = function(searchString, paramName) {
var i, val, params = searchString.split("&");
for (i=0;i<params.length;i++) {
val = params[i].split("=");
if (val[0] == paramName) {
return decodeURIComponent(val[1]);
}
}
return null;
};
$(document).ready(function () {
// mapUrl(window.location);
if (window.addEventListener){
window.addEventListener("message", handler, false)
} else {
window.attachEvent("onmessage", handler)
}
});
}(document, jQuery));
\ No newline at end of file
...@@ -83,6 +83,10 @@ ...@@ -83,6 +83,10 @@
} else { } else {
window.attachEvent("onmessage", handler) window.attachEvent("onmessage", handler)
} }
// $(window).on('hashchange', function() {
// console.log("LE HASH CHANGED");
// });
// $(window).trigger("hashchange");
}); });
}(document, jQuery)); }(document, jQuery));
\ No newline at end of file
// > grab URL with parameters of file to open
// > call addGadget with those parameters?
// > display a file from some storage (local/session)
// > storage type will also be a parameter in the url?
// return "browser://localstorage/foo"
// file=browser%3A%2F%2Flocalstorage%2Ffoo
/*global document, jQuery */ /*global document, jQuery */
"use strict"; "use strict";
(function (document, $) { (function (document, $) {
...@@ -24,44 +17,21 @@ ...@@ -24,44 +17,21 @@
}; };
var handler = function (event) { var handler = function (event) {
ajaxGet(event.data, function(value, status, jqXHR) { var type = event.data.type,
ajaxGet(value._links.enclosure.href, function(value, status, jqXHR) { method = type ? type.split("/")[0] : undefined;
if (value === "") { // prevent both renderJs and page events triggering on "run"
window.document.body.innerHTML = "file not found"; if (type === undefined || method !== "run") {
} else { ajaxGet(event.data, function(value, status, jqXHR) {
window.document.body.innerHTML = value; ajaxGet(value._links.enclosure.href, function(value, status, jqXHR) {
} if (value === "") {
}); window.document.body.innerHTML = "file not found";
}); } else {
} window.document.body.innerHTML = value;
}
var mapUrl = function (url) {
var searchString = url.href.split("?")[1],
fileToDisplay;
if (searchString) {
fileToDisplay = getParameter(searchString, "file");
if (fileToDisplay) {
$.ajax({
method: 'GET',
url: fileToDisplay,
context: $('body'),
error: function (jqXHR, textStatus, errorThrown) {
$(this).text(errorThrown);
},
success: function (value, textStatus, jqXHR) {
if (value === "") {
$(this).text("file not found");
} else {
$(this).text(value);
}
},
}); });
} });
} else {
$(this).text("no file to display");
} }
}; }
var getParameter = function(searchString, paramName) { var getParameter = function(searchString, paramName) {
var i, val, params = searchString.split("&"); var i, val, params = searchString.split("&");
...@@ -75,8 +45,58 @@ ...@@ -75,8 +45,58 @@
return null; return null;
}; };
$(document).ready(function () { var mapUrl = function (searchString) {
// mapUrl(window.location); var fileToDisplay = getParameter(searchString, "file"),
scope,
register,
service;
if (fileToDisplay) {
$.ajax({
method: 'GET',
url: fileToDisplay,
context: $('body'),
error: function (jqXHR, textStatus, errorThrown) {
$(this).text(errorThrown);
},
success: function (value, textStatus, jqXHR) {
scope = value._links.scope.href.slice(0,-1).split(/[/]+/).pop();
register = value._links.call.href
.replace("{method}", "register")
.replace("{scope}", scope )
.replace("{interaction}", "");
service = {
"type": "service/test",
"src": encodeURIComponent(window.location.href),
"rel": "preview",
"self": window.frameElement.id
};
$.ajax({
method: 'POST',
url: register,
context: $(this),
data: JSON.stringify(service),
error: function (jqXHR, textStatus, errorThrown) {
console.log("registration failed: " + errorThrown);
},
success: function (value, textStatus, jqXHR) {
// console.log("registration successful");
}
});
}
});
}
}
$(document).ready(function () {
var search = window.location.search;
if (search) {
mapUrl(search.slice(1));
} else {
$("body").text("No parameter found in url");
}
if (window.addEventListener){ if (window.addEventListener){
window.addEventListener("message", handler, false) window.addEventListener("message", handler, false)
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
// to publish their services // to publish their services
// -> find a way to prevent a gadget from reloading a plugin that's already // -> find a way to prevent a gadget from reloading a plugin that's already
// active on the page // active on the page
// -> for browser history, we would have to change the URL with a hash
// DISCUSSION POINTS: // DISCUSSION POINTS:
...@@ -466,6 +467,8 @@ ...@@ -466,6 +467,8 @@
"options": { "options": {
// passing "options":options will procude a DataCloneError, so // passing "options":options will procude a DataCloneError, so
// this is the only way (it seems) to pass the options object. // this is the only way (it seems) to pass the options object.
// beware frameElement does not work in cors, so actually
// THIS NEEDS A FIX!
"parentFrame": window.frameElement.getAttribute("id"), "parentFrame": window.frameElement.getAttribute("id"),
"id": options.id, "id": options.id,
"src": options.src, "src": options.src,
...@@ -509,6 +512,7 @@ ...@@ -509,6 +512,7 @@
"directories": spec.src || [], "directories": spec.src || [],
"map": [] "map": []
}; };
// listen for service postings to THIS renderJs instance // listen for service postings to THIS renderJs instance
if (window.addEventListener){ if (window.addEventListener){
window.addEventListener("message", priv.serviceHandler, false) window.addEventListener("message", priv.serviceHandler, false)
...@@ -556,6 +560,8 @@ ...@@ -556,6 +560,8 @@
priv.returnResult(event); priv.returnResult(event);
break; break;
} }
} else {
// no matching type!
} }
}; };
...@@ -578,14 +584,79 @@ ...@@ -578,14 +584,79 @@
// => run a service and post the result // => run a service and post the result
priv.runService = function (event) { priv.runService = function (event) {
var result = window[event.data.service].apply(this, event.data.parameters); var result;
window.top.postMessage({ // URL handling
"type": "result", if (event.data.url) {
"result": result, // let's go
"trackingId" : event.data.trackingId, $.ajax({
"callbackId": event.data.callbackId, url: event.data.parameters[0],
}, event.origin); method: 'GET',
error: function (jqXHR, textStatus, errorThrown) {
console.log("could not run service/interaction: " + errorThrown);
},
success: function (value, textStatus, jqXHR) {
$.ajax({
method: 'GET',
url: value._links.enclosure.href,
context: $('body'),
error: function (jqXHR, textStatus, errorThrown) {
$(this).text(errorThrown);
},
success: function (value2, textStatus, jqXHR) {
// this should be a deferred callback....
if (value === "") {
window.document.body.innerHTML = "file not found";
} else {
window.document.body.innerHTML = value2;
}
}
});
}
});
} else {
result = window[event.data.service].apply(this, event.data.parameters);
// only callback if we have to - should also be done via AJAX
if (event.data.callbackId) {
window.top.postMessage({
"type": "result",
"result": result,
"trackingId" : event.data.trackingId,
"callbackId": event.data.callbackId,
}, event.origin);
}
}
};
// => construct an iFrame selector from an array of ids
priv.assembleSelectorForService = function (selector) {
var targetWindow;
// for plain nested gadgets (no iFrame/sandbox) this will return
// only an empty array
// for iFrames/sandbox, selector will be an array of ids from
// which we have to construct our window element like so:
// http://bit.ly/12m3wJD
// http://mzl.la/17EeDiN
// final selector should look like this:
// window.frames["3a6b8d97"].contentWindow
// .frames["d63aca68"].contentWindow
// .frames["foo"].contentWindow
if (selector.length === 0) {
targetWindow = window;
} else {
try {
targetWindow = selector.reduce(function(tgt, o) {
return tgt && o[1] ?
tgt.frames[0] :
tgt.frames[o[0]].contentWindow || tgt.frames[o[0]];
}, window);
} catch (error) {
console.log(error);
}
}
return targetWindow;
}; };
// => request a service provided by a gadget // => request a service provided by a gadget
...@@ -595,10 +666,14 @@ ...@@ -595,10 +666,14 @@
event.data.type.split("/")[1] event.data.type.split("/")[1]
), ),
selector, selector,
targetWindow; targetWindow,
options;
if (callService) { if (callService) {
// services are stored by URL (not id), so we need to find the service // services are stored by URL (not id), because if inside an iFrame
// we cannot access the frame id, because of CORS.
// The only accessible parameter is the window.location.href URL, so
// services need to be stored with URL.
// 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(
...@@ -607,44 +682,41 @@ ...@@ -607,44 +682,41 @@
[] []
); );
// for plain nested gadgets (no iFrame/sandbox) this will return options = {
// only an empty array
// for iFrames/sandbox, selector will be an array of ids from
// which we have to construct our window element like so:
// http://bit.ly/12m3wJD
// http://mzl.la/17EeDiN
// final selector should look like this:
// window.frames["3a6b8d97"].contentWindow
// .frames["d63aca68"].contentWindow
// .frames["foo"].contentWindow
if (selector.length === 0) {
targetWindow = window;
} else {
try {
targetWindow = selector.reduce(function(tgt, o) {
return tgt && o[1] ?
tgt.frames[0] :
tgt.frames[o[0]].contentWindow || tgt.frames[o[0]];
}, window);
} catch (error) {
console.log(error);
}
}
// and request the service
targetWindow.postMessage({
"type": "run", "type": "run",
"trackingId": trackingId, "trackingId": trackingId,
"callbackId": event.data.callbackId, "callbackId": event.data.callbackId,
"service": event.data.service, "service": event.data.service,
"parameters": event.data.parameters "parameters": event.data.parameters,
}, event.origin); "url": callService.url || undefined
}
// we should not directly postMessage...
if (callService.url === "") {
targetWindow = priv.assembleSelectorForService(selector);
targetWindow.postMessage(options, event.origin);
} else {
// we need the selector array to construct our targetWindow
// because we cannot pass a window object through an ajax call...
options.selector = selector;
// let's go
$.ajax({
url: callService.url,
method: 'POST',
data: JSON.stringify(options),
error: function (jqXHR, textStatus, errorThrown) {
console.log("call to targetWindow failed: " + errorThrown);
},
// success: function (value, textStatus, jqXHR) {
// console.log("call to targetWindow successful");
// }
});
}
} }
}; };
// => check whether a service is available // => check whether a service is available
priv.findServiceInMap = function (requestedService, scope) { priv.findServiceInMap = function (requestedService, scope) {
// scope... use for ???
var i, var i,
service, service,
passback = null; passback = null;
...@@ -652,7 +724,13 @@ ...@@ -652,7 +724,13 @@
for (i = 0; i < that.gadgetService.map.length; i += 1) { for (i = 0; i < that.gadgetService.map.length; i += 1) {
service = that.gadgetService.map[i]; service = that.gadgetService.map[i];
if (service.rel === requestedService) { if (service.rel === requestedService) {
passback = service; if (scope) {
if (scope === service.scope) {
passback = service;
}
} else {
passback = service;
}
} }
} }
return passback; return passback;
...@@ -678,16 +756,6 @@ ...@@ -678,16 +756,6 @@
// => register gadget in index and tree // => register gadget in index and tree
priv.registerGadget = function (data, options) { priv.registerGadget = function (data, options) {
// create index
if (that.gadgetIndex === undefined) {
priv.createGadgetIndex();
}
// create tree
if (that.gadgetTree === undefined) {
priv.createGadgetTree();
}
// index ~ cache // index ~ cache
priv.addGadgetToIndex(data, options); priv.addGadgetToIndex(data, options);
...@@ -713,7 +781,8 @@ ...@@ -713,7 +781,8 @@
options = { options = {
"rel": service[j].rel, "rel": service[j].rel,
"type": service[j].type, "type": service[j].type,
"src": service[j].src || window.location.href.split("?")[0] "src": service[j].src || window.location.href.split("?")[0],
"url": ""
}; };
$(root).addService(options); $(root).addService(options);
} }
...@@ -800,7 +869,8 @@ ...@@ -800,7 +869,8 @@
"src": element.getAttribute("src") || "src": element.getAttribute("src") ||
window.location.href.split("?")[0], window.location.href.split("?")[0],
"type": element.getAttribute("type"), "type": element.getAttribute("type"),
"rel": element.getAttribute("rel") "rel": element.getAttribute("rel"),
"url": ""
}); });
} }
break; break;
...@@ -895,6 +965,12 @@ ...@@ -895,6 +965,12 @@
// 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 = priv.mapUrlString(window.location.search);
// create index
priv.createGadgetIndex();
// create tree
priv.createGadgetTree();
// all instances of renderJs should have an serviceMap // all instances of renderJs should have an serviceMap
priv.createServiceMap(spec); priv.createServiceMap(spec);
...@@ -932,19 +1008,22 @@ ...@@ -932,19 +1008,22 @@
callback = deferred; callback = deferred;
// store callback to be retrieved by response handler // store callback to be retrieved by response handler
priv.trackCallback(callbackId, callback, callbackFunction); if (callbackFunction) {
priv.trackCallback(callbackId, callback, callbackFunction);
// set a deferred, so the callback can run when everything is done
deferred.done(function(result, callbackFunction) {
if (callbackFunction) {
callbackFunction(result);
}
});
options.callbackId = callbackId;
}
// set type // set type
if (options.type === undefined) { if (options.type === undefined) {
options.type = "request/any"; options.type = "request/any";
} }
deferred.done(function(result, callbackFunction) {
if (callbackFunction) {
callbackFunction(result);
}
});
options.callbackId = callbackId;
window.top.postMessage(options, window.location.href); window.top.postMessage(options, window.location.href);
}; };
...@@ -1088,7 +1167,18 @@ ...@@ -1088,7 +1167,18 @@
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\//,
plumb_regexp = /^browser:\/\/plumb\/([\w\W]+)\//, plumb_regexp = /^browser:\/\/plumb\/([\w\W]+)\//,
key;
// 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]+)\//,
delegate_regexp = /^browser:\/\/delegate\/([\w\W]+)\//,
request_regexp = /^browser:\/\/request\/([\w\W]+)\//,
// vars
key, config, provider, param, value, targetWindow;
// 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];
if (this.method === "POST") { if (this.method === "POST") {
...@@ -1130,6 +1220,7 @@ ...@@ -1130,6 +1220,7 @@
'Content-Type': 'application/hal+json' 'Content-Type': 'application/hal+json'
}, JSON.stringify(response)); }, JSON.stringify(response));
// Session storage handler
} else if (ss_regexp.test(this.url)) { } else if (ss_regexp.test(this.url)) {
key = ss_regexp.exec(this.url)[1]; key = ss_regexp.exec(this.url)[1];
if (this.method === "POST") { if (this.method === "POST") {
...@@ -1162,22 +1253,20 @@ ...@@ -1162,22 +1253,20 @@
contents: [], contents: [],
} }
}; };
for (var key in sessionStorage){ for (var key in sessionStorage){
response._links.contents.push({href: 'browser://browse/ss/' + key}); response._links.contents.push({href: 'browser://browse/ss/' + key});
} }
this.respond(200, { this.respond(200, {
'Content-Type': 'application/hal+json' 'Content-Type': 'application/hal+json'
}, JSON.stringify(response)); }, JSON.stringify(response));
} else if (plumb_regexp.test(this.url)) { } else if (plumb_regexp.test(this.url)) {
console.log("PLUMB");
key = plumb_regexp.exec(this.url)[1]; key = plumb_regexp.exec(this.url)[1];
if (this.method === "POST") { if (this.method === "POST") {
if (key === "parentwindow") { if (key === "parentwindow") {
// XXX hardcoded * necessarity to send in case of file URL // as before...
// Fix needed!!!
window.parent.postMessage(this.requestBody, "*"); window.parent.postMessage(this.requestBody, "*");
this.respond(204, {}, ""); this.respond(204, {}, "");
} else { } else {
...@@ -1186,6 +1275,107 @@ ...@@ -1186,6 +1275,107 @@
} else { } else {
this.respond(405, {}, ""); this.respond(405, {}, "");
} }
// this looks up requests inside renderJs and
// triggers the respective postMessage
// should we use the key here or not and maybe pass the scope
// as parameter of the service object?
} else if (request_regexp.test(this.url)) {
// key = request_regexp.exec(this.url)[1];
if (this.method === "POST") {
// if (key === "map") {
config = JSON.parse(this.requestBody);
var options = {
"type":"request/" + config.scope,
"service" : config.service,
"parameters": config.parameters
};
window.postMessage(options, "*");
this.respond(204, {}, "");
//} else {
// this.respond(404, {}, "");
//}
} else {
this.respond(405, {}, "");
}
// this handles communication from child > parent
// using browser://call/{method}/{interaction/service}
} else if (call_regexp.test(this.url)) {
param = call_regexp.exec(this.url)[1].split("/")
key = param[0];
value = param[1];
if (this.method === "POST") {
if (key === "register") {
// still inside child frame
// add to tree, so lookup is possible when service is requested
config = JSON.parse(this.requestBody);
window.parent.postMessage({
"type": "tree/update",
"options": {
"id": config.self,
"src": config.src,
"children": []
}
}, "*");
// generate a url to be called once the service is requested
// this is a parent > child URL, so we delegate
// Need provider and rel here, because later we can remove
// from data being sent along with this URL
provider = config.self || "any";
// update config
config.url = 'browser://delegate/' + provider + '/' + config.rel
config.scope = value || "any";
// register service
window.parent.postMessage(config, "*");
this.respond(204, {}, "");
} else if (key === "service") {
// inside child frame, request service to be run
var sendToParent = "data://application/hal+json;base64," +
window.btoa(JSON.stringify({
_links: {
self: {href: this.url},
request: {href: this.requestBody}
}}));
window.parent.postMessage(sendToParent, "*");
} else {
this.respond(404, {}, "");
}
} else {
this.respond(405, {}, "");
}
// this handles communication from parent > child
// using browser://delegate/{window_id}/{interaction/service}
// the id is only to reconfirm, because for nested windows, we need
// to reconstruct the complate selector
} else if (delegate_regexp.test(this.url)) {
// key = delegate_regexp.exec(this.url)[1];
if (this.method === "POST") {
// if (key === "map") {
config = JSON.parse(this.requestBody);
// get the target
targetWindow = priv.assembleSelectorForService(config.selector);
// cleanup
delete config.selector;
// post, this will call both the internal and on page handler!
targetWindow.postMessage(config, "*");
this.respond(204, {}, "");
// } else {
// this.respond(404, {}, "");
// }
} else {
this.respond(405, {}, "");
}
} 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