/*********************************************************************** * MyLittleJavaScript * ************************************************************************ * Created by Michael Loesler * * * * This script is part of my little forum * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***********************************************************************/ /*********************************************************************** * NOTICE: In order to reduce bandwidth usage, a minimized version of * * this script is used by default (main.min.js). Changes in this file * * do not have any effect unless it is loaded by the template * * (themes/[THEME FOLDER]/main.tpl). * * The minimized version was created with the YUI Compressor * * , i.e. * * . * ***********************************************************************/ /** * Liefert die CSS-Eigenschaften eines Elements * * @param el * @param cssProp * @return cssValue */ document.getStyle = function(el,styleProp) { if (el.currentStyle) return el.currentStyle[styleProp]; else if (window.getComputedStyle) return document.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp); return false; }; /** * Liefert eine Liste mit Elementen, die die * selbe CSS-Klasse haben * * @param class_name * @return node_list */ if(typeof document.getElementsByClassName != 'function') { document.getElementsByClassName = function (class_name) { var all_obj,ret_obj=new Array(),j=0,teststr; if(this.all) all_obj=this.all; else if(this.getElementsByTagName && !this.all) all_obj=this.getElementsByTagName("*"); var len=all_obj.length; for(var i=0;i'); el = document.createElement("<" + tagName + attr + ">"); } } el = el || document.createElement(tagName); for (var attribute in attributes) if (attribute.toLowerCase() != "type" && attribute.toLowerCase() != "name") el[attribute] = attributes[attribute]; if (parentElement) parentElement.appendChild(el); return el; }; /** * Erzeugt ein Element mit zusaetzlichen Attributen * Attribute werden als einfache Objekte uebergeben * {"class": "foo", "href": "#"} * Optional kann das Elternelement angegeben werden, * um das neue Element einzuhaengen * * @param tagName * @param attributes * @param parentElement * @return el * @see http://forum.de.selfhtml.org/archiv/2011/3/t204212/#m1382727 */ document.createElementWithAttributes = function(tagName, attributes, parentElement) { if (tagName.toLowerCase() == "input" || tagName.toLowerCase() == "button") return document.createInputElementWithAttributes(tagName, attributes, parentElement); var el = document.createElement(tagName); for (var attribute in attributes) el[attribute] = attributes[attribute]; if (parentElement) parentElement.appendChild(el); return el; }; /** * Liefert die Scroll-Position des aktuellen * Fensters * @return scrollPos * @see http://forum.de.selfhtml.org/archiv/2005/4/t106392/#m659379 */ document.getScrollPosition = function() { var l = 0, t = 0; if( typeof window.pageYOffset == "number" ) { t = window.pageYOffset; l = window.pageXOffset; } // else if( document.documentElement && typeof document.documentElement.scrollLeft == "number" && typeof document.documentElement.scrollTop == "number" ) else if (document.compatMode && document.compatMode == "CSS1Compat") { t = document.documentElement.scrollTop; l = document.documentElement.scrollLeft; } else if( document.body && typeof document.body.scrollLeft == "number" && typeof document.body.scrollTop == "number" ) { t = document.body.scrollTop; l = document.body.scrollLeft; } return { left: l, top: t }; }; /** * Liefert die Groesse des Dokuments * @return docSize * @see http://forum.de.selfhtml.org/archiv/2009/1/t181640/ */ document.getWindowSize = function() { var l, t, windowWidth, windowHeight; if (window.innerHeight && window.scrollMaxY) { l = document.body.scrollWidth; t = window.innerHeight + window.scrollMaxY; } else if (document.body.scrollHeight > document.body.offsetHeight){ l = document.body.scrollWidth; t = document.body.scrollHeight; } else { l = document.getElementsByTagName("html").item(0).offsetWidth; t = document.getElementsByTagName("html").item(0).offsetHeight; l = (l < document.body.offsetWidth) ? document.body.offsetWidth : l; t = (t < document.body.offsetHeight) ? document.body.offsetHeight : t; } if (window.innerHeight) { windowWidth = window.innerWidth; windowHeight = window.innerHeight; } //else if (document.documentElement && document.documentElement.clientHeight) { else if (document.compatMode && document.compatMode == "CSS1Compat") { windowWidth = document.documentElement.clientWidth; windowHeight = document.documentElement.clientHeight; } else if (document.body) { windowWidth = document.getElementsByTagName("html").item(0).clientWidth; windowHeight = document.getElementsByTagName("html").item(0).clientHeight; windowWidth = (windowWidth == 0) ? document.body.clientWidth : windowWidth; windowHeight = (windowHeight == 0) ? document.body.clientHeight : windowHeight; } var pageHeight = (t < windowHeight) ? windowHeight : t; var pageWidth = (l < windowWidth) ? windowWidth : l; return { pageWidth: pageWidth, pageHeight: pageHeight, windowWidth: windowWidth, windowHeight: windowHeight }; }; /** * Liefert den zum Tastendruck gehoerenden Event-Key * return keyCode */ document.getKeyCode = function(ev) { ev = ev || window.event; if ((typeof ev.which == "undefined" || (typeof ev.which == "number" && ev.which == 0)) && typeof ev.keyCode == "number") return ev.keyCode; else return ev.which; }; /** * Liefert die Position und Groesse eines Elements im Dokument * @param el * @return elPositionAndSize * @see http://www.quirksmode.org/js/findpos.html */ document.getElementPoSi = function(el){ var r = { top:0, left:0, width:0, height:0 }; if(!el || typeof(el) != 'object') return r; if(typeof(el.offsetTop) != 'undefined') { r.height = el.offsetHeight; r.width = el.offsetWidth; r.left = r.top = 0; while(el && el.tagName != 'BODY') { r.top += parseInt( el.offsetTop ); r.left += parseInt( el.offsetLeft ); el = el.offsetParent; } } return r; }; /** * Liefert das erste direkte Kindelement eines Elternknotens, * welches optionale eine bestimmte CSS-Klasse haben muss * * @param par * @param tagName * @param cssClasses * return el */ document.getFirstChildByElement = function(par, tagName, cssClasses) { if (cssClasses && typeof(cssClasses) != "object") cssClasses = [cssClasses]; if (par && par.hasChildNodes()) { var childNodeFromPar = par.firstChild; while (childNodeFromPar != null) { if (childNodeFromPar.nodeName.toLowerCase() == tagName) { if (!cssClasses) return childNodeFromPar; else { var teststr = ","+childNodeFromPar.className.split(" ").join(",")+","; for (var i=0; i1?decodeURIComponent(v[1]):""; } }; var saveNewOrder = function() { if (!isChanged) return; var page = getLocationQueryByParameter(queryKey); var order = getRowOrder(); if (!page || !order) return; var querys = [ new Query("mode", mode), new Query("action", "reorder"), new Query(page, order) ]; new Request("index.php", "POST", querys); }; var updateClasses = function() { for (var i=0; i 3) order += rows[i].id.substring(3) + ","; return order.substr(0, order.length-1); }; var ondrag = function(row) { if (!row) return; }; var ondrop = function(row) { if (!row) return; updateClasses(); saveNewOrder(); }; var start = function() { window.document.onmousemove = function(e) { if (typeof oldOnMouseMoveFunc == "function") oldOnMouseMoveFunc(e); if (!dragObject) return; var mPos = document.getMousePos(e); var currentTop = mPos.top - dragObject.handlePos.top + dragObject.elementPos.top; var currentRow = findDropTargetRow( currentTop ); if (tableTop != currentTop && currentRow && dragObject != currentRow) { var movingDown = currentTop > tableTop; tableTop = currentTop; if (movingDown) currentRow = currentRow.nextSibling; dragObject.parentNode.insertBefore(dragObject, currentRow); isChanged = true; ondrag(dragObject); } if(e && e.preventDefault) e.preventDefault(); return false; }; window.document.onmouseup = function (e) { window.document.onmouseup = window.document.onmousemove = null; if (typeof oldOnMouseUpFunc == "function") oldOnMouseUpFunc(e); if (typeof oldOnMouseMoveFunc == "function") window.document.onmousemove = oldOnMouseMoveFunc; ondrop(dragObject); dragObject = null; isChanged = false; return false; }; }; var findDropTargetRow = function(top) { for (var i=0; i= (rowPoSi.top - h)) && (top < (rowPoSi.top + h))) { return rows[i]; } } return null; }; var add = function(row) { row.classList.add("js-cursor-move"); row.title = lang["drag_and_drop_title"]; row.onmousedown = function(e){ isChanged = false; var obj = document.getTarget(e); if (obj && obj.className.search(/control/) != -1) return false; this.className = "drag"; this.elementPos = document.getElementPoSi(this); this.handlePos = document.getMousePos(e); dragObject = this; start(); return false; }; var links = row.cells[row.cells.length-1].getElementsByTagName("a"); if (links && links.length > 0) { for (var i=0; i 0) for (var i=0; i1?q[1]:0; } var lis = ul.getElementsByTagName("li"); var uls = ul.getElementsByTagName("ul"); var self = this; var icon = new Image(); var repliesInfo = null; if (ul.parentNode.nodeName != "TD") { var tail = document.getFirstChildByElement(lis[0], "span", ["tail"]); if (tail && lis.length > 1) { repliesInfo = document.getFirstChildByElement(tail, "span", ["replies"]); if (!repliesInfo) { repliesInfo = document.createElementWithAttributes("span", {"className": "replies"}, tail); repliesInfo.appendChild( document.createTextNode( " (" + (lis.length-1) + ")" ) ); } } } this.isFold = function() { return uls.length > 0 && uls[0].classList.contains("js-display-none"); }; this.setFold = function(fold, changeCSS) { changeCSS = changeCSS || false; if (fold) { icon.src = templatePath + settings["expand_thread_image"]; icon.classList.remove("fold-thread"); icon.classList.add("expand-thread"); icon.alt = ""; icon.onerror = function(e) { this.alt = "[+]"; }; icon.title = lang["expand_fold_thread_linktitle"]; if (repliesInfo) repliesInfo.classList.remove("js-display-none"); if (changeCSS) { ul.classList.remove("expanded"); ul.classList.add("folded"); } } else { icon.src = templatePath + settings["fold_thread_image"]; icon.classList.remove("expand-thread"); icon.classList.add("fold-thread"); icon.alt = ""; icon.onerror = function(e) { this.alt = "[-]"; }; icon.title = lang["expand_fold_thread_linktitle"]; if (repliesInfo) repliesInfo.classList.add("js-display-none"); if (changeCSS) { ul.classList.remove("folded"); ul.classList.add("expanded"); } } for (var i=0; i 0 && lis[0].firstChild) lis[0].insertBefore(el, lis[0].firstChild); else lis[0].appendChild(el); }; var foldExpandWrapper = document.createElementWithAttributes("span", {"className": "fold-expand"}, null); if (lis.length == 1) { var inactiveFoldExpandImg = document.createElementWithAttributes("img", {"src": templatePath + settings["expand_thread_inactive_image"], "className": "expand-thread-inactive", "alt": "", "onerror": function(e) { this.alt = "[]"; } }, foldExpandWrapper) setIcon(foldExpandWrapper); } else { var link = document.createElementWithAttributes("a", {"href": "#", "onclick": function(e) {self.setFold(!self.isFold()); this.blur(); return false;} }, foldExpandWrapper); this.setFold(this.isFold()); link.appendChild(icon); setIcon(foldExpandWrapper); } }; /** * Erzeugt aus einer ID ein Posting, welches ein- und ausgeklappt werden kann * @param pid */ function Posting(pid) { if (!pid) return; var pWrapper = document.getElementById("p" + pid); var pHeadline = document.getElementById("headline-" + pid); if (!pWrapper || !pHeadline) return; var self = this; pHeadline.classList.add("js-cursor-pointer"); pHeadline.title = lang["fold_posting_title"]; pHeadline.onclick = function(e) { self.setFold(!self.isFold()); }; this.isFold = function() { return pWrapper.classList.contains("js-display-fold"); }; this.setFold = function(fold) { if (fold) { pWrapper.classList.add("js-display-fold"); } else { pWrapper.classList.remove("js-display-fold"); } }; this.setFold(this.isFold()); }; function FullSizeImage(els) { if (!els) return; els = (typeof els == "object" || typeof els == "function") && typeof els.length == "number"?els:[els]; var hashTrigger = null; var body = document.body; // http://aktuell.de.selfhtml.org/weblog/kompatibilitaetsmodus-im-internet-explorer-8 var isIELower8 = /*@cc_on!@*/false && !(document.documentMode && document.documentMode >= 8); var imageCanvas = document.getElementById("image-canvas") || document.createElementWithAttributes("div", {"id": "image-canvas"}, body); imageCanvas.setVisible = function(visible) { if (visible) this.classList.remove("js-display-none"); else this.classList.add("js-display-none"); }; var stopTrigger = function() { if (hashTrigger) { window.clearInterval(hashTrigger); var scrollPos = document.getScrollPosition(); if (!isIELower8) window.history.back(); else window.location.hash="GET_OPERA"; // Fuer den Fall, dass man bei eingeblendeten Bild gescrollt hat window.scrollTo(scrollPos.left, scrollPos.top); } }; var oldOnKeyPressFunc = window.document.onkeypress; window.document.onkeypress = function(e) { var keyCode = document.getKeyCode(e); if (keyCode == 27) { imageCanvas.setVisible(false); stopTrigger(); } if (typeof oldOnKeyPressFunc == "function") oldOnKeyPressFunc(e); }; imageCanvas.onclick = function(e) { imageCanvas.setVisible(false); stopTrigger(); }; imageCanvas.setVisible(false); var fullSizeImage = document.getElementById("fullSizeImage") || document.createElementWithAttributes("img", {"id": "fullSizeImage"}, imageCanvas); for (var i=0; i (boxX+boxWidth) || posY < boxY || posY > (boxY+boxHeight)) && obj.className != 'ap') { self.setVisible(false); } } } }; this.pin = function() { pinned = !pinned; }; this.isPinned = function() { return pinned; }; this.getContentElement = function() { return contentEl; }; this.getMainElement = function() { return mainEl; }; this.hideURI = function(hide) { hideURI = hide; }; this.setPosition = function(x, y) { win.style.left = x + "px"; win.style.top = y + "px"; var winWidth = this.getWidth(); var documentWidth = document.getWindowSize().windowWidth; if ((x+winWidth) >= documentWidth) { this.moveHorizontal( documentWidth-25-(x+winWidth) ); } else { this.moveHorizontal( 0 ); } }; this.getWidth = function() { return mainEl.offsetWidth; }; this.getHeight = function() { return win.offsetHeight + mainEl.offsetHeight; }; this.setOpener = function(op) { opEl = op; }; this.getOpener = function() { return opEl; }; this.isVisible = function() { return !win.classList.contains("js-display-none"); }; this.getDocumentPosition = function() { var left = win.offsetLeft; var top = win.offsetTop; return { top: top, left: left + xShift }; }; this.moveHorizontal = function(val) { xShift = val; mainEl.style.left = val + "px"; }; this.setVisible = function(visible) { if (visible) { win.classList.remove("js-display-none"); win.classList.add("js-display-block"); } else { win.classList.remove("js-display-block"); win.classList.add("js-display-none"); pinned = false; } }; this.setText = function(str) { contentEl.innerHTML = str; if (str != "") { if (!replylinkLink.firstChild) replylinkLink.appendChild( document.createTextNode( lang["reply_link"] )); if (!hideURI) { replylinkWrapper.appendChild( replylinkLink ); contentEl.appendChild( replylinkWrapper ); } new FullSizeImage(contentEl); } else { contentEl.appendChild( throbberIcon ); } }; this.setURI = function(uri) { if (!uri) { replylinkLink.href = "#"; replylinkWrapper.classList.remove("js-display-block"); replylinkWrapper.classList.add("js-display-none"); } else { replylinkWrapper.classList.remove("js-display-none"); replylinkWrapper.classList.add("js-display-block"); replylinkLink.href = uri; } }; } /** * Hauptfunktion des Forums */ function MyLittleJavaScript() { var templatePath = null; var ajaxPreviewWindow = null; var sidebar = null; var strURL = 'index.php'; var threads = []; var postings = []; var regExpFID = new RegExp(/[?|&]id=([0-9]+)(#p([0-9]+))?/); var self = this; /** * Ermittelt die Posting ID aus einer URI * @param link * @return id */ var getPostingId = function(link) { if (link && regExpFID.test(link.href)) { var q = regExpFID.exec(link.href); return q[3]?q[3]:q[1]; } return false; } /** * Liefert den Pfad zum gewaehlten Template, * welcher aus einem LINK-Element ermittelt wird. * @return path */ this.getTemplatePath = function() { if (templatePath != null) return templatePath; var el = document.getElementsByTagName("link"); for (var i=0; i 0; var pid = isResponse?par2[0]:par1; var xml = isResponse?par1:false; var imgEl = null; if (!pid || !(imgEl = document.getElementById('markimg_'+pid))) return; imgEl.src = templatePath + settings["mark_process_image"]; imgEl.alt = '[ ]'; var querys = [ new Query("mode", "posting"), new Query("mark", pid), new Query("method", "ajax") ]; if (!isResponse) new Request(strURL, "POST", querys, this, "selectPosting", pid, true); else if (isResponse && xml && document.getElementById('marklink_'+pid)) { var linkEl = document.getElementById('marklink_'+pid); var selectPosting = xml.getElementsByTagName('action') && xml.getElementsByTagName('action')[0].firstChild.data == "1"; if(selectPosting) { imgEl.src = templatePath + settings["marked_image"]; imgEl.alt = '[●]'; linkEl.title = lang["unmark_linktitle"]; imgEl.title = lang["unmark_linktitle"]; } else { imgEl.src = templatePath + settings["unmarked_image"]; imgEl.alt = '[○]'; linkEl.title = lang["mark_linktitle"]; imgEl.title = lang["mark_linktitle"]; } } }; /** * Oeffnet/Schliesst alle Threads * @param expand */ var expandAllThreads = function(expand) { expand = expand || false; for (var i=0; i1&&q[1]=="1"; foldingLink.onclick = function(e) { expandAllThreads( !isExpand ); this.className = this.className.replace(foldRegExp, "fold-" + (isExpand?2:1) ); this.firstChild.replaceData(0, this.firstChild.nodeValue.length, (isExpand?lang["expand_threads"]:lang["fold_threads"]) ); this.title = isExpand?lang["expand_threads_linktitle"]:lang["fold_threads_linktitle"]; isExpand = !isExpand; this.blur(); return false; } } }; /** * Erzeugt die Links (Sprechblase) zum Vorschaufenster * auf der Forenhauptseite an den gewuenschten Elementen, * sofern das Posting Inhalt besitzt. * @param els */ var setPreviewBoxToMainPage = function(els) { if (!els) return; initThreadFoldingInSubMenu(); for (var i=0; i= 2) { for (var j=0; j= 1) { var link = links[0]; el.insertBefore(createAjaxPreviewLink(pid), link); el.insertBefore(document.createTextNode( String.fromCharCode(160) ), link); } else { el.appendChild(document.createTextNode( String.fromCharCode(160) )); el.appendChild(createAjaxPreviewLink(pid)); } } // thread, folded oder expanded - Reicht eigentlich die Suche nach thread? if (li.parentNode.className.search(/thread/) != -1 && li.parentNode.className.search(/[folded|expanded]/) != -1) { threads.push( new Thread( li.parentNode, templatePath) ); } } var editAreas = document.getElementsByClassName("options"); if (editAreas.length > 0) { for (var i=0; i 0) { for (var j=0; j0?pEls:document.getElementsByClassName("thread-posting"); new FullSizeImage(pEls); }; var setDefaultInputValue = function(id) { var inp = document.getElementById(id); if (!inp) return; //var value = inp.value; var value = (inp.alt) ? inp.alt : inp.value; inp.onfocus = function(e) { if (this.value == value) this.value=""; }; inp.onblur = function(e) { if(this.value.trim() == "") this.value = value; }; }; /** * Durchsucht Seite nach einem Formular innerhalb von * >CONTENT< und setzt den Fokus auf das erste INPUT * Trift auf Anmeldung und Antworten zu */ var setFocusToContentForm = function() { if (document.getElementById("content")) { var f = document.getElementById("content").getElementsByTagName("form"); if (f && f.length>0) { for (var i=0; i"; ajaxPreviewWindow.setText( content ); }; /** * Zeigt das Vorschaufenster an. Erwartet das Objekt, * welches den Aufruf hervorgerufen hat (Opener), und * ob das Fesnster geoffnet bleiben soll (pin). * Schliesst das Fenster, wenn auf den selben Opener * erneut geklickt wird. * @param obj * @param pin */ this.showAjaxPreviewWindow = function(obj, pin) { if (!obj || !ajaxPreviewWindow) return; if (obj == ajaxPreviewWindow.getOpener() && ajaxPreviewWindow.isVisible() && pin) { ajaxPreviewWindow.pin(); if (!ajaxPreviewWindow.isPinned()) { ajaxPreviewWindow.setVisible(false); ajaxPreviewWindow.setOpener(null); } } else if (!ajaxPreviewWindow.isPinned()) { if (pin && !ajaxPreviewWindow.isPinned()) ajaxPreviewWindow.pin(); var elPos = document.getElementPoSi(obj); ajaxPreviewWindow.setOpener(obj); ajaxPreviewWindow.setText(""); ajaxPreviewWindow.setVisible(true); ajaxPreviewWindow.setPosition( elPos.left, elPos.top ); var querys = [ new Query("mode", "entry"), new Query("ajax_preview", "true"), new Query("id", obj.pid) ]; new Request(strURL, "POST", querys, this, "updateAjaxPreviewWindow", null, true); } }; /** * Liefert das Vorschaufenster * @return win */ this.getAjaxPreviewWindow = function() { return ajaxPreviewWindow; } /** * Sendet das Formular im Submenue ab, wenn sich der * Wert im Drop-Down-Menue aendert */ var setAutoSubmitSubNaviForms = function() { var subNav = document.getElementById("subnav-2"); if (subNav) { var f = subNav.getElementsByTagName("form"); for (var i=0; i