/*
* File: el-search.js
* Author: MastCell
* Language: Javascript
* Dependencies:
* jQuery (bundled with MediaWiki)
* api.js (by Conrad Irwin; original at http://en.wiktionary.org/wiki/User:Conrad.Irwin/Api.js)
* Other credits:
* Leverages code from a variety of sources, including ^demon's old CSD-rationale script
* =================================================================================================
* Purpose: This script adds a drop-down selection box to restrict external-link searches to
* a specific namespace. Often, one is only interested in external links in
* articlespace, so it's useful to be able to filter these. The MediaWiki API
* has a handy option to restrict external-link queries by namespace, but
* for whatever reason, it doesn't have an associated UI gadget at
* Special:LinkSearch. This script is intended to fill that gap.
* =================================================================================================
* Under the hood:
* Pretty straightforward. The script:
* 1. Adds a namespace selection box to Special:LinkSearch.
* 2. Intercepts the "Search" button
* 3. Reroutes it to the API via AJAX
* 4. Throws the results into human-readable form.
* Note that the script runs on the client side, so you won't be able to bookmark results.
* =================================================================================================
* Usage:
* To use this gadget, go to your vector.js file (or, if you use a skin besides vector, go to
* the appropriate .js file). For me, it's at User:MastCell/vector.js.
*
* Once you're in your vector.js file, simply add the following line:
* importScript('User:MastCell/el-search.js');
* ... then save and reload. After that, it should just work. You can go to
* Special:LinkSearch and try it out. You should see a drop-down box next to the
* "Search" button, with a list of namespaces.
*/
// Include local copy of api.js, which facilitates AJAX queries to the MediaWiki API
// The original library is at http://en.wiktionary.org/wiki/User:Conrad.Irwin/Api.js
importScript('User:MastCell/api.js');
/*
* Function: fillSelect()
* Parameters: None
* Return value: Returns a Select object filled in with Wikipedia's namespaces
* and corresponding numerical values
* ==================================================================================
* This is a helper function to fill in a drop-down box. The function creates a "select"
* input, fills it with the relevant namespaces and corresponding numerical values,
* and then returns the drop-down box, which can then be inserted into the DOM.
*
* The drop-down box is assigned the id "nsoptions", so that it can be
* located easily later on.
*/
function fillSelect() {
var namespaceList = [ {
"value" : "-99",
"display" : "All namespaces"
}, {
"value" : "0",
"display" : "Article"
}, {
"value" : "1",
"display" : "Talk"
}, {
"value" : "2",
"display" : "User"
}, {
"value" : "3",
"display" : "User Talk"
}, {
"value" : "4",
"display" : "Wikipedia"
}, {
"value" : "5",
"display" : "Wikipedia Talk"
}, {
"value" : "6",
"display" : "Image"
}, {
"value" : "7",
"display" : "Image Talk"
}, {
"value" : "8",
"display" : "MediaWiki"
}, {
"value" : "9",
"display" : "MediaWiki Talk"
}, {
"value" : "10",
"display" : "Template"
}, {
"value" : "11",
"display" : "Template Talk"
}, {
"value" : "12",
"display" : "Help"
}, {
"value" : "13",
"display" : "Help Talk"
}, {
"value" : "14",
"display" : "Category"
}, {
"value" : "15",
"display" : "Category Talk"
} ];
var sel = document.createElement("select");
sel.disabled = false;
for (var i = 0; i < namespaceList.length; i++) {
var opt = new Option(namespaceList[i].display, namespaceList[i].value);
// catches stupid IE error
if (opt.innerHTML != namespaceList[i].display) {
opt.innerHTML = namespaceList[i].display;
}
sel.appendChild(opt);
}
sel.name = "nsoptions";
sel.id = "nsoptions";
sel.style.marginLeft = "10px";
return sel;
}
/*
* Function: handleFormSubmission()
* Params: None.
* Returns: Nothing.
* ================================================================================================
* This function is called when the user clicks on the "Search" button on the HTML form. It calls the
* MediaWiki API, using api.js, and then returns. The result is sent back asynchronously and dispatched
* to processELresults() for handling.
*
* This function sets the UI to a "busy" state; it disables the Search button (to prevent multiple
* simultaneous queries) and shows a spinner while waiting for the results. Note that the AJAX
* callback function (in this case, processELresults()) is responsible for restoring the UI
* to its functional state once the query is complete.
*/
function handleFormSubmission() {
// Set the "busy" UI...
$("#mw-linksearch-form :submit").attr("value", "Searching...");
$("#mw-linksearch-form :submit").attr("disabled", "true");
if ($("#progress-spinner").length > 0) {
// Show spinner
$("#progress-spinner").show();
} else {
// Create and show spinner
$("#mw-linksearch-form :submit").after('<span id="progress-spinner"><img src="http://upload.wikimedia.org/wikipedia/commons/4/42/Loading.gif" alt="Loading..."></span>');
}
// AJAX call to retrieve results...
var targetLink = $("#target").val();
var localAPI = JsMwApi();
var namespaceOpt = $("#nsoptions").val();
if (namespaceOpt == -99) {
// Search all namespaces
localAPI({action: "query", list: "exturlusage", euquery: targetLink, eulimit: "1000"}, processELresults);
} else {
// Search only the restricted namespace
localAPI({action: "query", list: "exturlusage", euquery: targetLink, eulimit: "1000", eunamespace: namespaceOpt}, processELresults);
}
}
/*
* Function: processELresults()
* Params: result (a query object returned by api.js, containing the results of the user request)
* Returns: Nothing
* ====================================================================================================================================
* This function is called when the AJAX query returns with results from the MediaWiki database. It processes the results and
* puts them in a user-friendly list, patterned after the result view from Special:LinkSearch.
*
* Note that this function is responsible for restoring the functional UI (from the "busy" state) once it is completed.
*/
function processELresults(result) {
// Remove old list, if any
if ($("#el-result-list").length > 0) {
$("#el-result-list").remove();
}
if (result.query.exturlusage.length == 0) {
// No links were found
var noneFound = '<div id="el-result-list">No links to ';
noneFound += $("#target").val();
noneFound += " were found in the given namespace.</div>";
$("#mw-linksearch-form").after(noneFound);
} else {
// Create a result list
$("#mw-linksearch-form").after('<ol id="el-result-list"></ol>');
// Populate the result list
for (var i = 0; i < result.query.exturlusage.length; i++) {
var listItem = '<li><a href="';
listItem += result.query.exturlusage[i].url;
listItem += '" class="external">';
listItem += result.query.exturlusage[i].url;
listItem += '</a> is linked from <a href="';
// Make sure the wikilinks work from the secure server
if (document.domain == "secure.wikimedia.org") {
listItem += '/wikipedia/en/wiki/';
} else {
listItem += '/wiki/';
}
listItem += encodeURI(result.query.exturlusage[i].title);
listItem += '" title="';
listItem += result.query.exturlusage[i].title;
listItem += '">';
listItem += result.query.exturlusage[i].title;
listItem += "</a></li>";
$("#el-result-list").append(listItem);
}
}
// Clear the "busy" UI...
$("#mw-linksearch-form :submit").attr("value", "Search");
$("#mw-linksearch-form :submit").removeAttr("disabled");
$("#progress-spinner").hide();
}
// Adds a hook to check if we're on Special:LinkSearch. If so,
// we create and place the drop-down box. Then we intercept clicks
// on the "Search" button and re-route them to our handler.
addOnloadHook(function() {
if (mw.config.get('wgPageName') == "Special:LinkSearch") {
var sel = fillSelect();
$("#target").after(sel);
$("#mw-linksearch-form").submit(function(event) {
event.preventDefault();
handleFormSubmission();
return false;
});
}
});