User:MastCell/el-search.js

/*

* 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('Loading...');

}

// 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 = '

No links to ';

noneFound += $("#target").val();

noneFound += " were found in the given namespace.

";

$("#mw-linksearch-form").after(noneFound);

} else {

// Create a result list

$("#mw-linksearch-form").after('

    ');

    // Populate the result list

    for (var i = 0; i < result.query.exturlusage.length; i++) {

    var listItem = '

  1. ';

    listItem += result.query.exturlusage[i].url;

    listItem += ' is linked from

    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 += "

  2. ";

    $("#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;

    });

    }

    });