drop support for legacy iframe
parent
311f709dc4
commit
9a733cca0e
@ -1,7 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<script src="respond.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
@ -1,173 +0,0 @@
|
|||||||
(function () {
|
|
||||||
|
|
||||||
var Frame = {};
|
|
||||||
|
|
||||||
var uid = function () {
|
|
||||||
return Number(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER))
|
|
||||||
.toString(32).replace(/\./g, '');
|
|
||||||
};
|
|
||||||
|
|
||||||
// create an invisible iframe with a given source
|
|
||||||
// append it to a parent element
|
|
||||||
// execute a callback when it has loaded
|
|
||||||
Frame.create = function (parent, src, onload, timeout) {
|
|
||||||
var iframe = document.createElement('iframe');
|
|
||||||
|
|
||||||
timeout = timeout || 10000;
|
|
||||||
var to = window.setTimeout(function () {
|
|
||||||
onload('[timeoutError] could not load iframe at ' + src);
|
|
||||||
}, timeout);
|
|
||||||
|
|
||||||
iframe.setAttribute('id', 'cors-store');
|
|
||||||
|
|
||||||
iframe.onload = function (e) {
|
|
||||||
onload(void 0, iframe, e);
|
|
||||||
window.clearTimeout(to);
|
|
||||||
};
|
|
||||||
// We must pass a unique parameter here to avoid cache problems in Firefox with
|
|
||||||
// the NoScript plugin: if the iframe's content is taken from the cache, the JS
|
|
||||||
// is not executed with NoScript....
|
|
||||||
iframe.setAttribute('src', src + '?t=' + new Date().getTime());
|
|
||||||
|
|
||||||
parent.appendChild(iframe);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* given an iframe with an rpc script loaded, create a frame object
|
|
||||||
with an asynchronous 'send' method */
|
|
||||||
Frame.open = function (e, A, timeout) {
|
|
||||||
var win = e.contentWindow;
|
|
||||||
|
|
||||||
var frame = {};
|
|
||||||
|
|
||||||
var listeners = {};
|
|
||||||
var timeouts = {};
|
|
||||||
|
|
||||||
timeout = timeout || 5000;
|
|
||||||
|
|
||||||
frame.accepts = function (o) {
|
|
||||||
return A.some(function (e) {
|
|
||||||
switch (typeof(e)) {
|
|
||||||
case 'string': return e === o;
|
|
||||||
case 'object': return e.test(o);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var changeHandlers = frame.changeHandlers = [];
|
|
||||||
|
|
||||||
frame.change = function (f) {
|
|
||||||
if (typeof(f) !== 'function') {
|
|
||||||
throw new Error('[Frame.change] expected callback');
|
|
||||||
}
|
|
||||||
changeHandlers.push(f);
|
|
||||||
};
|
|
||||||
|
|
||||||
var _listener = function (e) {
|
|
||||||
if (!frame.accepts(e.origin)) {
|
|
||||||
console.log("message from %s rejected!", e.origin);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var message = JSON.parse(e.data);
|
|
||||||
var uid = message._uid;
|
|
||||||
var error = message.error;
|
|
||||||
var data = message.data;
|
|
||||||
|
|
||||||
if (!uid) {
|
|
||||||
console.log("No uid!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uid === 'change' && changeHandlers.length) {
|
|
||||||
changeHandlers.forEach(function (f) {
|
|
||||||
f(data);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeouts[uid]) {
|
|
||||||
window.clearTimeout(timeouts[uid]);
|
|
||||||
}
|
|
||||||
if (listeners[uid]) {
|
|
||||||
listeners[uid](error, data, e);
|
|
||||||
delete listeners[uid];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
window.addEventListener('message', _listener);
|
|
||||||
|
|
||||||
frame.close = function () {
|
|
||||||
window.removeEventListener('message', _listener);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* method (string): (set|get|remove)
|
|
||||||
key (string)
|
|
||||||
data (string)
|
|
||||||
cb (function) */
|
|
||||||
var send = frame.send = function (method, key, data, cb) {
|
|
||||||
var req = {
|
|
||||||
method: method,
|
|
||||||
key: key,
|
|
||||||
data: data,
|
|
||||||
};
|
|
||||||
|
|
||||||
var id = req._uid = uid();
|
|
||||||
// uid must not equal 'change'
|
|
||||||
while(id === 'change') {
|
|
||||||
id = req._uid = uid();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof(cb) === 'function') {
|
|
||||||
//console.log("setting callback!");
|
|
||||||
listeners[id] = cb;
|
|
||||||
//console.log("setting timeout of %sms", timeout);
|
|
||||||
timeouts[id] = window.setTimeout(function () {
|
|
||||||
// when the callback is executed it will clear this timeout
|
|
||||||
cb('[TimeoutError] request timed out after ' + timeout + 'ms');
|
|
||||||
}, timeout);
|
|
||||||
} else {
|
|
||||||
console.log(typeof(cb));
|
|
||||||
}
|
|
||||||
|
|
||||||
win.postMessage(JSON.stringify(req), '*');
|
|
||||||
};
|
|
||||||
|
|
||||||
frame.set = function (key, val, cb) {
|
|
||||||
send('set', key, val, cb);
|
|
||||||
};
|
|
||||||
|
|
||||||
frame.setBatch = function (map, cb) {
|
|
||||||
send('batchset', void 0, map, cb);
|
|
||||||
};
|
|
||||||
|
|
||||||
frame.get = function (key, cb) {
|
|
||||||
send('get', key, void 0, cb);
|
|
||||||
};
|
|
||||||
|
|
||||||
frame.getBatch = function (keys, cb) {
|
|
||||||
send('batchget', void 0, keys, cb);
|
|
||||||
};
|
|
||||||
|
|
||||||
frame.remove = function (key, cb) {
|
|
||||||
send('remove', key, void 0, cb);
|
|
||||||
};
|
|
||||||
|
|
||||||
frame.removeBatch = function (keys, cb) {
|
|
||||||
send('batchremove', void 0, keys, cb);
|
|
||||||
};
|
|
||||||
|
|
||||||
frame.keys = function (cb) {
|
|
||||||
send('keys', void 0, void 0, cb);
|
|
||||||
};
|
|
||||||
|
|
||||||
return frame;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (typeof(module) !== 'undefined' && module.exports) {
|
|
||||||
module.exports = Frame;
|
|
||||||
} else if (typeof(define) === 'function' && define.amd) {
|
|
||||||
define(['jquery'], function () {
|
|
||||||
return Frame;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
window.Frame = Frame;
|
|
||||||
}
|
|
||||||
}());
|
|
@ -1,93 +0,0 @@
|
|||||||
var validDomains = [
|
|
||||||
/cryptpad.fr$/i,
|
|
||||||
];
|
|
||||||
|
|
||||||
var isValidDomain = function (o) {
|
|
||||||
return validDomains.some(function (e) {
|
|
||||||
switch (typeof(e)) {
|
|
||||||
case 'string': return e === o;
|
|
||||||
case 'object': return e.test(o);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var isArray = function (o) { return Object.prototype.toString.call(o) === '[object Array]'; };
|
|
||||||
|
|
||||||
window.addEventListener('message', function(e) {
|
|
||||||
if (!isValidDomain(e.origin)) { return; }
|
|
||||||
var payload = JSON.parse(e.data);
|
|
||||||
var parent = window.parent;
|
|
||||||
var respond = function (error, data) {
|
|
||||||
var res = {
|
|
||||||
_uid: payload._uid,
|
|
||||||
error: error,
|
|
||||||
data: data,
|
|
||||||
};
|
|
||||||
parent.postMessage(JSON.stringify(res), '*');
|
|
||||||
};
|
|
||||||
|
|
||||||
//console.log(payload);
|
|
||||||
|
|
||||||
switch(payload.method) {
|
|
||||||
case 'set':
|
|
||||||
localStorage.setItem(payload.key, JSON.stringify(payload.data));
|
|
||||||
respond();
|
|
||||||
break;
|
|
||||||
case 'batchset':
|
|
||||||
if (isArray(payload.data) || typeof(payload.data) !== 'object') {
|
|
||||||
respond('[batchset.TypeError] expected key-value pairs to set');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Object.keys(payload.data).forEach(function (k) {
|
|
||||||
localStorage.setItem(k, JSON.stringify(payload.data[k]));
|
|
||||||
});
|
|
||||||
respond();
|
|
||||||
break;
|
|
||||||
case 'get':
|
|
||||||
respond(void 0, JSON.parse(localStorage.getItem(payload.key)));
|
|
||||||
break;
|
|
||||||
case 'batchget':
|
|
||||||
if (!isArray(payload.data)) {
|
|
||||||
respond('[batchget.TypeError] expected array of keys to return');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var map = {};
|
|
||||||
payload.data.forEach(function (k) {
|
|
||||||
map[k] = JSON.parse(localStorage.getItem(k));
|
|
||||||
});
|
|
||||||
respond(void 0, map);
|
|
||||||
break;
|
|
||||||
case 'remove':
|
|
||||||
//console.log("Removing %s from localStorage", payload.key);
|
|
||||||
localStorage.removeItem(payload.key);
|
|
||||||
respond();
|
|
||||||
break;
|
|
||||||
case 'batchremove':
|
|
||||||
if (!isArray(payload.data)) {
|
|
||||||
respond('[batchremove.TypeError] expected array of keys to remove');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
payload.data.forEach(function (k) {
|
|
||||||
localStorage.removeItem(k);
|
|
||||||
});
|
|
||||||
respond();
|
|
||||||
break;
|
|
||||||
case 'keys':
|
|
||||||
respond(void 0, Object.keys(localStorage));
|
|
||||||
break;
|
|
||||||
case undefined:
|
|
||||||
respond('No method supplied');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener('storage', function (ev) {
|
|
||||||
parent.postMessage(JSON.stringify({
|
|
||||||
_uid: 'change',
|
|
||||||
data: {
|
|
||||||
key: ev.key,
|
|
||||||
oldValue: ev.oldValue,
|
|
||||||
newValue: ev.newValue,
|
|
||||||
}
|
|
||||||
}), '*');
|
|
||||||
});
|
|
@ -1,28 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<script data-main="test" src="/bower_components/requirejs/require.js"></script>
|
|
||||||
<style>
|
|
||||||
#status { border: 5px solid red; }
|
|
||||||
#status.working { border: 5px solid green; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<p>This page opens up an iframe which connects to beta.cryptpad.fr</p>
|
|
||||||
|
|
||||||
<p>the idea is that some other subdomain of cryptpad.fr should be able to use this technique to open up a connection
|
|
||||||
to beta.cryptpad.fr and read from its local storage, so that we can make a seamless transition from beta
|
|
||||||
to www. or *.cryptpad.fr.</p>
|
|
||||||
|
|
||||||
<div id="status">
|
|
||||||
<p>If this box turns green, you've configured your scripts correctly.</p>
|
|
||||||
|
|
||||||
<p>If your scripts are not working correctly, check that:
|
|
||||||
<ol>
|
|
||||||
<li>/customize/share/respond.js is configured to respond to requests from your domain (see the validDomains variable)</li>
|
|
||||||
<li>the script attempting to connect to this endpoint is configured to listen for responses from it (in this case main.js)</li>
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
@ -1,124 +0,0 @@
|
|||||||
define([
|
|
||||||
'jquery',
|
|
||||||
'/customize/share/frame.js'
|
|
||||||
], function ($, Frame) {
|
|
||||||
|
|
||||||
var domain = 'https://beta.cryptpad.fr';
|
|
||||||
|
|
||||||
var path = '/customize/share/frame.html';
|
|
||||||
|
|
||||||
var acceptResponseFrom = [
|
|
||||||
/cryptpad.fr$/
|
|
||||||
];
|
|
||||||
|
|
||||||
var lock = 0;
|
|
||||||
|
|
||||||
var unlock = function (i) {
|
|
||||||
lock--;
|
|
||||||
console.log("Test #%s passed", i + 1);
|
|
||||||
if (!lock) { $('#status').addClass('working'); }
|
|
||||||
};
|
|
||||||
|
|
||||||
var runTest = function (test, i) {
|
|
||||||
lock++;
|
|
||||||
test(i);
|
|
||||||
};
|
|
||||||
|
|
||||||
var randInt = function () {
|
|
||||||
return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
|
||||||
};
|
|
||||||
|
|
||||||
var handleErr = function (err) {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var areNull = function (keys, data) {
|
|
||||||
return !keys.some(function (k) { return data[k] !== null; });
|
|
||||||
};
|
|
||||||
|
|
||||||
Frame.create(document.body, domain + path, function (err, iframe) {
|
|
||||||
if (handleErr(err)) { return; }
|
|
||||||
console.log("Created iframe");
|
|
||||||
|
|
||||||
// open a channel into the frame, accept messages from (sub)domain(s)
|
|
||||||
var frame = window.Beta = Frame.open(iframe, acceptResponseFrom);
|
|
||||||
|
|
||||||
/* Run your actual tests */
|
|
||||||
|
|
||||||
[function (i) { // test #1
|
|
||||||
var pew = randInt();
|
|
||||||
frame.set('pew', pew, function (err) {
|
|
||||||
if (handleErr(err)) { return; }
|
|
||||||
frame.get('pew', function (err, num) {
|
|
||||||
if (handleErr(err)) { return; }
|
|
||||||
if (pew === num) {
|
|
||||||
frame.remove('pew', function (err) {
|
|
||||||
if (handleErr(err)) { return; }
|
|
||||||
|
|
||||||
frame.get('pew', function (err, data) {
|
|
||||||
if (handleErr(err)) { return; }
|
|
||||||
if (data !== null) { return; }
|
|
||||||
unlock(i);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, function (i) { // test #2
|
|
||||||
var map = {
|
|
||||||
bang: randInt(),
|
|
||||||
pow: randInt(),
|
|
||||||
lol: randInt(),
|
|
||||||
};
|
|
||||||
|
|
||||||
var keys = Object.keys(map);
|
|
||||||
|
|
||||||
frame.setBatch(map, function (err) {
|
|
||||||
if (handleErr(err)) { return; }
|
|
||||||
frame.getBatch(keys, function (err) {
|
|
||||||
if (handleErr(err)) { return; }
|
|
||||||
frame.removeBatch(Object.keys(map), function (err) {
|
|
||||||
if (handleErr(err)) { return; }
|
|
||||||
|
|
||||||
frame.getBatch(keys, function (err, data) {
|
|
||||||
if (areNull(keys, data)) { unlock(i); }
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, function (i) { // test #3
|
|
||||||
var map = {
|
|
||||||
bang2: true,
|
|
||||||
pow2: true,
|
|
||||||
lol2: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
var keys = Object.keys(map);
|
|
||||||
|
|
||||||
// set some keys to arbitrary values
|
|
||||||
frame.setBatch(map, function (err) {
|
|
||||||
if (handleErr(err)) { return; }
|
|
||||||
|
|
||||||
// remove those values
|
|
||||||
frame.removeBatch(keys, function (err) {
|
|
||||||
if (handleErr(err)) { return; }
|
|
||||||
|
|
||||||
// check that they were actually removed
|
|
||||||
frame.getBatch(keys, function (err, data) {
|
|
||||||
if (handleErr(err)) { return; }
|
|
||||||
|
|
||||||
// all keys should be null after you've removed them
|
|
||||||
if (areNull(keys, data)) {
|
|
||||||
unlock(i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("Expected all keys to return null");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}].forEach(runTest);
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in New Issue