Difference between revisions of "MediaWiki:Common.js"
From Australis Ultima 30k
m |
m |
||
(4 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
/* Any JavaScript here will be loaded for all users on every page load. */ | /* Any JavaScript here will be loaded for all users on every page load. */ | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
Line 71: | Line 62: | ||
this.speed = 1; //float - multiplication factor | this.speed = 1; //float - multiplication factor | ||
//Probably can't set these to null through wiki | //Probably can't set these to null through wiki | ||
− | this.strLeft = " | + | this.strLeft = ""; //Intro string part 1 - null for none |
− | this.strRight = " | + | this.strRight = ""; //intro part 3 - null for none |
− | this.strLinkURI = " | + | this.strLinkURI = ""; //part 2 url |
− | this.strLinkText = " | + | this.strLinkText = ""; //part 2 text. null for no link. |
this.schowControls = false; //pause/restart | this.schowControls = false; //pause/restart | ||
this.tickSpeed = 1; | this.tickSpeed = 1; |
Latest revision as of 19:04, 18 October 2013
/* Any JavaScript here will be loaded for all users on every page load. */ /*globals Bawolff getElementsByClassName hookEvent wgServer wgArticlePath addLoadEvent*/ /* __This is Ticker2-0.9__ This is an attempt to redesign the ticker system. I believe that well the current ticker system is a good idea, it can be improved on Then again, this may just be overthinking things. time will tell. ###### Design goals *modular - should be able to have more then one transition between items *user configurable - should be able to customize on wiki (aka {{ticker|for=Africa|speed=...}}) **The user should never have to do anything in js **Downside: have to be extra-careful about XSS *fast - performance was an issue with the other system cavets: *Doesn't handle multilevel lists well *onblur/onfocus?? (works in opera, firefox, broken in MSIE) Todo: *change intro string to a control string with escape sequences (think printf) **Play/pause button *better fade transitions (current one kind of sucks) *Change state system to number instead of T,F,U. *make fade work in IE *multiple speed variables #### Note: Setting disable_ticker2 to true will disable the ticker. */ //to avoid name conflicts (we already have way to many global variables as is imho) //Everything should be a member of Bawolff.Ticker if (typeof Bawolff !== "object") Bawolff = {}; if (typeof Bawolff.Ticker === "Object") throw new Error("Can not initilize ticker. Already initilized, or someone stole its name!"); Bawolff.Ticker = function() { /* This is the constructor function for new Ticker objects. Call as: var some_ticker_object = new Bawolff.Ticker; Its primary purpose is to set defaults and create new Ticker objects. It takes no arguments. Ticker Objects should have the following methods: *setUp - set up ticker properties (and does sanity checks) *engines - functions for transitions probably more */ var t_s = Bawolff.Ticker; //shortcut this.arg = ""; //defaults to none, if uspecified. (should this be an arg to this function?). unphrased definition of options this.elm = null; //element to work ticker magic on. setUp method will throw an error if this isn't set by then //method setUp will take care of these. These are the actual options (defaults here) this.engineNumb = t_s.eng.none; //constant representing engine number this.speed = 1; //float - multiplication factor //Probably can't set these to null through wiki this.strLeft = ""; //Intro string part 1 - null for none this.strRight = ""; //intro part 3 - null for none this.strLinkURI = ""; //part 2 url this.strLinkText = ""; //part 2 text. null for no link. this.schowControls = false; //pause/restart this.tickSpeed = 1; this.resetSpeed=1; //Internal thingies (don't change) this.listIndex = 0; this.charIndex = 0; this.curState = "ok"; //for pausing this.resumeFunc = null; //storage for resume function this.resumeDelay = 0; //wait time before executing } Bawolff.Ticker.prototype.setUp = function() { /* This function takes no arguments. call as: some_ticker_object.setUp(); It initilizes ticker options based on what the class name of the ticker element is. The options are (mostly) encoded as follows in a class attribute: Ticker_<option name- no dashes, underscore allowed>-<urlencoded option value(must end in alphanumeric or _ character)> options are separated by a space (each is a different class). ################################################### ##This function must be extra careful not to be ## ##vulnurable to an xss attack as it directly ## ##deals with editable on wiki data, that could be## ##malicious! be careful ## ################################################### */ //check to see if we really have an element if (!(this.elm && this.elm.nodeType && this.elm.nodeType === 1)) throw new Error("no element, or invalid element for ticker"); var propMatch = /\bTicker_(\w+)-(\S*)\b/g; var res; var plusSign = /\+/g; while(res = propMatch.exec(this.arg)) { switch(res[1]) { //option name case "speed": var speed = parseFloat(decodeURIComponent(res[2])); if (isNaN(speed)) break; speed = 1/speed; //turn delay into speed multiplier if (speed < 1e-5) break; if (speed > 1e2) break; this.speed = speed; break; case "strRight": res[2] = res[2].replace(plusSign, '%20');//encode + with % encode. does this work w/unicode res[2] = res[2].replace('%00', ''); this.strRight = decodeURIComponent(res[2]); break; case "strLeft": res[2] = res[2].replace(plusSign, '%20');//encode + with % encode. does this work w/unicode res[2] = res[2].replace('%00', ''); this.strLeft = decodeURIComponent(res[2]); break; case "strLinkText": res[2] = res[2].replace(plusSign, '%20');//encode + with % encode. does this work w/unicode res[2] = res[2].replace('%00', ''); this.strLinkText = decodeURIComponent(res[2]); break; case "strLinkURI": //despite name, actually local page name, not a URI var page = encodeURIComponent(decodeURIComponent(res[2])); //note encode not decode if (page.match(/^special(%3A|:)userlogout/i)) break; //link is malicious this.strLinkURI = (page.length > 0) ? wgServer + wgArticlePath.replace("$1", page) : null; break; case "engine": //takes a literal engine name var engName = decodeURIComponent(res[2]); if (engName.match(/^\d+$/)||engName.length === 0) break; this.engineNumb = (typeof Bawolff.Ticker.eng[engName] === "number" ? Bawolff.Ticker.eng[engName] : this.engineNumb); default: //throw new Error("not implemented"); } } this.bigList = this.elm.getElementsByTagName("li"); //items to cycle ticker through this.listLength = this.bigList.length; } Bawolff.Ticker.prototype.start = function() { //Start the ticker sets it up as well) separate from restart /* Creates a <ul class="actualTicker"> - actualTicker <span class="tickerIntroduction">(into <a class="tickerLink">stuff</a>):</span> - realTicker <li > ...</li> (dummyItem) </ul> */ this.elm.style.display = "none"; //hide the list var actualTicker = this.tickerElm = document.createElement("ul"); actualTicker.className = "actualTicker"; var realTicker = document.createElement("Span"); realTicker.className = "tickerIntroduction"; realTicker.appendChild(document.createTextNode(this.strLeft)); var realTickerLink = document.createElement("a"); realTickerLink.href= this.strLinkURI; realTickerLink.title = this.strLinkText; realTickerLink.className = "tickerLink"; realTickerLink.appendChild(document.createTextNode(this.strLinkText)); realTicker.appendChild(realTickerLink); realTicker.appendChild(document.createTextNode(this.strRight)); //Start the 2nd (Actual) span actualTicker.appendChild(realTicker); var dummyItem = document.createElement("li"); actualTicker.appendChild(dummyItem); this.elm.parentNode.insertBefore(actualTicker, this.elm); this[Bawolff.Ticker.eng[this.engineNumb]](true); //Start the engine (ticker) } Bawolff.Ticker.prototype.pause = function () { this.curState = "paused"; } Bawolff.Ticker.prototype.restart = function () { if (this.curState !== "paused") return false; this.curState = "ok"; window.setTimeout(this.resumeFunc, this.resumeDelay); } /* #### functions that are direct properties of the ticker constructor (not in prototype chain) #### */ Bawolff.Ticker.eng = []; //Stores object mapping engine name to engine number Bawolff.Ticker.registerEngine = function (engName, engine) { /* This function takes care of hooking up engines (transitions) into the system. Arguments: String engName - name of engine (can not be a number) function engine - function containing engine code Structure of what an engine should look like is noted somewhere (FIXME) */ //to prevent screwing around with length property. considered an array index, even if passed a string with an interger value if (typeof engName !== "string" || (engName.match(/^\d+$/) !== null)) throw new Error("Invalid engine name. (can't be a number)"); var te_s = Bawolff.Ticker.eng; var listLen = te_s.length; te_s[listLen] = "eng-" + engName; te_s[engName] = listLen; Bawolff.Ticker.prototype["eng-" + engName] = engine; //is that really the best way to add the engine functions? } Bawolff.Ticker.registerEngine("none", function(state) { /* This function is a dummy transition (no animation, but changes it) called as: tick() - advance one letter forward (unused) tick(flase) - last tick before break tick(true) - set up/first tick */ if (!state) return true; //Shouldn't happen as null transition. normally can't do this if (state) { var newItem = this.bigList[this.listIndex].cloneNode(true); //true means deep this.tickerElm.replaceChild(newItem, this.tickerElm.lastChild); this.listIndex++; this.listIndex >= this.listLength ? this.listIndex = 0: true; var cur_obj = this; //needed, as otherwise executes in context of window var resF = function() { cur_obj[Bawolff.Ticker.eng[cur_obj.engineNumb]].call(cur_obj, true); } var resD = 7000*cur_obj.speed*cur_obj.resetSpeed; if (this.curState === "paused") { this.resumeFunc = resF; this.resumeDelay = resD; } else { //assume "ok" but allow other states window.setTimeout(resF, resD); } } }); Bawolff.Ticker.registerEngine("std", function(state) { /* This function is a standard - 1 char at a time ticker //this is not the greatest done tick function. In a paticular it expects a list formated // a specific way, and does not handle exceptional conditions as it should //this should be fixed later called as: tick() - advance one letter forward (unused) tick(flase) - last tick before break tick(true) - set up/first tick */ if (state === false) { this.tickerElm.lastChild.firstChild.firstChild.data = this.fullItem.substring(0,this.charIndex); // kill ... var cur_obj = this; //needed, as otherwise executes in context of window var resF = function() { cur_obj[Bawolff.Ticker.eng[cur_obj.engineNumb]].call(cur_obj, true); } var resD = 7000*cur_obj.speed*cur_obj.resetSpeed; if (this.curState === "paused") { this.resumeFunc = resF; this.resumeDelay = resD; } else { //assume "ok" but allow other states window.setTimeout(resF, resD); } } if (state === void 0) { //undefined as in normal tick if (this.charIndex === this.fullItem.length) { //if we're done var cur_obj = this; //needed, as otherwise executes in context of window var resF = function() { cur_obj[Bawolff.Ticker.eng[cur_obj.engineNumb]].call(cur_obj, false); } var resD = 60*cur_obj.speed*cur_obj.tickSpeed; if (this.curState === "paused") { this.resumeFunc = resF; this.resumeDelay = resD; } else { //assume "ok" but allow other states window.setTimeout(resF, resD); } return true; } this.charIndex++; this.tickerElm.lastChild.firstChild.firstChild.data = this.fullItem.substring(0,this.charIndex) + '...'; var cur_obj = this; //needed, as otherwise executes in context of window var resF = function() { cur_obj[Bawolff.Ticker.eng[cur_obj.engineNumb]].call(cur_obj); } var resD = 60*cur_obj.speed*cur_obj.tickSpeed; if (this.curState === "paused") { this.resumeFunc = resF; this.resumeDelay = resD; } else { //assume "ok" but allow other states window.setTimeout(resF, resD); } return true; } if (state) { var newItem = this.bigList[this.listIndex].cloneNode(true); //true means deep //This still doesn't handle exceptional situations as good as possible, but it won't indef loop or freeze if (newItem.firstChild.firstChild !== null) { //Link and then text this.fullItem = newItem.firstChild.firstChild.data; newItem.firstChild.firstChild.data = ""; } else if (newItem.firstChild !== null) { //just text this.fullItem = newItem.firstChild.data; newItem.replaceChild(document.createElement("span"), newItem.firstChild); newItem.firstChild.appendChild(document.createTextNode("")); } else { //input confused script. send error message newitem.insertBefore(document.createElement("strong"), null); newitem.firstChild.className = "error"; newitem.firstChild.appendChild(document.createTextNode("Error: List item incorrectly formated for this ticker type. Please use unformatted text, or a single unformatted link (or otherwise one element deep).")); this.fullItem = newItem.firstChild.firstChild.data; newItem.firstChild.firstChild.data = ""; } this.charIndex = 0; this.tickerElm.replaceChild(newItem, this.tickerElm.lastChild); this.listIndex++; this.listIndex >= this.listLength ? this.listIndex = 0: true; var cur_obj = this; //needed, as otherwise executes in context of window cur_obj[Bawolff.Ticker.eng[cur_obj.engineNumb]].call(cur_obj); } }); Bawolff.Ticker.registerEngine("fade", function(state) { /* This function is a fade in effect This is relies on Css3+MSIE extentions, and thus isn't all that cross browser compatible called as: tick() - advance one letter forward (unused) tick(flase) - last tick before break tick(true) - set up/first tick */ if (state === false) { //sleep var cur_obj = this; //needed, as otherwise executes in context of window var resF = function() { cur_obj[Bawolff.Ticker.eng[cur_obj.engineNumb]].call(cur_obj, true); } var resD = 7000*cur_obj.speed*cur_obj.resetSpeed; if (this.curState === "paused") { this.resumeFunc = resF; this.resumeDelay = resD; } else { //assume "ok" but allow other states window.setTimeout(resF, resD); } } if (state === void 0) { //undefined as in normal tick if (this.charIndex === 100) { //if we're done var cur_obj = this; //needed, as otherwise executes in context of window var resF = function() { cur_obj[Bawolff.Ticker.eng[cur_obj.engineNumb]].call(cur_obj, false); } var resD = 40*cur_obj.speed*cur_obj.tickSpeed; if (this.curState === "paused") { this.resumeFunc = resF; this.resumeDelay = resD; } else { //assume "ok" but allow other states window.setTimeout(resF, resD); } return true; } this.charIndex++; Bawolff.setTrans(this.tickerElm.lastChild, this.charIndex/100); var cur_obj = this; //needed, as otherwise executes in context of window var resF = function() { cur_obj[Bawolff.Ticker.eng[cur_obj.engineNumb]].call(cur_obj); } var resD = 40*cur_obj.speed*cur_obj.tickSpeed; if (this.curState === "paused") { this.resumeFunc = resF; this.resumeDelay = resD; } else { //assume "ok" but allow other states window.setTimeout(resF, resD); } return true; } if (state) { this.charIndex = 0; var newItem = this.bigList[this.listIndex].cloneNode(true); //true means deep Bawolff.setTrans(newItem, 0); (navigator && navigator.appName === "Microsoft Internet Explorer") ? newItem.style.display = 'inline-block' : true; this.tickerElm.replaceChild(newItem, this.tickerElm.lastChild); this.listIndex++; this.listIndex >= this.listLength ? this.listIndex = 0: true; var cur_obj = this; //needed, as otherwise executes in context of window cur_obj[Bawolff.Ticker.eng[cur_obj.engineNumb]].call(cur_obj); } }); /*Not really used. To make all pause call Bawolff.Ticker.allDo("pause"); Bawolff.Ticker.allDo = function (func) { var l = Bawolff.Ticker.allTickers.length; for (var i=0;i<l;i++) { Bawolff.Ticker.allTickers[i][func](); } } */ Bawolff.Ticker.allDoPause = function () { var l = Bawolff.Ticker.allTickers.length; for (var i=0;i<l;i++) { Bawolff.Ticker.allTickers[i].pause(); } } Bawolff.Ticker.allDoRestart = function () { var l = Bawolff.Ticker.allTickers.length; for (var i=0;i<l;i++) { Bawolff.Ticker.allTickers[i].restart(); } } Bawolff.setTrans = function(elm, opacity/*1 being full visible, 0 being invisible*/) { if (!Bawolff.setTrans.opacityMethod) { //standard way (CSS3) if (elm.style && (typeof elm.style.opacity != "undefined")) { Bawolff.setTrans.opacityMethod = 1; } else if (elm.style && (typeof elm.style.MozOpacity != "undefined")) { //old moz Bawolff.setTrans.opacityMethod = 2; } else if (elm.style && (typeof elm.style.filter != "undefined")) { Bawolff.setTrans.opacityMethod = 3; } else { //throw new Error("opacity is not supported on this platform (or this script needs to be fixed to include support on your platform"); } } switch (Bawolff.setTrans.opacityMethod) { case 1: elm.style.opacity = opacity; break; case 2: elm.style.MozOpacity = opacity; break; case 3: elm.style.filter = "alpha(opacity=" + opacity*100 + ")"; //No guarantees this works break; default: //do nothing, so other browsers not inconvianced break; } } Bawolff.Ticker.init = function () { //handled elsewhere if (!document.getElementById("enableTickers")) return false; //Bcause getting all elements by class is expensive var tickerList = getElementsByClassName(document.body, "div", "isATicker"); var l = tickerList.length; var i = 0; //index of which ticker we are on. Bawolff.Ticker.allTickers = []; if (document.getElementById("singleTickerForPage")) { //for simplifications. if only one on page Bawolff.Ticker.allTickers[i] = new Bawolff.Ticker; Bawolff.Ticker.allTickers[i].elm = document.getElementById("singleTickerForPage"); Bawolff.Ticker.allTickers[i].arg = document.getElementById("singleTickerForPage").className; Bawolff.Ticker.allTickers[i].setUp(); Bawolff.Ticker.allTickers[i].start(); i++; } for (;i<l;i++) { Bawolff.Ticker.allTickers[i] = new Bawolff.Ticker; Bawolff.Ticker.allTickers[i].elm = tickerList[i]; Bawolff.Ticker.allTickers[i].arg = tickerList[i].className; Bawolff.Ticker.allTickers[i].setUp(); Bawolff.Ticker.allTickers[i].start(); } if (!(navigator && navigator.appName === "Microsoft Internet Explorer")) { //blur sometimes fires too much on MSIE and makes things not work hookEvent('blur', Bawolff.Ticker.allDoPause);//stop anim on loss of focus, and restart it on gain of focus. hookEvent from wikibits hookEvent('focus', Bawolff.Ticker.allDoRestart); } } Bawolff.Ticker.init(); //already from a load event