686 lines
27 KiB
JavaScript
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);
|
|
})();
|