1037 lines
46 KiB
JavaScript
1037 lines
46 KiB
JavaScript
/*
|
|
Dieses Script wurde geschrieben von Mitja Stachowiak (www.mitjastachowiak.de)
|
|
Es benoetigt ausserdem frameCommunicator.js.
|
|
|
|
Dokumentation unter http://www.mitjastachowiak.de/code/js/dynamicIFrame
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
function getTickCount () { // returns the milliseconds since beginning of the current year
|
|
var T = new Date();
|
|
return T.getMilliseconds() + T.getSeconds() * 1000 + T.getMinutes() * 60000 + T.getHours() * 3600000 + T.getDay() * 86400000;
|
|
}
|
|
function createOverscrollListener (doc, wait, callback) {
|
|
var o = new Object();
|
|
o.doc = doc;
|
|
o.lastScroll = 0;
|
|
o.lastTry = 0;
|
|
o.lastInnerWidth = window.innerWidth;
|
|
o.wait = wait / 2;
|
|
o.callback = callback;
|
|
o.scrollFkt = function () {
|
|
o.lastScroll = getTickCount();
|
|
}
|
|
o.scrollEventFkt = function (ev) {
|
|
if (getTickCount() < o.lastScroll + o.wait) { o.lastTry = 0; return; }
|
|
if (o.lastTry == 0) o.lastTry = getTickCount();
|
|
if (getTickCount() < o.lastTry + o.wait) { o.lastInnerWidth = window.innerWidth; return; }
|
|
if (o.lastInnerWidth != window.innerWidth) { o.lastInnerWidth = window.innerWidth; return; }
|
|
o.lastTry = 0;
|
|
if (!ev) ev = window.event;
|
|
var dir = ev.wheelDelta || -ev.detail;
|
|
if (!callback) return;
|
|
if (dir) { o.callback(dir < 0); return; }
|
|
if (window.pageYOffset > 0) { o.callback(true); return; }
|
|
if (ev.keyCode) { o.callback(ev.keyCode == 40); return; }
|
|
}
|
|
o.free = function () {
|
|
o.doc.removeEventListener('scroll', o.scrollFkt, false);
|
|
o.doc.removeEventListener('DOMMouseScroll', o.scrollEventFkt, false);
|
|
o.doc.removeEventListener('mousewheel', o.scrollEventFkt, false);
|
|
o.doc.removeEventListener('keypress', o.scrollEventFkt, false);
|
|
o.callback = null;
|
|
o.doc = null;
|
|
o = null;
|
|
}
|
|
// EventListener setzen
|
|
var d = o.doc;
|
|
var _d = null;
|
|
while (d && d != _d) {
|
|
try {
|
|
_d = d;
|
|
d.addEventListener('scroll', o.scrollFkt, false);
|
|
d = d.defaultView.parent.document;
|
|
} catch (e) { break; }
|
|
}
|
|
o.doc.addEventListener('DOMMouseScroll', o.scrollEventFkt, false);
|
|
o.doc.addEventListener('mousewheel', o.scrollEventFkt, false);
|
|
o.doc.addEventListener('keypress', o.scrollEventFkt, false);
|
|
return o;
|
|
}
|
|
|
|
|
|
/*
|
|
Dies sind zwei standard-Effekte. Diese koennen Sie als Vorlage fuer eigene Effekte verwenden
|
|
|
|
Parameter:
|
|
el : iframe-Element
|
|
s : Wert zwischen 0 und 1; Ausnahme -1 (0 = Effekt beginnt, 0.5 = Effekt ist bei der Haelfte, 1 = Effekt ist fertig, -1 = saemtliche von diesem Effekt benutzten css-Eigenschaften zuruecksetzen)
|
|
blendIn : Wenn true, soll das iframe eingeblendet werden, ansonsten ausgeblendet
|
|
*/
|
|
|
|
function EffectBlend (el, s, blendIn) {
|
|
if (s < 0) { el.style.opacity = 1; return; }
|
|
if (!blendIn) s = 1-s;
|
|
el.style.opacity = s;
|
|
}
|
|
|
|
function EffectBlendAndSlide (el, s, blendIn) {
|
|
if (s < 0) { el.style.marginTop = '0px'; el.style.opacity = 1; return; }
|
|
if (!blendIn) s = 1-s;
|
|
el.style.opacity = s;
|
|
el.style.marginTop = -100 * (1-s) * (1-s) + 'px';
|
|
}
|
|
|
|
function EffectAppendAndSlide (el1, el2, s, dir) {
|
|
if (s < 0) {
|
|
el1.style.marginTop = '0px';
|
|
el2.style.marginTop = '0px';
|
|
el1.parentElement.style.overflow = 'visible';
|
|
return;
|
|
}
|
|
el1.parentElement.style.overflow = 'hidden';
|
|
if (dir) {
|
|
el1.style.marginTop = -el1.offsetHeight * (1-s);
|
|
el2.style.marginTop = el1.offsetHeight * (s);
|
|
} else {
|
|
el2.style.marginTop = -el2.offsetHeight * (s);
|
|
el1.style.marginTop = el2.offsetHeight * (1-s);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
Dieses Objekt darf nur einmal in einem HTML-Dokument erstellt werden und erlaubt, das Laden von Seiten in einem iframe mit Effekt zu versehen.
|
|
|
|
Parameter:
|
|
FrameBox : ein DIV-Element, das genau 2 iframes enthaellt. Jedes IFrame benoetigt ein eindeutriges name-Attribut. Nur so kann die Kompatibilitaet mit Links ohne JavaScript gewaehrleistet werden (<A href="frameSeite.html" target="frameName">).
|
|
|
|
Eigenschaften und Funktionen:
|
|
whitelist : Array aus RegExp-Objekten. Alle Seiten, die im Frame geladen werden sollen, muessen entweder von der gleichen Domain sein, oder auf die Whitelist passen
|
|
addURLToWhitelist : Wandelt die uebergebene URL in ein RegExp-Objekt um und fuegt sie der whitelist hinzu. In der URL sind *-Zeichen erlaubt. Innerhalb des Hostname-Bereiches haben diese jedoch spezielle Aufgaben und es kann nicht jede beliebige Zeichenfolge fuer ein * stehen.
|
|
differentQueryDifferentSites : Boolean - wenn true, dann werden Menuelinks nur hervorgehoen, wenn auch das QUerystring des Menuelinks und der Seite im Frame gleich ist.
|
|
whitelist : Array aus Strigs (Darf Platzhalter (*) enthalten). Nur Seiten, die in dieses Profil passen, duerfen im Frame geladen werden. Seiten von der eigenen Domain duerfen immer geladen werden.
|
|
maxWaitForSite : diese Zeit (ms) wird maximal gewartet, bis die neue Seite eingeblendet wird. Ist die Seite bis dahin nicht vollstaendig geladen, kann der Besucher beobachten, wie sie im iframe fertig laedt.
|
|
blendOutTime : Dauer des Ausblendens (ms)
|
|
blendInDelay : Verzoegerung - so viele Millisekunden nach Beginn des Ausblendens beginnt das Einblenden
|
|
blendInTime : Dauer des Einblendens (ms)
|
|
blendInEffect : Uebergeben Sie hier die Effekt-Funktion fuer das Einblenden
|
|
blendOutEffect : Uebergeben Sie hier die Effekt-Funktion fuer das Ausblenden
|
|
function loadSite : Rufen Sie diese Funktion mit einer URL auf, um diese URL mit Effekt in den iframe zu laden (Die Seite wird nur geladen, wenn sie von der gleichen Domain ist oder auf die Whitelist passt)
|
|
function scrollTo : uebergeben werden kann eine y-Koordinate aus Sicht des aktuellen Iframes oder der Name eines Ankers innerhalb des aktuellen Iframes. ScrollTo scrollt dann zu diesem Ziel. Ein zweiter Parameter darf nur vom Objekt selbst uebergeben werden.
|
|
autoFillMenu : Falls die Menu-Links ein Inhaltsverzeichnis darstellen, kann fuer autoFillMenu eine Zahl eingesetzt werden, bis zu der H*-Elemente der Frame-Seite gescant und automatisch im Inhaltsverzeichnis ergaenzt werden. Ein Wert von 3 z.B. bedeutet, dass fuer alle H1, H2 und H3-Elemente automatisch Links im Inhaltsverzeichnis beim Laden der Seite angelegt werden.
|
|
*/
|
|
function DynamicIFrame (FrameBox, debugLogging=false) { with (this) {
|
|
// private
|
|
var box = FrameBox;
|
|
var frames = FrameBox.getElementsByTagName('iframe');
|
|
var current = 0;
|
|
var next = 1;
|
|
var communicators = new Array();
|
|
var aTarget, aTarget2;
|
|
var isAutoFrameHeight = true;
|
|
var menuLinks = new Array();
|
|
var printLinks = new Array();
|
|
var blendInfo = new Object();
|
|
var scrollInfo = new Object();
|
|
var autoHeightEl = new Array(); // Alle Elemente, deren NoJsHeight-Classname gesetzt/entfernt wird
|
|
var loadWithoutEffect = false;
|
|
var startPage = '';
|
|
var incompatibleBrowser = false;
|
|
var domWasReady = false;
|
|
var selfHostname;
|
|
var currentSite = '';
|
|
var loadingSiteAnchor = ''; // Anker der zu ladenden Seite aus URL, wird gespeichert fuer scroll-Effekt
|
|
var currentSiteAnchors = new Array(); // Array aus allen Ueberschrifen-Ankern der aktuellen Seite (kann nach absOffsetTop der Anker sortiert werden)
|
|
var anchorPos = 0; // index in currentSiteAnchors des gerade aktiven Ankers
|
|
var overscrollListener = null;
|
|
var currentHirachy = null;
|
|
var oldQuery = '';
|
|
var scriptLoadingPage = '';
|
|
|
|
// public
|
|
this.differentQueryDifferentSites = false;
|
|
this.whitelist = new Array();
|
|
this.maxWaitForSite = 1000; // Nach dieser Zeit wird die Seite anzegeigt, auch wenn noch nicht vollst. geladen
|
|
this.blendOutTime = 0;
|
|
this.blendInDelay = 0;
|
|
this.blendInTime = 0;
|
|
this.scrollTime = 500;
|
|
this.blendInEffect = null;
|
|
this.blendOutEffect = null;
|
|
this.browseEffect = EffectAppendAndSlide;
|
|
this.browseDuration = 2000;
|
|
this.scrollFunction = function (s) { return (-2*s+3)*s*s; }
|
|
this.browseScrollFunction = function (s) { return s; }
|
|
this.autoFillMenu = 0; // Bis zu dieser Zahl * werden H*-Elemente im Menue ergaenzt
|
|
this.autoChangeAnchor = false;
|
|
this.nummerateMenu = false;
|
|
this.onSiteLoaded = null;
|
|
this.onLinkActivate = null;
|
|
this.onMenuChange = null;
|
|
this.onTitleChange = null;
|
|
this.onContentResize = null;
|
|
|
|
var _this = this;
|
|
var onEvent = /* private */ function (el, event, fkt, param, behavior) { // provides easy eventListeners. el: Element to set the listener; event: string-name of the event(without "on"); fkt: a Function to call ift the event occours, fkt is called in the scope of _this; param: any parameter, that is given to fkt; behavior: flags - 1=only the param is given to fkt (otherwise there is also given the element and the event), 2=event is not given to the element
|
|
var f;
|
|
if (behavior & 1) f = function (ev) {
|
|
if (!ev) ev = window.event;
|
|
fkt.call(_this,param);
|
|
if (behavior & 2) { if (ev.preventDefault) ev.preventDefault(); return false; }
|
|
}
|
|
else f = function (ev) {
|
|
if (!ev) ev = window.event;
|
|
fkt.call(_this,this,ev,param);
|
|
if (behavior & 2) { if (ev.preventDefault) ev.preventDefault(); return false; }
|
|
}
|
|
if (window.addEventListener) el.addEventListener(event, f, false);
|
|
else el.attachEvent('on'+event,f);
|
|
return false;
|
|
};
|
|
|
|
var getAbsOffsetTop = function (el) { // returns the offset top of the given element seen from the document top (el CAN be in the current IFRAME)
|
|
var pos = el.offsetTop;
|
|
while (el.offsetParent) {
|
|
if (el.offsetParent == el) break;
|
|
el = el.offsetParent;
|
|
pos += el.offsetTop;
|
|
}
|
|
try {
|
|
if (el == frames[current].contentWindow.document.body || el == frames[current].contentWindow.document.documentElement) pos += getAbsOffsetTop(frames[current]);
|
|
} catch (e) { }
|
|
return pos;
|
|
};
|
|
|
|
var getAnchorFromURL = /* private */ function (url) {
|
|
var i = url.lastIndexOf('#');
|
|
if (i < 0) return '';
|
|
var a = url.substring(i+1, url.length);
|
|
if ((/[^(A-Za-z0-9_)]/).test(a)) return '';
|
|
return a;
|
|
};
|
|
|
|
var getSiteFromURL = /* private */ function (url) {
|
|
var i = url.lastIndexOf('#');
|
|
var j = url.indexOf('?');
|
|
if (!differentQueryDifferentSites && j >= 0 && j < j) i = j;
|
|
if (i < 0) i = url.length;
|
|
return url.substring(0,i);
|
|
};
|
|
|
|
var create = /* private */ function () {
|
|
if ((!window.addEventListener && !window.attachEvent) || !document.body || !document.getElementsByTagName) { incompatibleBrowser = true; return; }
|
|
if (!window.fapi) { incompatibleBrowser = true; throw 'DynamicIFrame benoetigt frameCommunicator.js!'; }
|
|
if (window.jsw && jsw.units.switchableDesign) jsw.units.switchableDesign.unit.requireDesignFile('dynamicIFrame', box);
|
|
selfHostname = getHostnameAndProtocol(self.location.href);
|
|
// Re-Create Frame elements, because browser does stupid things on hard coded iframes when re-loading a site...
|
|
startPage = frames[0].src;
|
|
aTarget = frames[0].getAttribute('name', 0);
|
|
aTarget2 = frames[1].getAttribute('name', 0);
|
|
frames[1].parentElement.removeChild(frames[1]);
|
|
frames[0].parentElement.removeChild(frames[0]);
|
|
if (frames.length > 0) throw 'Not more than two frames allowed in HTML!';
|
|
var f = document.createElement('iframe');
|
|
f.setAttribute('name', aTarget);
|
|
f.id = aTarget;
|
|
FrameBox.appendChild(f);
|
|
f = document.createElement('iframe');
|
|
f.setAttribute('name', aTarget2);
|
|
f.id = aTarget2;
|
|
FrameBox.appendChild(f);
|
|
// prepare communicators
|
|
communicators[0] = new FrameCommunicator(frames[0], (debugLogging)?'0':'');
|
|
communicators[1] = new FrameCommunicator(frames[1], (debugLogging)?'1':'');
|
|
communicators[0].autoHeight = true;
|
|
communicators[1].autoHeight = true;
|
|
communicators[0].onContentResize = function (w, h) { siteResize(0, h); };
|
|
communicators[1].onContentResize = function (w, h) { siteResize(1, h); };
|
|
communicators[0].onURLChanged = setQueryString;
|
|
communicators[1].onURLChanged = setQueryString;
|
|
communicators[0].onload = manipulateCurrentSite;
|
|
communicators[1].onload = manipulateCurrentSite;
|
|
communicators[0].onTitleChanged = titleChange;
|
|
communicators[1].onTitleChanged = titleChange;
|
|
if (document.addEventListener) document.addEventListener("DOMContentLoaded", domReady, false);
|
|
else {
|
|
var oldReadyStateChange = document.onreadystatechange;
|
|
document.onreadystatechange = function () {
|
|
try { oldReadyStateChange(); } catch (e) { }
|
|
if(document.readyState == "interactive" || document.readyState == "complete") domReady();
|
|
}
|
|
}
|
|
// QueryString untersuchen
|
|
if (window.addEventListener) window.addEventListener('popstate', evalQueryString, false);
|
|
}
|
|
|
|
var domReady = /* private */ function () {
|
|
if (domWasReady) return;
|
|
domWasReady = true;
|
|
// Links auf JavaScript umstellen
|
|
for (var i = 0; i < document.getElementsByTagName('a').length; i++)
|
|
linkJSenhance(document.getElementsByTagName('a')[i]);
|
|
if (nummerateMenu) buildMenuNumbers();
|
|
activateCurrentLink();
|
|
// AutoHeight-Elemente finden
|
|
for (var i = 0; i < document.getElementsByTagName('div').length; i++) if (document.getElementsByTagName('div')[i].className.indexOf('NoJsHeight') >= 0) autoHeightEl.push(document.getElementsByTagName('div')[i])
|
|
if (!isAutoFrameHeight) {
|
|
isAutoFrameHeight = true;
|
|
autoFrameHeight(false);
|
|
}
|
|
// Scroll-Event setzen
|
|
window.addEventListener('scroll', sitescroll, false);
|
|
// Seite aus Querystring laden
|
|
window.setTimeout(function () { // for whatever reason, events do not pass before dom content is loaded.
|
|
if (scriptLoadingPage != '' || !evalQueryString()) {
|
|
if (scriptLoadingPage != '') {
|
|
debugLog('Load site set by script: '+scriptLoadingPage);
|
|
loadSite(scriptLoadingPage, 1);
|
|
} else {
|
|
debugLog('Load start site: '+startPage);
|
|
var hashtag = window.location.href.split('#');
|
|
if (hashtag.length > 1) hashtag = '#'+hashtag.pop();
|
|
else hashtag = '';
|
|
loadSite(startPage+hashtag, 1);
|
|
}
|
|
}
|
|
}, 0);
|
|
};
|
|
|
|
var debugLog = /* private */ function (msg) {
|
|
if (!debugLogging) return;
|
|
var d = new Date();
|
|
console.log('['+d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate()+' '+d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds()+'] '+msg);
|
|
}
|
|
|
|
var evalQueryString = /* private */ function (effect) {
|
|
// Wird in domready und beim klicken auf den Vorwaerts/Rueckwaerts-Button im Browser aufgerufen
|
|
var newSite = self.location.href.split('?');
|
|
newSite.shift();
|
|
if (newSite.length == 0) return false;
|
|
newSite[0] = newSite[0].split('&');
|
|
var isFB = false;
|
|
for (var i = 0; i < newSite[0].length; i++)
|
|
if (newSite[0][i].indexOf('fbclid=') == 0 || newSite[0][i].indexOf('\/gclid=') == 0) {
|
|
newSite[0].splice(i, 1);
|
|
isFB = true;
|
|
break;
|
|
}
|
|
if (newSite[0].length == 0) return false;
|
|
newSite[0] = newSite[0].join('&');
|
|
if (isFB) newSite[0] = newSite[0].split('%2F').join('\/');
|
|
var newSite = absolutePath(newSite.join('?'));
|
|
if (isNotInWhitelist(newSite)) return false;
|
|
debugLog('Load site by query: '+newSite);
|
|
loadSite(newSite, (effect)?0:1);
|
|
return true;
|
|
};
|
|
|
|
this.addURLToWhitelist = /* public */ function (url) {
|
|
var rep = new RegExp('([^\\w&^\\*])', 'g');
|
|
var host = getHostnameAndProtocol(url);
|
|
var i = host.length;
|
|
host = host.replace(rep, '\\$1');
|
|
var path = url.substring(i, url.length).replace(rep, '\\$1');
|
|
if (path == '' && host.length > 0 && host.charAt(host.length-1) == '*') path = '*';
|
|
while (host.length > 0 && host.charAt(host.length-1) == '*') host = host.substring(0, host.length-1);
|
|
if (host == '') throw 'URL has wrong syntax';
|
|
rep = new RegExp('\\*', 'g');
|
|
path = path.replace(rep, '[a|^a]*'); // innerhalb des path-Bereiches koennen die * fuer beliebige Inhalte stehen
|
|
// innerhalb des hostname-Bereiches haben die * spezielle Aufgaben
|
|
var a = host.split('\\\:\\\/\\\/');
|
|
if (a.length == 1) {
|
|
a = a[0].split('*');
|
|
if (a.length == 2)
|
|
host = a[0] + '(\\w)*\\:\\/\\/((\\w)+\\.)*' + a[1];
|
|
else throw 'URL has wrong syntax';
|
|
} else if (a.length == 2) {
|
|
rep = new RegExp('(\\*)', 'g');
|
|
a[0] = a[0].replace(rep, '(\\w)*');
|
|
a[1] = a[1].replace(rep, '((\\w)+\\.)*');
|
|
host = a[0] + '\\:\\/\\/' + a[1];
|
|
} else throw 'URL has wrong syntax';
|
|
whitelist.push(new RegExp('\^'+host+path));
|
|
};
|
|
|
|
var isNotInWhitelist = /* private */ function (src) {
|
|
if (getHostnameAndProtocol(src) == selfHostname) return false;
|
|
for (var i = 0; i < whitelist.length; i++) if (whitelist[i].test(src)) return false;
|
|
return true;
|
|
};
|
|
|
|
var buildMenuNumbers = /* private */ function () {
|
|
if (!nummerateMenu) return;
|
|
for (var i = 0; i < menuLinks.length; i++) {
|
|
if (menuLinks[i]['el'].parentElement.tagName.toLowerCase() != 'li') continue;
|
|
var ol = menuLinks[i]['el'].parentElement;
|
|
var a = new Array();
|
|
while (ol.parentElement && ol.parentElement.tagName.toLowerCase() == 'ol') {
|
|
var nr = 1;
|
|
var el = ol.parentElement.firstElementChild;
|
|
while (el && el != ol) {
|
|
el = el.nextElementSibling;
|
|
if (el.tagName.toLowerCase() == 'li') nr++;
|
|
}
|
|
a.unshift(nr);
|
|
ol = ol.parentElement;
|
|
}
|
|
if (!menuLinks[i]['numberEl']) {
|
|
menuLinks[i]['numberEl'] = document.createElement('span');
|
|
menuLinks[i]['el'].insertBefore(menuLinks[i]['numberEl'], menuLinks[i]['el'].firstChild);
|
|
}
|
|
menuLinks[i]['numberEl'].innerHTML = a.join('.')+'. ';
|
|
}
|
|
};
|
|
|
|
var activateLink = /* private */ function (link) { // das in link uebergebene MenuLink-Objekt wird aktiviert, ggf. akuell aktive Links werden deaktiviert
|
|
if (window.opera && link) { link['el'].style.visibility = 'hidden'; link['el'].style.visibility = 'visible'; } // Komisches Bug
|
|
if (link && link['active']) return;
|
|
for (var i = 0; i < menuLinks.length; i++) if (menuLinks[i]['active']) {
|
|
menuLinks[i]['active'] = false;
|
|
var c = menuLinks[i]['el'].className.split(' ');
|
|
for (var j = c.length-1; j >= 0; j--) if (c[j] == 'active') c.splice(j, 1);
|
|
menuLinks[i]['el'].className = c.join(' ');
|
|
}
|
|
if (!link) { if (onLinkActivate) onLinkActivate(null); return; }
|
|
link['active'] = true;
|
|
link['el'].className += ' active';
|
|
if (onLinkActivate) onLinkActivate(link['el']);
|
|
activateCurrentHirachy();
|
|
};
|
|
|
|
var activateCurrentHirachy = /* private */ function () {
|
|
var link = null;
|
|
for (var i = 0; i < menuLinks.length; i++)
|
|
if (menuLinks[i]['active']) {
|
|
link = menuLinks[i];
|
|
break;
|
|
}
|
|
if (!link || !currentHirachy) return;
|
|
var found = false;
|
|
for (var i = currentHirachy.length-1; i >= 0; i--)
|
|
if (found) {
|
|
if (currentHirachy[i].link && currentHirachy[i].link['el'].getAttribute('alwaysactive') == 'yes' && !currentHirachy[i].link['active']) {
|
|
currentHirachy[i].link['active'] = true;
|
|
currentHirachy[i].link['el'].className += ' active';
|
|
}
|
|
} else if (currentHirachy[i].link == link) found = true;
|
|
};
|
|
|
|
var activateCurrentLink = /* private */ function () {
|
|
// Seite und Anker ermitteln
|
|
var site = currentSite;
|
|
var anchor = getAnchorFromURL(communicators[current].contentURL);
|
|
if (site.indexOf('?') != -1) site = site.substring(0, site.indexOf('?'));
|
|
// Links mit gleicher Seite suchen
|
|
var a = new Array();
|
|
for (var i = 0; i < menuLinks.length; i++)
|
|
if (site == menuLinks[i]['site'])
|
|
a.push(menuLinks[i]);
|
|
// Keinen passenden Link gefunden
|
|
if (a.length == 0) {
|
|
activateLink(null);
|
|
return;
|
|
}
|
|
// Falls aktueller Anker direkt existiert
|
|
for (var i = 0; i < a.length; i++)
|
|
if (a[i]['anchor'] == anchor) {
|
|
activateLink(a[i]);
|
|
return;
|
|
}
|
|
// Falls keine Ueberschriften-Anker bekannt
|
|
if (currentSiteAnchors.length == 0) {
|
|
activateLink(a[0]);
|
|
return;
|
|
}
|
|
// Falls verknuepfter menuLink schon bekannt
|
|
if ((currentSiteAnchors.length > anchorPos) && currentSiteAnchors[anchorPos]['link']) {
|
|
activateLink(currentSiteAnchors[anchorPos]['link']);
|
|
return;
|
|
}
|
|
// Anker-Rangfolge erstellen
|
|
var b = new Array();
|
|
var j = anchorPos-1;
|
|
var h = currentSiteAnchors[anchorPos]['hNr'];
|
|
b[currentSiteAnchors[anchorPos]['hNr']] = currentSiteAnchors[anchorPos];
|
|
for (var i = anchorPos-1; i >= 0; i--)
|
|
if (currentSiteAnchors[i]['hNr'] < h) {
|
|
h = currentSiteAnchors[i]['hNr'];
|
|
b[h] = currentSiteAnchors[i];
|
|
}
|
|
// naheliegensten Menulink aktivieren
|
|
for (var i = b.length-1; i >= 0; i--) {
|
|
if (!b[i]) continue;
|
|
for (var j = 0; j < a.length; j++) if (a[j]['anchor'] == b[i]['name']) { activateLink(a[j]); return; }
|
|
}
|
|
activateLink(a[0]);
|
|
};
|
|
|
|
var setQueryString = /* private */ function () { // Diese Funktion haengt an die URL der aktuellen Seite das ?UrlVonFrame an.
|
|
var P = communicators[current].contentURL;
|
|
if (P == '') P = communicators[current].contentHostname;
|
|
if (P == '' || P.indexOf('about:blank') == 0) return;
|
|
currentSite = getSiteFromURL(P);
|
|
if (isNotInWhitelist(P)) {
|
|
frames[current].style.visibility = 'hidden';
|
|
frames[current].setAttribute('notInWhitelist', 'yes');
|
|
} else {
|
|
frames[current].style.visibility = 'visible';
|
|
frames[current].removeAttribute('notInWhitelist');
|
|
}
|
|
activateCurrentLink();
|
|
var L = self.location.href;
|
|
i = L.indexOf('?');
|
|
if (i < 0) i = L.length;
|
|
var Q = L.substring(i+1, L.length);
|
|
L = L.substring(0, i);
|
|
i = L.indexOf('#');
|
|
if (i > 0) L = L.substring(0, i);
|
|
if (P.split('#')[0].toLowerCase() == startPage.toLowerCase()) {
|
|
if (P.split('#').length == 2) P = '#'+P.split('#').pop();
|
|
else P = '';
|
|
} else {
|
|
var H = getHostnameAndProtocol(communicators[current].contentURL);
|
|
if (H == '') return;
|
|
if (selfHostname == H) P = P.substring(H.length, P.length);
|
|
if (P == Q) return;
|
|
P = '?' + P;
|
|
}
|
|
if (history.pushState && window.location.href != L+P) {
|
|
var stateObj = { foo: "bar" };
|
|
var title = '';
|
|
try { title = frames[current].contentWindow.document.title; } catch (e) {}
|
|
if (oldQuery.split('#')[0] == P.split('#')[0]) history.replaceState(stateObj, document.title+': '+title, L+P);
|
|
else history.pushState(stateObj, document.title+': '+title, L+P);
|
|
oldQuery = P;
|
|
}
|
|
};
|
|
|
|
this.linkJSenhance = function (el, inFrameSite=false) { // replace simple links by javascript-enhanced links
|
|
if (inFrameSite) {
|
|
if ((el.target == '_self' || el.target == '') && el.href != '') {
|
|
var a = el.href.split('#');
|
|
if (a[0].indexOf('javascript:') != 0 && a[0].indexOf('callto:') != 0 && a[0].indexOf('mailto:') != 0 && a[0].indexOf('webcal:') != 0 && el.download == '') { // check, this is a common link
|
|
if (isNotInWhitelist(el.href)) el.target = '_blank';
|
|
else if (a[0] == frames[current].contentWindow.location.href.split('#')[0] && a.length > 1) onEvent(el, 'click', scrollTo, a[1], 3);
|
|
else if ((' '+el.className+' ').indexOf(' WindowLink ') == -1) onEvent(el, 'click', loadSite, el.href, 3);
|
|
}
|
|
}
|
|
} else {
|
|
if (el.target == aTarget) {
|
|
if ((' '+el.className+' ').indexOf(' MenuLink ') >= 0) { // Menue-Links, die hervorgehoben werden sollen, vorbereiten
|
|
var href = absolutePath(el.href);
|
|
menuLinks.push({ // menuLinks koennen auch in manipulateCurrentSite erzeugt werden!
|
|
el : el,
|
|
href : href,
|
|
anchor : getAnchorFromURL(href),
|
|
site : getSiteFromURL(href),
|
|
subMenuId : el.getAttribute('submenu'),
|
|
active : false
|
|
});
|
|
}
|
|
onEvent(el, 'click', loadSite, el.href, 3);
|
|
}
|
|
if (el.href.toLowerCase() == 'javascript:'+aTarget.toLowerCase()+'.print()') printLinks.push(el);
|
|
}
|
|
};
|
|
|
|
var scanElements = function (el, comm) {
|
|
for (var i = 0; i < el.childNodes.length; i++)
|
|
if (el.childNodes[i].nodeType == 1) {
|
|
var eli = el.childNodes[i];
|
|
var tagName = eli.tagName.toLowerCase();
|
|
if (tagName == 'a')
|
|
linkJSenhance(eli, true);
|
|
else if ((/h\d/i).test(tagName)) { // add headlines to currentSiteAnchors
|
|
// find or create headline's id
|
|
var id = eli.id;
|
|
if (!id && eli.getElementsByTagName('a').length > 0) id = eli.getElementsByTagName('a')[0].id;
|
|
if (!id) { // auto-generate an id
|
|
var txt = eli.textContent.toLowerCase();
|
|
id = '';
|
|
for (var j = 0; j < txt.length; j++)
|
|
if (txt.charAt(j) == ' ' && id != '') id += '_';
|
|
else if (txt.charCodeAt(j) >= 97 && txt.charCodeAt(j) <= 122) id += txt.charAt(j);
|
|
else if (txt.charCodeAt(j) >= 48 && txt.charCodeAt(j) <= 57 && id != '') id += txt.charAt(j);
|
|
else if (txt.charCodeAt(j) == 228) id += 'ae';
|
|
else if (txt.charCodeAt(j) == 246) id += 'oe';
|
|
else if (txt.charCodeAt(j) == 252) id += 'ue';
|
|
else if (txt.charCodeAt(j) == 223) id += 'ss';
|
|
var j = 2;
|
|
while (document.getElementById(id)) {
|
|
id += '_'+j;
|
|
j++;
|
|
}
|
|
eli.id = id;
|
|
}
|
|
// add headline to current site anchors
|
|
currentSiteAnchors.push({
|
|
el: eli,
|
|
hNr: parseInt(tagName.substring(1)),
|
|
id: id,
|
|
content: eli.textContent,
|
|
site: comm.contentURL.split('#')[0],
|
|
pos: getAbsOffsetTop(eli),
|
|
link: null
|
|
});
|
|
}
|
|
scanElements(eli, comm);
|
|
}
|
|
}
|
|
|
|
var manipulateCurrentSite = /* private */ function (comm) { // wird von iframe.communicator.onload aufgerufen, sobald der Inhalt des frames geladen hat und dessen Hoehe bekannt ist.
|
|
var _this = this;
|
|
var frameNr = communicators.indexOf(comm);
|
|
if (frameNr != current)
|
|
return;
|
|
debugLog('manipulate frame '+frameNr+'; url='+comm.contentURL);
|
|
currentSiteAnchors = new Array();
|
|
anchorPos = 0;
|
|
try { // Innerhalb von try-catch: Aenderungen an der Frame-Seite
|
|
frames[current].contentWindow.document.body.style.overflow = (isAutoFrameHeight)?'auto':'hidden';
|
|
if (window.jsw) window.jsw.processSite(frames[current].contentWindow.document.body, jswMainWindow);
|
|
scanElements(frames[current].contentWindow.document.body, comm);
|
|
} catch (e) {}
|
|
// find this site's root menu link (first menu link, that points to this site)
|
|
var hirachy = new Array();
|
|
hirachy.push(new Object());
|
|
hirachy[0]['link'] = null;
|
|
hirachy[0]['subMenu'] = null;
|
|
for (var i = 0; i < menuLinks.length; i++)
|
|
if (menuLinks[i]['site'] == comm.contentURL.split('#')[0]) {
|
|
hirachy[0]['link'] = menuLinks[i];
|
|
hirachy[0]['subMenu'] = null;
|
|
if (menuLinks[i]['el'].getAttribute('submenu'))
|
|
hirachy[0]['subMenu'] = document.getElementById(menuLinks[i]['el'].getAttribute('submenu'));
|
|
if (!hirachy[0]['subMenu'] && menuLinks[i]['el'].parentElement.tagName.toLowerCase() == 'li') {
|
|
var nextEl = menuLinks[i]['el'].parentElement.nextElementSibling;
|
|
while (nextEl)
|
|
if (nextEl.tagName.toLowerCase() == 'li' || nextEl.tagName.toLowerCase() == 'ol') break;
|
|
else nextEl = nextEl.nextElementSibling;
|
|
if (nextEl && nextEl.tagName.toLowerCase() == 'ol') hirachy[0]['subMenu'] = nextEl;
|
|
else if (autoFillMenu > 0) {
|
|
hirachy[0]['subMenu'] = document.createElement('ol');
|
|
if (nextEl) menuLinks[i]['el'].parentElement.parentElement.insertBefore(hirachy[0]['subMenu'], nextEl);
|
|
else menuLinks[i]['el'].parentElement.parentElement.appendChild(hirachy[0]['subMenu']);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// here, hirachy[0] contains the root link to this site and the destination ol-list for headline anchors. Now expand hirachy towards higher levels
|
|
linkBaseSearch:
|
|
while (hirachy[0]['link'] && hirachy[0]['link']['el'].parentElement.tagName.toLowerCase() == 'li') {
|
|
var ol = hirachy[0]['link']['el'].parentElement.parentElement;
|
|
while (ol.tagName.toLowerCase() == 'ol') {
|
|
hirachy.unshift({
|
|
link: null,
|
|
subMenu: ol
|
|
});
|
|
if (ol.id != '')
|
|
for (var i = 0; i < menuLinks.length; i++)
|
|
if (menuLinks[i].subMenuId == ol.id) {
|
|
hirachy[0].link = menuLinks[i];
|
|
continue linkBaseSearch;
|
|
}
|
|
ol = ol.parentElement;
|
|
}
|
|
break;
|
|
}
|
|
// actualize menu with currentSiteAnchors
|
|
var h = hirachy.length-1;
|
|
if (h >= 0 && hirachy[h]['subMenu'] && currentSiteAnchors.length > 0) {
|
|
for (var i = 0; i < currentSiteAnchors.length; i++) { // search or create related links for all anchors (don't do this in try..catch)
|
|
// find related menu link to this anchor
|
|
var isSingleTopHeadline = (currentSiteAnchors[i]['el'].tagName.toLowerCase() == 'h1') && (currentSiteAnchors[i]['el'].ownerDocument.getElementsByTagName('h1').length == 1);
|
|
for (var j = 0; j < menuLinks.length; j++)
|
|
if (menuLinks[j]['site'] == comm.contentURL.split('#')[0] && (menuLinks[j]['anchor'] == currentSiteAnchors[i]['id'] || isSingleTopHeadline && menuLinks[j]['anchor'] == '')) {
|
|
var pel = menuLinks[j]['el'].parentElement;
|
|
if (pel.tagName.toLowerCase() != 'li')
|
|
if (isSingleTopHeadline) {
|
|
currentSiteAnchors[i]['link'] = menuLinks[j];
|
|
currentSiteAnchors[i]['isSingleTopHeadline'] = true;
|
|
break;
|
|
} else continue; // this link is not a list-element. Ignore!
|
|
while (pel)
|
|
if (pel == hirachy[0]['subMenu']) break
|
|
else pel = pel.parentElement;
|
|
if (!pel) continue; // this link is outside of the hirachy-ol and has to remain untouched!
|
|
currentSiteAnchors[i]['link'] = menuLinks[j];
|
|
break;
|
|
}
|
|
var link = currentSiteAnchors[i]['link'];
|
|
if (link) {
|
|
// remove li-element from DOM (maybe add it to an other location, later)
|
|
if (link == hirachy[h]['link']) continue; // don't touch root link
|
|
link['el'].parentElement.parentElement.removeChild(currentSiteAnchors[i]['link']['el'].parentElement);
|
|
} else if (currentSiteAnchors[i]['hNr'] <= autoFillMenu && (!currentSiteAnchors[i]['el'] || currentSiteAnchors[i]['el'].getAttribute('autocompletemenu') !== 'no')) {
|
|
// create a new menu link, if missing
|
|
link = {
|
|
href: comm.contentURL.split('#')[0] + '#' + currentSiteAnchors[i]['id'],
|
|
anchor: currentSiteAnchors[i]['id'],
|
|
site: comm.contentURL.split('#')[0],
|
|
active: false,
|
|
el: document.createElement('a')
|
|
};
|
|
link['el'].textContent = currentSiteAnchors[i]['content'];
|
|
link['el'].className = 'MenuLink';
|
|
link['el'].target = aTarget;
|
|
link['el'].href = link['href'];
|
|
onEvent(link['el'], 'click', loadSite, link['href'], 3);
|
|
currentSiteAnchors[i]['link'] = link;
|
|
document.createElement('li').appendChild(link['el']);
|
|
menuLinks.push(link);
|
|
}
|
|
if (!link) continue;
|
|
// insert menu link at correct position, create missing ol-hirachies
|
|
if (i == 0 || currentSiteAnchors[i-1]['isSingleTopHeadline'])
|
|
hirachy[h]['subMenu'].insertBefore(link['el'].parentElement, hirachy[h]['subMenu'].firstChild);
|
|
else {
|
|
var hnr = currentSiteAnchors[i-1]['hNr'];
|
|
var nextSiblingForLi = currentSiteAnchors[i-1]['el'].parentElement.nextSibling;
|
|
// enter necessary sub-menus
|
|
while (hnr < currentSiteAnchors[i]['hNr']) {
|
|
var newOl = null;
|
|
if (hnr == currentSiteAnchors[i-1]['hNr']) {
|
|
if (currentSiteAnchors[i-1]['link']['el'].parentElement.nextElementSibling && currentSiteAnchors[i-1]['link']['el'].parentElement.nextElementSibling.tagName.toLowerCase() == 'ol') newOl = currentSiteAnchors[i-1]['link']['el'].parentElement.nextElementSibling;
|
|
else {
|
|
newOl = document.createElement('ol');
|
|
hirachy[h]['subMenu'].insertBefore(newOl, currentSiteAnchors[i-1]['el'].parentElement.nextSibling);
|
|
}
|
|
} else {
|
|
if (hirachy[h]['subMenu'].firstElementChild && hirachy[h]['subMenu'].firstElementChild.tagName.toLowerCase() == 'ol')
|
|
newOl = hirachy[h]['subMenu'].firstElementChild;
|
|
else {
|
|
newOl = document.createElement('ol');
|
|
hirachy[h]['subMenu'].insertBefore(newOl, hirachy[h]['subMenu'].firstChild);
|
|
}
|
|
}
|
|
hnr++;
|
|
h++;
|
|
hirachy.push({
|
|
link: null,
|
|
subMenu: newOl
|
|
});
|
|
nextSiblingForLi = newOl.firstChild;
|
|
}
|
|
// exit unneccessary sub-menus
|
|
while (hnr > currentSiteAnchors[i]['hNr'] && h > 0) {
|
|
nextSiblingForLi = hirachy[h]['subMenu'].nextSibling;
|
|
h--;
|
|
hnr--;
|
|
hirachy.pop();
|
|
}
|
|
hirachy[h]['subMenu'].insertBefore(link['el'].parentElement, nextSiblingForLi);
|
|
}
|
|
}
|
|
}
|
|
currentHirachy = hirachy;
|
|
activateCurrentHirachy();
|
|
// Nummerierung
|
|
if (nummerateMenu) {
|
|
buildMenuNumbers();
|
|
for (var i = 0; i < currentSiteAnchors.length; i++)
|
|
if (currentSiteAnchors[i]['link'] && currentSiteAnchors[i]['link']['numberEl']) {
|
|
var nrEl = currentSiteAnchors[i]['el'].getElementsByTagName('span')[0];
|
|
if (!nrEl || (' '+nrEl.className+' ').indexOf(' number ') < 0) {
|
|
nrEl = frames[current].contentWindow.document.createElement('span');
|
|
currentSiteAnchors[i]['el'].insertBefore(nrEl, currentSiteAnchors[i]['el'].firstChild);
|
|
}
|
|
nrEl.innerHTML = currentSiteAnchors[i]['link']['numberEl'].innerHTML;
|
|
}
|
|
}
|
|
if (onMenuChange) onMenuChange();
|
|
// sonstiges
|
|
setQueryString();
|
|
blendInfo['currentSiteReady'] = true;
|
|
if (onSiteLoaded) {
|
|
debugLog('Call onSiteLoaded'+((loadWithoutEffect)?' without effect':''));
|
|
onSiteLoaded(frames[current].contentWindow, loadWithoutEffect);
|
|
}
|
|
loadingSiteAnchor = getAnchorFromURL(communicators[current].contentURL);
|
|
if (loadWithoutEffect && loadingSiteAnchor != '') {
|
|
debugLog('Try to scroll to #'+loadingSiteAnchor);
|
|
scrollTo(loadingSiteAnchor, 2);
|
|
} else if (loadingSiteAnchor == '') scrollTo(0, 2);
|
|
};
|
|
|
|
var sitescroll = /* private */ function () { // funktion fuer Scrollevent
|
|
if (!autoChangeAnchor || currentSiteAnchors.length == 0 || scrollInfo['scrolling']) return;
|
|
// richtigen Anker ermitteln
|
|
var pos = window.pageYOffset;
|
|
var nr = anchorPos;
|
|
while (nr > 0 && currentSiteAnchors[nr]['pos'] > pos + 100) nr--;
|
|
while (nr < currentSiteAnchors.length-1 && currentSiteAnchors[nr+1]['pos'] <= pos + 100) nr++;
|
|
// Ankerposition testen
|
|
if (!currentSiteAnchors[nr]) return; // ToDo: unknown error!
|
|
var top = getAbsOffsetTop(currentSiteAnchors[nr]['el']);
|
|
if (Math.abs(top - currentSiteAnchors[nr]['pos']) > 5) {
|
|
currentSiteAnchors[nr]['pos'] = top;
|
|
sitescroll();
|
|
return;
|
|
}
|
|
if (pos < getAbsOffsetTop(frames[current])) nr = -1;
|
|
// Anker wechseln
|
|
if (nr != anchorPos) {
|
|
anchorPos = nr;
|
|
var i = frames[current].contentWindow.location.href.lastIndexOf('#');
|
|
if (i < 0) i = frames[current].contentWindow.location.href.length;
|
|
var stateObj = { foo: "bar" };
|
|
var anchorHashtag = '';
|
|
if (nr >= 0) anchorHashtag = '#'+currentSiteAnchors[nr]['id'];
|
|
frames[current].contentWindow.history.replaceState(stateObj, '', frames[current].contentWindow.location.href.substring(0,i)+anchorHashtag);
|
|
communicators[current].newURL(frames[current].contentWindow.location.href.substring(0,i)+anchorHashtag); // Bugfix: Beim reload der Seite werden im Frame die Funktionen replaceState und pushState nicht ueberwacht
|
|
}
|
|
};
|
|
|
|
var autoFrameHeight = /* private */ function (auto) {
|
|
// wenn true uebergeben wird, wird die Hoehe des iframe-Bereiches auf ~100% der Seitenhoehe (das ClassName 'NoJsHeight' wird wieder an alle Elemente, die dies zu Anfang trugen, angehaengt) angepasst, ansonsten richtet sich die Hoehe nach dem Inhalt des aktuellen frames.
|
|
if (auto == isAutoFrameHeight) {
|
|
debugLog('Auto frame height already '+((auto)?'activated':'deactivated')+'.');
|
|
return;
|
|
}
|
|
debugLog(((auto)?'Activate':'Deactivate')+' auto frame height...');
|
|
isAutoFrameHeight = auto;
|
|
for (var i = 0; i < autoHeightEl.length; i++) {
|
|
var a = autoHeightEl[i].className.split(' ');
|
|
var n = '';
|
|
for (var j = 0; j < a.length; j++) {
|
|
if (a[j] == 'NoJsHeight') continue;
|
|
if (n != '') n += ' ';
|
|
n += a[j];
|
|
}
|
|
autoHeightEl[i].className = n;
|
|
}
|
|
if (auto) {
|
|
for (var i = 0; i < autoHeightEl.length; i++) {
|
|
if (autoHeightEl[i].className != '') autoHeightEl[i].className = autoHeightEl[i].className + ' ';
|
|
autoHeightEl[i].className = autoHeightEl[i].className + 'NoJsHeight';
|
|
}
|
|
frames[current].style.height = '100%';
|
|
try { frames[current].contentWindow.document.body.style.overflow = 'auto'; } catch (e) { }
|
|
} else {
|
|
try { frames[current].contentWindow.document.body.style.overflow = 'hidden'; } catch (e) { }
|
|
}
|
|
};
|
|
|
|
var siteResize = /* private */ function (nr, h) {
|
|
if (nr != current) return;
|
|
debugLog('Resize info from frame '+nr+' received. Height = '+h);
|
|
if (loadingSiteAnchor != '') scrollTo(loadingSiteAnchor, 2);
|
|
if (onContentResize) onContentResize(communicators[current].contentWidth, communicators[current].contentHeight, communicators[current]);
|
|
if (blendInfo['blending'] && !(blendInfo['state'] & 2)) return; // kein Resize fuer noch nicht sichtbare Seiten
|
|
if (blendInfo['blending'] && isAutoFrameHeight && h >= 0) frames[next].style.height = frames[next].offsetHeight + 'px'; // automatisch gegebene Hoehe einfrieren, bevor autoFrameHeight false wird
|
|
autoFrameHeight(h < 0);
|
|
};
|
|
|
|
var titleChange = /* private */ function (title, communicator) {
|
|
if (communicator != communicators[current]) return;
|
|
if (onTitleChange) onTitleChange(title);
|
|
};
|
|
|
|
var blend = /* private */ function () {
|
|
// Loop fuer Einblendeeffekt
|
|
if (!blendInfo['timer']) blendInfo['timer'] = window.setInterval(blend, 40);
|
|
var t = getTickCount();
|
|
// blendState - Flags: 1 = alter Frame wurde ausgeblendet 2 = neue Seite hat geladen und Verzoegerung ist um 4 = neue Seite wurde eingeblendet
|
|
if ((blendInfo['state'] & 1) != 1 && !blendInfo['browse']) { // Wenn Flag 1 nicht gesetzt (alte Seite ausblenden)
|
|
if (t - blendInfo['start'] < blendOutTime) {
|
|
if (blendOutEffect) blendOutEffect(frames[next], (t - blendInfo['start'])/blendOutTime, false);
|
|
} else {
|
|
blendInfo['state'] += 1;
|
|
frames[next].style.display = 'none';
|
|
communicators[next].setSrc('about:blank');
|
|
if (blendOutEffect) blendOutEffect(frames[next], -1, false);
|
|
}
|
|
}
|
|
if (((blendInfo['state'] & 2) != 2) && (blendInfo['currentSiteReady'] || t - blendInfo['start'] > maxWaitForSite) && (t - blendInfo['start'] > blendInDelay)) { // Wenn Flag 2 nicht gesetzt und Bedingungen fuer Einblenden von neuer Seite erfuellt (neue Seite anzeigen)
|
|
if (blendInEffect && !blendInfo['browse']) blendInEffect(frames[current], 0, true);
|
|
else if (browseEffect && blendInfo['browse']) browseEffect(frames[current], frames[next], 0, blendInfo['dir']);
|
|
frames[current].style.maxHeight = 'none';
|
|
blendInfo['startDelay'] = t;
|
|
blendInfo['state'] += 2;
|
|
siteResize(current, communicators[current].contentHeight);
|
|
if (blendInfo['browse']) {
|
|
if (blendInfo['dir']) loadingSiteAnchor = communicators[current].contentHeight + frames[current].parentElement.offsetTop - window.innerHeight;
|
|
else loadingSiteAnchor = 0;
|
|
}
|
|
if (blendInfo['browse']) scrollTo(loadingSiteAnchor, 5);
|
|
else if (loadingSiteAnchor != '') scrollTo(loadingSiteAnchor, 1);
|
|
}
|
|
if (((blendInfo['state'] & 4) != 4) && (blendInfo['state'] & 2)) { // wenn Flag 2 gesetzt aber Flag 4 noch nicht (neue Seite einblenden)
|
|
if (blendInfo['browse']) {
|
|
if (t - blendInfo['startDelay'] < browseDuration) {
|
|
if (browseEffect) browseEffect(frames[current], frames[next], (t-blendInfo['startDelay'])/browseDuration, blendInfo['dir']);
|
|
} else {
|
|
blendInfo['state'] |= 5;
|
|
frames[next].style.display = 'none';
|
|
communicators[next].setSrc('about:blank');
|
|
if (browseEffect) browseEffect(frames[current], frames[next], -1, blendInfo['dir']);
|
|
}
|
|
} else {
|
|
if (t - blendInfo['startDelay'] < blendInTime) {
|
|
if (blendInEffect) blendInEffect(frames[current], (t - blendInfo['startDelay'])/blendInTime, true);
|
|
} else {
|
|
blendInfo['state'] |= 4;
|
|
if (blendInEffect) blendInEffect(frames[current], -1, true);
|
|
}
|
|
}
|
|
}
|
|
if ((blendInfo['state'] & 5) == 5) { // wenn Flag 1 und 4 gesetzt (Blendvorgang beenden)
|
|
if (blendInfo['timer']) window.clearInterval(blendInfo['timer']);
|
|
blendInfo['timer'] = null;
|
|
blendInfo['blending'] = false;
|
|
}
|
|
};
|
|
|
|
this.loadSite = /* public */ function (src, behavior) { // behavior : 0=normal, 1=kein Effekt, 2=blaettern, 4=nach oben blaettern
|
|
if (!behavior) behavior = 0;
|
|
if (incompatibleBrowser || src == 'about:blank') {
|
|
debugLog('Incompatible site load blocked: '+src);
|
|
return;
|
|
}
|
|
src = absolutePath(src);
|
|
if (isNotInWhitelist(src)) {
|
|
debugLog('Not whitelisted site blocked: '+src);
|
|
return;
|
|
}
|
|
if (!domWasReady && behavior == 1) {
|
|
this.scriptLoadingPage = src;
|
|
return;
|
|
}
|
|
// Wenn neue Seite gleich aktueller Seite, nur scrollTo ausfuehren
|
|
if (getSiteFromURL(src) == currentSite) {
|
|
if (~behavior & 2) scrollTo(getAnchorFromURL(src));
|
|
debugLog('Loading of site blocked, because it already is loaded! ('+src+')');
|
|
return;
|
|
}
|
|
// Einstellungen
|
|
loadWithoutEffect = (behavior & 1) == 1;
|
|
if (loadWithoutEffect) debugLog('Load without effect');
|
|
else debugLog('Load with effect');
|
|
currentSiteAnchors = new Array();
|
|
anchorPos = 0;
|
|
// Wenn Effekt aktiv, nur neue Seite in aktuellen Frame laden
|
|
if (blendInfo['blending']) {
|
|
debugLog('Replacing url of currently loading site in frame '+current+' with '+src);
|
|
communicators[current].setSrc(src);
|
|
return;
|
|
}
|
|
// current und next wechseln
|
|
current = next;
|
|
next = (current == 0)?1:0;
|
|
// neue Seite laden
|
|
if (!loadWithoutEffect) {
|
|
blendInfo['currentSiteReady'] = false;
|
|
blendInfo['blending'] = true;
|
|
}
|
|
debugLog('Frame '+current+' starts loading of '+src+' | behavior = '+behavior);
|
|
communicators[current].setSrc(src);
|
|
// PrintLinks umstellen
|
|
if (current == 0)
|
|
for (var i = 0; i < printLinks.length; i++)
|
|
printLinks[i].href = 'javascript:'+aTarget+'.print()';
|
|
else
|
|
for (var i = 0; i < printLinks.length; i++)
|
|
printLinks[i].href = 'javascript:'+aTarget2+'.print()';
|
|
// Blenduebergang starten
|
|
if (loadWithoutEffect) {
|
|
frames[next].style.display = 'none';
|
|
frames[current].style.display = 'block';
|
|
} else {
|
|
frames[current].style.maxHeight = '0px';
|
|
frames[current].style.display = 'block'; // display = block ist notwendig, damit Seite im Frame beginnt zu laden!
|
|
blendInfo['state'] = 0;
|
|
blendInfo['browse'] = (behavior & 2) == 2;
|
|
blendInfo['dir'] = (behavior & 4) == 4;
|
|
blendInfo['start'] = getTickCount();
|
|
blend();
|
|
}
|
|
};
|
|
|
|
var scroll = /* private */ function () {
|
|
// Loop fuer Scroll-Effekt
|
|
if (!scrollInfo['timer']) scrollInfo['timer'] = window.setInterval(scroll, 40);
|
|
var t = getTickCount();
|
|
var d = scrollInfo['blendEffectTime'];
|
|
if (scrollInfo['start'] + d > t) {
|
|
var s = (t - scrollInfo['start']) / d;
|
|
s = scrollInfo['fkt'](s);
|
|
s = scrollInfo['startPos'] * (1-s) + scrollInfo['endPos'] * s;
|
|
window.scrollTo(window.pageXOffset, s);
|
|
} else {
|
|
scrollInfo['scrolling'] = false;
|
|
if (scrollInfo['timer']) window.clearInterval(scrollInfo['timer'], 40);
|
|
scrollInfo['timer'] = null;
|
|
window.scrollTo(window.pageXOffset, scrollInfo['endPos']);
|
|
}
|
|
};
|
|
|
|
this.scrollTo = /* public */ function (target, scrollbehavior) { // scrollbehavior: 0=normal, 1=scrollt so lange, wie Einblendeeffekt, 2=springt sofort zu neuer Position (kein Effekt), 4=scrollFkt = browseScrollFkt
|
|
if (!scrollbehavior) scrollbehavior = 0;
|
|
if (incompatibleBrowser) return;
|
|
if (scrollbehavior & 4) scrollInfo['fkt'] = browseScrollFunction;
|
|
else scrollInfo['fkt'] = scrollFunction;
|
|
// Scrollziel suchen
|
|
var pos = 0;
|
|
if (!isNaN(target)) pos = target;
|
|
else {
|
|
try {
|
|
var el = frames[current].contentWindow.document.getElementById(target);
|
|
if (!el) el = frames[current].contentWindow.document.getElementsByName(target)[0];
|
|
if (el) pos = getAbsOffsetTop(el);
|
|
} catch (e) { return; }
|
|
try {
|
|
var L = frames[current].contentWindow.location.href;
|
|
var i = L.lastIndexOf('#');
|
|
if (i > 0 && L.lastIndexOf('?') < i) L = L.substring(0, i);
|
|
var stateObj = { foo: "bar" };
|
|
if (frames[current].contentWindow.location.href != L+'#'+target)
|
|
frames[current].contentWindow.history.replaceState(stateObj, document.title+': '+frames[current].contentWindow.document.title, L+'#'+target);
|
|
} catch (e) { }
|
|
}
|
|
// Scrollziel setzen
|
|
if (loadingSiteAnchor != '' && getAbsOffsetTop(frames[current]) + frames[current].offsetHeight >= pos) {
|
|
debugLog('Anchor of loading site is reachable.');
|
|
loadingSiteAnchor = '';
|
|
}
|
|
scrollInfo['endPos'] = pos;
|
|
if (scrollInfo['scrolling']) return;
|
|
// Scrolleffekt starten
|
|
scrollInfo['scrolling'] = true;
|
|
scrollInfo['start'] = getTickCount();
|
|
if (scrollbehavior & 2) scrollInfo['start'] = 0;
|
|
scrollInfo['startPos'] = window.pageYOffset;
|
|
scrollInfo['blendEffectTime'] = scrollTime;
|
|
if (scrollbehavior & 1) scrollInfo['blendEffectTime'] = blendInTime;
|
|
if (scrollbehavior & 5 == 5) scrollInfo['blendEffectTime'] = browseDuration;
|
|
scroll();
|
|
return;
|
|
};
|
|
|
|
this.enableOverscroll = function () {
|
|
if (overscrollListener) return;
|
|
overscrollListener = createOverscrollListener(document, 1000, function (dir) {
|
|
for (var i = 0; i < menuLinks.length; i++) if (menuLinks[i]['active']) {
|
|
if (dir && i < menuLinks.length - 1) { loadSite(menuLinks[i+1].href, 2); activateLink(menuLinks[i+1]); }
|
|
else if (!dir && i > 0) { loadSite(menuLinks[i-1].href, 6); activateLink(menuLinks[i-1]); }
|
|
return;
|
|
}
|
|
});
|
|
};
|
|
|
|
this.getActiveContentWindow = function () {
|
|
return frames[current].contentWindow;
|
|
};
|
|
|
|
this.getActiveCommunicator = function () {
|
|
return communicators[current];
|
|
};
|
|
|
|
create(); // Objekt sollte vollstaendig geladen sein, bevor Create aufgerufen wird
|
|
} }
|