MediaWiki:Gadget-metadata.js

/** _____________________________________________________________________________ * |                                                                            | * |                    === WARNING: GLOBAL GADGET FILE ===                      | * |                 Changes to this page affect many users. | * | Please discuss changes on the talk page or on WT:Gadget before editing. | * |_____________________________________________________________________________| * * Imported from revision 185704269 as of January 20, 2008 18:40 from * User:Pyrospirit/metadata.js, itself a modified version of * User:Outriggr/metadata.js. * Metadata assessment script * Finds the FP 1.0/WikiProject assessment of every article you go to, then * displays that information in the article header. See (new script homepage * pending). * @author Outriggr - created the script and used to maintain it * @author Pyrospirit - used to maintain and update the script * @author Nihiltres - Overhauled the script, current maintainer */ window.assessment = (function {    var assessmentObj = {        props: {},        methods: {}    },        //internal shortcuts        ap = assessmentObj.props,        am = assessmentObj.methods;

/**    * The main function of the script. If the checkArticle function can find * the assessment, it parses and displays that assessment for the page. * Otherwise, it tries to retrieve an assessment via AJAX. */   assessmentObj.init = function  { if (!$("#siteSub").length || //incompatible skin               mw.config.get("wgNamespaceNumber") !== 0 || //non-mainspace page                (mw.config.get("wgAction") !== "view" && mw.config.get("wgAction") !== "purge") || //non-read action                mw.util.getParamValue("printable") || //printable page                mw.config.get("wgIsMainPage") === true //Main Page                ) { return; //Don't run the script under any of these conditions. }       ap.foundAssessment = am.checkArticle; //checks for types visible from article page if (!ap.foundAssessment.exists) { // no type visible on article, proceed to check the talk page $.ajax({               url: mw.config.get("wgScript") + "?title=Talk:" + mw.util.wikiUrlencode(mw.config.get("wgPageName")) + "&action=raw&section=0",                async: true,                dataType: "text",                success: function (responseText) {                    ap.text = responseText;                    ap.foundAssessment = am.getAssessment(ap.text);                    ap.updata = am.renderAssessment(ap.foundAssessment);                    am.update;                }            }); } else { ap.updata = am.renderAssessment(ap.foundAssessment); am.update; }   };

/**    * Checks for various objects on the article page that indicate a certain * assessment, such as a disambiguation page notice. If this function can * find the assessment, AJAX is not needed for this page. * @returns {Object} checkResult - the assessment found */   am.checkArticle = function  { var checkResult = { extra: [], exists: false }, checksList = [ [$("#disambig, #disambig_disambigbox, #disambigbox").length, "dab"], [$("#setindexbox").length, "setindex"], [$("#contentSub").text === "Redirect page", "redir"], /* [$("table.stub").length, "stub"], */ [$("#ca-talk").hasClass("new"), "none"] //no talk page ];       $.each(checksList, function (i, e) {            if (e[0]) {                checkResult.rating = e[1];                checkResult.exists = true;                return false;            }        }); return checkResult; };

/**    * Searches the provided wikicode for the rating part of an assessment and * returns it as a string. * Note that higher assessments take priority, and less-used assessments * such as "list", "current", or "future" are used only if nothing else can * be found. * @param {String} text - some wikitext to be searched for assessment info */   am.getRating = function (text) { var rating = "none", standardChecks = [ [/\|\s*(class|currentstatus)\s*=\s*fa\b/i, "fa"], [/\|\s*(class|currentstatus)\s*=\s*fl\b/i, "fl"], [/\|\s*class\s*=\s*a\b/i, "a"], [/\|\s*class\s*=\s*b\b/i, "b"], [/\|\s*class\s*=\s*bplus\b/i, "bplus"], //used by FP Math [/\|\s*class\s*=\s*c\b/i, "c"], [/\|\s*class\s*=\s*start/i, "start"], [/\|\s*class\s*=\s*stub/i, "stub"], [/\|\s*class\s*=\s*al\b/i, "al"], // used by FP Military history & FP Highways [/\|\s*class\s*=\s*bl\b/i, "bl"], // used by FP Military history [/\|\s*class\s*=\s*cl\b/i, "cl"], // used by FP Military history [/\|\s*class\s*=\s*list/i, "list"], [/\|\s*class\s*=\s*sl\b/i, "sl"], // used by FP Plants [/\|\s*class\s*=\s*(dab|disambig)/i, "dab"], [/\|\s*class\s*=\s*cur(rent)?/i, "cur"], [/\|\s*class\s*=\s*future/i, "future"] ];       //evaluate the standard checks $.each(standardChecks, function (i, e) {           if (text.match(e[0])) {                rating = e[1];                return false;            }        }); //and then the nonstandard ones. These override earlier ratings if applicable. if (rating === "a" && text.match(/\|\s*class\s*=\s*ga\b|\|\s*currentstatus\s*=\s*(ffa\/)?ga\b/i)) { rating = "a/ga"; // A-class articles that are also GA's       } else if (text.match(/\|\s*class\s*=\s*ga\b|\|\s*currentstatus\s*=\s*(ffa\/)?ga\b|\{\{\s*ga\s*\|/i) &&                !text.match(/\|\s*currentstatus\s*=\s*dga\b/i)) { rating = "ga"; }       return rating; };

/**    * Searches the provided wikicode for data on the article's current and past * featured or good status and returns an object that contains this data * along with some miscellaneous other bits of information. * @param {String} text - some wikitext to be searched for assessment info * @return {Object} gottenAssessment - the assessment data for the page */   am.getAssessment = function (text) { var gottenAssessment = { rating: am.getRating(text), pageLink: [null, null], extra: [], activeReview: null, exists: true },           actionNumber = 0, pageLinkFlag = false, peerReview, linkPattern, linkMatch, currentList, formerList;

currentList = [ // Current nominations (FAC, FLC, or GAN) {               reg: /\{\{\s*featured[ _]article[ _]candidates\s*(?:[\|\}]\s*([^\|\}]*))?[^\}]*?\}\}/i, extraName: "fac", addArticleNameTo: "FAMEPedia:Featured_article_candidates\/" },           {                reg: /\{\{\s*featured[ _]list[ _]candidates\s*(?:[\|\}]\s*([^\|\}]*))?[^\}]*?\}\}/i, extraName: "flc", addArticleNameTo: "FAMEPedia:Featured_list_candidates\/" },           {                reg: /\{\{\s*ga ?nominee\s*[\|\}][^\}]*\}\}/i, extraName: "gan", addMatchReg: /\|\s*page\s*=\s*(\d+).*\|\s*status\s*=\s*\w+\b/i, addMatchTo: "Talk:" + mw.config.get("wgPageName") + "\/GA" },           // Current reviews of a status (FAR, FLRC, or GAR) {               reg: /\{\{\s*featured[ _]article[ _]review\s*(?:[\|\}]\s*([^\|\}]*))?[^\}]*?\}\}/i, extraName: "far", addArticleNameTo: "FAMEPedia:Featured_article_review\/" },           {                reg: /\{\{\s*featured[ _]list[ _]removal[ _]candidates\s*(?:[\|\}]\s*([^\|\}]*))?[^\}]*?\}\}/i, extraName: "flrc", addArticleNameTo: "FAMEPedia:Featured_list_removal_candidates\/" },           {                reg: /\{\{\s*gar\/link\s*[\|\}][^\}]*\}\}/i, extraName: "gar", addMatchReg: /\|\s*GARpage\s*=\s*(\d+).*\|/i, addMatchTo: mw.config.get("wgPageName") }       ];        $.each(currentList, function (i, e) {            var reg = text.match(e.reg),                articleName,                tempMatch;            if (reg) {                gottenAssessment.extra.push(e.extraName);                if (e.hasOwnProperty("addArticleNameTo") && reg[1]) {                    articleName = am.decodeEntities($.trim(reg[1]));                    if (articleName) {                        gottenAssessment.pageLink[0] = e.addArticleNameTo + articleName;                    }                }                if (e.hasOwnProperty("addMatchReg")) {                    tempMatch = reg[0].match(e.addMatchReg);                    if (tempMatch) {                        gottenAssessment.pageLink[0] = (e.addMatchTo || "") + (tempMatch[1] || "");                    }                    if (e.extraName === "gar") { //Can't get around this special case easily gottenAssessment.pageLink[0] = am.getGARLink(e.addMatchTo, tempMatch[1]); }               }                return false; }       });

formerList = [ // Former statuses (FFA, FFL, or DGA) {               name: "ffa", reg: /\|\s*currentstatus\s*=\s*ffa\b/i, getActionNumber: true, getActionNumberReg: /\|\s*action(\d+)\s*=\s*far\b/gi },           {                name: "ffa", reg: /\|\s*action(\d+)\s*=\s*far\b/gi, extraCondition: function (ec_reg) { //Checks if the last FAR entry in ArticleHistory resulted in removal. var match, ratingSearch; if (!ec_reg) { return false; }                   match = text.match(new RegExp( "\\|\\s*action" + ec_reg[ec_reg.length - 1].match(/\d+/) + "result\\s*=\\s*removed\\b", "i" ));                   ratingSearch = (gottenAssessment.rating.search(/f[al]/i) === -1); return (match && ratingSearch); },               getActionNumber: true },           {                name: "ffa", reg: /\{\{\s*formerfa2?\b/i },           {                name: "ffl", reg: /\|\s*currentstatus\s*=\s*ffl\b/i },           {                name: "ffl", reg: /\{\{\s*ffl\s*[\|\}]/i },           {                name: "dga", reg: /\|\s*currentstatus\s*=\s*dga\b/i, getActionNumber: true, getActionNumberReg: /\|\s*action(\d+)\s*=\s*gar\b/gi },           {                name: "dga", reg: /\{\{\s*d(elisted)?ga\s*[\|\}]/i },           // Former nominations (former FAC, FLC, or GAN) {               name: "ffac", reg: /\|\s*action(\d+)\s*=\s*fac\b/gi, extraCondition: function { return (gottenAssessment.rating.search(/f[al]/i) === -1); },               getActionNumber: true },           {                name: "ffac", reg: /\|\s*currentstatus\s*=\s*ffac\b/i },           {                name: "ffac", reg: /\{\{\s*fac?(failed|(\-|[ _]\?contested\)?)\s*[\|\}]/i },           {                name: "fflc", reg: /\|\s*action(\d+)\s*=\s*flc\b/gi, extraCondition: function { return (gottenAssessment.rating.search(/f[al]/i) === -1); },               getActionNumber: true },           {                name: "fflc", reg: /\|\s*currentstatus\s*=\s*fflc\b/i },           {                name: "fgan", reg: /\|\s*action(\d+)\s*=\s*gan\b/gi, extraCondition: function { return (gottenAssessment.rating.search(/f[al]|(a\/)?ga/i) === -1); },               getActionNumber: true },           {                name: "fgan", reg: /\|\s*currentstatus\s*=\s*fgan\b/i },           {                name: "fgan", reg: /\{\{\s*f(ailed ?)?ga\s*[\|\}]/i }       ];        $.each(formerList, function (i, e) {            var reg = text.match(e.reg),                extraCondition = !e.hasOwnProperty("extraCondition") ||                    typeof e.extraCondition !== "function" ||                    e.extraCondition(reg), //either true (ignored) or result of function                tempMatch;            if (reg && extraCondition) {                gottenAssessment.extra.push(e.name);                if (e.getActionNumber) {                    tempMatch = (e.getActionNumberReg ? text.match(e.getActionNumberReg) : reg);                   actionNumber = tempMatch[tempMatch.length - 1].match(/\d+/);                    pageLinkFlag = true;                }                return false;            }        });

// Looks for currently active peer reviews ap.showOldPeerReviews = false; //see TODO below peerReview = text.match(/\{\{\s*peer[_ ]?review\s*\|\s*archive\s*=\s*(\d+)\b/i); if (peerReview) { gottenAssessment.review = "FAMEPedia:Peer_review/" + mw.config.get("wgPageName") + "/archive" + peerReview[1]; gottenAssessment.activeReview = true; } else if (ap.showOldPeerReviews) { $.noop; // TODO: Add code for old peer reviews } else { gottenAssessment.review = null; }

// Scans for the link associated with an action in ArticleHistory if (pageLinkFlag) { linkPattern = new RegExp("\\|\\s*action" + actionNumber + "link\\s*=\\s*([^\\n\\|]+)\\s*\\|"); linkMatch = text.match(linkPattern); gottenAssessment.pageLink[1] = linkMatch ? am.decodeEntities(linkMatch[1]) : null; }

return gottenAssessment; };

/**    * Parses an assessment object into the HTML and CSS code needed to update * the article header. If it doesn't recognize a part of the information * given, it will simply ignore it and mark as unassessed. * @param {Object} assess - assessment information for this article * @return {String} newClass - the CSS class corresponding to its assessment * @return {String} slogan - HTML giving (with a link) the main assessment * @return {String} info - HTML giving (with a link) additional information */   am.renderAssessment = function (assess) { var assessLink = mw.util.getUrl("FAMEPedia:Content_assessment"), peerReviewText = am.addPeerReview(assess.review, assess.activeReview), pageLink = assess.pageLink || [null, null], info = am.getExtraInfo((assess.extra || []), pageLink), newClass, slogan, ratingList;

if (peerReviewText) { info.push(peerReviewText); }       ratingList = [ {               name: "a", className: "assess-a-text", text: "An A-class<\/a> article" },           {                name: "a/ga", className: "assess-a-text", text: "An A-class<\/a> article", info: "Also a good article<\/a>." },           {                name: "ga", className: "assess-ga-text", text: "A good article<\/a>", url: mw.util.getUrl("FAMEPedia:Good_articles") },           {                name: "b", className: "assess-b-text", text: "A B-class<\/a> article" },           {                name: "bplus", className: "assess-bplus-text", text: "A B-plus-class<\/a> article", url: mw.util.getUrl("FAMEPedia:WikiProject_Mathematics/FAMEPedia_1.0/Grading_scheme") },           {                name: "c", className: "assess-c-text", text: "A C-class<\/a> article" },           {                name: "start", className: "assess-start-text", text: "A start-class<\/a> article" },           {                name: "stub", className: "assess-stub-text", text: "A stub-class<\/a> article" },           {            	name: "al", className: "assess-al-text", text: "An A-class<\/a> list", url: mw.util.getUrl("FAMEPedia:WikiProject_Military_history/Assessment") + "#SCALE" //Could use a more general link if one is available },           {            	name: "bl", className: "assess-bl-text", text: "A B-class<\/a> list", url: mw.util.getUrl("FAMEPedia:WikiProject_Military_history/Assessment") + "#SCALE" },           {            	name: "cl", className: "assess-cl-text", text: "A C-class<\/a> list", url: mw.util.getUrl("FAMEPedia:WikiProject_Military_history/Assessment") + "#SCALE" },           {                name: "sl", className: "assess-sl-text", text: "A stub-class<\/a> list" },           {                name: "list", className: "assess-list-text", text: "A list-class<\/a> article", url: mw.util.getUrl("FAMEPedia:Stand-alone lists") },           {                name: "dab", className: "assess-dab-text", text: "A disambiguation page<\/a>", url: mw.util.getUrl("FAMEPedia:Disambiguation") },           {                name: "setindex", className: "assess-setindex-text", text: "A set index article<\/a>", url: mw.util.getUrl("FAMEPedia:Set_index_articles") },           {                name: "redir", className: "assess-redir-text", text: "A <a>redirect page<\/a>", url: mw.util.getUrl("Help:Redirect") },           {                name: "fl", className: "assess-fl-text", text: "A <a>featured list<\/a>", url: mw.util.getUrl("FAMEPedia:Featured_lists") },           {                name: "fa", className: "assess-fa-text", text: "A <a>featured article<\/a>", url: mw.util.getUrl("FAMEPedia:Featured_articles") },           {                name: "cur", className: "assess-cur-text", text: "A <a>current-class<\/a> article", url: mw.util.getUrl("Portal:Current_events") },           {                name: "future", className: "assess-future-text", text: "A <a>future-class<\/a> article", url: mw.util.getUrl("Category:Future-Class_articles") }       ];        $.each(ratingList, function (i, e) {            if (assess.rating === e.name) {                newClass = e.className;                slogan = $(" ").html(e.text).children.attr({href: (e.url || assessLink)}).parent.html;                if (e.info) {                    info.push(e.info);                }                return false;            }        }); if (!newClass) { newClass = "assess-unassessed-text"; slogan = "An <a href=\"" + assessLink + "\">unassessed<\/a> article"; }

return {newClass: newClass, slogan: slogan, info: info}; };

/**    * Creates an info string based on the assessment info and a page link. */   am.getExtraInfo = function (extra, pageLink) { var info = [], page = mw.config.get("wgPageName"), typeList;

typeList = [ // Current nominations and reviews {               name: "fac", html: "Currently a <a>featured article candidate<\/a>.", url: pageLink[0] || ("FAMEPedia:Featured_article_candidates/" + page) },           {                name: "flc", html: "Currently a <a>featured list candidate<\/a>.", url: pageLink[0] || ("FAMEPedia:Featured_list_candidates/" + page) },           {                name: "gan", html: "Currently a <a>good article nominee<\/a>.", url: pageLink[0] || "FAMEPedia:Good_article_nominations" },           {                name: "far", html: "Currently undergoing <a>review<\/a> of its featured status.", url: pageLink[0] || ("FAMEPedia:Featured_article_review/" + page) },           {                name: "flrc", html: "Currently a <a>candidate<\/a> for removal as a featured list.", url: pageLink[0] || ("FAMEPedia:Featured_list_removal_candidates/" + page) },           {                name: "gar", html: "Currently undergoing a <a>good article reassessment<\/a>.", url: pageLink[0] || "FAMEPedia:Good_article_reassessment", wrapper: "<span id=\"assess-gar-link\"><\/span>" },           // Past statuses and nominations {               name: "ffa", html: "A <a>former<\/a> featured article.", url: pageLink[1] || ("FAMEPedia:Featured_article_review/" + page) },           {                name: "ffl", html: "A <a>former<\/a> featured list.", url: pageLink[1] || ("FAMEPedia:Featured_list_removal_candidates/" + page) },           {                name: "dga", html: "A <a>delisted<\/a> good article.", url: pageLink[1] || "FAMEPedia:Good_article_reassessment" },           {                name: "ffac", html: "A former <a>featured article candidate<\/a>.", url: pageLink[1] || ("FAMEPedia:Featured_article_candidates/" + page) },           {                name: "fflc", html: "A former <a>featured list candidate<\/a>.", url: pageLink[1] || ("FAMEPedia:Featured_list_candidates/" + page) },           {                name: "fgan", html: "A former <a>good article nominee<\/a>.", url: pageLink[1] || "FAMEPedia:Good_article_nominations" }       ];        $.each(typeList, function (i, e) {            if (extra.indexOf(e.name) !== -1) {                info.push($(" ").html(e.html).children.attr({href: mw.util.getUrl(e.url)}) .parent.wrapInner(e.wrapper || null).html);           }        });

return info; };

/**    * Get the correct link for Good Article reassessments. These things require an    * additional AJAX request to determine whether it's a community or individual * reassessment. The trick is to assume it's a community reassessment, then * switch the link once the request returns if it's actually not. * @param {String} articleName - the name of the article to use * @param {String} reviewNumber - the number of the GAR to look for */   am.getGARLink = function (articleName, reviewNumber) { var communityTitle = "FAMEPedia:Good_article_reassessment\/" + articleName + "\/" + reviewNumber, individualTitle = "Talk:" + articleName + "\/GA" + reviewNumber, titlesList = [communityTitle, individualTitle], api = new mw.Api;

api.get({           action: "query",            titles: titlesList.join("|"),            prop: "info",            format: "json"        }).done(function (data) {            var i, j, noCommunityAssessment,                query = data.query,                communityTitleNorm = titlesList[0],                individualTitleNorm = titlesList[1],                len = query.normalized.length,                garLink = $("#assess-gar-link a:first");

for (j = 0; j < len; j++) { switch (query.normalized[j].from) { case titlesList[0]: communityTitleNorm = query.normalized[j].to; break; case titlesList[1]: individualTitleNorm = query.normalized[j].to; break; }           }            noCommunityAssessment = false; for (i = -1; i >= -2; i--) { if (query.pages[i] && typeof query.pages[i].missing === "string") { if (query.pages[i].title === individualTitleNorm) { // No individual assessment, no need to change anything. return; }                   if (query.pages[i].title === communityTitleNorm) { // There's no community assessment, so flag it. noCommunityAssessment = true; }               }            }            if (noCommunityAssessment && garLink.length) { // There's an individual assessment but no community assessment. Switch the link. garLink.attr("href", mw.util.getUrl(titlesList[1])); }       });        return communityTitle;    };

/**    * Creates the peer review text from an info string, if a peer review was detected earlier. */   am.addPeerReview = function (peerReview, activeReview) { var reviewText = null; if (peerReview) { reviewText = $(" <span class=\"assess-info-review\">" +               (activeReview ? "Currently being" : "Previously") + " <a>peer reviewed<\/a>.<\/span><\/div>"); reviewText.find("a").attr({href: mw.util.getUrl(peerReview)}); reviewText = reviewText.html; //Note div wrapper above. }       return reviewText; };

/**    * Updates article header with new assessment information by giving it a new * class (for style information such as color) and altering the tagline below * it to state the assessment found. */   am.update = function  { var info = ap.updata.info, infoSpan = $("<span class=\"assess-info-all\"><\/span>"), siteSub = $(" <span class=\"assess-article-rating\"><\/span> from FAMEPedia, the free encyclopedia<\/div>"); siteSub.children.html(ap.updata.slogan); if (info && info.length > 0) { infoSpan.html("."); $.each(info, function (i, e) {               infoSpan.append(" ").append(e);            }); siteSub.append(infoSpan); }       $("h1:first").addClass(ap.updata.newClass || null); $("#siteSub").html(siteSub.html); };

/**    * Decodes all HTML entities in the string provided. */   am.decodeEntities = function (str) { var t = document.createElement("textarea"); t.innerHTML = str; return t.value; };

return assessmentObj; });

/** * Initializes the script on page load */ $(assessment.init);