ผู้ใช้:Jutiphan/iScript/helper.js
< ผู้ใช้:Jutiphan | iScript
หมายเหตุ: หลังเผยแพร่ คุณอาจต้องล้างแคชเว็บเบราว์เซอร์ของคุณเพื่อดูการเปลี่ยนแปลง
- ไฟร์ฟอกซ์ / ซาฟารี: กด Shift ค้างขณะคลิก Reload หรือกด Ctrl-F5 หรือ Ctrl-R (⌘-R บนแมค)
- กูเกิล โครม: กด Ctrl-Shift-R (⌘-Shift-R บนแมค)
- อินเทอร์เน็ตเอกซ์พลอเรอร์ และ Edge: กด Ctrl ค้างขณะคลิก Refresh หรือกด Ctrl-F5
- โอเปร่า: กด Ctrl-F5
// ==============================================================
// สคริปต์จัดให้: helper module
// Available functions:
// * JSON - [Object].toJSONString
// * Global Error Handling Support
// * [XMLDOM]
// * dynamicSort
// * [Array].indexOf
// * [Array].every
// * [Array].toSource
// * addTab
// * addToolboxLink
// * addMenu
// * assignToEditForm
// * assignToEditTalkForm
// * createElement
// * getPname
// * getSelText
// * getSelTextArea
// * getUploader
// * getThaiFullMonthName
// * qid_getFileHistory (required for getUploader)
// * SetCaretTo
// * openInNewWindow
// * isIPAddress
// * userIsInGroup
// * [String].trim
// * [String.replaceAll
// * htmlNode
// * [Status]
// * [QueryString]
// * [Wikipedia API]
// * [sprintf]
//
// Copyright (C) 2006-2011, Jutiphan Mongkolsuthree
// Certain functions are copyrighted by their
// respective copyright holders.
//
// No warranty expressed or implied. Use at your own risk.
//
// Created: 1/12/2006
// Replaced: none
//
// Additional Credits Information:
// ==============================================================
// JSON - [Object].toJSONString
// 2008-03-14 Public Domain
// See //www.JSON.org/js.html
// TODO: This is now superceded by json2 and needs to be updated later
//
// ==============================================================
// Array functions
// Taken from //www.dustindiaz.com/basement/sugar-arrays.html
// TODO: This needs to be replaced by uniformed JS 1.6 Library for non-supported browsers
//
// ==============================================================
// getUploader and qid_getFileHistory functions
// Source: en:User:Howcheng/quickimgdelete.js, adapted & further modified by user:Jutiphan
// Current version: 1.13.1
// Created by [[User:Howcheng|Howard Cheng]]
// Released under the [[GNU Public License]] (GPL)
// Full documentation at [[User talk:Howcheng/quickimgdelete.js]]
// NOTE: DO NOT UPGRADE TO NEWER VER WITHOUT MERGE. This is custom, also included sysop fix.
//
// ==============================================================
// setCaretTo function
// Source: //parentnode.org/javascript/working-with-the-cursor-position/
//
// ==============================================================
// replace function
// Source: //www.irt.org/script/242.htm
// ==============================================================
//
// This information may be incomplete. Apologize if incomplete or inaccurate.
// Feel free to inform at [[User Talk:Jutiphan]]
//
/* <pre><nowiki> */
// ========== XMLDOM ==========
window.XMLDOM = function window$XMLDOM(markup) {
if (!window.DOMParser) {
var progIDs = [ 'Msxml2.DOMDocument.3.0', 'Msxml2.DOMDocument' ];
for (var i = 0; i < progIDs.length; i++) {
try {
var xmlDOM = new ActiveXObject(progIDs[i]);
xmlDOM.loadXML(markup);
xmlDOM.setProperty('SelectionLanguage', 'XPath');
return xmlDOM;
}
catch (ex) {
}
}
return null;
}
else {
try {
var domParser = new window.DOMParser();
return domParser.parseFromString(markup, 'text/xml');
} catch (ex) {
return null;
}
}
return null;
};
// ========== dynamicSort ==========
// http://stackoverflow.com/questions/1129216/sort-array-of-objects-by-string-property-value-in-javascript
function dynamicSort(property) {
var sortOrder = 1;
if(property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a,b) {
var result = a[property].localeCompare(b[property]);
return result * sortOrder;
}
}
// ========== [Array].indexOf ==========
// NOTE: This is included in Javascript 1.6 which is not yet available in IE or ECMAScript
// Taken from //www.dustindiaz.com/basement/sugar-arrays.html
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(el, start) {
var start = start || 0;
for (var i = start; i < this.length; ++i) {
if (this[i] === el) {
return i;
}
}
return -1;
};
}
// ========== [Array].every ==========
// NOTE: This is included in Javascript 1.6 which is not yet available in IE or ECMAScript
// Taken from //www.dustindiaz.com/basement/sugar-arrays.html
if (!Array.prototype.every) {
Array.prototype.every = function(fn, thisObj) {
var scope = thisObj || window;
for ( var i=0, j=this.length; i < j; ++i ) {
if ( !fn.call(scope, this[i], i, this) ) {
return false;
}
}
return true;
};
}
// ========== [Array].toSource ==========
if (!Array.prototype.toSource) {
Array.prototype.toSource = function() {
var L = this.length,s = '[',t,i;
for (i = 0; i < L; i++) {
if (i > 0) s += ',';
if (this[i].constructor == Array) s += this[i].toSource();
else switch (typeof this[i]) {
case "number" : s += this[i]; break;
case "boolean" : s += this[i]; break;
default : s += '"' + this[i].toString().split('"').join('\\"') + '"';
}
}
return s + ']';
};
}
function AddVectorTab(url, name, id, title, key, before) {
var tabs = document.getElementById('p-views');
var tabItems = tabs.childNodes[3];
var vectorTabLink = createElement('a', name, {'title':title, 'href':url});
var vectorTabTitle = createElement('span', vectorTabLink, '');
var vectorTab = createElement('li', vectorTabTitle, {'id':id, 'class':'collapsible'});
if(before == null) {
var before = document.getElementById('ca-watch');
}
if(before == null) before = document.getElementById('ca-unwatch');
tabItems.insertBefore(vectorTab, before);
}
function addTab(url, name, id, title, key, after) {
return mw.util.addPortletLink('p-cactions', url, name, id, title, key, after);
}
//WARNING: This function requires iScript sidebox
function addToolboxLink(url, name, id, key) {
return mw.util.addPortletLink('p-mScripts', url, name, id, key);
}
//WARNING: This function requires iScript sidebox
function addBookmarkLink(url, name, id, key) {
return mw.util.addPortletLink('p-mBookmarks', url, name, id, key);
}
function addMenu(type, url, name, id, tooltip, accesskey, nextnode) {
addMenuItem('iScript-menu1', 'แจ้ง▼', type, url, name, id, tooltip, accesskey, nextnode);
}
function addWPMenu(type, url, name, id, tooltip, accesskey, nextnode) {
addMenuItem('iScript-menu2', 'แจ้งอยู่ในโครงการ▼', type, url, name, id, tooltip, accesskey, nextnode);
}
function addMenuItem(target, title, type, url, name, id, tooltip, accesskey, nextnode) {
//Use addTab function instead of specify to
if(iScriptConfig.useOldTabsNavigation) {
addTab(url, name, id, tooltip, accesskey, nextnode);
return;
}
var na, mn;
var li;
var color = " #1e90ff";
var menu = document.getElementById(target);
//Create menu if not yet exist
if(menu) {
if(skin == "vector") {
menu = document.getElementById(target);
} else {
menu = menu.getElementsByTagName('ul')[0];
}
} else {
if(skin == "vector") {
title = title.replace("▼","");
var tabs = document.getElementById('right-navigation');
var menuTitle = createElement('span', title, "");
var menuTitle2 = createElement('span', title, "");
var menuLink = createElement('a', "", {'href':"#"});
var menuHeading = createElement('h3', menuTitle2 , "");
menuHeading.appendChild(menuLink);
var menuHolder = createElement('div', menuHeading, {'id':"p-iScriptMenu", 'role':"navigation", 'class':"vectorMenu"});
var menuDiv;
if(target == 'iScript-menu2') {
menuDiv = createElement('div', "", {'id':target, 'class':"menu wikiMenu"});
} else {
menuDiv = createElement('div', "", {'id':target, 'class':"menu"});
}
menuHolder.appendChild(menuDiv);
menu = createElement("ul", "", "");
menuDiv.appendChild(menu);
//var menuTab = createElement("li", [menu, title], {'id':target, 'class':"tabmenu", 'title':"แจ้ง..."});
var iScriptMenu = document.getElementById(target);
//menuHolder.appendChild(menuTab);
if(iScriptMenu && (target == "ca-menu" || target == "ca-menu2")) {
iScriptMenu.appendChild(menu);
menu = document.getElementById(target);
} else {
var beforeElement = document.getElementById("p-search");
tabs.insertBefore(menuHolder, beforeElement);
}
} else {
var tabs = document.getElementById('p-cactions').getElementsByTagName('ul')[0];
menu = createElement("ul", "", {'class':"tabmenu"});
var menuTab = createElement("li", [menu, title], {'id':target, 'class':"tabmenu", 'title':"แจ้ง..."});
var menu2 = document.getElementById("ca-menu2");
if(menu2 && target == "ca-menu") {
tabs.insertBefore(menuTab, menu2);
} else {
tabs.appendChild(menuTab);
}
}
//IE6 Support
if (!window.XMLHttpRequest && document.all) {
//menu.style.marginLeft = "1.6em";
menuTab.onmouseover = function() {
menuTab.style.zIndex = 3;
menu.style.display = "block";
};
menuTab.onmouseout = function() {
menuTab.style.zIndex = 0;
menu.style.display = "none";
};
}
}
if(type) {
switch(type) {
case 'serious': color = '#b22222'; break;
case 'content' : color = '#f28500'; break;
case 'style' : color = '#f4c430'; break;
case 'merge' : color = '#9932cc'; break;
case 'notice' : color = '#1e90ff'; break;
case 'growth': color = '#228b22'; break;
default: color = type;
}
}
if (!id) id = name;
if (!url) url = '#';
(na = document.createElement("a")).appendChild(document.createTextNode(name));
na.href = url;
if (accesskey) {
na.setAttribute( "accesskey", accesskey);
tooltip += " ["+accesskey+"]";
}
if(tooltip) na.setAttribute('title', tooltip);
mn = document.createElement("ul");
(li = document.createElement("li")).appendChild(na);
li.style.cssText = "border-left: 10px solid " + color + ";";
//li.appendChild(mn);
if (id) li.id = id;
if(skin == "vector" && menu.localName != "ul") {
menu = menu.getElementsByTagName('ul')[0];
}
if (nextnode) {
menu.insertBefore(li, nextnode);
} else {
menu.appendChild(li);
}
return mn; // useful because it gives us the <ul> to add <li>s to
}
// ========== assignToEditForm designed for iScript ==========
function assignToEditForm(iScriptAction, param1, param2, param3, param4) {
if(iScriptConfig.useAjaxApi && iScriptAction.indexOf("addMessageTemplate") == 0) {
AddTemplate(wgPageName, param1, param2, param3, param4);
return;
}
var link = wgScript + "?title=" + encodeURIComponent(wgPageName) + "&action=edit&iScriptAction=" + iScriptAction;
if(param1 != null) {
link += "&iScriptParam1=" + param1;
}
if(param2 != null) {
link += "&iScriptParam2=" + param2;
}
if(param3 != null) {
link += "&iScriptParam3=" + param3;
}
if(param4 != null) {
link += "&iScriptParam4=" + param4;
}
location.assign(link);
}
//Send the page with provided action and params to Talk Page.
//Added fragile partial support for non-main namespaces
//Added incomplete support for universal use even on talk page.
function assignToEditTalkForm(iScriptAction, param1, param2, param3) {
var ns = "พูดคุย:";
if(wgNamespaceNumber > 0) {
ns = wgPageName.substr(0, wgPageName.indexOf(":") + 1);
if(wgNamespaceNumber % 2 == 0) {
if(ns.indexOf("ผู้ใช้") >= 0) {
ns = "คุยกับ" + ns;
} else {
ns = "คุยเรื่อง" + ns;
}
}
}
if(iScriptConfig.useAjaxApi == true) {
if(iScriptAction.indexOf("doWP") == 0) {
AddWPBanner(ns + mw.config.get('wgTitle'), param1, param2, param3);
} else if (iScriptAction.indexOf("addMessageTemplate") == 0) {
AddTemplate(ns + mw.config.get('wgTitle'), param1, param2, param3);
}
return;
}
ns = encodeURIComponent(ns);
if(wgAction.indexOf("edit") == 0) {
if(iScriptAction.indexOf("doWP") == 0) {
doWP(param1, param2, param3);
return;
} else if (iScriptAction.indexOf("addMessageTemplate") == 0) {
addMessageTemplate(param1, param2, param3);
return;
}
}
var link = wgScript + "?title=" + ns + encodeURIComponent(mw.config.get('wgTitle')) + "&action=edit&iScriptAction=" + iScriptAction;
if(param1 != null) {
link += "&iScriptParam1=" + param1;
}
if(param2 != null) {
link += "&iScriptParam2=" + param2;
}
if(param3 != null) {
link += "&iScriptParam3=" + param3;
}
location.assign(link);
}
/** extended createElement function *************************************
*
* Description: createElement function with additional params
* Added by: [[User:Jutiphan]]
* Maintainers: [[User:Jutiphan]]
* Source: //zh.wikipedia.org/wiki/mediawiki:common.js
*/
function createElement(tag, children, props) {
var element = document.createElement(tag);
if (!(children instanceof Array)) {
children = [children];
}
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (typeof child == 'string') {
child = document.createTextNode(child);
}
if (child) {
element.appendChild(child);
}
}
if (typeof props == 'object') {
for (var k in props) {
switch (k) {
case 'styles':
var styles = props.styles;
for (var s in styles) {
element.style[s] = styles[s];
}
break;
case 'events':
var events = props.events;
for (var e in events) {
addHandler(element, e, events[e]);
}
break;
case 'class':
element.className = props[k];break;
case 'toJSONString':
break;
default:
element.setAttribute(k, props[k]);
}
}
}
return element;
}
//Returns the name of the page. For example, if you were browsing the "[[foo]]" WP page, getPname() would return "foo"
function getPname() {
if (typeof wgPageName != 'undefined' && wgPageName != null) {
return wgPageName.replace(/_/g, ' ');
} else {
return document.getElementsByTagName('h1')[0].firstChild.nodeValue;
//return document.title.substr(0, document.title.lastIndexOf(' - วิกิพีเดีย'));
/*
z=document.getElementById("content").childNodes;
for (var n=0;n<z.length;n++) {
if (z[n].className=="firstHeading") return URLEncoding(z[n].innerHTML);
}
*/
}
}
//Return selected text if any. User getSelTextArea to get selected text in textbox
function getSelText() {
var text = "";
if (window.getSelection
&& window.getSelection().toString()
&& $(window.getSelection()).attr('type') != "Caret") {
text = window.getSelection().toString();;
return text;
} else if (document.getSelection
&& document.getSelection().toString()
&& $(document.getSelection()).attr('type') != "Caret") {
text = document.getSelection().toString();;
return text;
} else {
var selection = document.selection && document.selection.createRange();
if (!(typeof selection === "undefined")
&& selection.text
&& selection.text.toString()) {
text = selection.text;
return text;
}
}
if (window.getSelection) {
selText = window.getSelection();
} else if (document.getSelection) {
selText = document.getSelection();
} else if (document.selection) {
selText = document.selection.createRange();
selText = selText.text;
} else {
return "";
}
}
//Get selected text in textbox.
function getSelTextArea() {
var txtArea = document.editform.wpTextbox1;
if($.client.profile().layout == 'gecko') {
if (txtArea.selectionStart || txtArea.selectionStart == '0') {
var startPos = txtArea.selectionStart;
var endPos = txtArea.selectionEnd;
return (txtArea.value).substring(startPos, endPos);
}
} else {
var selText = "";
if (window.getSelection) {
selText = window.getSelection();
} else if (document.getSelection) {
selText = document.getSelection();
} else if (document.selection) {
selText = document.selection.createRange();
selText = selText.text;
}
return selText;
}
return "";
}
//===== getUploader =====
//Source: en:User:Howcheng/quickimgdelete.js, adapted & further modified by user:Jutiphan
//NOTE: DO NOT UPGRADE TO NEWER VER WITHOUT MERGE. This is custom, include sysop fix. See below.
/*
* Current version: 1.10.4
* Updated to version: 1.14.2 (Hotfixes only)
* =======================================
* Created by [[User:Howcheng|Howard Cheng]]
* Released under the [[GNU Public License]] (GPL)
* Full documentation at [[User talk:Howcheng/quickimgdelete.js]]
* =======================================
*/
//NOTE: DOES NOT work in Edit page
// Get uploader from first point in the list under "File history"
// Uploader is stored in second A tag in UL tag under "File history"
// Returns title of user page (without name space) in URL form
function getUploader() {
// Returns title of user page (without name space) in URL form
var trs = qid_getFileHistory();
var els = new Array();
var tr = trs[0]; // skip first one because it's the header
do {
tr = tr.nextSibling;
var tds = tr.childNodes;
var td = tds[(userIsInGroup("sysop") ? 5 : 4)]; // uploader info
els[els.length] = td;
} while (tr.nextSibling);
var uploaders = new Array();
var re1 = new RegExp(('/wiki/').replace(/\./g, '\\.') + 'ผู้ใช้:(.*)$');
var re2 = new RegExp((wgServer + wgScript).replace(/\./g, '\\.') + '\\?title=ผู้ใช้:([^&]*)');
var re3 = /(คุยกับ)?ผู้ใช้:(.*?)( \((ยังไม่ได้สร้าง|หน้านี้ไม่มี)\))?$/; // this is for IE and handling Unicode characters
var m;
var uploader;
var uploaderList = "";
var count = 0;
for (var i = 0; i < els.length; i++) {
var el = els[i];
if (!el) continue;
var as = el.childNodes;
if (!as) continue;
for (var k=0; k<as.length; k++) {
if (as[k].tagName != 'A') continue;
m = re3.exec(as[k].title);
if (m) uploader = encodeURIComponent(m[2]);
m = re1.exec(as[k].href);
if (m) uploader = m[1];
m = re2.exec(as[k].href);
if (m) uploader = m[1];
if (uploader) break;
}
if (uploaderList.indexOf(uploader) == -1) {
if (count > 0) uploaderList += "; ";
uploaderList += count + " - " + uploader;
uploaders[uploaders.length] = uploader;
count += 1;
}
}
if (!uploaders || uploaders.length == 0) {
alert("getUploader: ไม่สามารถดึงชื่อผู้ใช้ที่อัปโหลดได้ กรุณาแจ้งผู้ใช้:Jutiphan");
return null;
}
if (uploaders.length == 1)
return uploaders[0];
var which = parseInt(window.prompt("กรุณาเลือกชื่อผู้ใช้ที่ต้องการจะแจ้ง: " + uploaderList, ""));
if (isNaN(which) || which < 0 || which >= uploaders.length) {
alert("getUploader: ไม่มีชื่อผู้ใช้ที่เลือก หยุดการดำเนินการ");
return null;
}
return uploaders[which];
}
function GetThaiFullMonthName(monthNo) {
switch (monthNo) {
case 1:
return "มกราคม";
case 2:
return "กุมภาพันธ์";
case 3:
return "มีนาคม";
case 4:
return "เมษายน";
case 5:
return "พฤษภาคม";
case 6:
return "มิถุนายน";
case 7:
return "กรกฎาคม";
case 8:
return "สิงหาคม";
case 9:
return "กันยายน";
case 10:
return "ตุลาคม";
case 11:
return "พฤศจิกายน";
case 12:
return "ธันวาคม";
default:
return "";
}
}
//===== qid_getFileHistory =====
//Part of getUploader. See above.
function qid_getFileHistory() {
var el = document.getElementById('mw-imagepage-section-filehistory');
if (!el) {
alert("getUploader: ไม่พบประวัติไฟล์ หยุดการดำเนินงาน กรุณาแจ้งผู้ใช้:Jutiphan");
return null;
}
el = el.firstChild;
while (el.nextSibling) {
el = el.nextSibling;
if (el.tagName && el.tagName.toLowerCase() == 'table')
break;
}
if (!el) {
alert("getUploader: ไม่พบป้าย TABLE หยุดการทำงาน กรุณาแจ้งผู้ใช้:Jutiphan");
return null;
}
var trs = el.getElementsByTagName('tr');
if (!trs) {
alert("getUploader: ไม่พบป้าย TR หยุดการทำงาน กรุณาแจ้งผู้ใช้:Jutiphan");
return null;
}
return trs;
}
//===== Set Cursor Position in given Textbox =====
//Source: //parentnode.org/javascript/working-with-the-cursor-position/
function setCaretTo(obj, pos) {
if (obj.createTextRange) {
/* Create a TextRange, set the internal pointer to
a specified position and show the cursor at this
position
*/
var range = obj.createTextRange();
range.move("character", pos);
range.select();
} else if (obj.selectionStart) {
/* Gecko is a little bit shorter on that. Simply
focus the element and set the selection to a
specified position
*/
obj.focus();
obj.setSelectionRange(pos, pos);
}
}
// ========== Open In New Window ==========
function openInNewWindow(website, windowName, isFocus) {
if(!windowName) {
windowName = '_blank';
}
var newWindow = window.open(website, windowName);
if(isFocus) {
newWindow.focus();
}
}
// ========== Check if the user is an IP Address ==========
/* Returns true if given string contains a valid IP-address, that is, from 0.0.0.0 to 255.255.255.255*/
function isIPAddress(string) {
var res = /(\d{1,4})\.(\d{1,3})\.(\d{1,3})\.(\d{1,4})/.exec(string);
return res != null && res.slice(1, 5).every(function(e) {
return e < 256;
});
}
// ========== Check if the user belongs to the given group ==========
function userIsInGroup(groupName) {
for (var i = 0; i < wgUserGroups.length; i++) {
if (wgUserGroups[i] == groupName)
return true;
}
return false;
}
// ========== Replace string ==========
// Javascript from //www.irt.org/script/242.htm
function replace(string, text, by) {
// Replaces text with by in string
var strLength = string.length, txtLength = text.length;
if ((strLength == 0) || (txtLength == 0)) return string;
var i = string.indexOf(text);
if ((!i) && (text != string.substring(0, txtLength))) return string;
if (i == -1) return string;
var newstr = string.substring(0, i) + by;
if (i + txtLength < strLength)
newstr += replace(string.substring(i + txtLength, strLength), text, by);
return newstr;
}
// ========== [String].trim ==========
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/, '');
};
// Replaces all instances of the given substring.
String.prototype.replaceAll = function(
strTarget, // The substring you want to replace
strSubString // The string you want to replace in.
) {
var strText = this;
var intIndexOfMatch = strText.indexOf(strTarget);
// Keep looping while an instance of the target string
// still exists in the string.
while (intIndexOfMatch != -1) {
// Relace out the current instance.
strText = strText.replace(strTarget, strSubString);
// Get the index of any next matching substring.
intIndexOfMatch = strText.indexOf(strTarget);
}
// Return the updated string with ALL the target strings
// replaced out with the new substring.
return( strText );
};
// Simple helper function to create a simple node
function htmlNode(type, content, color) {
var node = document.createElement(type);
if (color) {
node.style.color = color;
}
node.appendChild(document.createTextNode(content));
return node;
}
// ========== Error Handling Support ==========
function errorHandler(message, url, line)
{
Status.error("ขออภัย พบเจอข้อผิดพลาด " + message + " บรรทัดที่ " + line + " ใน " + url + ". กรุณาแจ้งปัญหานี้ที่ ผู้ใช้:Jutiphan");
return true;
}
//Install the global error-handler
window.onerror = errorHandler;
//Simple exception handling
Exception = function( message ) {
this.message = message || '';
this.name = "Exception";
};
Exception.prototype.what = function() {
return this.str;
};
// ========== Status class ==========
function Status( text, stat, type ) {
this.text = this.codify(text);
this.stat = this.codify(stat);
this.type = type || 'status';
this.generate();
if( stat ) {
this.render();
}
}
Status.init = function( root ) {
if( !( root instanceof Element ) ) {
throw new Exception( 'object not an instance of Element' );
}
while( root.hasChildNodes() ) {
root.removeChild( root.firstChild );
}
Status.root = root;
var cssNode = document.createElement('style');
cssNode.type = 'text/css';
cssNode.rel = 'stylesheet';
cssNode.appendChild( document.createTextNode("")); // Safari bugfix
document.getElementsByTagName("head")[0].appendChild(cssNode);
var styles = cssNode.sheet ? cssNode.sheet : cssNode.stylesSheet;
styles.insertRule(".tw_status_status { color: SteelBlue; }", 0);
styles.insertRule(".tw_status_info { color: ForestGreen; }", 0);
styles.insertRule(".tw_status_warn { color: OrangeRed; }", 0);
styles.insertRule(".tw_status_error { color: OrangeRed; font-weight: 900; }", 0);
};
Status.root = null;
Status.prototype = {
stat: null,
text: null,
type: 'status',
target: null,
node: null,
linked: false,
link: function() {
if( ! this.linked && Status.root ) {
Status.root.appendChild( this.node );
this.linked = true;
}
},
unlink: function() {
if( this.linked ) {
Status.root.removeChild( this.node );
this.linked = false;
}
},
codify: function( obj ) {
if ( ! ( obj instanceof Array ) ) {
obj = [ obj ];
}
var result;
result = document.createDocumentFragment();
for( var i = 0; i < obj.length; ++i ) {
if( typeof obj[i] == 'string' ) {
result.appendChild( document.createTextNode( obj[i] ) );
} else if( obj[i] instanceof Element ) {
result.appendChild( obj[i] );
} // Else cosmic radiation made something shit
}
return result;
},
update: function( status, type ) {
this.stat = this.codify( status );
if( type ) {
this.type = type;
}
this.render();
},
generate: function() {
this.node = document.createElement( 'div' );
this.node.appendChild( document.createElement('span') ).appendChild( this.text );
this.node.appendChild( document.createElement('span') ).appendChild( document.createTextNode( ': ' ) );
this.target = this.node.appendChild( document.createElement( 'span' ) );
this.target.appendChild( document.createTextNode( '' ) ); // dummy node
},
render: function() {
this.node.className = 'tw_status_' + this.type;
while( this.target.hasChildNodes() ) {
this.target.removeChild( this.target.firstChild );
}
this.target.appendChild( this.stat );
this.link();
},
status: function( status ) {
this.update( status, 'status');
},
info: function( status ) {
this.update( status, 'info');
},
warn: function( status ) {
this.update( status, 'warn');
},
error: function( status ) {
this.update( status, 'error');
}
};
Status.status = function( text, status ) {
return new Status( text, status, 'status' );
};
Status.info = function( text, status ) {
return new Status( text, status, 'info' );
};
Status.warn = function( text, status ) {
return new Status( text, status, 'error' );
};
Status.error = function( text, status ) {
return new Status( text, status, 'error' );
};
/**
* Maps the querystring to an object
*
* Functions:
*
* QueryString.exists(key)
* returns true if the particular key is set
* QueryString.get(key)
* returns the value associated to the key
* QueryString.equals(key, value)
* returns true if the value associated with given key equals given value
* QueryString.toString()
* returns the query string as a string
* QueryString.create( hash )
* creates an querystring and encodes strings via encodeURIComponent and joins arrays with |
*
* In static context, the value of location.search.substring(1), else the value given to the constructor is going to be used. The mapped hash is saved in the object.
*
* Example:
*
* var value = QueryString.get('key');
* var obj = new QueryString('foo=bar&baz=quux');
* value = obj.get('foo');
*/
function QueryString(qString) {
this.string = qString;
this.params = {};
if( qString.length == 0 ) {
return;
}
qString.replace(/\+/, ' ');
var args = qString.split('&');
for( var i = 0; i < args.length; ++i ) {
var pair = args[i].split( '=' );
var key = decodeURIComponent( pair[0] ), value = key;
if( pair.length == 2 ) {
value = decodeURIComponent( pair[1] );
}
this.params[key] = value;
}
}
QueryString.static = null;
QueryString.staticInit = function() {
if( QueryString.static == null ) {
QueryString.static = new QueryString(location.search.substring(1));
}
};
QueryString.get = function(key) {
QueryString.staticInit();
return QueryString.static.get(key);
};
QueryString.prototype.get = function(key) {
return this.params[key] ? this.params[key] : null;
};
QueryString.exists = function(key) {
QueryString.staticInit();
return QueryString.static.exists(key);
};
QueryString.prototype.exists = function(key) {
return this.params[key] ? true : false;
};
QueryString.equals = function(key, value) {
QueryString.staticInit();
return QueryString.static.equals(key, value);
};
QueryString.prototype.equals = function(key, value) {
return this.params[key] == value ? true : false;
};
QueryString.toString = function() {
QueryString.staticInit();
return QueryString.static.toString();
};
QueryString.prototype.toString = function() {
return this.string ? this.string : null;
};
QueryString.create = function( arr ) {
var resarr = Array();
var editToken; // KLUGE: this should always be the last item in the query string (bug TW-B-0013)
for( var i in arr ) {
if( typeof arr[i] == 'undefined' ) {
continue;
}
var res;
if( arr[i] instanceof Array ){
var v = Array();
for(var j = 0; j < arr[i].length; ++j ) {
v[j] = encodeURIComponent( arr[i][j] );
}
res = v.join('|');
} else {
res = encodeURIComponent( arr[i] );
}
if( i == 'wpEditToken' ) {
editToken = res;
} else {
resarr.push( encodeURIComponent( i ) + '=' + res );
}
}
if( typeof editToken != 'undefined' ) {
resarr.push( 'wpEditToken=' + editToken );
}
return resarr.join('&');
};
QueryString.prototype.create = QueryString.create;
// Accessor functions for wikiediting and api-access
Wikipedia = {};
// we dump all XHR here so they won't loose props
Wikipedia.dump = [];
Wikipedia.numberOfActionsLeft = 0;
Wikipedia.nbrOfCheckpointsLeft = 0;
Wikipedia.actionCompleted = function( self ) {
if( --Wikipedia.numberOfActionsLeft <= 0 && Wikipedia.nbrOfCheckpointsLeft <= 0 ) {
Wikipedia.actionCompleted.event( self );
}
};
// Change per action wanted
Wikipedia.actionCompleted.event = function() {
new Status( Wikipedia.actionCompleted.notice, Wikipedia.actionCompleted.postfix, 'info' );
if( Wikipedia.actionCompleted.redirect != null ) {
// if it isn't an url, make it an relative to self (probably this is the case)
if( !/^\w+\:\/\//.test( Wikipedia.actionCompleted.redirect ) ) {
Wikipedia.actionCompleted.redirect = wgServer + wgArticlePath.replace( '$1', encodeURIComponent( Wikipedia.actionCompleted.redirect ).replace( /\%2F/g, '/' ) );
}
window.setTimeout( function() { window.location = Wikipedia.actionCompleted.redirect; } , Wikipedia.actionCompleted.timeOut );
}
};
wpActionCompletedTimeOut = typeof(wpActionCompletedTimeOut) == 'undefined' ? 5000 : wpActionCompletedTimeOut;
wpMaxLag = typeof(wpMaxLag) == 'undefined' ? 10 : wpMaxLag; // Maximum lag allowed, 5-10 is a good value, the higher value, the more agressive.
Wikipedia.editCount = 10;
Wikipedia.actionCompleted.timeOut = wpActionCompletedTimeOut;
Wikipedia.actionCompleted.redirect = null;
Wikipedia.actionCompleted.notice = 'Action';
Wikipedia.actionCompleted.postfix = 'เรียบร้อย';
Wikipedia.addCheckpoint = function() {
++Wikipedia.nbrOfCheckpointsLeft;
};
Wikipedia.removeCheckpoint = function() {
if( --Wikipedia.nbrOfCheckpointsLeft <= 0 && Wikipedia.numberOfActionsLeft <= 0 ) {
Wikipedia.actionCompleted.event();
}
};
/*
currentAction: text, the current action (required)
query: Object, the query (required)
oninit: function, the function to call when page gotten
*/
Wikipedia.api = function( currentAction, query, oninit, statelem ) {
this.currentAction = currentAction;
this.query = query;
this.query['format'] = 'xml'; //LET THE FORCE BE WITH YOU!!!
this.oninit = oninit;
if( statelem ) {
statelem.status( currentAction );
} else {
this.statelem = new Status( currentAction );
}
++Wikipedia.numberOfActionsLeft;
};
Wikipedia.api.prototype = {
currentAction: '',
oninit: null,
query: null,
responseXML: null,
statelem: null,
counter: 0,
post: function() {
var xmlhttp = sajax_init_object();
Wikipedia.dump.push( xmlhttp );
xmlhttp.obj = this;
xmlhttp.overrideMimeType('text/xml');
xmlhttp.open( 'POST' , wgServer + wgScriptPath + '/api.php', true);
xmlhttp.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xmlhttp.onerror = function() {
this.obj.statelem.error( "พบเจอข้อผิดพลาด " + this.target.status + " ระหว่างกำลังดึงข้อมูลผ่าน API" );
};
xmlhttp.onload = function() {
this.obj.responseXML = this.responseXML;
if( this.obj.oninit ) {
this.obj.oninit( this.obj );
}
Wikipedia.actionCompleted();
};
xmlhttp.send( QueryString.create( this.query ) );
}
};
/*
currentAction: text, the current action (required)
query: Object, the query (required)
oninit: function, the function to call when page gotten (required)
onsuccess: function, a function to call when post succeeded
onerror: function, a function to call when we abort failed posts
onretry: function, a function to call when we try to retry a post
*/
Wikipedia.wiki = function( currentAction, query, oninit, onsuccess, onerror, onretry ) {
this.currentAction = currentAction;
this.query = query;
this.oninit = oninit;
this.onsuccess = onsuccess;
this.onerror = onerror;
this.onretry = onretry;
this.statelem = new Status( currentAction );
++Wikipedia.numberOfActionsLeft;
};
Wikipedia.wiki.prototype = {
currentAction: '',
onsuccess: null,
onerror: null,
onretry: null,
oninit: null,
query: null,
postData: null,
responseXML: null,
statelem: null,
counter: 0,
post: function( data ) {
this.postData = data;
if( Wikipedia.editCount <= 0 ) {
this.query['maxlag'] = wpMaxLag; // are we a bot?
} else {
--Wikipedia.editCount;
}
var xmlhttp = sajax_init_object();
Wikipedia.dump.push( xmlhttp );
xmlhttp.obj = this;
xmlhttp.overrideMimeType('text/xml');
xmlhttp.open( 'POST' , wgServer + wgScriptPath + '/index.php?useskin=monobook&' + QueryString.create( this.query ), true);
xmlhttp.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xmlhttp.onerror = function(e) {
var self = this.obj;
self.statelem.error( "Error " + e.target.status + " occurred while posting the document." );
};
xmlhttp.onload = function(e) {
var self = this.obj;
var status = e.target.status;
if( status != 200 ) {
if( status == 503 ) {
var retry = e.target.getResponseHeader( 'Retry-After' );
var lag = e.target.getResponseHeader( 'X-Database-Lag' );
if( lag ) {
self.statelem.warn( "current lag of " + lag + " seconds is more than our defined maximum lag of " + wpMaxLag + " seconds, will retry in " + retry + " seconds" );
window.setTimeout( function( self ) { self.post( self.postData ); }, retry * 1000, self );
return;
} else {
self.statelem.error( "Error " + status + " occurred while posting the document." );
}
}
return;
}
var xmlDoc;
xmlDoc = self.responseXML = this.responseXML;
var xpathExpr = 'boolean(//div[@class=\'previewnote\']/p/strong[contains(.,\'Sorry! We could not process your edit due to a loss of session data\')])';
var nosession = xmlDoc.evaluate( xpathExpr, xmlDoc, null, XPathResult.BOOLEAN_TYPE, null ).booleanValue;
if( nosession ) {
// Grabbing the shipping token, and repost
var new_token = xmlDoc.evaluate( '//input[@name="wfEditToken"]/@value', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue;
self.postData['wfEditToken'] = new_token;
self.post( self.postData );
} else {
if( self.onsuccess ) {
self.onsuccess( self );
} else {
var link = document.createElement( 'a' );
link.setAttribute( 'href', wgArticlePath.replace( '$1', self.query['title'] ) );
link.setAttribute( 'title', self.query['title'] );
link.appendChild( document.createTextNode( self.query['title'] ) );
self.statelem.info( [ 'เรียบร้อย (' , link , ')' ] );
}
Wikipedia.actionCompleted();
}
};
xmlhttp.send( QueryString.create( this.postData ) );
},
get: function() {
this.onloading( this );
var redirect_query = {
'action': 'query',
'titles': this.query['title'],
'redirects': ''
};
var wikipedia_api = new Wikipedia.api( "กำลังตรวจสอบและข้ามหน้าเปลี่ยนทาง", redirect_query, this.postget, this.statelem );
wikipedia_api.parent = this;
wikipedia_api.post();
},
postget: function() {
var xmlDoc = self.responseXML = this.responseXML;
var to = xmlDoc.evaluate( '//redirects/r/@to', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue;
if( !this.followRedirect ) {
this.parent.statelem.info('ไม่สนใจหน้าเปลี่ยนทาง');
} else if( to ) {
this.parent.query['title'] = to;
}
this.parent.onloading( this );
var xmlhttp = sajax_init_object();
Wikipedia.dump.push( xmlhttp );
xmlhttp.obj = this.parent;
xmlhttp.overrideMimeType('text/xml');
xmlhttp.open( 'GET' , wgServer + wgScriptPath + '/index.php?useskin=monobook&' + QueryString.create( this.parent.query ), true);
xmlhttp.onerror = function() {
var self = this.obj;
self.statelem.error( "Error " + this.status + " occurred while receiving the document." );
};
xmlhttp.onload = function() {
this.obj.onloaded( this.obj );
this.obj.responseXML = this.responseXML;
this.obj.responseText = this.responseText;
this.obj.oninit( this.obj );
};
xmlhttp.send( null );
},
onloading: function() {
this.statelem.status( 'กำลังโหลด...' );
},
onloaded: function() {
this.statelem.status( 'ข้อมูลโหลดแล้ว...' );
}
};
// Sprintf implementation based on perl similar
function sprintf() {
if( arguments.length == 0 ) {
throw "Not enough arguments for sprintf";
}
var result = "";
var format = arguments[0];
var index = 1;
var current_index = 1;
var flags = {};
var in_operator = false;
var relative = false;
var precision = false;
var fixed = false;
var vector = false;
var vector_delimiter = '.';
for( var i = 0; i < format.length; ++i ) {
var current_char = format.charAt(i);
if( in_operator ) {
switch( current_char ) {
case 'i':
current_char = 'd';
break;
case 'F':
current_char = 'f';
break;
case '%':
case 'c':
case 's':
case 'd':
case 'u':
case 'o':
case 'x':
case 'e':
case 'f':
case 'g':
case 'X':
case 'E':
case 'G':
case 'b':
var value = arguments[current_index];
if( vector ) {
r = value.toString().split( '' );
result += value.toString().split('').map( function( value ) {
return sprintf.format( current_char, value.charCodeAt(), flags );
}).join( vector_delimiter );
} else {
result += sprintf.format( current_char, value, flags );
}
if( !fixed ) {
++index;
}
current_index = index;
flags = {};
relative = false;
in_operator = false;
precision = false;
fixed = false;
vector = false;
vector_delimiter = '.';
break;
case 'v':
vector = true;
break;
case ' ':
case '0':
case '-':
case '+':
case '#':
flags[current_char] = true;
break;
case '*':
relative = true;
break;
case '.':
precision = true;
break;
}
if( /\d/.test( current_char ) ) {
var num = parseInt( format.substr( i ) );
var len = num.toString().length;
i += len - 1;
var next = format.charAt( i + 1 );
if( next == '$' ) {
if( num <= 0 || num >= arguments.length ) {
throw "out of bound";
}
if( relative ) {
if( precision ) {
flags['precision'] = arguments[num];
precision = false;
} else if( format.charAt( i + 2 ) == 'v' ) {
vector_delimiter = arguments[num];
}else {
flags['width'] = arguments[num];
}
relative = false;
} else {
fixed = true;
current_index = num;
}
++i;
} else if( precision ) {
flags['precision'] = num;
precision = false;
} else {
flags['width'] = num;
}
} else if ( relative && !/\d/.test( format.charAt( i + 1 ) ) ) {
if( precision ) {
flags['precision'] = arguments[current_index];
precision = false;
} else if( format.charAt( i + 1 ) == 'v' ) {
vector_delimiter = arguments[current_index];
} else {
flags['width'] = arguments[current_index];
}
++index;
if( !fixed ) {
current_index++;
}
relative = false;
}
} else {
if( current_char == '%' ) {
in_operator = true;
continue;
} else {
result += current_char;
continue;
}
}
}
return result;
}
sprintf.format = function sprintfFormat( type, value, flags ) {
// Similar to how perl printf works
if( value == undefined ) {
if( type == 's' ) {
return '';
} else {
return '0';
}
}
var result;
var prefix = '';
var fill = '';
var fillchar = ' ';
switch( type ) {
case '%':
result = '%';
break;
case 'c':
result = String.fromCharCode( parseInt( value ) );
break;
case 's':
result = value.toString();
break;
case 'd':
result = parseInt( value ).toString();
break;
case 'u':
result = Math.abs( parseInt( value ) ).toString(); // it's not correct, but JS lacks unsigned ints
break;
case 'o':
result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(8);
break;
case 'x':
result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(16);
break;
case 'b':
result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(2);
break;
case 'e':
var digits = flags['precision'] ? flags['precision'] : 6;
result = (new Number( value ) ).toExponential( digits ).toString();
break;
case 'f':
var digits = flags['precision'] ? flags['precision'] : 6;
result = (new Number( value ) ).toFixed( digits ).toString();
case 'g':
var digits = flags['precision'] ? flags['precision'] : 6;
result = (new Number( value ) ).toPrecision( digits ).toString();
break;
case 'X':
result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(16).toUpperCase();
break;
case 'E':
var digits = flags['precision'] ? flags['precision'] : 6;
result = (new Number( value ) ).toExponential( digits ).toString().toUpperCase();
break;
case 'G':
var digits = flags['precision'] ? flags['precision'] : 6;
result = (new Number( value ) ).toPrecision( digits ).toString().toUpperCase();
break;
}
if(flags['+'] && parseFloat( value ) > 0 && ['d','e','f','g','E','G'].indexOf(type) != -1 ) {
prefix = '+';
}
if(flags[' '] && parseFloat( value ) > 0 && ['d','e','f','g','E','G'].indexOf(type) != -1 ) {
prefix = ' ';
}
if( flags['#'] && parseInt( value ) != 0 ) {
switch(type) {
case 'o':
prefix = '0';
break;
case 'x':
case 'X':
prefix = '0x';
break;
case 'b':
prefix = '0b';
break;
}
}
if( flags['0'] && !flags['-'] ) {
fillchar = '0';
}
if( flags['width'] && flags['width'] > ( result.length + prefix.length ) ) {
var tofill = flags['width'] - result.length - prefix.length;
for( var i = 0; i < tofill; ++i ) {
fill += fillchar;
}
}
if( flags['-'] && !flags['0'] ) {
result += fill;
} else {
result = fill + result;
}
return prefix + result;
};
/* </nowiki></pre> */