assets/js/frameCommunicator.js

686 lines
27 KiB
JavaScript

/*
Dieses Script wurde entwickelt von Mitja Stachowiak.
Fuer Details lesen Sie unter "http://www.mitjastachowiak.de/components/ecmascript/framecommunicator/index.html" nach.
*/
var selfScriptSource_huwheigif = document.getElementsByTagName('script')[document.getElementsByTagName('script').length-1].src;
var fapiStandard = 41;
// window.fapi und window.fapiFull werden am Ende des Scripts gesetzt
function getHostnameAndProtocol (loc) {
if (!loc) loc = '';
let i = loc.indexOf('?');
if (i < 0) i = loc.length;
let j = loc.indexOf('#');
if (j > 0 && j < i) i = j;
j = -1;
do {
j = loc.indexOf('\/', j+1);
} while (j >= 0 && !((j == 0 || loc.charAt(j-1) != '\/') && (j == loc.length-1 || loc.charAt(j+1) != '\/')));
if (j >= 0 && j < i) i = j;
let h = loc.substring(0,i);
return h;
}
function absolutePath (rel, absFrom) { // Diese Funktion wird nicht in diesem Script benoetigt, jedoch von vielen Scripts, die dieses verwenden.
if (!absFrom) absFrom = self.location.href;
let i = rel.indexOf('?');
if (i < 0) i = rel.length;
let j = rel.indexOf('#');
if (j >= 0 && j < i) i = j;
let Q = '';
if (i < rel.length) Q = rel.substring(i,rel.length);
rel = rel.substring(0,i); // ab hier: Querystring/Anker wurde von rel abgetrennt und in Q gespeichert
if (rel.indexOf(':') >= 0 && rel.charAt(0) != '\/') return rel+Q; // rel ist schon absolut;
i = absFrom.indexOf('?');
if (i < 0) i = absFrom.length;
j = absFrom.indexOf('#');
if (j >= 0 && j < i) i = j;
j = absFrom.lastIndexOf('/',i);
if (j >= 0 && j < i-1) i = j+1;
j = absFrom.lastIndexOf(':',i);
if (j > i) i = j+1;
absFrom = absFrom.substring(0,i); // ab hier: abs ist ohne Anker, Querystring und Dateiname
let host = getHostnameAndProtocol(absFrom);
if (rel.indexOf('/') == 0) return host + rel + Q; // rel ist relativ zu Root
while (rel.indexOf('./') == 0) rel = rel.substring(2,rel.length);
while (rel.indexOf('../') == 0) {
rel = rel.substring(3,rel.length);
j = absFrom.lastIndexOf('/',absFrom.length-2);
if (j >= host.length) absFrom = absFrom.substring(0,j+1);
}
if (absFrom.lastIndexOf('/') != absFrom.length-1) absFrom += '/'; // ab hier: fuer jedes ../ wurde ein Ordner von absFrom abgehaengt
return absFrom + rel + Q; // rel ist relativ zur Seite
}
function relativePath (abs, absFrom) {
if (!absFrom) absFrom = self.location.href;
let h = getHostnameAndProtocol(abs);
if (h == '' && abs.indexOf('\/') == 0) { // falls abs relativ zu Root ist, absolut machen
abs = absolutePath(abs, absFrom);
h = getHostnameAndProtocol(abs);
}
if (h == '') return abs; // abs ist schon relativ
if (h != getHostnameAndProtocol(absFrom)) return abs; // abs kann nicht relativ werden
let i = absFrom.length;
let j = absFrom.indexOf('#');
if (j != -1 && j < i) i = j;
j = absFrom.indexOf('?');
if (j != -1 && j < i) i = j;
j = (absFrom.indexOf('\/', h.length) == h.length)?h.length+1:h.length;
i = absFrom.lastIndexOf('\/', i);
let fromPath = new Array();
if (i > j) fromPath = absFrom.substring(j, i).split('\/'); // ab hier: fromPath besteht nur noch aus den Ordnern von absFrom
i = abs.length;
j = abs.indexOf('#');
if (j != -1 && j < i) i = j;
j = abs.indexOf('?');
if (j != -1 && j < i) i = j;
j = (abs.indexOf('\/', h.length) == h.length)?h.length+1:h.length;
i = abs.lastIndexOf('\/', i);
let targetPath = new Array();
if (i > j) targetPath = abs.substring(j, i).split('\/'); // ab hier: targetPath besteht nur noch aus den Ordnern von abs
if (abs.indexOf('\/', i) == i) i++;
let datQ = abs.substring(i, abs.length); // alles nach den Ordnern
i = 0;
while (targetPath.length > i && fromPath.length > i && targetPath[i] == fromPath[i]) i++;
let rel = '';
for (j = i; j < fromPath.length; j++) rel += '../';
for (j = i; j < targetPath.length; j++) rel += targetPath[j] + '/';
rel += datQ;
return rel;
}
function createScrollRectEventListener (el, callback, win) {
//console.log('ScrollRectListener startet for '+win.location.href+'!');
var o = new Object();
o.el = el;
o.el2 = (el.tagName.toLowerCase() == 'html')?((el.getElementsByTagName('body').length == 0)?null:el.getElementsByTagName('body')[0]):el; // wenn el == documentElement, versuche, body zum einhaengen von heihtGetter zu finden
o.callback = callback;
o.win = win;
o.lastH = -1;
o.lastW = -1;
o.pause = 0;
o.pauseTimer = null;
o.search = true;
o.padding = 0;
o.freed = false;
o.resize = function () {
if (o.freed) return;
if (o.pause != 0) { o.pause = 2; return; }
o.pause = 1;
o.pauseTimer = win.setTimeout(function () {
o.pauseTimer = null;
if (o.pause == 2) {
o.pause = 0;
o.resize();
} else o.pause = 0;
}, 50);
try { o.win.document.body.width = '500px'; } catch (e) {}
let w = o.el.scrollWidth;
let h = o.el.scrollHeight;
let wh = 0;
if (o.win) try { wh = o.win.innerHeight; } catch (e) {}
else wh = o.el.offsetHeight;
if (h > wh + 4) o.search = true; // nach Overflow max-Suche wiederholen
else if (o.el2) { // wenn scrollHeigt nicht groesser, als offsetHeight
if (!o.heightGetter) { // beim Erstaufruf heightGetter einfuegen
o.heightGetter = o.win.document.createElement('hr');
o.heightGetter.style.height = '1px'; // komisches null-height-Bug erkennen
o.heightGetter.style.margin = '0px';
o.heightGetter.style.visibility = 'hidden';
o.heightGetter.style.clear = 'both';
o.el2.appendChild(o.heightGetter);
o.max = o.heightGetter;
}
if (o.el2.lastChild != o.heightGetter) {
o.el2.removeChild(o.heightGetter);
o.el2.appendChild(o.heightGetter);
}
try {
h = o.max.offsetTop + o.max.offsetHeight;
if (isNaN(h)) {
h = -1;
o.search = true;
}
} catch (e) {
h = -1;
o.search = true;
}
if (h == 0) return; // null-height-Bug: Eine nicht mehr geladene Seite hat das Event ausgeloest
if (o.search) { // Tiefstes Element suchen und in o.max speichern
for (let i = 0; i < o.el2.childNodes.length; i++) {
let _el = o.el2.childNodes[i];
if (_el.nodeType != 1) continue;
let ch = _el.offsetTop + _el.offsetHeight;
try { ch += parseInt(o.win.getComputedStyle(_el).marginBottom); } catch (e) {}
if (!isNaN(ch) && ch > h) {
h = ch;
o.max = _el;
}
}
try {
o.padding = parseInt(o.win.getComputedStyle(o.max).marginBottom) + parseInt(o.win.getComputedStyle(o.el2).paddingBottom);
} catch (e) {
o.padding = 0;
}
if (isNaN(o.padding)) o.padding = 0;
o.search = false;
}
h += o.padding;
} else if (o.el.getElementsByTagName('body').length != 0) { // versuche body zu finden
o.el2 = o.el.getElementsByTagName('body')[0];
o.resize();
return;
}
if (Math.abs(h + 2 - o.lastH) <= 2 && Math.abs(w + 2 - o.lastW) <= 2) return; // keine Aenderung seit letztem Event
o.lastH = h;
o.lastW = w;
//console.log('New height for '+win.location.href+' = '+h);
o.callback(o.el, w, h);
}
// destructor
o.free = function () {
if (o.freed) return;
try { o.observer.disconnect(); } catch (e) {
o.el.removeEventListener('DOMNodeInserted', o.resize);
o.el.removeEventListener('DOMNodeRemoved', o.resize);
o.el.removeEventListener('DOMCharacterDataModified', o.resize);
o.el.removeEventListener('DOMAttrModified', o.resize);
o.el.removeEventListener('DOMContentLoaded', o.resize);
}
o.win.removeEventListener('resize', o.resize);
o.el.removeEventListener('overflow', o.resize);
o.el.removeEventListener('overflowchanged', o.resize);
if (o.pauseTimer) o.win.clearTimeout(o.pauseTimer);
o.win.clearInterval(o.timer);
if (o.heightGetter) o.el2.removeChild(o.heightGetter);
o.freed = true;
for (let key in o) if (typeof o[key] == 'object') o[key] = null;
}
// constructor
try {
o.observer = new MutationObserver(o.resize);
let config = { attributes: true, childList: true, characterData: true, subtree: true };
o.observer.observe(el, config);
} catch (e) {
el.addEventListener('DOMNodeInserted', o.resize, false);
el.addEventListener('DOMNodeRemoved', o.resize, false);
el.addEventListener('DOMCharacterDataModified', o.resize, false);
el.addEventListener('DOMAttrModified', o.resize, false);
el.addEventListener('DOMContentLoaded', o.resize, false);
}
o.win.addEventListener('resize', o.resize, false);
o.timer = o.win.setInterval(function () { o.search = true; o.resize() }, 10000);
el.addEventListener('overflow', o.resize, false);
el.addEventListener('overflowchanged', o.resize, false);
o.resize();
return o;
}
function hostsAreFromSameDomain (host1, host2) {
var hosts = ['', ''];
for (var i = 0; i < 2; i++) {
hosts[i] = getHostnameAndProtocol(arguments[i]).split('\/\/');
if (hosts[i].length == 2) hosts[i] = hosts[i][1]; // remove protocol if exists
else hosts[i] = hosts[i][0];
hosts[i] = hosts[i].split(':')[0]; // remove port if exists
hosts[i] = hosts[i].split('.');
}
return hosts[0].length > 0 && hosts[1].length > 0 && hosts[0][hosts[0].length-1] == hosts[1][hosts[1].length-1] && (hosts[0].length == 1 || hosts[1].length == 1 || hosts[0][hosts[0].length-2] == hosts[1][hosts[1].length-2]);
}
function FrameCommunicator (iframe, debugLogName='') {
this.debugLogName = debugLogName;
// protected
this.el = iframe;
this.el.communicator = this;
// restliche proterties stehen nach Konstruktor
// init
var _this = this;
window.addEventListener('message', function (msg) {
_this.interpretMessage.call(_this, msg);
}, false);
this.el.addEventListener('load', function () {
_this.debugLog('onload fired');
_this.checkForNewSite(2);
if (_this.onload) _this.onload(_this);
}, false);
}
FrameCommunicator.prototype = {
// private
currentLoc : null,
currentPostMsg : null,
resizeRepeatH : 0,
resizeRepeatW : 0,
currentSiteHasFapi : false,
debugLogName : '',
// public readonly
siteAllows : 0,
contentHeight : -1,
contentWidth : -1,
contentHostname : '',
contentURL : '',
contentTitle : '',
// public
onContentResize : null, // wenn frame-seite ihre Groesse aendert
onSiteReady : null, // wenn frame-seite geparst/geladen wurde - wie onload, aber eventuell frueher, noch vor DOMReady
onURLChanged : null, // wenn frame-seite ihre URL aendert
onTitleChanged : null, // wenn frame-seite ihren Titel aendert
onload : null, // wenn frame-seite geladen - wie iframe.onload, wird jedoch erst aufgerufen, wenn Seitenhoehe bekannt ist
_autoHeight : false, get autoHeight () { return this._autoHeight; }, set autoHeight (v) { this._autoHeight = v; if (v) this.el.style.height = (this.contentHeight >= 0)?(this.contentHeight+'px'):this.autoHeightValue; },
_autoWidth : false, get autoWidth () { return this._autoWidth; }, set autoWidth (v) { this._autoWidth = v; if (v) this.el.style.width = (this.contentWidth >= 0)?(this.contentWidth+'px'):this.autoWidthValue; },
autoHeightValue : '100%',
autoWidthValue : '100px'
}
FrameCommunicator.prototype.checkForNewSite = /* private */ function (load, knownURL) {
if (load & 1 != 0) this.currentSiteHasFapi = true;
try { if (this.currentDoc != this.el.contentWindow.document.documentElement) { this.newSite(knownURL); return; } } catch (e) {
try {
if (this.el.contentWindow && this.currentLoc != this.el.contentWindow.location) {
this.newSite(knownURL);
return;
}
} catch (e) {}
if (this.el.contentWindow.postMessage == this.el.contentWindow.postMessage && this.currentPostMsg != this.el.contentWindow.postMessage) this.newSite(knownURL);
else if (load & 2 != 0 && this.el.contentWindow.postMessage != this.el.contentWindow.postMessage) this.newSite(knownURL);
}
}
FrameCommunicator.prototype.setSrc = /* public */ function (url) {
try {
el.contentWindow.location.replace(url); // tries to change URL without browser history change
} catch (e) {
this.el.src = url;
}
this.checkForNewSite(0, url);
}
FrameCommunicator.prototype.newSite = /* private */ function (knownURL) {
this.debugLog('New site detected...');
this.currentLoc = this.el.contentWindow.location;
this.currentPostMsg = this.el.contentWindow.postMessage;
try { this.currentDoc = this.el.contentWindow.document.documentElement; } catch (e) { this.currentDoc = null; }
// Informationen ueber Seite loeschen
this.contentHeight = -1;
this.contentWidth = -1;
this.contentHostname = (knownURL)?getHostnameAndProtocol(knownURL):'';
this.contentURL = (knownURL)?knownURL:'';
this.siteAllows = 0;
this.contentHeight = -1;
this.contentWidth = -1;
this.contentTitle = '';
// Events ausfuehren
if (this.onSiteReady) this.onSiteReady();
if (this.onContentResize) this.onContentResize(this.contentWidth, this.contentHeight);
if (this.onURLChanged) this.onURLChanged(this.contentHostname, this.contentURL);
if (this.onTitleChanged) this.onTitleChanged(this.contentTitle);
// Versuchen, neue Informationen zu bekommen / FrameAPI in der Seite zu erzeugen
try {
if (this.el.contentWindow.fapi) {
this.debugLog('Site is on same location ('+this.el.contentWindow.location.href+') and has fapi. Allow all messages...');
this.el.contentWindow.fapi.setTarget(this);
this.el.contentWindow.fapi.setAllowed(65535);
} else if (this.el.contentWindow.document.documentElement) {
this.debugLog('Site is on same location ('+this.el.contentWindow.location.href+') and has no fapi. Create fapi with all messages...');
let scr = this.el.contentWindow.document.createElement('script');
scr.src = selfScriptSource_huwheigif;
this.el.contentWindow.document.body.appendChild(scr);
}
} catch (e) {}
}
FrameCommunicator.prototype.checkForNewHostname = /* private */ function (host) {
try { host = getHostnameAndProtocol(this.el.contentWindow.location.href); } catch (e) {}
if (this.contentHostname == host) return;
this.contentHostname = host;
this.debugLog('New Hostname detected: '+this.contentHostname);
if (this.contentURL.indexOf(host) != 0) this.contentURL = '';
if (this.onURLChanged) this.onURLChanged(this.contentHostname, this.contentURL);
}
FrameCommunicator.prototype.interpretMessage = /* private */ function (msg) {
if (msg.source != this.el.contentWindow) {
this.debugLog('Message "'+msg.data+'" dropped because from wrong source!');
return;
} else this.debugLog('Message "'+msg.data+'" accepted!');
var data = msg.data.split('&');
this.checkForNewSite(1);
this.checkForNewHostname(msg.origin);
switch (data[0]) {
case 'FrameCommunicator' :
this.setState((data.length > 0)?parseInt(data[1]):0);
break;
case 'mousedown' :
var x = undefined;
var y = undefined;
if (data.length >= 3) {
x = parseInt(data[1]);
y = parseInt(data[2]);
}
this.raiseMouseEvent('mousedown', x, y);
break;
case 'mouseup' :
var x = undefined;
var y = undefined;
if (data.length >= 3) {
x = parseInt(data[1]);
y = parseInt(data[2]);
}
this.raiseMouseEvent('mouseup', x, y);
break;
case 'click' :
this.raiseMouseEvent('click');
break;
case 'resize' :
this.resize(parseInt(data[1]), parseInt(data[2]));
break;
case 'URLchange' :
if (data.length < 2) break;
var url = decodeURIComponent(data[1]);
var fromSameOrigin = false;
try { if (this.el.contentWindow.document) fromSameOrigin = true; } catch (e) {}
if (fromSameOrigin || msg.origin == getHostnameAndProtocol(url)) this.newURL(url);
break;
case 'TitleChange' :
if (data.length < 2) break;
this.setTitle(decodeURIComponent(data[1]));
break;
case 'mousewheel' :
this.raiseMouseEvent('mousewheel', parseInt(data[1]));
break;
}
}
FrameCommunicator.prototype.raiseMouseEvent = /* protected */ function (type, x, y) {
this.checkForNewSite(1);
if (type == 'click') this.siteAllows |= 4;
if (type == 'mousedown') this.siteAllows |= 8;
if (type == 'mouseup') this.siteAllows |= 16;
if (type == 'mousewheel') this.siteAllows |= 512;
if (document.dispatchEvent) {
var ev;
// Bei MouseEvent sind offsetX/Y und pageX/y nicht ueberschreibbar! daher document.createEvent().
ev = document.createEvent("Events");
ev.initEvent(type, true, true);
if (type == 'mousewheel') {
ev.wheelDelta = x;
} else if (!isNaN(x) && !isNaN(x)) { // falls gegeben, Cursorposition an Event haengen
this.siteAllows |= 2;
ev.offsetX = x;
ev.offsetY = y;
p = this.el;
do {
x += p.offsetLeft;
y += p.offsetTop;
p = p.offsetParent;
} while (p);
ev.pageX = x;
ev.pageY = y;
}
this.el.dispatchEvent(ev);
} else {
var ev = document.createEventObject();
this.el.fireEvent('on' + type, ev);
}
}
FrameCommunicator.prototype.debugLog = /* private */ function (msg) {
if (this.debugLogName == '') return;
var d = new Date();
console.log('['+d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate()+' '+d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds()+'] Frame "'+this.debugLogName+'": '+msg);
}
FrameCommunicator.prototype.setState = /* protected */ function (_allowed) {
this.checkForNewSite(1);
this.siteAllows = _allowed;
}
FrameCommunicator.prototype.resize = /* protected */ function (w, h) {
if (isNaN(w)) w = -1;
if (isNaN(h)) h = -1;
this.debugLog('Resize w='+w+' h='+h);
this.checkForNewSite(1);
if (this.contentWidth == w && this.contentHeight == h) return;
if (w != -1) this.siteAllows |= 64;
if (h != -1) this.siteAllows |= 32;
this.contentWidth = w;
this.contentHeight = h;
if (h >= 0 && this.autoHeight) {
var ch = this.el.offsetHeight;
if (h + 15 <= ch) this.resizeRepeatH++;
if (this.resizeRepeatH > 5) return; // Rekursion verhindern
if (h + 10 > ch || h < ch + 20) this.el.style.height = h + 15 + 'px';
if (this.resizeRepeatHTimer) window.clearTimeout(this.resizeRepeatHTimer);
var _this = this;
this.resizeRepeatHTimer = window.setTimeout(function () { _this.resizeRepeatH = 0; }, 100);
} else if (this.autoHeight) this.el.style.height = this.autoHeightValue;
if (w >= 0 && this.autoWidth) {
var cw = this.el.offsetWidth;
if (w <= cw) this.resizeRepeatW++;
if (this.resizeRepeatW > 5) return; // Rekursion verhindern
if (w > cw || w < cw - 5) this.el.style.width = w + 'px';
if (this.resizeRepeatWTimer) window.clearTimeout(this.resizeRepeatWTimer);
var _this = this;
this.resizeRepeatWTimer = window.setTimeout(function () { _this.resizeRepeatW = 0; }, 100);
} else if (this.autoWidth) this.el.style.width = this.autoWidthValue;
if (this.onContentResize) this.onContentResize(w, h);
}
FrameCommunicator.prototype.newURL = /* protected */ function (url) {
this.checkForNewSite(1);
if (!url) url = '';
if (url != '') this.siteAllows |= 128;
this.contentHostname = getHostnameAndProtocol(url);
this.contentURL = url;
if (this.onURLChanged) this.onURLChanged(this.contentHostname, this.contentURL);
}
FrameCommunicator.prototype.setTitle = /* protected */ function (title) {
this.checkForNewSite(1);
this.siteAllows |= 256;
this.contentTitle = title;
if (this.onTitleChanged) this.onTitleChanged(title, this);
}
function FrameAPI (__allowed, _target) {
// private
var win = (_target)?_target.el.contentWindow:window;
if (win.fapi) return win.fapi;
win.fapi = this;
var target = _target;
var allowed = 0;
var evListeners = new Object();
var _this = this;
var lastURL = '';
var autoFrameSize = false;
var debugLog = /* private */ function (msg) {
if (!target || target.debugLogName == '') return;
var d = new Date();
console.log('['+d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate()+' '+d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds()+'] Frame "'+target.debugLogName+'": '+msg);
};
var mouseevent = /* private */ function (ev, type) {
if (!ev) ev = win.event;
if (type == 'DOMMouseScroll') type = 'mousewheel';
var msg = [type];
if (type == 'mousewheel') msg.push(ev.wheelDelta || -ev.detail);
else if ((allowed & 2) && type != 'click') {
msg.push(ev.clientX);
msg.push(ev.clientY);
}
if (target) target.raiseMouseEvent.apply(target, msg);
else win.parent.postMessage(msg.join('&'), '*');
};
var postState = /* private */ function () {
/*if (target) target.setState(allowed);
else */win.parent.postMessage('FrameCommunicator&'+allowed, '*');
};
var resize = /* private */ function (el, w, h) {
try { if (autoFrameSize) return; } catch (e) { return; }
if (!(allowed & 32) || isNaN(h)) h = -1;
if (!(allowed & 64) || isNaN(w)) w = -1;
/*if (target) target.resize(w, h);
else */win.parent.postMessage('resize&'+w+'&'+h, '*');
};
var sendURL = /* private */ function () {
if (lastURL == win.location.href) return;
lastURL = win.location.href;
/*if (target) target.newURL(lastURL);
else */win.parent.postMessage('URLchange&'+encodeURIComponent(lastURL), '*');
};
var sendTitle = /* private */ function () {
/*if (target) target.setTitle(win.document.title);
else */win.parent.postMessage('TitleChange&'+encodeURIComponent(win.document.title), '*');
};
var redirectLink = /* private */ function (a) {
if (a.href.indexOf('http') != 0) return;
var hp = getHostnameAndProtocol(a.href);
};
this.setTarget = /* public */ function (_target) {
target = _target;
};
this.overrideAutoFrameSize = /* public */ function () {
autoFrameSize = true;
/*if (target) target.resize(-1, -1);
else */win.parent.postMessage('resize&-1&-1', '*');
};
this.redirectLinks = /* public */ function () {
var observer = new MutationObserver(function(mutationsList, observer) {
for (let mutation of mutationsList)
if (mutation.type === 'childList')
for (let i = 0; i < mutation.addedNodes.length; i++)
if (mutation.addedNodes[i].nodeType == 1 && mutation.addedNodes[i].tagName == 'a')
redirectLink(mutation-addedNodes[i]);
});
observer.observe(document.documentElement, { childList: true, subtree: true });
let a = document.documentElement.getElementsByTagName('a');
for (var i = 0; i < a.length; i++)
redirectLink(a[i]);
};
this.setAllowed = /* public */ function (_allowed) {
if (allowed == _allowed) {
//if (evListeners['resize']) evListeners['resize'].resize();
debugLog('New allowed flags ignored, because already set ('+win.location.href+').');
return;
}
if (win.parent == win) {
debugLog('New allowed flags ignored, because not in frame ('+win.location.href+').');
return;
}
allowed = _allowed;
debugLog('New allowed flags accepted ('+win.location.href+').');
function addListener (name, type, f, el, b) {
if (evListeners[name]) return;
if (!el) el = win.document;
var ev = new Object();
ev['event'] = type;
ev['el'] = el;
ev['fkt'] = function (ev) { f.call(_this, ev, type); }
el.addEventListener(type, ev['fkt'], b);
evListeners[name] = ev;
}
function rmListener (name) {
if (!evListeners[name]) return;
evListeners[name]['el'].removeEventListener(evListeners[name]['event'], evListeners[name]['fkt']);
delete evListeners[name];
}
if (allowed & 1) { postState(); addListener('postState', 'load', postState, win); } else rmListener('postState');
if (allowed & 4) addListener('mouseeventC', 'click', mouseevent); else rmListener('mouseeventC');
if (allowed & 8) addListener('mouseeventD', 'mousedown', mouseevent); else rmListener('mouseeventD');
if (allowed & 16) addListener('mouseeventU', 'mouseup', mouseevent); else rmListener('mouseeventU');
if (allowed & 96) { if (!evListeners['resize']) evListeners['resize'] = createScrollRectEventListener(win.document.documentElement, resize, win); }
else { if (evListeners['resize']) { evListeners['resize'].free(); delete evListeners['resize']; } }
if (allowed & 128) {
lastURL = '';
sendURL();
addListener('sendURLL', 'load', sendURL, win);
addListener('sendURLH', 'hashchange', sendURL, win);
addListener('sendURLP', 'popstate', sendURL, win);
try { // bekanntes Bug: Das abhoeren von replaceState und PushState funktioniert nach reload der Seite nicht!
if (!evListeners['OldPushState']) { evListeners['OldPushState'] = win.history.pushState; win.history.pushState = function (obj, title, url) { evListeners['OldPushState'].call(win.history, obj, title, url); sendURL(); }; }
if (!evListeners['OldReplaceState']) { evListeners['OldReplaceState'] = win.history.replaceState; win.history.replaceState = function (obj, title, url) { evListeners['OldReplaceState'].call(win.history, obj, title, url); sendURL(); }; }
} catch (e) {}
} else {
rmListener('sendURLL');
rmListener('sendURLH');
rmListener('sendURLP');
try {
if (evListeners['OldPushState']) { win.history.pushState = evListeners['OldPushState']; delete evListeners['OldPushState']; }
if (evListeners['OldReplaceState']) { win.history.replaceState = evListeners['OldReplaceState']; delete evListeners['OldReplaceState']; }
} catch (e) {}
}
if (allowed & 256) {
sendTitle();
addListener('sendTitleL', 'load', sendTitle, win);
try {
if (!evListeners['titleObserver']) {
evListeners['titleObserver'] = new MutationObserver(sendTitle);
var config = { childList: true };
evListeners['titleObserver'].observe(win.document.getElementsByTagName('title')[0], config);
}
} catch (e) { addListener('sendTitleI', 'DOMNodeInserted', sendTitle, win.document.getElementsByTagName('title')[0]); }
} else {
rmListener('sendTitleL');
try {
if (evListeners['titleObserver']) {
evListeners['titleObserver'].disconnect();
delete evListeners['titleObserver'];
}
} catch (e) { rmListener('sendTitleI'); }
}
if (allowed & 512) {
addListener('sendMousewheel1', 'mousewheel', mouseevent, win.document);
addListener('sendMousewheel2', 'DOMMouseScroll', mouseevent, win.document);
} else {
rmListener('sendMousewheel1');
rmListener('sendMousewheel2');
}
}
// init
if (__allowed) this.setAllowed(__allowed);
}
function fapiIndexLocation (loc) {
if (navigator.userAgent.indexOf(' Atom\/') >= 0) return; // keep simple site without frame in Atom-preview
if (/bot|googlebot|bingbot|crawler|spider|robot|crawling/i.test(navigator.userAgent)) return; // don't forward crawlers!
if (loc != '' && parent == self)
parent.location.href = absolutePath(loc, self.location.href) + '?' + self.location.href;
}
(function () {
let fapiAllowed = fapiStandard;
try {
if (parent.fapi) fapiAllowed = 65535;
} catch (e) { }
if (!window.fapi) new FrameAPI(fapiAllowed);
})();