You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

160 lines
4.4 KiB
JavaScript

2 weeks ago
/** IFrame API
* @constructor
* @param {Window} win
* @param {number} id
* @param {string} targetOrigin
* @internal
*/
var MapIFrameAPI = function(win, id, targetOrigin) {
// IFrame
this.win = win;
// API id
this.id = id;
//
this.targetOrigin = targetOrigin;
// Callback counter
this.counter = 0;
// List of function
this.fn = {
on: function(key, fn) {
return this.addIFrameListener(key, fn);
}.bind(this),
un: function(listener) {
return this.removeIFrameListener(listener);
}.bind(this),
mapInput: function(key, input, value) {
if (!(input instanceof Element)) {
input = document.getElementById(input);
}
if (input.tagName==='INPUT') {
if (value) input.value = value;
// Set change
this.addIFrameListener(key, function(data) {
input.value = data;
}, value);
// Get input change
input.addEventListener('change', function() {
this.call(key, input.value);
}.bind(this));
}
}.bind(this)
};
// list of listener
this.listener = {};
// Get API fn
window.addEventListener('message', function(e) {
if (e.data.id === this.id && e.data.api === 'getAPI') {
var name = e.data.data;
name.forEach(function(n) {
this.fn[n] = function(data, fn) {
this.call(n, data, fn);
}.bind(this)
}.bind(this));
}
}.bind(this), false);
};
/**
* @param {string} key api function
* @param {Object|function} data argments or a callback function to get returned Transferable
* @param {function} fn callback function to get returned Transferable
*/
MapIFrameAPI.prototype.call = function(key, data, fn) {
if (typeof(data)==='function') {
fn = data;
data = undefined;
}
if (typeof(fn) === 'function') {
var n = this.counter++;
var listener = function(e) {
if (e.data.id === this.id && e.data.counter === n) {
fn.call(this, e.data.data);
window.removeEventListener('message', listener);
}
}.bind(this);
window.addEventListener('message', listener, false);
this.win.postMessage({
api: key,
id: this.id,
counter: n,
data: data
}, this.targetOrigin);
} else {
this.win.postMessage({
api: key,
id: this.id,
data: data
}, this.targetOrigin);
}
};
/** Add iframe listener
* @param {string} key event key
* @param {function} fn callback function
* @return {function} IFrameListener
*/
MapIFrameAPI.prototype.addIFrameListener = function(key, fn, data) {
var callback = function(e) {
if (e.data.id === this.id && e.data.api === key) {
fn.call(this, e.data.data);
}
}.bind(this)
window.addEventListener('message', callback, false);
if (!this.listener[key]) {
this.listener[key] = data;
}
return callback;
};
/** Remove iframe listener
* @param {function} listener IFrameListener
*/
MapIFrameAPI.prototype.removeIFrameListener = function(listener) {
window.removeEventListener('message', listener, false);
};
MapIFrameAPI.prototype.idAPI = 1;
/** Get API whenready
* @param {string|Element} iframe the iframe or the iframe ID
* @param {function} ready a function that takes an api as first argument
* @param {string} targetOrigin
*/
MapIFrameAPI.ready = function(iframe, ready, targetOrigin) {
console.log('ready')
var idAPI = MapIFrameAPI.prototype.idAPI++;
targetOrigin = targetOrigin || '*';
var iframeWin;
if (typeof(iframe)==='string') {
iframeWin = document.getElementById(iframe).contentWindow;
} else {
iframeWin = iframe.contentWindow;
}
if (!iframeWin) {
console.error('ERROR: Can\'t access iframe content');
return;
}
function onready(e) {
if (e.data.api==='ready') {
if (!e.data.id) {
iframeWin.postMessage({
api: 'ready',
id: idAPI
}, targetOrigin);
} else if (e.data.id===idAPI) {
var api = new MapIFrameAPI(iframeWin, idAPI, targetOrigin);
window.removeEventListener('message', onready);
api.call('getAPI', null, function() {
ready(api.fn);
// register listeners
for (var k in api.listener) {
api.win.postMessage({
listener: k,
data: api.listener[k]
}, targetOrigin);
}
});
}
}
}
window.addEventListener('message', onready, false);
iframeWin.postMessage({
api: 'ready'
}, targetOrigin);
};