User:Garzfoth/common.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. |
![]() | The accompanying .css page for this skin is at User:Garzfoth/common.css. |
/* jshint browser: true, devel: true, jquery: true, maxerr: 500, -W082, -W014, scripturl: true, expr: true, undef: true */
/* globals $: false, mw: false, importScript: false, importStylesheet: false, document: false, MutationObserver: false, OO: false, clearTimeout: false, citeTemplate: false */
// http://jshint.com/docs/
// unused: true
// jslint
// long, white, single
// (breaks and/or screws with several parsers in proper form)
// http://stackoverflow.com/questions/14427077/function-declarations-should-not-be-placed-in-blocks-use-a-function-expression
// (less important to fix)
// http://stackoverflow.com/questions/27623822/disable-jshint-wrning-expected-an-assignment-or-function-call-and-instead-saw-a
// (more important to fix)
//
// GENERAL NOTE: The use of commented nowiki tags in a handful of places is done to resolve the issue raised by Brvhelios under "Category:WikiProjects participating in Wikipedia 1.0 assessments" on http://en.wiki.x.io/wiki/User_talk:Garzfoth/common.js. Basically this should be done for any template reference, and at least certain types of special wiki tags.
//
// FROM: http://en.wiki.x.io/wiki/User:Ale_jrb/Scripts
// SINCE: 7/21/2015 (not installed)
// DISABLED: importScript('User:Ale_jrb/Scripts/userhist.js'); //[[User:Ale_jrb/Scripts]]
// REASON: Possible conflict, uncertain need, but may want to use in the future.
// Note that the source page may have some other worthwhile ones, but not at the moment.
importScript('User:Technical_13/Scripts/OneClickArchiver.js'); // Backlink: [[User:Technical_13/Scripts/OneClickArchiver]]
// Migrated to standalone script on 2021-05-05
importScript('User:Garzfoth/Scripts/CompareLink.js');
// Migrated to standalone script on 2021-05-05
importScript('User:Garzfoth/Scripts/SafetyEdit.js');
// Migrated to standalone script on 2021-05-05
importScript('User:Garzfoth/Scripts/BetterTwinklePrefs.js');
// Migrated to standalone script on 2021-05-05
importScript('User:Garzfoth/Scripts/CustomEditSummaryPresets.js');
// Migrated to standalone script on 2021-05-05
importScript('User:Garzfoth/Scripts/CustomQuickInsertButtons.js');
// Migrated to standalone script on 2021-05-05
importScript('User:Garzfoth/Scripts/WatchlistUpdateNotice.js');
//
// Implement conditional logging for debugging purposes
//
// Unless you are currently in the middle of actively debugging an issue, this should be left disabled (set to false).
// If this is left enabled unnecessarily, it will cause issues with performance and console log spam.
var logOverride = true;
// Don't touch this. Declaring this by default is required for the if statement to work correctly (declaring it only when it is true does not work).
// On a side note, that may have simply been a function scope issue...
var enableLogger = false;
if (logOverride === true) {
enableLogger = true;
} else {
var url = window.location.href;
// Extracts "debug" from the URL starting after #, so only if #debug is at the end of the URL (or contained within the URL)
var lastPart = url.substr(url.lastIndexOf('#') + 1);
if (lastPart === "debug") {
enableLogger = true;
}
}
// Based on https://stackoverflow.com/a/25867340
// For the lulz (and since a syntax change is required anyways), I'm changing the name from logifneeded to beaver
// The general syntax change required is logifneeded() => beaver.log()
// I'm not sure if this can be accessible from the global scope if it's placed in a module, especially given the load order dependency. Perhaps declaring it in the common.js file could be enough? Although it may still become inaccessible from modules...
var beaver = (function (enableLogger) {
if (enableLogger === false) {
return {
log: function() {},
warn: function() {},
error: function() {}
}
}
return {
log: function() {
var args = Array.prototype.slice.call(arguments);
console.log.apply(console, args);
},
warn: function() {
var args = Array.prototype.slice.call(arguments);
console.warn.apply(console, args);
},
error: function() {
var args = Array.prototype.slice.call(arguments);
console.error.apply(console, args);
}
}
}(enableLogger));
// test cases
/*
var name = "Alex";
var arr = [1, 2, 3];
var obj = { a:1, b:2, c:3 };
var hello = function(msg){alert(msg);};
console.log("Name: ", name);
beaver.log("Name: ", name);
console.log("Window Debug: ", window);
beaver.log("Window Debug: ", window);
console.error("Something error happen");
beaver.error("Something error happen");
console.warn("Ahh... Warning", arr, obj);
beaver.warn("Ahh... Warning", arr, obj);
console.log("more parameter: ", arr, obj, hello);
beaver.log("more parameter: ", arr, obj, hello);
*/
//
// End of conditional debug logging code
//
//
// Name TBD, as I don't really know what this does anymore. It has something to do with filtering on watchlists. I started off with the oh-so-clear comments "Now for something new...", and "Lets see... hmm... " — those don't really help matters.
// This depends on the conditional debug logging code.
//
// No clue what this snippet is from. I think perhaps this was originally unified, and was later split into the two variants for watchlists and recentchangeslinked?
// || ( mw.config.get('wgCanonicalSpecialPageName') === "RecentChangesLinked" )
if (mw.config.get('wgCanonicalSpecialPageName') === "Watchlist") {
function addWatchlistSpecialUserFilters() {
beaver.log("Started processing a new watchlist...");
// I hope this doesn't screw up stuff like CiteTB...
// FUTURE FEATURE: OFFER A MARK UNREAD BUTTON???
// Declare the watchlist array for future use. Note that sub-arrays cannot be declared until the parent has been declared as an array.
var watchlist = Array();
// Declare iw with initial value 0. This is incremented at the end of each ul.special loop.
// I think this could technically be replaced by parentIndex?
var iw = 0;
// Each section is a ul.special element representing a specific date for commits. It is a container element holding all commits made on that date.
$('ul.special').each(function (parentIndex, parentElement) {
beaver.log("Started working on ul.special:", parentElement);
// Declare a watchlist[iw] sub-array for this value of iw (i.e. for this ul.special loop)
watchlist[iw] = Array();
// Each child is a li element representing an individual commit (entry/line) within the parent section
$(parentElement).children().each(function (childIndex, childElement) {
beaver.log("Started working on ul.special child:", childElement);
// Not entirely sure what this was meant to address at this point, or if it's even working correctly given that there seem to be issues with return [true]...
if ($(childElement).is('div.mw-rcfilters-ui-changesListWrapperWidget-previousChangesIndicator')) {
// https://stackoverflow.com/questions/481601/how-to-skip-to-next-iteration-in-jquery-each-util/481611
return;
}
// The breaking item is a wikidata edit, denoted "D".
// Wikidata edits seem to set the .mw-changeslist-src-mw-wikibase class on the edit's li.mw-changeslist-line element, which should prove helpful...
// Note that the li's contents are totally different for these wikidata edits, they totally lack the span.mw-changeslist-line-inner wrapper child, and just dump a bunch of nasty html into the li directly with only some mixed element class name reuse (but now nested differently!)
// If I'm recalling things correctly, this is actually more or less the way that all watchlist items used to work before the last major watchlist overhaul (the migration to the current "New filters for edit review" version, which has been such a bloody gargantuan headache to adapt scripts to work with)...
// VERY crude TEMPORARY STOPGAP workaround/"fix" for the above
// to be replaced by something that actually fixes the numerous problems posed by this, including not the least the bloody lack of highlighting (and/or ignoring this item if it's the first occurance)
if ($(childElement).is('li.mw-changeslist-line.mw-changeslist-src-mw-wikibase')) {
return false;
// Doesn't work, but kills execution, which is a workaround of sorts I guess.
// Note that this only kills execution for the rest of this specific ul.special. So in the edge case where there's a ul.special without any wikidata elements, then that ul.special will actually process successfully even if there are other ones that failed due to this.
//
// return [true] also didn't work (other issue — it's flat-out broken).
}
// I need to either:
// • (Option A): Somehow convert the parent loops to $.each() (which would require excising jQuery, or at least figuring out how to bridge the JS objects from that to jQuery objects for all calls)
// • (Option B): Just wrap most of this function in a giant negated if statement and call it a day
// e.g. if ( !($(childElement).is('div.mw-rcfilters-ui-changesListWrapperWidget-previousChangesIndicator')) && !($(childElement).is('li.mw-changeslist-line.mw-changeslist-src-mw-wikibase')) ) { [rest of function] }
//
// ultimately I still will eventually need to figure out a real replacement that doesn't depend on negation, but this spagetti code is a nightmare to maintain.
//
// on a side note, the [+] expansion buttons generate (incorrectly) for wikidata items, and throw an error when clicked. I wonder if I could actually fix those to preview wikidata, or if I'll be stuck with conditional hiding of them on wikidata items (and oh boy, trying to identify those in that code will be sooo fun /s).
// .attr() pseudo-documentation
//----------------------------------------
//beaver.log("Processed:", $(childElement).attr('processed'));
// get (may throw undefined):
//$(childElement).attr('processed');
// set:
//$(childElement).attr('processed', ''); // not sure about behavior here?
//$(childElement).attr('processed', 1);
// delete (either one of these work):
//$(childElement).attr('processed', null);
//$(childElement).removeAttr('processed');
//----------------------------------------
//beaver.log("Processed:", $(childElement).attr('processed'));
// Check if we've already processed this element before.
if ($(childElement).attr('processed') != 1) {
beaver.log("This item has not been processed yet, starting processing...");
// Determine the full page key/ID for this page, which contains the page type ID (denoting a type of main, talk, etc) and the page name encoded in CSS class format (this is primarily done by replacing spaces with underscores)
var sliceAndDiceWatchlist = $(childElement).attr('class').match(/watchlist-([0-9]+)-([^\s]*)/);
beaver.log("sliceAndDiceWatchlist:", sliceAndDiceWatchlist);
// Determine the CSS full page ID. Formerly named "cssid".
var cssFullPageID = sliceAndDiceWatchlist[0];
// Determine the CSS page type component. Formerly named "pagetypecss".
var cssPageType = sliceAndDiceWatchlist[1];
// Determine the CSS page name component. Formerly named "pagenamecss".
var cssPageName = sliceAndDiceWatchlist[2];
//
// This block retrieves the commit's author
//
// Other approaches to detecting author. Not sure if these were tested.
//----------------------------------------
//var detectedauthortext = $(childElement).children('a').class('mw-userlink').attr('title').match(/User:[^/]*/);
//var detectedauthortext = $(childElement).children('a').match(/User:[^/]*/);
//
// This was tested and immediately failed for obvious reasons
//var brilliantidea = $(childElement).children('a').$(.mw-userlink).match(/^User:.*$/);
//var detectedauthortext = brilliantidea[0];
//----------------------------------------
// Declare the candidates array for later use
var candidates = Array();
// Specific children are <a> elements with the .mw-userlink class
// Note that the regex User match is actually bad, as it'll fail on IP users (both IPv4 & IPv6)
// For those users, matching based on the URL may work... Alternatively, the regex title attribute match could be adapted further. The current approach is really quite bad.
// Note that IP users have an additional .mw-anonuserlink class.
// Note that there can be multiple potential matches due to the use of user mentions in edit summaries for reversions!
$(childElement).find('a').each(function (matchIndex, matchElement) {
// Set the candidates array entry at the key equal to the match's index to the user retrieved from the <a> (i.e. link) element's title via a regex match. Note that this actually stores an array for the match results rather than the actual raw value of a specific match result.
// TODO: Is there a more optimized way of doing this?
candidates[matchIndex] = $(matchElement).attr('title').match(/^User:[^/]*$/);
// This is what actually throws the error, seemingly due to at least a lack of a .attr('title') on the $(matchElement) it found.
// However since that's just locating by 'a' children under the current $(childElement), it's not going to be very useful...
});
beaver.log("[Author] candidates:", candidates);
// Passing true to $.grep() means that inversion is turned on, and thus we only need to detect null elements
var thematch = $.grep(candidates, function (item, index) { return $.isEmptyObject(item); }, true);
// Because the set method stores an array instead of the raw value, we need to retrieve the raw value for match 0 here
var detectedauthortext = thematch[0];
beaver.log("detectedauthortext:", detectedauthortext);
// End of commit author retrieval block
// Check if we've seen this page before within this specific iteration (i.e. this specific ul.special parent element) by checking for the existence of the relevant array entry, then style it with reduced opacity if we've seen it before.
if (typeof watchlist[iw][cssFullPageID] === 'undefined') {
// If the entry for this iteration and cssFullPageID (which is a unique identifier for this page) in the double-deep watchlist array for this specific iteration (i.e. this specific ul.special parent element) does NOT already exist, then create it by initializing a new array for that set of keys.
watchlist[iw][cssFullPageID] = Array();
} else {
// If the entry DOES already exist, then we've already seen this page at least once before within this specific ul.special element. Therefore set the element style to 65% opacity.
$(childElement).css("opacity", "0.65");
}
// Some sort of prototype for extending the existing system with a way to determine marking, page count, etc through extension of watchlist[iw][cssFullPageID].
//----------------------------------------
// so n is 0 for page, 1 for talk, 3 for user, etc
// but ignore that!!
// DOES watchlist[i][cssFullPageID] EXIST?
// IF NO:
// watchlist[i][cssFullPageID] = Array();
//watchlist[i][cssFullPageID][n] = n
//watchlist[i][cssFullPageID][name] = name
//watchlist[i][cssFullPageID][count] = 1
//watchlist[i][cssFullPageID][marked] = 0
// ==> DISTINGUISH AS PRIMARY <==
// (AKA DO NOTHING?)
// IF YES:
//watchlist[i][cssFullPageID][count] = self + 1
// ==> DISTINGUISH AS SECONDARY <==
// (AKA GREY IT OUT A WEE BIT)
// $(this).css(‘opacity’, 0.65);
//----------------------------------------
// All items (regardless of page type) for the page "WikiProject Medicine" are styled with a unique background color at 15% opacity.
if ((typeof cssPageName !== 'undefined') && (cssPageName == 'WikiProject_Medicine')) {
$(childElement).css("background-color", "rgba(51, 111, 153, 0.15)"); // #3DB870 = rgb(61, 184, 112)
}
// This is just too fucking ugly for me to keep using it
// Style all (talk?) pages with a unique background color at 35% opacity.
//if ((typeof cssPageType !== 'undefined') && (cssPageType == '1')) {
// $(childElement).css("background-color", "rgba(22, 44, 65, 0.35)"); // #3DB870 = rgb(61, 184, 112)
//}
// This has to go last [update: why? was it to allow prior entries that potentially overrode or conflicted with it?]
// Style all of my edits with a unique background color at 35% opacity.
if ((typeof detectedauthortext !== 'undefined') && (detectedauthortext == 'User:Garzfoth')) {
$(childElement).css("background-color", "rgba(61, 184, 112, 0.35)"); // #3DB870 = rgb(61, 184, 112)
}
$(childElement).attr('processed', 1);
} else {
beaver.log("This item was already processed!");
}
//beaver.log("Processed:", $(childElement).attr('processed'));
beaver.log("Processing for this item is now complete.");
});
iw++;
});
beaver.log("Processing of watchlist is complete, here is your watchlist array:", watchlist);
}
/*
function theOnesWhoStartTheFires() {
console.log("A fire has been started! [wikipage.content was fired]");
}
mw.hook('wikipage.content').add(theOnesWhoStartTheFires);
*/
// Okay, so wikipage.content fires once on initial page load, then ***any changes to any options that refresh the watchlist*** will fire it ***twice*** with a tiny but sometimes human perceivable delay in between (which is the origin of certain issues)
/*
function theOnesWhoFightTheFires() {
console.log("The firefighters have arrived!");
}
mw.hook('wikipage.content').add(theOnesWhoFightTheFires);
*/
// Firing is apparently sequential and not affected by hooks.
// AHHHH I think the stupid fucking blur is part of the problem! Damn it. I wonder how to minimize the performance impact of double-processing everything? Not to mention wiping the watchlist array... hmm.
// Execute function when wikipage.content fires.
mw.hook('wikipage.content').add(addWatchlistSpecialUserFilters);
// Execute function directly. Obsolete.
//$(addWatchlistSpecialUserFilters);
}
//
// THIS IS ALSO DEPENDENT ON THE CONDITIONAL LOGGING CODE IMPLEMENTED PRIOR TO THE PREVIOUS FUNCTION
//
// || ( mw.config.get('wgCanonicalSpecialPageName') === "RecentChangesLinked" )
// In theory this should work because of scope, right? Just have to adapt it to
// handle how it's done here... so go to inner for checking name? oh, wait...
// here's how to fix for the in-line ajax stuff: https://www.google.com/search?q=event+fired+when+content+changed+via+ajax&oq=event+fired+when+content+changed+via+ajax&aqs=chrome..69i57.4675j0j7&sourceid=chrome&ie=UTF-8
// (note: make sure that it doesn't trigger onclick, or when loading watchlist, or when opening inline diff)
if ((mw.config.get('wgCanonicalSpecialPageName') === "Recentchanges") || (mw.config.get('wgCanonicalSpecialPageName') === "Recentchangeslinked")) {
function addChangelistSpecialUserFilters() {
beaver.log("Started processing a new set of changes...");
// I hope this doesn't screw up stuff like CiteTB...
// FUTURE FEATURE: OFFER A MARK UNREAD BUTTON???
var changelist = Array();
var i = 0;
// TODO: examine source and add comments as with the watchlist variant
$('ul.special').each(function (parentIndex, parentElement) {
changelist[i] = Array();
// TODO: examine source and add comments as with the watchlist variant
$(this).children().each(function (childIndex, childElement) {
beaver.log(this);
var cssid = $(this).find('a').first().attr('title');
//var cssidinit = $(this).attr('class').match(/watchlist-[0-9]-[^\s]*/);
//var cssid = cssidinit[0];
//beaver.log(cssidinit);
beaver.log(cssid);
if (typeof changelist[i][cssid] === 'undefined') {
changelist[i][cssid] = Array();
} else {
$(this).css("opacity", "0.65");
}
//ignore the below!!
// ----
// so n is 0 for page, 1 for talk, 3 for user, etc
// but ignore that!!
// DOES watchlist[i][CSSID] EXIST?
// IF NO:
// watchlist[i][CSSID] = Array();
//watchlist[i][CSSID][n] = n
//watchlist[i][CSSID][name] = name
//watchlist[i][CSSID][count] = 1
//watchlist[i][CSSID][marked] = 0
// ==> DISTINGUISH AS PRIMARY <==
// (AKA DO NOTHING?)
// IF YES:
//watchlist[i][CSSID][count] = self + 1
// ==> DISTINGUISH AS SECONDARY <==
// (AKA GREY IT OUT A WEE BIT)
// $(this).css(‘opacity’, 0.65);
});
i++;
});
}
mw.hook('wikipage.content').add(addChangelistSpecialUserFilters);
}
// END
// See [[mw:Reference Tooltips]] // http://en.wiki.x.io/wiki/MediaWiki:Gadget-ReferenceTooltips.js
//window.pg || $(document).ready(function ($) {
window.pg || $(function () {
// Make sure we are in defined namespaces (notably increased vs. default set)
if ($.inArray(mw.config.get('wgCanonicalNamespace'), ['' , 'Project' , 'Help', 'Draft', 'User', 'Talk', 'Project talk', 'Template' ]) !== -1) {
mw.messages.set({
"RT-enable": "Enable Reference Tooltips",
"RT-disable": "Disable Reference Tooltips",
"RT-disablenote": "Once disabled, Reference Tooltips can be re-enabled using a link in the footer of the page.",
"RT-delay": "Delay before the tooltip appears (in milliseconds): ",
"RT-activationmethod": "Tooltip is activated by:",
"RT-hovering": "hovering",
"RT-clicking": "clicking",
"RT-options": "Reference Tooltips options",
"RT-options-save": "Save settings",
"RT-settings": "Tooltip settings"
});
function toggleRT(o) {
mw.loader.using("mediawiki.cookie", function () {
mw.cookie.set("RTsettings",o+"|"+ settings[1] + "|" + settings[2], {path:"/",expires:90});
location.reload();
});
}
var settings = document.cookie.split("RTsettings=")[1];
settings = settings ? settings.split(";")[0].split("%7C") : [1, 200, +("ontouchstart" in document.documentElement)];
if (settings[0] === 0) {
var footer = $("#footer-places, #f-list");
if (footer.length === 0) {
footer = $("#footer li").parent();
}
footer.append($("<li>").append(
$("<a>")
.text( mw.message( "RT-enable" ) )
//.attr("href","javascript:(function (){})()")
.attr("href","")
//.click(function (){toggleRT(1);})
.click(function (e){
e.preventDefault();
toggleRT(1);
})
));
return;
}
var isTouchscreen = +settings[2],
timerLength = isTouchscreen ? 0 : +settings[1],
settingsMenu;
$(".reference").each(function () {
var tooltipNode, hideTimer, showTimer, checkFlip = false;
function findRef(h) {
h = h.firstChild; h = h && h.getAttribute && h.getAttribute("href"); h = h && h.split("#"); h = h && h[1];
h = h && document.getElementById( h );
h = h && h.nodeName == "LI" && h;
return h;
}
function hide(refLink) {
if (tooltipNode && tooltipNode.parentNode == document.body) {
hideTimer = setTimeout(function () {
$(tooltipNode).animate({opacity: 0}, 100, function () {
document.body.removeChild(tooltipNode);
});
}, isTouchscreen ? 16 : 100);
} else {
$(findRef(refLink)).removeClass("RTTarget");
}
}
function show() {
if (!tooltipNode.parentNode || tooltipNode.parentNode.nodeType === 11) {
document.body.appendChild(tooltipNode);
checkFlip = true;
}
$(tooltipNode).stop().animate({opacity: 1}, 100);
clearTimeout(hideTimer);
}
function openSettingsMenu() {
if (settingsMenu) {
settingsMenu.dialog("open");
} else {
settingsMenu = $("<form>")
.append(
//$("<button>").css("width","100%").text( mw.msg( "RT-disable", mw.user ) ).button().click(function (){toggleRT(0);}),
$("<button>").css("width","100%").text(mw.msg("RT-disable", mw.user)).button().click(function (e) {
e.preventDefault();
toggleRT(0);
}),
$("<br>"),
$("<small>").text(mw.msg("RT-disablenote")),
$("<hr>"),
$("<label>").text(mw.msg("RT-delay")).append($("<input>").attr({ "type": "number", "value": settings[1], step: 50, min: 0, max: 5000 })),
$("<br>"),
$("<span>").text(mw.msg("RT-activationmethod", mw.user)),
$("<label>").append(
$("<input>").attr({ "type":"radio", "name":"RTActivate", "checked":settings[2]===0&&"checked" }),
mw.msg("RT-hovering", mw.user)
),
$("<label>").append(
$("<input>").attr({ "type":"radio", "name":"RTActivate", "checked":settings[2]==1&&"checked" }),
mw.msg("RT-clicking", mw.user)
)
)
.submit(function (e) {
e.preventDefault();
})
.dialog({
modal: true,
width: 500,
title: mw.msg("RT-options"),
buttons: [{
text: mw.msg("RT-options-save", mw.user),
click: function () {
var a = this.getElementsByTagName("input"),
b = +a[0].value;
/*if( "ontouchstart" in document.documentElement && a[1].checked && !confirm( mw.msg( "RT-confirm-mouseloss", mw.user ) ) ) {
return false;
}*/
mw.cookie.set("RTsettings","1|"+ (b > -1 && b < 5001 ? b : settings[1]) + (a[1].checked ? "|0" : "|1"), { path: "/", expires: 90 });
location.reload();
}
}]
});
}
}
function onStartEvent(e) {
var _this = this;
if (window.pg) {
return;
}
if (isTouchscreen) {
e.preventDefault();
(tooltipNode && tooltipNode.parentNode == document.body) || setTimeout( function (){
$( document.body ).on("click touchstart", function ( e ) {
e = e || event;
e = e.target || e.srcElement;
for( ; e && !$( e ).hasClass( "referencetooltip" ) ; )
e = e.parentNode;
if( !e ){
clearTimeout( showTimer );
hide( _this );
$(document.body).off("click touchstart", arguments.callee);
}
});
}, 0);
}
hideTimer && clearTimeout(hideTimer);
showTimer && clearTimeout(showTimer);
showTimer = setTimeout(function () {
var h = findRef(_this);
if (!h) {
return;
}
var windowTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0,
hOffsetTop = $( h ).offset().top;
if (!isTouchscreen && windowTop < hOffsetTop && windowTop + $(window).height() > hOffsetTop + h.offsetHeight) {
$(h).addClass("RTTarget");
return;
}
if (!tooltipNode) {
tooltipNode = document.createElement("ul");
tooltipNode.className = "referencetooltip";
var c = tooltipNode.appendChild( $( h ).clone( true )[ 0 ] );
try {
if (c.firstChild.nodeName != "A") {
while (c.childNodes[1].nodeName == "A" && c.childNodes[1].getAttribute( "href" ).indexOf("#cite_ref-") !== -1) {
do { c.removeChild(c.childNodes[1]); } while (c.childNodes[1].nodeValue == " ");
}
}
} catch (e) {
mw.log(e);
}
c.removeChild(c.firstChild);
$(tooltipNode.firstChild.insertBefore(document.createElement("span"), tooltipNode.firstChild.firstChild)).addClass("RTsettings").attr("title", mw.msg("RT-settings")).click(function () {
mw.loader.using(["mediawiki.cookie","jquery.ui"], openSettingsMenu);
});
tooltipNode.appendChild( document.createElement( "li" ) );
isTouchscreen || $(tooltipNode).on("mouseenter", show).on("mouseleave", hide);
}
show();
var o = $(_this).offset(), oH = tooltipNode.offsetHeight;
$(tooltipNode).css({top: o.top - oH, left: o.left - 7 });
if (tooltipNode.offsetHeight > oH) {
// is it squished against the right side of the page?
$(tooltipNode).css({ left: 'auto', right: 0 });
tooltipNode.lastChild.style.marginLeft = (o.left - tooltipNode.offsetLeft) + "px";
}
if (checkFlip) {
if (o.top < tooltipNode.offsetHeight + (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0)) {
// is part of it above the top of the screen?
$(tooltipNode).addClass("RTflipped").css({top: o.top + 12});
} else if (tooltipNode.className === "referencetooltip RTflipped") {
// cancel previous
$(tooltipNode).removeClass("RTflipped");
}
checkFlip = false;
}
}, timerLength);
}
function onEndEvent() {
clearTimeout(showTimer); hide(this);
}
$(this).on( isTouchscreen ? { click: onStartEvent } : { mouseenter: onStartEvent, mouseleave: onEndEvent } );
//
// see old revisions for relevant archived commented-out text
//
});
}
});
// the folowing borrowed in part from twinkle plugin used previously
// Set URL prefix -- fixed?
//var pre = location.protocol + '//' + mw.config.wgPageContentLanguage + '.' + wgNoticeProject + '.org' + '/w/index.php?title=';
//var pre = location.protocol + '//' + mw.config.get("wgPageContentLanguage") + '.' + mw.config.get("wgNoticeProject") + '.org' + '/wiki/';
// Add the MED/PHARM/D/WP:PHARM special changes links in the user links line at page tops, next to the usual Preferences link
// This should really be optimized into one call... Like a lot of stuff... whatever.
/*$('li#pt-watchlist').after('<li id="pt-pharmacologyWikiProject" style="margin-left:.2em" title="Wikiproject Pharmacology (see subpages!)">' +
'<a href="' + pre + 'Wikipedia:WikiProject_Pharmacology">[WP:PHARM]</a></li>');
$('li#pt-watchlist').after('<li id="pt-pharmacologyWatchlistSecondary" style="margin-left:.2em" title="Wikiproject Pharmacology (Infobox drug articles) recent changes">' +
'<a href="' + pre + 'Special:RecentChangesLinked/Wikipedia:WikiProject_Pharmacology/Lists_of_pages/Infobox_drug_articles">[D]</a></li>');
$('li#pt-watchlist').after('<li id="pt-pharmacologyWatchlistMain" style="margin-left:.2em" title="Wikiproject Pharmacology recent changes">' +
'<a href="' + pre + 'Special:RecentChangesLinked/Wikipedia:WikiProject_Pharmacology/Lists_of_pages/Pharmacology_articles">[PHARM]</a></li>');
$('li#pt-watchlist').after('<li id="pt-medicineWatchlist" style="margin-left:.2em" title="Wikiproject Medicine recent changes">' +
'<a href="' + pre + 'Special:RecentChangesLinked/Wikipedia:WikiProject_Medicine/Lists_of_pages/Articles">[MED]</a></li>');*/
// Honestly I don't know if an array is actually faster, but why not try...
// My theory is that the multiple UI updates are much more inefficient.
// This may just be a drop in the bucket, but I have other goals for this too...
// In the interest of usability, I'm going to do this normally. Thankfully, I don't need to reverse the array!!
// subarray definition: id (full), title (on hover), wikilink (just the wl), displaytext (including brackets)
var watchlistitemstoadd = [
[
'pt-medicineWatchlist',
'Wikiproject Medicine recent changes',
'Special:RecentChangesLinked/Wikipedia:WikiProject_Medicine/Lists_of_pages/Articles',
'[MED]'
],
[
'pt-pharmacologyWatchlistMain',
'Wikiproject Pharmacology recent changes',
'Special:RecentChangesLinked/Wikipedia:WikiProject_Pharmacology/Lists_of_pages/Pharmacology_articles',
'[PHARM]'
],
[
'pt-pharmacologyWatchlistSecondary',
'Wikiproject Pharmacology (Infobox drug articles) recent changes',
'Special:RecentChangesLinked/Wikipedia:WikiProject_Pharmacology/Lists_of_pages/Infobox_drug_articles',
'[D]'
]
];
// Define pre
var pre = location.protocol + '//' + mw.config.get("wgPageContentLanguage") + '.' + mw.config.get("wgNoticeProject") + '.org' + '/wiki/';
var theStitchedHtml = '';
// Define the function
function generateHtmlItem(value, index, array) {
theStitchedHtml += '<li id="'+value[0]+'" style="margin-left: 0.2em;" title="'+value[1]+'"><a href="'+pre+value[2]+'">'+value[3]+'</a></li>';
}
watchlistitemstoadd.forEach(generateHtmlItem);
$('li#pt-watchlist').after(theStitchedHtml);
// $('li#pt-watchlist').after('<li id="pt-medicineWatchlist" style="margin-left:.2em" title="Wikiproject Medicine recent changes">' +
// '<a href="' + pre + 'Special:RecentChangesLinked/Wikipedia:WikiProject_Medicine/Lists_of_pages/Articles">[MED]</a></li>');
// userbar formatting
$('#pt-preferences > a').text('Prefs');
$('#pt-mycontris > a').text('Contribs');
$('#pt-betafeatures').remove();
$('li#pt-preferences').after('<li id="pt-twinklePrefs" style="margin-left:.2em" title="View/Edit JS">' +
'<a href="' + pre + 'User:Garzfoth/common.js">[JS]</a></li>');
$('li#pt-preferences').after('<li id="pt-twinklePrefs" style="margin-left:.2em" title="View/Edit CSS">' +
'<a href="' + pre + 'User:Garzfoth/common.css">[CSS]</a></li>');
importScript('User:Ugog Nizdast/displayNumberOfTags.js'); // [[User:Ugog Nizdast/displayNumberOfTags.js]]
importScript('User:Gary/subjects age from year.js'); // [[User:Gary/subjects age from year.js]]
//importScript('User:Zhaofeng Li/RefToggle.js'); // Backlink: [[User:Zhaofeng Li/RefToggle.js]]
// No updates in 4 years, so to speed up load times I'm directly importing it (with minor tweaks):
//$(document).ready(function () {
$(function () {
var refToggle = mw.util.addPortletLink("p-tb", "#", "Toggle references");
$(refToggle).click(function () {
$(".reference").toggle();
});
});
// Temporarily disabled due to error "TypeError: $.wikiEditor.isSupported is not a function" at approximately line 582
//importScript('User:קיפודנחש/TemplateParamWizard.js'); // chars seem to glitch out the editor on this line
// for above: http://en.wiki.x.io/wiki/User:%D7%A7%D7%99%D7%A4%D7%95%D7%93%D7%A0%D7%97%D7%A9/TemplateParamWizard
importScript('User:Salix alba/Citoid.js'); // http://en.wiki.x.io/wiki/User:Salix_alba/Citoid
//importScript('User:Opencooper/lastEdit.js'); // Backlink: [[User:Opencooper/lastEdit.js]]
// This script reimplements the last edit banner used on mobile
// See: [[User:Opencooper/lastEdit]] => http://en.wiki.x.io/wiki/User:Opencooper/lastEdit
// While this was updated 8 months ago, I want to customize this, load times are an issue, this script is a good candidate for importation, etc, so I'm importing it and customizing it...
// This function has been modified to show the last edit info on more types of pages
function requestRevision() {
// If we're not reading or editing an article, do nothing
// don't see any need for "&& mw.config.get('wgIsArticle')" -- removed. possibly a bad choice?
if (!((mw.config.get('wgAction') === "view" || mw.config.get('wgAction') === "edit" || mw.config.get('wgAction') === "submit")
&& mw.config.get("wgPageName") !== "Main_Page"
&& mw.config.get('wgCanonicalSpecialPageName') !== "Watchlist"
&& mw.config.get('wgCanonicalSpecialPageName') !== "Recentchanges" || mw.config.get('wgCanonicalSpecialPageName') === "Recentchangeslinked")) {
// Do nothing!
//console.log("RETURN CALLED");
return;
}
// API docs: https://www.mediawiki.org/wiki/API:Revisions
var apiUrl = location.origin + "/w/api.php";
$.ajax({
url: apiUrl,
data: {
action: "query",
prop: "revisions",
format: "json",
titles: mw.config.get("wgPageName"),
rvprop: "timestamp|user|comment|tags|ids"
},
success: parseEdit
/*
This is a good example of how to port from the old style to the newer data array definitions!
Worth reusing...
url: "http://en.wiki.x.io/w/api.php?action=query&prop=revisions&format=json&titles="
+ mw.config.get('wgPageName')
+ "&rvprop=timestamp%7Cuser%7Ccomment%7Ctags%7Cids",
success: displayEdit
*/
});
}
function parseEdit(response) {
/*if (typeof(jsvariable) == 'undefined') {
//
}*/
//console.log("Please inspect the following:");
//console.log(response);
var pageId = mw.config.get('wgArticleId');
var pageInfo = response.query.pages[pageId].revisions[0];
var relativeTimestamp = calculateRelativeTimestamp(pageInfo.timestamp);
var editComment = pageInfo.comment;
if (!editComment) {
editComment = "[No edit summary]";
}
editComment = editComment.replace(/'/g, "'"); // HTML encode quotes
var lastEdit = "<a href='/wiki/Special:Diff/" + pageInfo.revid
+ "' title='" + editComment + "'> Last edited "
+ relativeTimestamp + " ago</a>";
var lastEditor = "<a href='/wiki/Special:Contributions/" + pageInfo.user + "'>" + pageInfo.user + "</a>";
// Can be filtered if needed
var pageTags = "";
if (pageInfo.tags.length > 0) {
pageTags = "<span class='mw-tag-markers'> (" + pageInfo.tags + ")</span>";
}
var noticeText = lastEdit + " by " + lastEditor + pageTags;
var notice = "<div id='lastEdit' style='float: right;'>" + noticeText + "</div>"
displayEdit(notice);
}
// Adapted from https://github.com/wikimedia/mediawiki-extensions-MobileFrontend/blob/master/resources/mobile.modifiedBar/time.js
function calculateRelativeTimestamp(timestamp) {
// Supposedly Date parsing is a bit wonky with respect to browsers and
// timezones, but since we have an ISO-6801 date we can risk it
var editTimestamp = new Date(timestamp).getTime() / 1000;
var currentTimestamp = Math.round( new Date().getTime() / 1000);
var timestampDelta = currentTimestamp - editTimestamp;
var units = [ 'second', 'minute', 'hour', 'day', 'month', 'year' ],
limits = [ 1, 60, 3600, 86400, 2592000, 31536000 ];
var i = 0;
while ( i < limits.length && timestampDelta > limits[i + 1] ) {
++i;
}
var delta = Math.round(timestampDelta / limits[i]);
var deltaUnit = units[i];
// Pluralize units
if (delta > 1) {
deltaUnit += "s";
}
return delta + " " + deltaUnit;
}
// Display the last edit info to the right of the site subhead
function displayEdit(notice) {
// [[MediaWiki:Gadget-metadata.js]] replaces the siteSub element so wait
// for it to run first
// Check if script is enabled and if it hasn't ran already
if ($("script").text().search("ext.gadget.metadata") != -1 && !$(".assess-article-rating").length) {
var target = document.querySelector("#siteSub");
var observer = new MutationObserver(function(mutations) { // IE 11+
$("#siteSub").append(notice);
observer.disconnect();
});
observer.observe(target, {childList: true});
} else {
$("#siteSub").append(notice);
}
// Unfortunately [[Template:Coords]] absolutely positions itself so we
// have to move it down so we don't get obscured
var sheet = window.document.styleSheets[0];
sheet.insertRule('#coordinates { top: 2em !important; }', sheet.cssRules.length);
}
if (mw.config.get( 'skin' ) != "minerva") {
$(requestRevision);
}
//importScript('User:Dudemanfellabra/diffs.js'); // Backlink: [[User:Dudemanfellabra/diffs.js]]
// No updates in 3 years, so to speed up load times I'm directly importing it (with some tweaks and code cleanup):
function DateSub(Date1, Date2) {
var timeDifference = Date2 - Date1;
var minutesAgo = Math.round(timeDifference / 1000 / 60);
var hoursAgo = 0;
var daysAgo = 0;
var hoursText = 'hour';
var daysText = 'day';
while (minutesAgo >= 60) {
minutesAgo = minutesAgo-60;
hoursAgo++;
}
while (hoursAgo >= 24) {
hoursAgo = hoursAgo-24;
daysAgo++;
}
if (hoursAgo != 1) {
hoursText = hoursText + 's';
}
if (daysAgo != 1) {
daysText = daysText + 's';
}
if (daysAgo > 0) {
if (hoursAgo > 0) {
if (minutesAgo <= 1) {
minutesAgo = daysAgo + ' ' + daysText + ', ' + hoursAgo + ' ' + hoursText;
} else {
minutesAgo = daysAgo + ' ' + daysText + ', ' + hoursAgo + ' ' + hoursText + ', ' + minutesAgo + ' minutes';
}
} else {
if (minutesAgo <= 1) {
minutesAgo = daysAgo + ' ' + daysText;
} else {
minutesAgo = daysAgo + ' ' + daysText + ', ' + minutesAgo + ' minutes';
}
}
} else {
if (hoursAgo > 0) {
if (minutesAgo <= 1) {
minutesAgo = hoursAgo + ' ' + hoursText;
} else {
minutesAgo = hoursAgo + ' ' + hoursText + ', ' + minutesAgo + ' minutes';
}
} else {
if (minutesAgo <= 1) {
minutesAgo = 'Less than a minute';
} else {
minutesAgo = minutesAgo + ' minutes';
}
}
}
return minutesAgo;
}
if (document.getElementById('mw-diff-otitle1') || document.getElementById('mw-diff-ntitle1')) {
function convertTimestampStringToDate(id) {
var timestamp = document.getElementById(id).firstChild.firstChild.firstChild.nodeValue;
var str = /evision as of /g;
str.lastIndex = 0;
str.test(timestamp);
var date = timestamp.substring(str.lastIndex);
/*
All this following bogus crap is because Safari
doesn't recognize Wikipedia's date format.
Every other browser can just use the date string
object above, but Safari is retarded
*/
var str1 = /[A-z]+/;
var str2 = /\d+/g;
var monthtext = date.match(str1);
var testdate = date.match(str2);
var hours = testdate[0];
var minutes = testdate[1];
var day = testdate[2];
var year = testdate[3];
var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
for (i in months) {
if (monthtext == months[i]) {
var month = i;
break;
}
i++;
}
// End Safari madness
date = new Date(year, month, day, hours, minutes);
return date;
}
var leftNode = document.getElementById('mw-diff-otitle1');
var rightNode = document.getElementById('mw-diff-ntitle1');
var firstDate = convertTimestampStringToDate('mw-diff-otitle1');
var secondDate = convertTimestampStringToDate('mw-diff-ntitle1');
function TimeBetweenDiffs() {
var minutesAgo = DateSub(firstDate, secondDate);
var newNode = document.createElement('span');
newNode.setAttribute('style', 'font-weight:bold; color:red;');
newNode.appendChild(document.createTextNode('(' + minutesAgo + ' later)'));
newNode.appendChild(document.createElement('br'));
rightNode.insertBefore(newNode, rightNode.firstChild);
}
function TimeSinceDiff() {
var DateNow = new Date();
var minutesAgo1 = DateSub(firstDate, DateNow);
var minutesAgo2 = DateSub(secondDate, DateNow);
document.getElementById('mw-diff-otitle1').title=minutesAgo1 + ' ago';
document.getElementById('mw-diff-ntitle1').title=minutesAgo2 + ' ago';
var t = setTimeout("TimeSinceDiff()", 60000);
}
// Adds time since displayed diffs as tooltip
$(window).load(TimeSinceDiff);
// Adds time between diffs
$(window).load(TimeBetweenDiffs);
}
var inspectText = "+";
var showText = "+";
var hideText = "-";
//importScript("User:Writ Keeper/Scripts/commonHistory.js");
// http://en.wiki.x.io/wiki/User:Writ_Keeper/Scripts/inlineDiffDocs
// There are changes in http://en.wiki.x.io/w/index.php?title=User:Writ_Keeper/Scripts/commonHistory.js&action=history that can be imported, I think I've imported all of the important ones though...
//var diffRequestLocked = "f";
if (typeof inspectText == "undefined") {
var inspectText = "inspect diff";
}
if (typeof showText == "undefined") {
var showText = "show diff";
}
if (typeof hideText == "undefined") {
var hideText = "hide diff";
}
/*if (mw.config.get("wgCanonicalSpecialPageName") == "Watchlist" || mw.config.get("wgCanonicalSpecialPageName") == "Recentchanges" || mw.config.get("wgCanonicalSpecialPageName") == "Recentchangeslinked" || mw.config.get("wgCanonicalSpecialPageName") == "Contributions" || mw.config.get("wgAction") == "history") {*/
var specialPageName = mw.config.get("wgCanonicalSpecialPageName");
if (specialPageName == "Watchlist" ||
specialPageName == "Recentchanges" ||
specialPageName == "Contributions" ||
mw.config.get("wgAction") == "history" ||
specialPageName == "Recentchangeslinked") {
function inspectionEachHelper(index, element) {
var findString;
if (mw.config.get("wgAction") == "history" || $(element).hasClass("mw-enhanced-rc-nested")) {
findString = 'a:contains("prev")';
} else {
findString = 'a:contains("diff")';
}
var regex;
//if (mw.config.get("wgCanonicalSpecialPageName") == "Contributions") {
if (specialPageName == "Contributions") {
regex = /&oldid=(\d+)$/;
} else {
regex = /&diff=(\d+)&oldid=/;
}
var diffLink = $(element).find(findString);
if (diffLink.length > 0) {
var regexResult = regex.exec(diffLink[0].href);
if (regexResult !== null && regexResult.length >= 2) {
var diffID = regexResult[1];
//don't re-add if it already exists
if ($("#" + diffID).length > 0)
{
return;
}
var inlineDiffButton;
if (typeof inlineDiffBigUI === "undefined") {
inlineDiffButton = document.createElement("a");
inlineDiffButton.href = "#";
inlineDiffButton.innerHTML = '<b><span style="color:black;"> [</span><span style="color:#339900;">'+inspectText+'</span><span style="color:black;">] </span></b>';
} else {
inlineDiffButton = document.createElement("input");
inlineDiffButton.type = "button";
inlineDiffButton.value = "Inspect edit";
}
inlineDiffButton.id = diffID;
$(inlineDiffButton).addClass("inspectDiffButton");
$(inlineDiffButton).click(function () {
return inspectWatchlistDiff(this);
});
if ($(element).find("tr:first").length === 0) {
$(element).find(".mw-changeslist-separator:first").css("padding-right", 0);
$(inlineDiffButton).insertAfter($(element).find(".mw-changeslist-separator:first"));
} else {
$(element).find("tr:first").append("<td></td>");
$(element).find("tr:first>td:last").append(inlineDiffButton);
}
}
}
}
function addWatchlistInspectionBoxes() {
mw.loader.using("mediawiki.diff.styles").done(function () {
var entries = $("#mw-content-text table.mw-enhanced-rc");
if (entries.length === 0) {
$("#mw-content-text ul").each(function (ind, el) {
$(el).children("li").each(inspectionEachHelper);
});
} else {
entries.each(inspectionEachHelper);
$("td.mw-enhanced-rc-nested").each(inspectionEachHelper);
}
});
//mw.loader.load('mediawiki.action.history.diff');
}
function inspectWatchlistDiff(button) {
mw.loader.using(['mediawiki.api']).done(function () {
var mwApi = new mw.Api();
mwApi.get({
action: "query",
prop: "revisions",
format: "json",
rvprop: "timestamp",
rvdiffto: "prev",
revids: button.id
}).done(function (response) {
if (response === null) {
alert("Request failed!");
return false;
}
var diffString = response.query.pages[Object.keys(response.query.pages)[0]].revisions[0].diff["*"];
if (diffString === null) {
alert("Request failed!");
return false;
}
var newTable = document.createElement("table");
newTable.className = "diff";
$(newTable).html('<colgroup><col class="diff-marker"><col class="diff-content"><col class="diff-marker"><col class="diff-content"></colgroup>');
$(newTable).append(diffString);
var diffParent = null;
if ($("#"+ button.id).parent("td").length > 0 && !($("#"+ button.id).parent("td").hasClass("mw-enhanced-rc-nested"))) {
$("#"+ button.id).parents("table.mw-enhanced-rc:first").after(newTable);
} else {
diffParent = $("#"+button.id).parent();
diffParent.append(newTable);
}
newTable.id = button.id + "display";
//$(button).unbind("click");
$(button).off("click");
if (typeof inlineDiffBigUI === "undefined") {
$(button).html('<b><span style="color:black;"> [</span><span style="color:#339900;">'+hideText+'</span><span style="color:black;">] </span></b>');
$(button).click(function (){
return hideSmallEditInspection(this);
});
} else {
$(button).attr("value","Hide edit");
$(button).click(function (){
return hideEditInspection(this);
});
}
/*if (typeof markAsViewed != "undefined" && markAsViewed) {
mwApi.post({action : "setnotificationtimestamp", revids: button.id, token : mw.user.tokens.get("csrfToken")}).done(function (data) {
if (diffParent !== null) {
diffParent.removeClass("mw-changeslist-line-watched");
diffParent.addClass("mw-changeslist-line-not-watched");
}
});
}*/
/*if (typeof markAsViewed != "undefined" && markAsViewed) {
mwApi.postWithToken('csrf', {
action: "setnotificationtimestamp",
revids: button.id
}).done(function (data) {
if (diffParent != null) {
diffParent.removeClass("mw-changeslist-line-watched");
diffParent.addClass("mw-changeslist-line-not-watched");
}
});
}*/
//diffRequestLocked = "f";
});
}
); // this line can hypothetically be commented out?
return false;
}
function showEditInspection(button) {
$("#"+button.id+"display").css("display", "");
$(button).attr("value","Hide edit");
//$(button).unbind("click");
$(button).off("click");
$(button).click(function (){
return hideEditInspection(this);
});
return false;
}
function hideEditInspection(button) {
$("#"+button.id+"display").css("display", "none");
$(button).attr("value","Show edit");
//$(button).unbind("click");
$(button).off("click");
$(button).click(function (){
return showEditInspection(this);
});
return false;
}
function showSmallEditInspection(button) {
$("#"+button.id+"display").css("display", "");
$(button).html('<b><span style="color:black;"> [</span><span style="color:#339900;">'+hideText+'</span><span style="color:black;">] </span></b>');
//$(button).unbind("click");
$(button).off("click");
$(button).click(function () {
return hideSmallEditInspection(this);
});
return false;
}
function hideSmallEditInspection(button) {
$("#"+button.id+"display").css("display", "none");
$(button).html('<b><span style="color:black;"> [</span><span style="color:#339900;">'+showText+'</span><span style="color:black;">] </span></b>');
//$(button).unbind("click");
$(button).off("click");
$(button).click(function () {
return showSmallEditInspection(this);
});
return false;
}
//$(document).ready(addWatchlistInspectionBoxes);
mw.hook('wikipage.content').add(addWatchlistInspectionBoxes);
}
importScript("User:PleaseStand/userinfo.js"); // http://en.wiki.x.io/wiki/User:PleaseStand/User_info
// From: User:David Condrey/bookmarknav.js
// Documentation: http://en.wiki.x.io/wiki/User:David_Condrey/bookmarknav
// HEAVILY MODIFIED
/*$('#p-interaction').clone(true).insertAfter($('#p-interaction')).addClass('mylinks').removeAttr('id').find('h3').text('Quick References');
$('.mylinks li').remove();
$('.mylinks div ul').append('<li><a class="myLinks1"></a></li>');
$('.mylinks div ul').append('<li><a class="myLinks2"></a></li>');
$('.mylinks div ul').append('<li><a class="myLinks3"></a></li>');
$('.mylinks div ul').append('<li><a class="myLinks4"></a></li>');
$('.mylinks div ul').append('<li><a class="myLinks5"></a></li>');
$('.mylinks div ul').append('<li><a class="myLinks6"></a></li>');
$('.mylinks div ul').append('<li><a class="myLinks7"></a></li>');
// Set each new link's text and url
$('.myLinks1').text('Policies').attr('href', 'http://en.wiki.x.io/wiki/Wikipedia:List_of_policies');
$('.myLinks2').text('Guidelines').attr('href', 'http://en.wiki.x.io/wiki/Wikipedia:List_of_guidelines');
$('.myLinks3').text('Main Style').attr('href', 'http://en.wiki.x.io/wiki/Wikipedia:Manual_of_Style/Contents');
$('.myLinks4').text('Wiki Markup').attr('href', 'http://en.wiki.x.io/wiki/Help:Wiki_markup');
$('.myLinks5').text('Template Tagging').attr('href', 'http://en.wiki.x.io/wiki/Wikipedia:Template_messages');
$('.myLinks6').text('Cleanup Tags').attr('href', 'http://en.wiki.x.io/wiki/Wikipedia:Template_messages/Cleanup#General_cleanup');
$('.myLinks7').text('List of Infoboxes').attr('href', 'http://en.wiki.x.io/wiki/Wikipedia:List_of_infoboxes');*/
function createHtmlForList(listarray) {
var textblob = '';
function generateListHtmlItem(value, index, array) {
textblob += '<li><a href="'+value[1]+'">'+value[0]+'</a></li>';
}
listarray.forEach(generateListHtmlItem);
return textblob;
}
function initializeNewItem(newclass, newtext, listarray) {
$('#p-interaction').clone(true).insertAfter($('#p-interaction')).addClass(newclass).removeAttr('id').find('h3').text(newtext);
$('.'+newclass+' li').remove();
$('.'+newclass+' div ul').append(createHtmlForList(listarray));
}
// ideally generate it all in one single html blob for addition with looping and such so I only need one JS call to set all at once (might improve performance)
// fuck it I'll just implement it anyways. might as well try to cut down on page loading time as much as possible...
// subarray definition: text, URL
var listarray0 = [
[
'Policies',
'http://en.wiki.x.io/wiki/Wikipedia:List_of_policies'
],
[
'Guidelines',
'http://en.wiki.x.io/wiki/Wikipedia:List_of_guidelines'
],
[
'MoS',
'http://en.wiki.x.io/wiki/Wikipedia:Manual_of_Style/Contents'
],
[
'Wiki markup',
'http://en.wiki.x.io/wiki/Help:Wiki_markup'
],
[
'Template tagging',
'http://en.wiki.x.io/wiki/Wikipedia:Template_messages'
],
[
'Cleanup tags',
'http://en.wiki.x.io/wiki/Wikipedia:Template_messages/Cleanup#General_cleanup'
],
[
'List of infoboxes',
'http://en.wiki.x.io/wiki/Wikipedia:List_of_infoboxes'
]
];
// subarray definition: text, URL
var listarray1 = [
[
'Pharmacology',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Pharmacology'
],
[
'Medicine',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Medicine'
],
[
'Medical genetics task force',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Medicine/Medical_genetics_task_force'
],
[
'Psychiatry task force',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Medicine/Psychiatry_task_force'
],
[
'Energy',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Energy'
],
[
'Energy (portal)',
'http://en.wiki.x.io/wiki/Portal:Energy/Explore'
],
[
'Environment',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Environment'
],
[
'Aviation',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Aviation'
],
[
'Aircraft',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Aircraft'
],
[
'Canada',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Canada'
],
[
'Genetics',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Genetics'
],
[
'Nursing',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Nursing'
],
[
'Technology',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Technology'
],
[
'Electronics',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Electronics'
],
[
'Engineering',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Engineering'
],
[
'Dams',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Dams'
],
[
'Electrical engineering',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Electrical_engineering'
],
[
'Computing-related (broad)',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Council/Directory/Science#Computing'
],
[
'Computing',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Computing'
],
[
'Computer networking task force',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Computing/Computer_networking_task_force'
],
[
'Telecommunications',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Telecommunications'
],
[
'Internet',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Internet'
],
[
'Physics',
'http://en.wiki.x.io/wiki/Wikipedia:WikiProject_Physics'
]
];
// subarray definition: text, URL
var listarray2 = [
[
'Abbreviations',
'http://en.wiki.x.io/wiki/Wikipedia:Wikipedia_abbreviations'
],
[
'Markup',
'http://en.wiki.x.io/wiki/Help:Wiki_markup'
],
[
'Cheatsheet',
'http://en.wiki.x.io/wiki/Help:Cheatsheet'
],
[
'HTML',
'http://en.wiki.x.io/wiki/Help:HTML_in_wikitext'
],
[
'Lists',
'http://en.wiki.x.io/wiki/Help:List'
],
[
'Tables',
'http://en.wiki.x.io/wiki/Help:Table'
],
[
'Magic words',
'http://en.wiki.x.io/wiki/Help:Magic_words'
],
[
'Templates',
'http://en.wiki.x.io/wiki/Help:Template'
],
[
'Major templates',
'http://en.wiki.x.io/wiki/Wikipedia:Template_messages'
],
[
'Transclusion',
'http://en.wiki.x.io/wiki/Wikipedia:Transclusion'
],
[
'Wiki Markup',
'http://en.wiki.x.io/wiki/Help:Wiki_markup'
]
];
initializeNewItem('myglinks', 'Quick References', listarray0);
initializeNewItem('mywikiprojects', 'WikiProjects', listarray1);
initializeNewItem('myplinks', 'Personal Toolbox', listarray2);
// NOTE: Need to enable this ONLY on pages where refToolbar is used -- IMPOSSIBLE, YAY...
// oh jesus christ, I'm done. they've clearly modified something in refToolbar that breaks this, and I don't like my shitty "cite patent" option enough to care enough to spend the huge amount of time that it would take to redo that fucking native userscript implementation of refToolbar that I once tried... So I'm just disabling this. Good riddance.
/*CiteTB.getOpenTemplate = function () {
var dialogs = $(".ui-dialog-content.ui-widget-content:visible");
var templatename = $(dialogs[0]).find(".cite-template").val();
return CiteTB.Templates[templatename];
};*/
/*CiteTB.getOpenTemplate = function () {
return "cite web";
};*/
// AYYYY JAVASCRIPT. *sobs*
// mw, $
(function () {
if ($.inArray(mw.config.get('wgAction'), ['edit', 'submit']) !== -1 ) {
//console.log("YES I AM ALIVE THANK YOU FOR CHECKING");
importScript('MediaWiki:Gadget-refToolbarBase.js');
//console.log(mw.config.get('wgAction'));
}
})();
// (mediaWiki, jQuery)
//console.log(mw.config.get('wgAction'));
/*jshint smarttabs:true, loopfunc:true,forin:false*/
/*global mw, $, importScript */
// the above no longer true???
// TODO: make autodate an option in the CiteTemplate object, not a preference
// Global object
// TODO:
// * Remove this once the page is moved to a module 'ext.gadget.refToolbarDialogs' depending on 'ext.gadget.refToolbarBase'
if (typeof CiteTB === 'undefined') {
var CiteTB = {
"Templates" : {}, // All templates
"Options" : {}, // Global options
"UserOptions" : {}, // User options
"DefaultOptions" : {}, // Script defaults
"ErrorChecks" : {} // Error check functions
};
}
// Only execute on edit, unless it is a user JS/CSS page
// TODO: Remove tests already done by [[MediaWiki:Gadget-refToolbar.js]]
if ((mw.config.get('wgAction') === 'edit' || mw.config.get('wgAction') === 'submit') && ((mw.config.get('wgNamespaceNumber') !== 2 && mw.config.get('wgNamespaceNumber') !== 4) || (mw.config.get('wgPageName').indexOf('.js') === -1 && mw.config.get('wgPageName').indexOf('.css') === -1))) {
//mw.loader.using( 'mediawiki.util', function () {
//mw.loader.using(['mediawiki.util']).done(function () {
//mw.loader.using( 'mediawiki.util', function () {
$.when( mw.loader.using( 'mediawiki.util' ), $.ready ).then( function () {
// TODO: Move this to [[MediaWiki:Gadget-refToolbarDialogs.css]] and add it to the definition of module 'ext.gadget.refToolbarDialogs'
/*mw.util.addCSS(".cite-form-td {"+
"height: 0 !important;"+
"padding: 0.1em !important;"+
"}");*/
mw.util.addCSS(' .cite-form-td { height: 0 !important; padding: 0.1em !important; } ');
});
// Default options, these mainly exist so the script won't break if a new option is added
CiteTB.DefaultOptions = {
"date format": "<year>-<zmonth>-<zdate>",
"autodate fields": [],
"months": ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
"modal": true,
"autoparse": false,
"expandtemplates": false
};
// Get an option - user settings override global which override defaults
CiteTB.getOption = function (opt) {
if (CiteTB.UserOptions[opt] !== undefined) {
return CiteTB.UserOptions[opt];
} else if (CiteTB.Options[opt] !== undefined) {
return CiteTB.Options[opt];
}
return CiteTB.DefaultOptions[opt];
};
CiteTB.init = function () {
/* Main stuff, build the actual toolbar structure
* 1. get the template list, make the dropdown list and set up the template dialog boxes
* 2. actually build the toolbar:
* * A section for cites
* ** dropdown for the templates (previously defined)
* ** button for named refs with a dialog box
* ** button for errorcheck
* 3. add the whole thing to the main toolbar
*/
if (typeof $('div[rel=cites]')[0] !== 'undefined') { // Mystery IE bug workaround
return;
}
$('head').trigger('reftoolbarbase');
var $target = $('#wpTextbox1');
var temlist = {};
for (var t in CiteTB.Templates) {
var tem = CiteTB.Templates[t];
var sform = CiteTB.escStr(tem.shortform);
var actionobj = {
type: 'dialog',
module: 'cite-dialog-'+sform
};
var dialogobj = {};
dialogobj['cite-dialog-'+sform] = {
resizeme: false,
titleMsg: 'cite-dialog-'+sform,
id: 'citetoolbar-'+sform,
init: function () {},
html: tem.getInitial(),
dialog: {
width:675,
open: function () {
$(this).html(CiteTB.getOpenTemplate().getForm());
/** @param {jQuery.Event} e */
$('.cite-prev-parse').on( 'click', function ( e ) {
e.preventDefault();
CiteTB.prevParseClick();
});
},
buttons: {
'cite-form-submit': function () {
var ref = CiteTB.getRef(false, true);
$(this).dialog( 'close' );
$.wikiEditor.modules.toolbar.fn.doAction( $(this).data( 'context' ), {
type: 'encapsulate',
options: {
post: ref
}
}, $(this) );
},
'cite-form-showhide': CiteTB.showHideExtra,
'cite-refpreview': function () {
var ref = CiteTB.getRef(false, false);
var template = CiteTB.getOpenTemplate();
var div = $("#citetoolbar-"+CiteTB.escStr(template.shortform));
div.find('.cite-preview-label').show();
div.find('.cite-ref-preview').text(ref).show();
if (CiteTB.getOption('autoparse')) {
CiteTB.prevParseClick();
} else {
div.find('.cite-prev-parse').show();
div.find('.cite-prev-parsed-label').hide();
div.find('.cite-preview-parsed').html('');
}
},
'wikieditor-toolbar-tool-link-cancel': function () {
$(this).dialog( 'close' );
},
'cite-form-reset': function () {
CiteTB.resetForm();
}
}
}
};
$target.wikiEditor('addDialog', dialogobj);
//if (!CiteTB.getOption('modal')) {
//$('#citetoolbar-'+sform).dialog('option', 'modal', false);
//}
temlist[sform] = {label: tem.templatename, action: actionobj };
}
var refsection = {
'sections': {
'cites': {
type: 'toolbar',
labelMsg: 'cite-section-label',
groups: {
'template': {
tools: {
'template': {
type: 'select',
labelMsg: 'cite-template-list',
list: temlist
}
}
},
'namedrefs': {
labelMsg: 'cite-named-refs-label',
tools: {
'nrefs': {
type: 'button',
action: {
type: 'dialog',
module: 'cite-toolbar-namedrefs'
},
icon: '//up.wiki.x.io/wikipedia/commons/thumb/b/be/Nuvola_clipboard_lined.svg/22px-Nuvola_clipboard_lined.svg.png',
section: 'cites',
group: 'namedrefs',
labelMsg: 'cite-named-refs-button'
}
}
},
'errorcheck': {
labelMsg: 'cite-errorcheck-label',
tools: {
'echeck': {
type: 'button',
action: {
type: 'dialog',
module: 'cite-toolbar-errorcheck'
},
icon: '//up.wiki.x.io/wikipedia/commons/thumb/a/a3/Nuvola_apps_korganizer-NO.png/22px-Nuvola_apps_korganizer-NO.png',
section: 'cites',
group: 'errorcheck',
labelMsg: 'cite-errorcheck-button'
}
}
}
}
}
}
};
var defaultdialogs = {
'cite-toolbar-errorcheck': {
titleMsg: 'cite-errorcheck-label',
id: 'citetoolbar-errorcheck',
resizeme: false,
init: function () {},
html: '<div id="cite-namedref-loading">'+
'<img src="//up.wiki.x.io/wikipedia/commons/4/42/Loading.gif" />'+
' '+mw.usability.getMsg('cite-loading')+'</div>',
dialog: {
width:550,
open: function () {
CiteTB.loadRefs();
},
buttons: {
'cite-errorcheck-submit': function () {
var errorchecks = $("input[name='cite-err-test']:checked");
var errors = [];
for (var i=0; i<errorchecks.length; i++) {
errors = errors.concat(CiteTB.ErrorChecks[$(errorchecks[i]).val()].run());
}
CiteTB.displayErrors(errors);
$(this).dialog( 'close' );
},
'wikieditor-toolbar-tool-link-cancel': function () {
$(this).dialog( 'close' );
}
}
}
},
'cite-toolbar-namedrefs': {
titleMsg: 'cite-named-refs-title',
resizeme: false,
id: 'citetoolbar-namedrefs',
html: '<div id="cite-namedref-loading">'+
'<img src="//up.wiki.x.io/wikipedia/commons/4/42/Loading.gif" />'+
' '+mw.usability.getMsg('cite-loading')+'</div>',
init: function () {},
dialog: {
width: 550,
open: function () {
CiteTB.loadRefs();
},
buttons: {
'cite-form-submit': function () {
var refname = $("#cite-namedref-select").val();
if (refname === '') {
return;
}
$(this).dialog( 'close' );
$.wikiEditor.modules.toolbar.fn.doAction( $(this).data( 'context' ), {
type: 'encapsulate',
options: {
post: CiteTB.getNamedRef(refname, true)
}
}, $(this) );
},
'wikieditor-toolbar-tool-link-cancel': function () {
$(this).dialog( 'close' );
}
}
}
}
};
$target.wikiEditor('addDialog', defaultdialogs);
$('#citetoolbar-namedrefs').off('dialogopen');
if (!CiteTB.getOption('modal')) {
//$('#citetoolbar-namedrefs').dialog('option', 'modal', false);
//$('#citetoolbar-errorcheck').dialog('option', 'modal', false);
// THIS MAY CRASH, FIX NOT TESTED:
$.when( mw.loader.using( 'mediawiki.util' ), $.ready ).then( function () {
mw.util.addCSS(".ui-widget-overlay {"+
"display:none !important;"+
"}");
});
}
$target.wikiEditor('addToToolbar', refsection);
};
// Load local data - messages, cite templates, etc.
$(document).ready( function () {
switch( mw.config.get('wgUserLanguage') ) {
case 'de': // German
importScript('MediaWiki:RefToolbarMessages-de.js');
break;
default: // English
importScript('MediaWiki:RefToolbarMessages-en.js');
}
});
// Setup the main object
CiteTB.mainRefList = [];
CiteTB.refsLoaded = false;
// REF FUNCTIONS
// Actually assemble a ref from user input
CiteTB.getRef = function (inneronly, forinsert) {
var i;
var template = CiteTB.getOpenTemplate();
var templatename = template.templatename;
var res = '';
var refobj = {'shorttag':false};
if (!inneronly) {
var group = $('#cite-'+CiteTB.escStr(template.shortform)+'-group').val();
var refname = $('#cite-'+CiteTB.escStr(template.shortform)+'-name').val();
//<nowiki>
res += '<ref';
//</nowiki>
if (refname) {
refname = $.trim(refname);
res+=' name='+CiteTB.getQuotedString(refname);
refobj.refname = refname;
}
if (group) {
group = $.trim(group);
res+=' group='+CiteTB.getQuotedString(group);
refobj.refgroup = group;
}
res+='>';
}
var content ='{{'+templatename;
for (var g in template.incrementables ) {
group = template.incrementables[g];
for (i=1; i<=group.val; i++) {
for (j=0; j<group.fields.length; j++) {
var fieldname = group.fields[j].field;
var fieldid = fieldname.replace('<N>', i.toString());
var field = $('#cite-'+CiteTB.escStr(template.shortform)+'-'+fieldid).val();
if (field) {
content+='|'+fieldid+'=';
content+= $.trim(field);
}
}
}
}
for( i=0; i<template.basic.length; i++ ) {
if (template.basic[i].increment_group) {
continue;
}
var fieldname = template.basic[i].field;
var field = $('#cite-'+CiteTB.escStr(template.shortform)+'-'+fieldname).val();
if (field) {
content+='|'+fieldname+'=';
content+= $.trim(field);
}
}
if ($('#cite-form-status').val() !== 'closed') {
for( i=0; i<template.extra.length; i++ ) {
if (template.extra[i].increment_group) {
continue;
}
var fieldname = template.extra[i].field;
var field = $('#cite-'+CiteTB.escStr(template.shortform)+'-'+fieldname).val();
if (field) {
content+='|'+fieldname+'=';
content+= $.trim(field);
}
}
}
content+= '}}';
res+=content;
refobj.content = content;
if (!inneronly) {
res+= '</ref>';
}
if (forinsert) {
CiteTB.mainRefList.push(refobj);
}
return res;
};
// Make a reference to a named ref
CiteTB.getNamedRef = function (refname, forinsert) {
if (forinsert) {
CiteTB.mainRefList.push( {'shorttag':true, 'refname':refname} );
}
//<nowiki>
return '<ref name='+CiteTB.getQuotedString(refname)+' />';
//</nowiki>
};
// Function to load the ref list
CiteTB.loadRefs = function () {
if (CiteTB.refsLoaded) {
return;
}
CiteTB.getPageText(CiteTB.loadRefsInternal);
};
// Function that actually loads the list from the page text
CiteTB.loadRefsInternal = function (text) {
// What this does: extract first name/group, extract second name/group, shorttag, inner content
var refsregex = /< *ref(?: +(name|group) *= *(?:"([^"]*?)"|'([^']*?)'|([^ '"\/\>]*?)) *)? *(?: +(name|group) *= *(?:"([^"]*?)"|'([^']*?)'|([^ '"\/\>]*?)) *)? *(?:\/ *>|>((?:.|\n)*?)< *\/ *ref *>)/gim;
// This should work regardless of the quoting used for names/groups and for linebreaks in the inner content
while (true) {
var ref = refsregex.exec(text);
if (ref === null) {
break;
}
var refobj = {};
if (ref[9]) { // Content + short tag check
//alert('"'+ref[9]+'"');
refobj.content = ref[9];
refobj.shorttag = false;
} else {
refobj.shorttag = true;
}
if (ref[1] !== '') { // First name/group
if (ref[2]) {
refobj['ref'+ref[1]] = ref[2];
} else if (ref[3]) {
refobj['ref'+ref[1]] = ref[3];
} else {
refobj['ref'+ref[1]] = ref[4];
}
}
if (ref[5] !== '') { // Second name/group
if (ref[6]) {
refobj['ref'+ref[5]] = ref[6];
} else if (ref[7]) {
refobj['ref'+ref[5]] = ref[7];
} else {
refobj['ref'+ref[5]] = ref[8];
}
}
CiteTB.mainRefList.push(refobj);
}
CiteTB.refsLoaded = true;
CiteTB.setupErrorCheck();
CiteTB.setupNamedRefs();
};
// AJAX FUNCTIONS
// Parse some wikitext and hand it off to a callback function
CiteTB.parse = function (text, callback) {
$.post( mw.util.wikiScript( 'api' ),
{action:'parse', title:mw.config.get('wgPageName'), text:text, prop:'text', format:'json'},
function (data) {
var html = data.parse.text['*'];
callback(html);
},
'json'
);
};
// Use the API to expand templates on some text
CiteTB.expandtemplates = function (text, callback) {
$.post( mw.util.wikiScript( 'api' ),
{action:'expandtemplates', title:mw.config.get('wgPageName'), text:text, format:'json'},
function (data) {
var restext = data.expandtemplates['*'];
callback(restext);
},
'json'
);
};
// Function to get the page text
CiteTB.getPageText = function (callback) {
var section = $("input[name='wpSection']").val();
if ( section !== '' ) {
var postdata = {action:'query', prop:'revisions', rvprop:'content', pageids:mw.config.get('wgArticleId'), format:'json'};
if (CiteTB.getOption('expandtemplates')) {
postdata.rvexpandtemplates = '1';
}
$.get( mw.util.wikiScript( 'api' ),
postdata,
function (data) {
var pagetext = data.query.pages[mw.config.get('wgArticleId').toString()].revisions[0]['*'];
callback(pagetext);
},
'json'
);
} else {
if (CiteTB.getOption('expandtemplates')) {
CiteTB.expandtemplates($('#wpTextbox1').wikiEditor('getContents').text(), callback);
} else {
callback($('#wpTextbox1').wikiEditor('getContents').text());
}
}
};
// Autofill a template from an ID (ISBN, DOI, PMID, URL)
CiteTB.initAutofill = function () {
var elemid = $(this).attr('id');
var res = /^cite\-auto\-(.*?)\-(.*)\-(.*)$/.exec(elemid);
var tem = res[1];
var field = res[2];
var autotype = res[3];
var id = $('#cite-'+tem+'-'+field).val();
if (!id) {
return false;
}
var url = '//tools.wmflabs.org/reftoolbar/lookup.php?';
url+=autotype+'='+encodeURIComponent(id);
url+='&template='+encodeURIComponent(tem);
var s = document.createElement('script');
s.setAttribute('src', url);
s.setAttribute('type', 'text/javascript');
document.getElementsByTagName('head')[0].appendChild(s);
return false;
};
// Callback for autofill
//TODO: Autofill the URL, at least for DOI
CiteTB.autoFill = function (data, template, type) {
var cl = 'cite-'+template+'-';
var i,j, coauthors;
$('.'+cl+'title').val(data.title);
// Fill in authors
if (data.authors && data.authors.length > 0) {
if ($('.'+cl+'last-incr-1').length != 0) {
var classes = $('.'+cl+'last-incr-1').eq(0).attr('class').split(/\s+/);
var group = false;
var patt = '/cite-[^-]*?-incr-(.*)/';
for (var c=0; c<classes.length; c++) {
if (patt.exec(classes[c])) {
group = patt.exec(classes[c])[1];
break;
}
}
$('.'+cl+'last-incr-1').val(data.authors[0][0]);
$('.'+cl+'first-incr-1').val(data.authors[0][1]);
elemid = '#cite-incr-'+template+'-'+group;
for (var i=2; i<data.authors.length+1; i++) {
$(elemid).click();
$('.'+cl+'last-incr-'+i.toString()).val(data.authors[i-1][0]);
$('.'+cl+'first-incr-'+i.toString()).val(data.authors[i-1][1]);
}
} else if ($('.'+cl+'author-incr-1').length != 0) {
var classes = $('.'+cl+'author-incr-1').eq(0).attr('class').split(/\s+/);
var group = false;
var patt = '/cite-[^-]*?-incr-(.*)/';
for (var c=0; c<classes.length; c++) {
if (patt.exec(classes[c])) {
group = patt.exec(classes[c])[1];
break;
}
}
$('.'+cl+'author-incr-1').val(data.authors[0].join(', '));
elemid = '#cite-incr-'+template+'-'+group;
for (var i=2; i<data.authors.length+1; i++) {
$(elemid).click();
$('.'+cl+'author-incr-'+i.toString()).val(data.authors[i-1].join(', '));
}
} else if ($('.'+cl+'last1').length != 0) {
for(i=0; data.authors && i<data.authors.length; i++) {
if ($('.'+cl+'last'+(i+1)).length) {
$('.'+cl+'last'+(i+1)).val(data.authors[i][0]);
$('.'+cl+'first'+(i+1)).val(data.authors[i][1]);
} else {
coauthors = [];
for(j=i; j<data.authors.length; j++) {
coauthors.push(data.authors[j].join(', '));
}
$('.'+cl+'coauthors').val(coauthors.join('; '));
break;
}
}
} else if($('.'+cl+'author1').length !== 0) {
for(i=0; data.authors && i<data.authors.length; i++) {
if ($('.'+cl+'author'+(i+1)).length) {
$('.'+cl+'author'+(i+1)).val(data.authors[i].join(', '));
} else {
coauthors = [];
for(j=i; j<data.authors.length; j++) {
coauthors.push(data.authors[j].join(', '));
}
$('.'+cl+'coauthors').val(coauthors.join('; '));
break;
}
}
} else {
var authors = [];
for(i=0; data.authors && i<data.authors.length; i++) {
authors.push(data.authors[i].join(', '));
}
$('.'+cl+'authors').val(authors.join('; '));
}
}
if (type === 'pmid' || type === 'doi') {
if (data.date && (data.fulldate || !$('.'+cl+'month').length)) {
var DT = new Date(data.date);
var useday = /\d{4}-\d{2}-\d{2}/.test(data.date);
var usemonth = /\d{4}-\d{2}/.test(data.date);
$('.'+cl+'date').val(CiteTB.formatDate(DT, useday, usemonth));
} else if (!data.fulldate && $('.'+cl+'month').length && $('.'+cl+'year').length) {
if (data.month) { // lookup.php sets month to false if it isn't provided
$('.'+cl+'month').val( CiteTB.getOption('months')[parseInt(data.month)-1] );
}
$('.'+cl+'year').val(data.year);
} else {
$('.'+cl+'date').val(data.date);
}
$('.'+cl+'journal').val(data.journal);
$('.'+cl+'volume').val(data.volume);
$('.'+cl+'issue').val(data.issue);
$('.'+cl+'pages').val(data.pages);
if (type === 'pmid' && data.doi) {
$('.'+cl+'doi').val(data.doi);
}
} else if (type === 'isbn') {
$('.'+cl+'publisher').val(data.publisher);
$('.'+cl+'location').val(data.location);
$('.'+cl+'year').val(data.year);
$('.'+cl+'edition').val(data.edition);
} else if (type === 'url') {
if (data.date) {
var DT = new Date(data.date);
var useday = /\d{4}-\d{2}-\d{2}/.test(data.date) && template !== 'book';
var usemonth = /\d{4}-\d{2}/.test(data.date) && template !== 'book';
var yearOrDate = (template === 'book') ? 'year' : 'date';
$('.'+cl+yearOrDate).val(CiteTB.formatDate(DT, useday, usemonth));
}
$('.'+cl+'journal').val(data.journal);
$('.'+cl+'volume').val(data.volume);
$('.'+cl+'issue').val(data.issue);
$('.'+cl+'pages').val(data.pages);
$('.'+cl+'publisher').val(data.publisher);
$('.'+cl+'edition').val(data.edition);
$('.'+cl+'isbn').val(data.isbn);
$('.'+cl+'issn').val(data.issn);
$('.'+cl+'doi').val(data.doi);
// "en-US" isn't a valid value for the language parameter
if (data.language && data.language !== 'en-US' && data.language !== 'en-GB') {
$('.'+cl+'language').val(data.language);
}
$('.'+cl+'chapter').val(data.chapter);
}
};
// FORM DIALOG FUNCTIONS
// Add new incrementable fields
CiteTB.incrementFields = function () {
template = CiteTB.getOpenTemplate();
var currentrow = $(this).parents('tr')[0];
$(this).prev().css('width', '100%');
$(this).detach();
var elemid = $(this).attr('id');
var res = /^cite\-incr\-(.*?)\-(.*)$/.exec(elemid);
group = res[2];
increments = template.incrementables[group];
fields = increments.fields;
incrval = increments.val+1;
template.incrementables[group].val += 1;
trs = template.makeFormInner(fields, false);
trs.reverse();
for (var i=0; i<trs.length; i++) {
$(currentrow).after(trs[i]);
}
};
// fill the accessdate param with the current date
CiteTB.fillAccessdate = function () {
var elemid = $(this).attr('id');
var res = /^cite\-date\-(.*?)\-(.*)$/.exec(elemid);
var id = res[1];
var field = res[2];
var DT = new Date();
var datestr = CiteTB.formatDate(DT);
$('#cite-'+id+'-'+field).val(datestr);
return false;
};
CiteTB.formatDate = function (DT, useday, usemonth) {
if (typeof useday == "undefined") {
useday = true;
}
if (typeof usemonth == "undefined") {
usemonth = true;
}
var datestr = CiteTB.getOption('date format');
var zmonth = '';
var month = DT.getUTCMonth()+1;
if (month < 10) {
zmonth = "0"+month.toString();
} else {
zmonth = month.toString();
}
month = month.toString();
var zdate = '';
var date = DT.getUTCDate();
if (date < 10) {
zdate = "0"+date.toString();
} else {
zdate = date.toString();
}
date = date.toString();
if (useday) {
datestr = datestr.replace('<date>', date);
datestr = datestr.replace('<zdate>', zdate);
} else {
datestr = datestr.replace('<date>', '');
datestr = datestr.replace('<zdate>', '');
}
if (usemonth) {
datestr = datestr.replace('<month>', month);
datestr = datestr.replace('<zmonth>', zmonth);
datestr = datestr.replace('<monthname>', CiteTB.getOption('months')[DT.getUTCMonth()]);
} else {
datestr = datestr.replace('<month>', '');
datestr = datestr.replace('<zmonth>', '');
datestr = datestr.replace('<monthname>', '');
}
datestr = datestr.replace('<year>', DT.getUTCFullYear().toString());
return datestr.replace(/^[ \/\-\,\.]*(.*?)[ \/\-\,\.]*$/g, "$1"); // Cleanup any dangling spaces or connectors that might result from omitting date/month
};
// Function called after the ref list is loaded, to actually set the contents of the named ref dialog
// Until the list is loaded, its just a "Loading" placeholder
CiteTB.setupNamedRefs = function () {
var names = [], i;
for( i=0; i<CiteTB.mainRefList.length; i++) {
if (!CiteTB.mainRefList[i].shorttag && CiteTB.mainRefList[i].refname) {
names.push(CiteTB.mainRefList[i]);
}
}
var stuff = $('<div>');
$('#citetoolbar-namedrefs').html( stuff );
if (names.length === 0) {
stuff.html(mw.usability.getMsg('cite-no-namedrefs'));
} else {
stuff.html(mw.usability.getMsg('cite-namedrefs-intro'));
var select = $('<select id="cite-namedref-select">');
select.append($('<option value="" />').text(mw.usability.getMsg('cite-named-refs-dropdown')));
for(i=0; i<names.length; i++) {
select.append($('<option />').text(names[i].refname));
}
stuff.after(select);
select.before('<br/>');
var prevlabel = $('<div id="cite-nref-preview-label" style="display:none;" />').html(mw.usability.getMsg('cite-raw-preview'));
select.after(prevlabel);
prevlabel.before("<br/><br/>");
prevlabel.after('<div id="cite-namedref-preview" style="padding:0.5em; font-size:110%" />');
var parselabel = $('<span id="cite-parsed-label" style="display:none;" />').html(mw.usability.getMsg('cite-parsed-label'));
$('#cite-namedref-preview').after(parselabel);
parselabel.after('<div id="cite-namedref-parsed" style="padding-bottom:0.5em; font-size:110%" />');
var link = $('<a href="#" id="cite-nref-parse" style="margin:0 1em 0 1em; display:none; color:darkblue" />');
link.html(mw.usability.getMsg('cite-form-parse'));
$('#cite-namedref-parsed').after(link);
$("#cite-namedref-select").on( 'change', CiteTB.namedRefSelectClick);
$('#cite-nref-parse').on( 'click', CiteTB.nrefParseClick);
}
};
// Function to get the errorcheck form HTML
CiteTB.setupErrorCheck = function () {
var form = $('<div id="cite-errorcheck-heading" />').html(mw.usability.getMsg('cite-errorcheck-heading'));
var ul = $("<ul id='cite-errcheck-list' />");
var test;
for (var t in CiteTB.ErrorChecks) {
test = CiteTB.ErrorChecks[t];
ul.append(test.getRow());
}
form.append(ul);
$('#citetoolbar-errorcheck').html(form);
};
// Callback function for parsed preview
CiteTB.fillNrefPreview = function (parsed) {
$('#cite-parsed-label').show();
$('#cite-namedref-parsed').html(parsed);
};
// Click handler for the named-ref parsed preview
CiteTB.nrefParseClick = function () {
var choice = $("#cite-namedref-select").val();
if (choice === '') {
$('#cite-parsed-label').hide();
$('#cite-namedref-parsed').text('');
return false;
}
$('#cite-nref-parse').hide();
for( var i=0; i<CiteTB.mainRefList.length; i++) {
if (!CiteTB.mainRefList[i].shorttag && CiteTB.mainRefList[i].refname == choice) {
CiteTB.parse(CiteTB.mainRefList[i].content, CiteTB.fillNrefPreview);
return false;
}
}
};
// Click handler for the named-ref dropdown
CiteTB.lastnamedrefchoice = '';
CiteTB.namedRefSelectClick = function () {
var choice = $("#cite-namedref-select").val();
if (CiteTB.lastnamedrefchoice == choice) {
return;
}
CiteTB.lastnamedrefchoice = choice;
$('#cite-parsed-label').hide();
$('#cite-namedref-parsed').text('');
if (choice === '') {
$('#cite-nref-preview-label').hide();
$('#cite-namedref-preview').text('');
$('#cite-nref-parse').hide();
return;
}
for (var i = 0; i < CiteTB.mainRefList.length; i++) {
if (!CiteTB.mainRefList[i].shorttag && CiteTB.mainRefList[i].refname == choice) {
$('#cite-nref-preview-label').show();
$('#cite-namedref-preview').text(CiteTB.mainRefList[i].content);
if (CiteTB.getOption('autoparse')) {
CiteTB.nrefParseClick();
} else {
$('#cite-nref-parse').show();
}
}
}
};
// callback function for parsed preview
CiteTB.fillTemplatePreview = function (text) {
var template = CiteTB.getOpenTemplate();
var div = $("#citetoolbar-"+CiteTB.escStr(template.shortform));
div.find('.cite-prev-parsed-label').show();
div.find('.cite-preview-parsed').html(text);
};
// Click handler for template parsed preview
CiteTB.prevParseClick = function () {
var ref = CiteTB.getRef(true, false);
var template = CiteTB.getOpenTemplate();
var div = $("#citetoolbar-"+CiteTB.escStr(template.shortform));
div.find('.cite-prev-parse').hide();
CiteTB.parse(ref, CiteTB.fillTemplatePreview);
};
// Show/hide the extra fields in the dialog box
CiteTB.showHideExtra = function () {
var template = CiteTB.getOpenTemplate();
var div = $("#citetoolbar-"+CiteTB.escStr(template.shortform));
var setting = div.find(".cite-form-status").val();
if ( setting === 'closed' ) {
div.find(".cite-form-status").val('open');
div.find('.cite-extra-fields').show(1, function () {
// jQuery adds "display:block", which screws things up
div.find('.cite-extra-fields').attr('style', 'width:100%; background-color:transparent;');
});
} else {
div.find(".cite-form-status").val('closed');
div.find('.cite-extra-fields').hide();
}
};
// Resets form fields and previews
CiteTB.resetForm = function () {
var template = CiteTB.getOpenTemplate();
var div = $("#citetoolbar-"+CiteTB.escStr(template.shortform));
div.html(template.getForm());
};
// STRING UTILITY FUNCTIONS
// Returns a string quoted as necessary for name/group attributes
CiteTB.getQuotedString = function (s) {
var sq = /\'/.test(s); // single quotes
var dq = /\"/.test(s); // double quotes
if (!sq && !dq) {
// Always quotes for non-latin alphabet
return '"'+s+'"';
} else if (!dq) {
// Can use double quotes
return '"'+s+'"';
} else if (!sq) {
// Can use single quotes
return "'"+s+"'";
} else {
// Has double and single quotes
s = s.replace(/\"/g, '\'');
return '"'+s+'"';
}
};
// Fix up strings for output - capitalize first char, replace underscores with spaces
CiteTB.fixStr = function (s) {
s = s.slice(0,1).toUpperCase() + s.slice(1);
s = s.replace('_',' ');
return s;
};
// Escape spaces and quotes for use in HTML classes/ids
CiteTB.escStr = function (s) {
return s.replace(' ', '-').replace("'", "\'").replace('"', '\"');
};
// MISC FUNCTIONS
// Determine which template form is open, and get the template object for it
CiteTB.getOpenTemplate = function () {
var dialogs = $(".ui-dialog-content.ui-widget-content:visible");
var templatename = $(dialogs[0]).find(".cite-template").val();
return CiteTB.Templates[templatename];
};
// Display the report for the error checks
CiteTB.displayErrors = function (errors) {
$('#cite-err-report').remove();
var table = $('<table id="cite-err-report" style="width:100%; border:1px solid #A9A9A9; background-color:#FFEFD5; padding:0.25em; margin-top:0.5em" />');
$('#editpage-copywarn').before(table);
var tr;
var tr1 = $('<tr style="width:100%" />');
var th1 = $('<th style="width:60%; font-size:110%" />').html(mw.usability.getMsg('cite-err-report-heading'));
var th2 = $('<th style="text-align:right; width:40%" />');
var im = $('<img />').attr('src', '//up.wiki.x.io/wikipedia/commons/thumb/5/55/Gtk-stop.svg/20px-Gtk-stop.svg.png');
im.attr('alt', mw.usability.getMsg('cite-err-report-close')).attr('title', mw.usability.getMsg('cite-err-report-close'));
var ad = $('<a id="cite-err-check-close" />').attr('href', '#');
ad.append(im);
th2.append(ad);
tr1.append(th1).append(th2);
table.append(tr1);
$('#cite-err-check-close').on('click', function () { $('#cite-err-report').remove(); });
if (errors.length === 0) {
tr = $('<tr style="width:100%;" />');
var td = $('<td style="text-align:center; margin:1.5px;" />').html(mw.usability.getMsg('cite-err-report-empty'));
tr.append(td);
table.append(tr);
return;
}
for (var e in errors) {
var err = errors[e];
tr = $('<tr style="width:100%;" />');
var td1 = $('<td style="border: 1px solid black; margin:1.5px; width:60%" />').html(err.err);
var td2 = $('<td style="border: 1px solid black; margin:1.5px; width:40%" />').html(mw.usability.getMsg(err.msg));
tr.append(td1).append(td2);
table.append(tr);
}
};
} // End of code loaded only on edit
// Note to self: this is static, only partially supported by the offical files, so updates
// are going to be borked from now on. if they fix it, switch back. otherwise, this seems to
// work splendedly, might even be worth rewriting some stuff now with the source,
// expand it, whatever... not sure how badly it can break things, but whatever, it works.
//noooope
/*CiteTB.getOpenTemplate = function () {
return "cite web";
};*/
$('head').one('reftoolbarbase', function () {
// http://en.wiki.x.io/wiki/Template:Cite_patent
new citeTemplate('cite patent', 'patent',
[ // Basic fields
{"field": "country"},
{"field": "number"},
{"field": "status"},
{"field": "title", "autofillprop":"title"},
{"field": "pubdate"},
{"field": "gdate"},
{"field": "fdate"},
{"field": "pridate"},
{"field": "inventor"},
{"field": "invent<N>", "autofillprop":"invent-incr", 'increment_group':'invent', 'increment_button':true},
{"field": "assign<N>", "autofillprop":"assign-incr", 'increment_group':'assign', 'increment_button':true},
{"field": "class"},
{"field": "ref", "tooltip":"cite-ref-tooltip"}
],
[ // Expanded fields
// N/A
]);
// http://en.wiki.x.io/wiki/Template:Cite_report
new citeTemplate('cite report', 'report',
[ // Basic fields
{"field": "last<N>", "autofillprop":"last-incr", 'increment_group':'author'},
{"field": "first<N>", "autofillprop":"first-incr", 'increment_group':'author', 'increment_button':true},
{"field": "title", "autofillprop":"title"},
{"field": "journal", "autofillprop":"journal"}, // work
{"field": "date", "autofillprop":"date"},
{"field": "edition", "autofillprop":"edition"},
{"field": "series"},
{"field": "volume", "autofillprop":"volume"},
{"field": "issue", "autofillprop":"issue"}, // in conjunction with work
{"field": "page", "tooltip":"cite-page-tooltip"},
{"field": "pages", "autofillprop":"pages", "tooltip":"cite-pages-tooltip"},
{"field": "publisher", "autofillprop":"publisher"},
{"field": "doi", "autofillid":"doi", "autofillprop":"doi"},
{"field": "url", "autofillid":"url"},
{"field": "accessdate"},
{"field": "ref", "tooltip":"cite-ref-tooltip"},
],
[ // Expanded fields
{"field": "author<N>", 'increment_group':'author_alt', 'increment_button':true},
{"field": "authorlink<N>", "tooltip":"cite-authorlink-tooltip", 'increment_group':'authorlink', 'increment_button':true},
{"field": "editor<N>-last", "increment_group":"editor"},
{"field": "editor<N>-first", "increment_group":"editor", "increment_button":true},
{"field": "editor<N>-link", 'increment_group':'editorlink', 'increment_button':true},
{"field": "archiveurl"},
{"field": "archivedate"},
{"field": "at", "tooltip":"cite-at-tooltip"},
{"field": "trans-title"},
{"field": "location"},
{"field": "language", "autofillprop":"language"},
{"field": "format"},
{"field": "isbn"},
{"field": "issn", "autofillprop":"issn"},
{"field": "oclc"},
{"field": "ol"},
{"field": "osti"},
{"field": "jstor"},
{"field": "lccn"},
{"field": "rfc"},
{"field": "id"},
{"field": "quote"},
{"field": "postscript", "tooltip":"cite-postscript-tooltip"}
]);
});
// note: how about formatting? auto-insertion? easier insertion?
// what about fixing the author listings?
// main thing is adding help items - reftoolbar SUCKS at that as-is...
// http://en.wiki.x.io/wiki/MediaWiki:RefToolbarConfig.js
// http://en.wiki.x.io/wiki/Wikipedia:RefToolbar/2.0
// http://en.wiki.x.io/wiki/Wikipedia_talk:RefToolbar
// TODO (maybe):
// http://en.wiki.x.io/wiki/Template:Cite_thesis
// http://en.wiki.x.io/wiki/Template:Cite_techreport
// http://en.wiki.x.io/wiki/Template:Cite_speech
// http://en.wiki.x.io/wiki/Template:Cite_sign
// http://en.wiki.x.io/wiki/Template:Cite_serial
// http://en.wiki.x.io/wiki/Template:Cite_report
// http://en.wiki.x.io/wiki/Template:Cite_press_release [!!]
// http://en.wiki.x.io/wiki/Template:Cite_podcast
// http://en.wiki.x.io/wiki/Template:Cite_newsgroup
// http://en.wiki.x.io/wiki/Template:Cite_map
// http://en.wiki.x.io/wiki/Template:Cite_mailing_list
// http://en.wiki.x.io/wiki/Template:Cite_interview
// http://en.wiki.x.io/wiki/Template:Cite_episode
// http://en.wiki.x.io/wiki/Template:Cite_encyclopedia
// http://en.wiki.x.io/wiki/Template:Cite_DVD_notes
// http://en.wiki.x.io/wiki/Template:Cite_conference
// http://en.wiki.x.io/wiki/Template:Cite_AV_media_notes
// http://en.wiki.x.io/wiki/Template:Cite_AV_media