User:Shirik/guidebook.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. |
![]() | Documentation for this user script can be added at User:Shirik/guidebook. |
// <source lang="javascript">
/**
* Guidebook v0.1
* By Matthew "Shirik" Del Buono
*
* This script adjusts the "diff" window so that it shows relevant guidelines
* associated with the edit.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
// Some semaphore-like things that allow us to implement a barrier waiting for all other modules to load.
var guidebook_mootoolsLoaded = false;
var guidebook_patternsLoaded = false;
var guidebook_configLoaded = false;
var guidebook_onLoadOccurred = false;
function guidebook_checkLoaded()
{
if (guidebook_mootoolsLoaded && guidebook_patternsLoaded && guidebook_configLoaded && guidebook_onLoadOccurred)
{
guidebook_onReady();
}
}
function guidebook_loadDefaults()
{
mw.log("Loading guidebook defaults");
window.GUIDEBOOK_MAXDISPLAYEDPOLICIES = 3;
guidebook_configLoaded = true;
}
// Import libs
jQuery.getScript('//meta.wikimedia.org/w/index.php?title=User:Pathoschild/Scripts/MooTools.js&action=raw&ctype=text/javascript&9',
function() { guidebook_mootoolsLoaded = true; guidebook_checkLoaded(); });
// Load configuration
jQuery.getScript('//en.wikipedia.org/w/index.php?title=User:Shirik/guidebook_patterns.js&action=raw&ctype=text/javascript',
function() { guidebook_patternsLoaded = true; guidebook_checkLoaded(); });
function guidebook_onReady()
{
// If AJAX not supported, bail out
if(!wfSupportsAjax())
return;
// If this is a diff, then let's actually do something
var GET = guidebook_getUrlVars();
if (mw.config.get('wgAction') == 'view' && 'diff' in GET && (GET['diff'] > 0 || GET['diff'] == 'prev' || GET['diff'] == 'next'))
{
// This is a diff page. Do stuff!
var added = guidebook_getLines('diff-addedline');
var removed = guidebook_getLines('diff-deletedline');
var summary = guidebook_getSummary();
var guidelines = guidebook_lookupGuidelines(added, removed, summary);
if (guidelines.length > 0)
{
var editSummary = document.getElementById('mw-diff-ntitle3');
if (editSummary == undefined)
{
mw.log("Guidebook error: could not find edit summary block");
}
var block = new Element("div");
block.setProperty('style', 'font-style: italic');
block.appendText("Policies/Guidelines: ");
for (var i = 0; i < guidelines.length; ++i)
{
if (i > 0)
{
block.appendText(", ");
}
if (guidelines[i].href != undefined)
{
var link = new Element("a", {href: "/wiki/" + guidelines[i].href});
link.appendText(guidelines[i].text);
block.adopt(link);
}
else
{
block.appendText("...");
}
}
editSummary.adopt(block);
}
}
}
function guidebook_getUrlVars()
{
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value)
{
vars[key] = value;
});
return vars;
}
/// Gets the lines that were added in the current diff.
/// Parameters: lookupClass [string] - a class for the td element to identify (e.g., 'diff-deletedline'
/// Preconditions: Current page is a diff
/// Postconditions: Nothing has changed
/// Return value: An array of strings, each line that was added in the diff
function guidebook_getLines(lookupClass)
{
var content = document.getElementById('mw-content-text');
if (content == undefined)
{
// Error: Could not get content text
return;
}
var result = new Array();
var diffTable = content.getElement('table'); // should always be the first table
var diffTableBody = diffTable.getElement('tbody'); // a table BETTER only have one body
var rows = diffTableBody.getElements('tr');
for (var i = 0; i < rows.length; ++i) // iterate over each row
{
var cols = rows[i].getElements('td');
for (var j = 0; j < cols.length; ++j) // iterate over each cell
{
// Look for an line (has class 'diff-addedline', etc.)
if (cols[j].get('class') == lookupClass)
{
// This is an added line. Record it.
var div = cols[j].getElement('div'); // There should only be one div inside
if (div == undefined)
{
mw.log("Guidebook warning: Could not find line with class '" + lookupClass + "'");
}
else
{
result.push(div.textContent);
}
}
}
}
return result;
}
/// Gets the edit summary for the new revision
/// Preconditions: Current page is a diff
/// Postconditions: Nothing has changed
/// Return value: A string representation of the edit summary text
function guidebook_getSummary()
{
var content = document.getElementById('mw-diff-ntitle3');
if (content == undefined) return; // likely no edit summary
var text = (content.getElementsByClassName('comment').length > 0 ? content.getElementsByClassName('comment')[0] : undefined);
if (text == undefined) return; // likely no edit summary
return text.textContent.slice(1, -1); // Remove the ( and ) from the edit summary text
}
function guidebook_lookupGuidelines(addedLines, removedLines, summary)
{
var result = new Array();
for (var i = 0; i < GUIDEBOOK_PATTERNS.length; ++i)
{
// Compile the patterns first to improve performance since it might do a lot of tests
var modifiers = (GUIDEBOOK_PATTERNS[i].modifiers == undefined ? '' : GUIDEBOOK_PATTERNS[i].modifiers);
// Each pattern defaults to '' if it is undefined. That allows us to "always match" so that we ignore that pattern.
// Slightly slower in performance, but it really shouldn't be that big of a deal. It will look at the first character and finish.
// The alternative was some ugly-looking code, and this is just too much more elegant to pass up.
addedRegex = new RegExp(GUIDEBOOK_PATTERNS[i].added_regex == undefined ? '' : GUIDEBOOK_PATTERNS[i].added_regex, modifiers);
removedRegex = new RegExp(GUIDEBOOK_PATTERNS[i].removed_regex == undefined ? '' : GUIDEBOOK_PATTERNS[i].removed_regex, modifiers);
summaryRegex = new RegExp(GUIDEBOOK_PATTERNS[i].summary_regex == undefined ? '' : GUIDEBOOK_PATTERNS[i].summary_regex, modifiers);
// Local function to test it against each added line
function testLines(regex, lineArray)
{
if (lineArray.length == 0 && regex.test('')) return true; // No lines still gets a test against the empty string. If pass, successful.
for (var j = 0; j < lineArray.length; ++j)
{
if (regex.test(lineArray[j]))
{
return true;
}
}
return false;
}
if (testLines(addedRegex, addedLines) && testLines(removedRegex, removedLines) && testLines(summaryRegex, [summary]))
{
// Add to list of policies/guidelines to return
result.push({
href: GUIDEBOOK_PATTERNS[i].href,
text: GUIDEBOOK_PATTERNS[i].text
});
if (result.length > GUIDEBOOK_MAXDISPLAYEDPOLICIES)
{
mw.log("Guidebook: Too many matched policies. Capping at " + GUIDEBOOK_MAXDISPLAYEDPOLICIES);
result.pop(); // remove last (we found 1 too many so we know if we should put an ellipsis)
result.push({text: "..."}); // ellipsis to indicate "there was more"
return result;
}
}
}
return result;
}
addOnloadHook(function() {
guidebook_onLoadOccurred = true;
if (mw.user.isAnon() == false)
{
jQuery.getScript('//en.wikipedia.org/w/index.php?title=User:' + mw.user.getName() + '/guidebook_prefs.js&action=raw&ctype=text/javascript')
.done(function() { guidebook_configLoaded = true; guidebook_checkLoaded(); })
.fail(function() { mw.log("Error loading Guidebook user preferences"); guidebook_loadDefaults(); guidebook_checkLoaded(); }); // Offer a default set of options if page doesn't exist
}
else
{
guidebook_configLoaded = true;
}
});