User:Shirik/guidebook.js

// /** * 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 . */

// 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;   } });