Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// [[User:Quarl/util.js]] - miscellaneous utility functions for Wikipedia user scripts
// quarl 2006-01-09 initial version
// NON-NAMESPACED FUNCTION NAMES ARE DEPRECATED
// <pre><nowiki>
/////////////////////////////////////////////////////////////
// STRING UTILITY FUNCTIONS
util = new Object();
util.trimSpaces = function(s) {
if (!s) return s;
s = s.replace(/^\s+/,'');
s = s.replace(/\s+$/,'');
return s;
}
trimspaces = util.trimSpaces;
util.trimLines = function(s) {
return s.replace(/^\n+/, '').replace(/\n+$/, '');
}
trim_lines = util.trimLines;
util.stringQuoteEscape = function(str) {
if (!str) return str;
return "'" + str.replace(/\'/g, '\\\'').replace(/\%27/g, '\\\'') + "'";
}
string_quote_escape = util.stringQuoteEscape;
// wiki article name escaping
util.wpaEscape = function(s) {
// encodeURIComponent is better than 'escape' for unicode chars;
// it also escapes '+'.
// Don't escape ':'
return encodeURIComponent(s.replace(/ /g,'_')).replace(/%3A/g,':').replace(/%2F/g,'/');
}
wpaescape = wpaencode = util.wpaEscape;
util.wpaDecode = function(s) {
return decodeURIComponent(s).replace(/_/g,' ');
}
wpaunescape = wpadecode = util.wpaDecode;
util.urlGetPath = function(s) {
return s.replace(/^http:\/\/[^\/]+/, '');
}
url_getpath = util.urlGetPath;
// Return an authentication token useful to pass through URL for automatic
// edits, to prevent XSS attacks.
//
// requires md5.js
util.makeAuthToken = function() {
// I'd like to use something like readCookie('enwikiToken') + '%' +
// readCookie('enwiki_session')), but not sure how to get it cross-wiki
// compatible, so just use entire cookie for now.
return hex_md5('auth_token:'+Array.join(arguments, '%') +
'%%' + document.cookie);
}
makeAuthToken = util.makeAuthToken;
////////////////////////////////////////////////////////////
// DOM UTILITY FUNCTIONS
util.getElementsByClass = function(searchClass, node, tag) {
var classElements = [];
if (node == null)
node = document;
if (tag == null)
tag = '*';
var els = node.getElementsByTagName(tag);
var elsLen = els.length;
var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
for (var i = 0; i < elsLen; i++) {
if (pattern.test(els[i].className) ) {
classElements.push(els[i]);
}
}
return classElements;
}
getElementsByClass = util.getElementsByClass;
util.addClass = function(node, cls) {
node.className += ' '+cls;
}
addClass = util.addClass;
util.removeClass = function(node, cls) {
node.className = node.className.replace(
new RegExp("(^|\\s)"+cls+"(\\s|$)",'g'), ' ');
}
removeClass = util.removeClass;
util.addNodeBefore = function(node, newnode) {
node.parentNode.insertBefore(newnode, node);
return newnode;
}
add_before = util.addNodeBefore;
util.addNodeBefore = function(node, newnode) {
if (node.nextSibling) {
node.parentNode.insertBefore(newnode, node.nextSibling);
} else {
node.parentNode.appendChild(newnode);
}
return newnode;
}
add_after = util.addNodeBefore;
// return nodes in [node_start, node_end)
util.getNodesInRange = function(node_start, node_end) {
var nodes = [];
while (node_start != node_end) {
nodes.push(node_start);
node_start = node_start.nextSibling;
if (!node_start) return null; // didn't reach node_end!
}
return nodes;
}
getNodesInRange = util.getNodesInRange;
util.removeNodesInRange = function(node_start, node_end) {
if (!node_end) {
alert("## removeNodesInRange: node_end==null");
return null;
}
if (!util.getNodesInRange(node_start, node_end)) {
alert("## removeNodesInRange: range does not terminate");
return null;
}
var parent = node_start.parentNode;
while (node_start != node_end) {
var n = node_start.nextSibling; // save before it gets clobbered
parent.removeChild(node_start);
node_start = n;
if (!node_start) return null;
}
}
removeNodesInRange = util.removeNodesInRange;
util.createHref = function(href, title, inner) {
var a = document.createElement('a');
a.href = href;
a.title = title;
a.innerHTML = inner;
return a;
}
createHref = util.createHref;
util.findHref = function(href) {
href = util.wpaEscape(util.wpaDecode(href));
var links=document.links;
for(i=0;i<links.length;++i) {
// unescape and reescape to ensure canonical escaping
if (util.wpaEscape(util.wpaDecode(links[i].href)) == href) return links[i];
}
return null;
}
findHref = util.findHref;
// insert a new node as parent of node
util.insertNode = function(node, newNode) {
if (!node) return null;
node.parentNode.replaceChild(newNode, node);
newNode.appendChild(node);
return newNode;
}
insertNode = util.insertNode;
util.appendChildren = function(node, newNodes) {
for (var i in newNodes) {
node.appendChild(newNodes[i]);
}
}
appendChild = util.appendChild;
util.hookEventObj = function(obj, hookName, hookFunct) {
if (!obj) return;
if (obj.addEventListener)
obj.addEventListener(hookName, hookFunct, false);
else if (obj.attachEvent)
obj.attachEvent("on" + hookName, hookFunct);
}
hookEventObj = util.hookEventObj;
util.copyArray = function(a) {
var r = [];
for (var i=0; i < a.length; i++)
r[i] = a[i];
return r;
}
copyArray = util.copyArray;
// add a span around a node if there isn't one.
util.ensureSpan = function(node) {
if (node.parentNode.nodeName == 'SPAN') {
return node.parentNode;
}
return insertNode(node, document.createElement('span'));
}
ensureSpan = util.ensureSpan;
////////////////////////////////////////////////////////////
// STYLESHEET FUNCTIONS
util.addStylesheetRule = function(tag, style) {
var ss = document.styleSheets[0];
if (ss.insertRule) {
ss.insertRule(tag + '{' + style + '}', ss.cssRules.length);
} else if (ss.addRule) {
ss.addRule(tag, style);
}
}
addStylesheetRule = util.addStylesheetRule;
////////////////////////////////////////////////////////////
// AJAX FUNCTIONS
// cross-platform
util.HTTPClient = function() {
var http;
if(window.XMLHttpRequest) {
http = new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
http = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
http = new ActiveXObject("Microsoft.XMLHTTP");
} catch (E) {
http = false;
}
}
}
return http;
}
HTTPClient = util.HTTPClient;
util.asyncDownloadXML = function(url, callback, props) {
var req = util.HTTPClient();
if (!req) return null;
// add optional arguments
if (props) {
for (var k in props) {
req[k] = props[k];
}
}
req.open("GET", url, true);
req.overrideMimeType('text/xml');
// using onload instead of onreadystatechange allows multiple asynchronous requests
// TODO: since we now have access to 'req' as a variable, we could change back.
// Is there any advantage to using onreadystatechange?
req.onload = function(event) {
var req = event.target;
if (req.readyState == 4) callback(req);
};
req.send(null);
return req;
}
asyncDownloadXML = util.asyncDownloadXML;
util.buildParams = function(paramArray) {
var params = '';
for (k in paramArray) {
v = paramArray[k];
// if v is a Boolean then the form was a checkbox.
// unchecked checkboxes should not add any input fields.
if (v == false) continue;
if (v == true) v = 'on';
params += '&' + k + '=' + encodeURIComponent(v);
}
params = params.replace(/^&/,'');
return params;
}
buildParams = util.buildParams;
util.addFormHiddenParams = function(newform, d) {
for (var k in d) {
v = d[k];
// if v is a Boolean then the form was a checkbox.
// unchecked checkboxes should not add any input fields.
if (v == false) continue;
if (v == true) v = 'on';
var t = document.createElement('input');
t.type = 'hidden';
t.name = k;
t.value = d[k];
newform.appendChild(t);
}
return newform;
}
addFormHiddenParams = util.addFormHiddenParams;
util.asyncPostXML = function(url, parameters, callback, props) {
var req = util.HTTPClient();
if (!req) return null;
if (typeof parameters != 'string') parameters = buildParams(parameters);
// add optional arguments
if (props) {
for (var k in props) {
req[k] = props[k];
}
}
req.open("POST", url, true);
req.overrideMimeType('text/xml');
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.setRequestHeader("Content-length", parameters.length);
req.setRequestHeader("Connection", "close");
req.onload = function(event) {
var req = event.target;
if (req.readyState == 4) callback(req);
};
req.send(parameters);
return req;
}
asyncPostXML = util.asyncPostXML;
// Temporarily replace the content of statusNode with a non-clicakble, bolded string
// that shows we're doing something. statusNode should be the node that completely wraps
// an <a> element that was just clicked.
util.buttonShowStatus = function(statusNode, statusText) {
if (!statusNode) return;
if (!statusText) {
// use <a> tag to keep padding/margin/color/etc.
statusText = '<a><b>'+statusNode.textContent+'...</b></a>';
}
// Note: saving innerHTML doesn't work if we've messed with the document
// tree.
// statusNode.savedContent = statusNode.innerHTML;
// statusNode.innerHTML = statusText;
statusNode.savedContent = util.copyArray(statusNode.childNodes);
statusNode.innerHTML = statusText;
}
buttonShowStatus = util.buttonShowStatus;
util.buttonRestoreStatus = function(statusNode) {
if (statusNode && statusNode.savedContent) {
// statusNode.innerHTML = statusNode.savedContent;
statusNode.innerHTML = '';
util.appendChildren(statusNode, statusNode.savedContent);
}
}
buttonRestoreStatus = util.buttonRestoreStatus;
//
// </nowiki></pre>
You must be logged in to post a comment.