User:The Evil IP address/liedit.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
This user script seems to have a documentation page at User:The Evil IP address/liedit. |
/**
* Allows for one click modification of list items when viewing a page
* add importScript('User:The Evil IP address/liedit.js'); to your .js file to use it
* @author Janko Hoener (The Evil IP address)
* @version 0.9.9 (beta)
*/
mw.loader.load('mediawiki.api');
window.liedit = {
REGEX_WIKI: /^\s*(\*+)[^\*]*/,
REGEX_HTML: /^\s*<li>.+(<\/li>)?\s*$/,
SIBLING: -1,
PARENT: 1,
EDIT_SUM_LIMIT: 170,
arraysEqual: function(a, b) {
// stolen from StackOverflow
if (a === b) return true;
if (a === null || b === null) return false;
if (a.length != b.length) return false;
// If you don't care about the order of the elements inside
// the array, you should sort both arrays here.
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
},
onclick: function (event, $e) {
if ($e.is('table.infobox li')) {
liedit.set_error_msg('Sorry, cannot edit list items in infoboxes using this script.');
return;
}
if ($e.is('#toc li') || $e.has('form').length) {
return;
}
if (liedit.$e) {
liedit.cancel(event);
}
liedit.pagename = mw.config.get('wgPageName');
liedit.api = new mw.Api();
liedit.$e = $e;
liedit.api.get( {
action: 'parse',
page: liedit.pagename,
prop: 'sections',
format: 'json'
}).done( function (data) {
liedit.sections = {};
$.each(data.parse.sections, function (i, v) {
if (v.byteoffset) {
liedit.sections[v.anchor] = v.index;
}
}
);
cur_elem = liedit.$e[0];
liedit.index = 0;
abort = false;
last_move = liedit.SIBLING;
liedit.position = [0, 0];
for (i = 0; i < 10000 && !abort; i++) {
$cur_elem = $(cur_elem);
switch (cur_elem.localName) {
case 'li':
if (last_move == liedit.SIBLING) {
liedit.position[1]++;
}
if (last_move == liedit.PARENT) {
liedit.position.unshift(0);
}
break;
case 'ul':
liedit.position[0]++;
break;
case 'dl':
case 'dd':
if (last_move == liedit.PARENT) {
liedit.set_error_msg('Cannot edit this list item using this script.');
return;
}
break;
case 'h1':
case 'h2':
case 'h3':
case 'h4':
case 'h5':
case 'h6':
if ($cur_elem.attr('class') == 'firstHeading') {
liedit.index = 0;
abort = true;
break;
}
liedit.anchor = $cur_elem.find('span.mw-headline').first().attr('id');
if (liedit.anchor in liedit.sections) {
liedit.index = liedit.sections[liedit.anchor];
abort = true;
}
break;
}
if (cur_elem.previousElementSibling) {
cur_elem = cur_elem.previousElementSibling;
last_move = liedit.SIBLING;
}
else {
cur_elem = cur_elem.parentNode;
last_move = liedit.PARENT;
}
}
liedit.api.get( {
action: 'parse',
page: liedit.pagename,
section: liedit.index,
prop: 'wikitext',
format: 'json'
}).done( function (obj) {
liedit.wikitext = obj.parse.wikitext['*'];
liedit.wikitext = liedit.wikitext.replace(/([^\n])(<li>)/mgi, "$1\n$2");
liedit.lines = liedit.wikitext.split('\n');
currently_in_list = false;
current_list_wiki = false;
current_list_html = false;
cur_pos = [];
depth = liedit.position.length-1;
for (i = 0; i < liedit.position.length; i++) {
cur_pos.push(0);
}
for (i = 0; i < liedit.lines.length; i++) {
line = liedit.lines[i];
line_match_wiki = line.match(liedit.REGEX_WIKI);
line_match_html = line.match(liedit.REGEX_HTML);
if (line_match_html || line_match_wiki) {
if (!currently_in_list) {
currently_in_list = true;
if (line_match_wiki) {
current_list_wiki = true;
current_list_html = false;
}
else if (line_match_html) {
current_list_wiki = false;
current_list_html = true;
}
cur_pos[0]++;
cur_pos[1] = 1;
for (j = 2; j < cur_pos.length; j++) {
cur_pos[j] = 0;
}
}
else if (line_match_wiki && currently_in_list && current_list_html) {
cur_pos[0]++;
cur_pos[1] = 1;
for (j = 2; j < cur_pos.length; j++) {
cur_pos[j] = 0;
}
current_list_wiki = true;
current_list_html = false;
}
else if (line_match_html && currently_in_list && current_list_wiki) {
cur_pos[0]++;
cur_pos[1] = 1;
for (j = 2; j < cur_pos.length; j++) {
cur_pos[j] = 0;
}
current_list_wiki = false;
current_list_html = true;
}
else if (currently_in_list && current_list_wiki && line_match_wiki) {
line_depth = line.replace(liedit.REGEX_WIKI, '$1').length;
if (line_depth > depth) {
continue;
}
for (j = 1; j < line_depth; j++) {
if (cur_pos[j] === 0) {
cur_pos[j] = 1;
}
}
cur_pos[line_depth]++;
for (j = line_depth + 1; j < cur_pos.length; j++) {
cur_pos[j] = 0;
}
}
else if (currently_in_list && current_list_html && line_match_html) {
cur_pos[1]++;
}
liedit.li_index = i;
if (liedit.arraysEqual(liedit.position, cur_pos)) {
liedit.li_wikitext = line;
liedit.inputsize = liedit.li_wikitext.length*1.5;
var form = $('<form>').css('display', 'inline').submit(liedit.save);
var input = $('<input>').attr('id', 'liedit_input').attr('size', liedit.inputsize).val(liedit.li_wikitext);
var button1 = $('<button>').attr('id', 'liedit_submit').attr('type', 'submit').text('Save');
var button2 = $('<button>').attr('type', 'button').attr('id', 'liedit_cancel').text('Cancel').click(liedit.cancel);
$(form).append(input).append(button1).append(button2);
liedit.form = form;
$e.append(form);
return false;
}
}
else if (currently_in_list) {
currently_in_list = false;
}
}
liedit.set_error_msg('Sorry, this script could not identify the list item in the wikitext.')
liedit.li_wikitext = null;
liedit.li_index = null;
return false;
}
);
}
);
},
save: function () {
liedit.newwikitext = $(this).parent().find('input').val();
if (liedit.newwikitext == liedit.li_wikitext) return false;
if (liedit.newwikitext == '') {
liedit.lines.splice(liedit.li_index, 1);
liedit.line_removed = true;
}
else {
liedit.lines[liedit.li_index] = liedit.newwikitext;
liedit.line_removed = false;
}
liedit.wikitext = liedit.lines.join('\n');
$('#liedit_input, #liedit_submit, #liedit_cancel').attr('disabled', 'disabled');
liedit.summary = '';
if (liedit.anchor) {
liedit.summary += '/* ' + liedit.anchor + ' */ ';
}
if (liedit.line_removed) {
liedit.summary += 'List item removal using a [[User:The Evil IP address/liedit|script]] [beta]: ' + liedit.li_wikitext;
}
else {
liedit.summary += 'List item amendment using a [[User:The Evil IP address/liedit|script]] [beta]';
fullsum = liedit.summary + ': ' + liedit.li_wikitext + ' → ' + liedit.newwikitext;
if (fullsum.length < liedit.EDIT_SUM_LIMIT) {
liedit.summary = fullsum;
}
}
liedit.api.edit(liedit.pagename, function () {
return {
action: 'edit',
format: 'json',
minor: true,
section: liedit.index,
summary: liedit.summary,
text: liedit.wikitext,
};
}).then( function (resp) {
if (resp.result == 'Success') {
window.location.reload();
}
else if (resp.result == 'Failure') {
liedit.set_error_msg('API returned error code ' + data.error.code + ': ' + data.error.info);
}
else {
liedit.set_error_msg('Unknown API error.');
}
});
return false;
},
set_error_msg: function (msg) {
mw.notify(msg, {title: 'Error!', autoHide: false});
},
cancel: function (event) {
if (liedit.form) {
liedit.$e.show();
liedit.form.remove();
event.stopPropagation();
}
}
};
if (mw.config.get('wgNamespaceNumber') >= 0 && mw.config.get('wgAction') == 'view' && mw.config.get('wgIsProbablyEditable')) {
$('#mw-content-text ul li').click(function ( event ) {
liedit.onclick(event, $(this));
event.stopPropagation();
}
);
}