Vés al contingut

MediaWiki:Gadget-SegregaRefs.js

De la Viquipèdia, l'enciclopèdia lliure

Nota: Després de desar, heu de netejar la memòria cau del navegador per veure els canvis. En la majoria de navegadors amb Windows o Linux, premeu Ctrl+F5 o bé premeu Shift i cliqueu el botó "Actualitza" (Ctrl i "Actualitza" amb Internet Explorer). Vegeu més informació i instruccions per a cada navegador a Viquipèdia:Neteja de la memòria cau.

//<pre><nowiki>
 
/*  segregareferencies.js: Un script per simplificar l'edició d'articles
    amb moltes referències internes amb l'extensió Cite.php del MediaWiki.
 
    Copyright (c) 2010, PleaseStand, traducció per Joancreus

    Podeu trobar l'original a [[:en:User:PleaseStand/segregate-refs.js]].
    L'autor n'és PleaseStand, i l'ha llicenciat de la següent manera:
 
    This software is licensed under these licenses:
    1.  Creative Commons Attribution-Share Alike 3.0 Unported License
        (see <http://creativecommons.org/licenses/by-sa/3.0/> for the text)
    2.  GNU Free Documentation License, any published version.
        (see <http://www.gnu.org/copyleft/fdl.html> for the text)
    3.  Permission to use, copy, modify, and/or distribute this software for any
        purpose with or without fee is hereby granted, provided that the above
        copyright notice and this permission notice appear in all copies.
 
        THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
    You may select the license(s) of your choice if you wish to copy, modify, or
    distribute this software. If you modify the software and do not wish to
    license your changes under one or more of the licenses, please remove
    the license(s) from the list above.
*/
 
/*global window, SegregateRefsJsL10n,
SegregateRefsJsEmptyRefsWarningGiven, SegregateRefsJsAllowConversion,
SegregateRefsJsCompleteSearch, wikEdUseWikEd, WikEdUpdateTextarea,
WikEdUpdateFrame*/
 
// Translate the right-hand side of these if necessary.
// Put translations in a separate file, changing the first line to:
// var SegregateRefsJsL10n = {
var SegregateRefsJsMsgs = {
  version: 1.11,
  buttonText: "Segrega referències per editar",
  buttonStyle: "background: #dfd;",
  buttonConvertText: "Migra article a Referències Definides per Llistes",
  buttonConvertStyle: "background: #fdd;",
  autoWord: "Auto",
  emptyRefsWarning: "IMPORTANT: Aquesta pàgina conté una o més " +
    "notes de peu amb nom, la primera aparició de la qual no té " +
    "contingut i no és una bona pràctica. Tot i que aquest programa no fa malbé " +
    "aquestes referències hauries de saber que aquest programa NOMÉS " +
    "COMPROVA LA PRIMERA ETIQUETA. Qualsevol canvi a la nota buida substituirà " +
    "la nota sencera i deixarà el text antic amagat.\n\n" +
    "ABANS de concloure, a partir de la llista de notes, que una referència està buida, " +
    "si us plau comprova manualment totes les referències amb al mateix nom " +
    "per mirar els continguts.\n\nT'has adonat d'aquesta limitació del programa? NO CLIQUIS "+
    "D'ACORD FINS QUE HAGIS LLEGIT LA INFORMACIÓ DE MÉS AMUNT.",
  convertRefsWarning: "AVÍS: Necessites consens per migrar un article a un format de " +
    "referències definides per llista ABANS de fer-ho.\n\nClica " +
    "Cancel·la si no s'ha establert consens sobre això. " +
    "Si el consens és positiu, clica D'ACORD per fer-ho.",
  groupPrompt: "Si us plau escriu el nom d'un grup (com apareix al viquitext, " +
    "incloent possibles cometes). Deixa-ho en blanc si no n'estàs segur.",
  refsHeader: "Referències dins del text",
  convertHeader: "Llista de referències generada",
  refsCommentIncomplete: "<!-- Aquesta llista de notes podria ser incompleta. " +
    "No s'ha d'utilitzar per conversió. -->\n\n",
  refsCommentComplete: "<!-- Convertit a format de Referències Definides per Llista\n" +
    "     emprant el [[Usuari:Joancreus/segregareferencies.js|segregador de referències]] -->\n\n",
  convertSummary: "S'han convertit les notes de peu a format definit per llista (emprant " +
    "emprant el [[Usuari:Joancreus/segregareferencies.js|segregador de referències]])",
  convertFurther: "Aquest programa ha fet la major part de la feina. Tanmateix, encara " +
    "has de fer el següent:\n\n* Inserir la llista de referències a la nova caixa de text " +
    "al lloc adient a dins del text.\n* Si estàs convertint un grup " +
    "especial, pots treure opcionalment el grup d'atributs.\n* Reemplaça tots els " +
    "noms autogenerats amb noms manuals.\n\nPots fer tot això amb l'eina " +
    "Cerca/Reemplaça de molts editors de text, o bé amb els viquiestris. " +
    "Posteriorment, torna a col·locar el text a la caixa d'edició i desa la pàgina.",
  integrateWarning: "Les referències llistades més avall no es troben al text. Si vols " +
    "continuar, s'eliminaran permanentment. N'estàs segur?\n\nReferències no utilitzades: "
};
 
// Begin encapsulation (prevent interference with other scripts)
(function(){

// "Semi-global" variables (function-scoped variables private to this script)
var editForm, refsDiv, refsH2, mainTextbox, refsTextbox, randPrefix, messages,
    refsButton, convertButton, complete, unloadHandlerRegistered = false;

// Define a (very important) function that is better than hasOwnProperty
function has(obj, key) {
    return Object.hasOwnProperty.call(obj, key);
}

// Setting a slice of a string
function setSlice(t, replacement, indexFrom, indexTo) {
    if(typeof indexTo == "undefined") {
        return t.slice(0, indexFrom) + replacement;
    }
    return t.slice(0, indexFrom) + replacement + t.slice(indexTo);
}

// Unquoting from an HTML-quoted form
function htmlUnquote(t) {
    // Let's use the browser's functionality for the hard work,
    // since MediaWiki/PHP supports many different HTML entities.
    // (Note: innerHTML is not W3C-standard)
    var d = document.createElement("div");
    d.innerHTML = "<input value=" + t + "></input>";
    return d.firstChild.value;
}

// Quoting using HTML quotes. Chooses single quotes versus
// double quotes depending on which is shorter.
function htmlQuote(t) {
    // Escape ampersands
    var s = t.replace(/\&/g, "&amp;");
    // Try both kinds of quotes
    var sQ = "'" + s.replace(/'/g, "&#39;") + "'",
        dQ = '"' + s.replace(/"/g, "&quot;") + '"';
    // Choose the shorter, preferring double quotes if equal in length
    return (sQ.length < dQ.length ? sQ : dQ);
}

// OBJECTS

// RefScanner: Use for identifying ref tags in text. (No nested refs please)
function RefScanner(argWikiText) {
    this.wikiText = argWikiText;
    // The tags listed below other than "ref" are there for an obvious reason.
    // NB: "references" is here to prevent out-of-line refs from being returned.
    this.refScanRegex = /(?:<!--[\s\S]*?-->|<(nowiki|source|references|ref)(?:|\s(?:[^"']|"[^"]*"|'[^']*')*?)(?:\/>|(?:>[\s\S]*?<\/\1(?:|\s[^>]*)>)))/gi;
}
RefScanner.prototype = {
    // Returns the next ref found in the text
    getRef: function getRef() {
        var results;
        do {
            results = this.refScanRegex.exec(this.wikiText);
            if(!results) {
                return null;
            }
            if(typeof results[1] == "undefined") {
                results = [0,0];
            }
        } while(results[1].toString().toLowerCase() != "ref");
        return results[0];
    }
};

// RefParser: Use for extracting attributes from ref tags
function RefParser(argWikiText) {
   this.wikiText = argWikiText;
   // The below regex is mostly a copy of the refScanRegex above, except that
   // the whole string must be a ref, and no more, and two parts are extracted:
   // $1=attributes, $2=remaining portion of ref
   var refParseRegex = /^<ref(|\s(?:[^"']|"[^"]*"|'[^']*')*?)(\/>|(?:>[\s\S]*?<\/ref(?:|\s[^>]*)>))$/i;
   this.parsedRef = refParseRegex.exec(this.wikiText);
   if(!this.parsedRef) {
    throw new Error("invalid ref");
   }
}
RefParser.prototype = {
    getAttributes: function getAttributes() {
        // In this regex, we need to extract a single name-value pair at a time.
        var attParseRegex = /\s([^\s=>]+)\s*=\s*("[^"]*"|'[^']*'|[^\s"']*)/g;
        if(!this.parsedRef) {
            return null;
        }
        var attributes = {}, results;
        while((results = attParseRegex.exec(this.parsedRef[1]))) {
            attributes[results[1].toLowerCase()] = htmlUnquote(results[2]);
        }
        return attributes;
    }
};

// FUNCTIONS

// segregateRefs: Use for segregating refs from content.
// If completeSearch == true, the function looks in all occurrences for ref
// contents. If completeSearch == false, the function only checks the first.
// group is the reference group to limit the operation to. The empty string
// refers to all ungrouped refs. caseCues is whether or not to use
// capitalization to designate a preferred ref code location.
function segregateRefs(argWikiText, completeSearch, group, caseCues) {
    
    // Create a random prefix for autogenerated ref names.
    // in theory this has a 1/1296 probability of collision - extremely low
    var prefixChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
        randNo = Math.floor(Math.random() *
        (prefixChars.length * prefixChars.length));
    randPrefix = messages.autoWord + prefixChars.charAt(Math.floor(randNo /
        prefixChars.length)) + prefixChars.charAt(randNo % prefixChars.length) +
        "-";
    
    // Create the beginning of the code for a preferred ref location
    var refPreferred = caseCues ? "<REF " : "<ref ";
    
    // Variables for the main code
    var scanner = new RefScanner(argWikiText), unnamedRefs = 0, refNames = {},
        ref, refStored, parser, attributes, refName, refLong, refShort,
        refCodes = [], refEmpty, emptyRefsWarningGiven = false, refGroup;
    
    // Disable the empty refs warning (see below) if the user has disabled it
    if(typeof SegregateRefsJsEmptyRefsWarningGiven != "undefined" &&
    SegregateRefsJsEmptyRefsWarningGiven) {
        emptyRefsWarningGiven = true;
    }
    
    while((ref = scanner.getRef())) {
        parser = new RefParser(ref);
        attributes = parser.getAttributes();
        
        // First make sure that the ref is in the right group.
        refGroup = has(attributes, "group") ? attributes.group : "";
        if(group != refGroup) {
            continue;
        }
        
        // Does the ref have a name?
        // (Note: No matter how incorrect it seems, the empty string is
        // an acceptable ref name to the MediaWiki parser, as verified by
        // informal testing.)
        if(!has(attributes, "name")) {
            // Bad: it doesn't have one - create a name for it
            refStored = false;
            refEmpty = false;
            refName = randPrefix + (++unnamedRefs).toString(10);
            // Change the corresponding ref code
            refLong = "<ref name=" + htmlQuote(refName) +
                parser.parsedRef[1] + parser.parsedRef[2];
        } else {
            // Good: it has a name.
            refName = attributes.name;
            refLong = ref;
            // Check if the ref name has already been seen.
            refStored = has(refNames, refName);
            // Check if the ref has no contents.
            refEmpty = (parser.parsedRef[2].slice(-2) == "/>") ||
                (parser.parsedRef[2].slice(0, 3) == "></");
            // Since this script, when not set in complete search mode, checks
            // only the first occurrence of a ref for contents, inform the user
            // of this limitation if it may pose a problem.
            if(!completeSearch && !emptyRefsWarningGiven && !refStored) {
                if(refEmpty) {
                    if(!window.confirm(messages.emptyRefsWarning)) {
                        return false;
                    }
                    emptyRefsWarningGiven = true;
                }
            }
        }
        
        // Is the ref's name unique?
        if(!refStored) {
            // Unique: add it to the list of refs
            refNames[refName] = {
                code: refCodes.length,
                empty: refEmpty
            };
            refCodes[refNames[refName].code] = refLong;
            
            // Make a short code for the ref
            if(refEmpty) {
                refShort = refLong;
            } else if(!refGroup.length) {
                refShort = refPreferred + "name=" +
                    htmlQuote(refName) + "/>";
            } else {
                refShort = refPreferred + "name=" + htmlQuote(refName) +
                    " " + "group=" + htmlQuote(refGroup) + "/>";
            }
        // Otherwise, is the current longcode not empty?
        // (only when in complete search mode, and when another non-empty,
        // same-named ref has not been encountered)
        } else if (completeSearch && !refEmpty && refNames[refName].empty) {
            // Not empty: fill in the long code and make a short code
            refCodes[refNames[refName].code] = refLong;
            refNames[refName].empty = false;
            if(!refGroup.length) {
                refShort = refPreferred + "name=" +
                    htmlQuote(refName) + "/>";
            } else {
                refShort = refPreferred + "name=" + htmlQuote(refName) +
                    " " + "group=" + htmlQuote(refGroup) + "/>";
            }
        } else {
            // Leave the ref as-is in the original wikitext
            // (except if caseCues apply)
            if(caseCues) {
                refShort = refLong.replace(/^<REF/, "<ref");
            } else {
                refShort = refLong;
            }
        }
        // Replace the long code with the short code
        scanner.wikiText = setSlice(scanner.wikiText, refShort,
            scanner.refScanRegex.lastIndex - ref.length,
            scanner.refScanRegex.lastIndex);
        // Update lastIndex accordingly
        scanner.refScanRegex.lastIndex += refShort.length - ref.length;
    }
    return {
        wikiText: scanner.wikiText,
        refCodes: refCodes,
        randPrefix: randPrefix
        };
}

// integrateRefs: Use for inserting ref contents back into text
function integrateRefs(argWikiText, argRefText, randPrefix, caseCues) {
    
    // A function to remove an autogenerated ref name (if possible)
    function cleanRefLong(dirtyRef) {
        var cleanRegex = /^<(ref) name=(?:"[^"]*"|'[^']*'|[^\s"']*)/i;
        return dirtyRef.replace(cleanRegex, "<$1");
    }
    
    // Variables for the main code
    var scanner, ref, parser, attributes, refCodes = {}, usageFreq = {},
        preferredRef = {}, refLong;
    
    // First, we build an associative array of all the ref codes
    // that we might need to put back into the text.
    
    // NOTE: JavaScript does not actually offer real associative array
    // functionality, so we emulate it using objects and the has() function
    // we defined earlier that is used to verify a property's existence.
    scanner = new RefScanner(argRefText);
    while((ref = scanner.getRef())) {
        parser = new RefParser(ref);
        attributes = parser.getAttributes();
        if(has(attributes, "name")) {
            // Only use the first ref with each name
            if(!refCodes.hasOwnProperty(attributes.name)) {
                refCodes[attributes.name] = ref;   
            }
        }
    }
    
    // Next, we build an associative array that holds the usage frequency
    // of every ref name used in text, and whether there is a preferred ref,
    // if caseCues are selected.
    scanner = new RefScanner(argWikiText);
    while((ref = scanner.getRef())) {
        parser = new RefParser(ref);
        attributes = parser.getAttributes();
        if(has(attributes, "name")) {
            if(!has(usageFreq, attributes.name)) {
                // We found a new name
                usageFreq[attributes.name] = 1;
            } else {
                // We already found this name
                usageFreq[attributes.name]++;
            }
            if(caseCues) {
                if(ref.slice(0, 4) == "<REF") {
                    preferredRef[attributes.name] = true;
                }
            }
        }
    }
    
    // Finally, we go through the text again and this time we insert the
    // ref codes where we need to, but only in the first place
    // a ref name appears (or the first preferred location).
    scanner = new RefScanner(argWikiText);
    while((ref = scanner.getRef())) {
        parser = new RefParser(ref);
        attributes = parser.getAttributes();
        if(has(attributes, "name")) {
            // Is this name on the replacement list?
            if(has(refCodes, attributes.name)) {
                
                // If we are using caseCues, and another location is
                // preferred, skip to the next ref.
                if(caseCues && has(preferredRef, attributes.name) &&
                ref.slice(0, 4) != "<REF") {
                    continue;
                }
                
                // Is this name an autogenerated name?
                if(attributes.name.slice(0, randPrefix.length) == randPrefix) {
                    // Yes: is the name used multiple times?
                    if(usageFreq[attributes.name] > 1) {
                        // Multiple: the replacement code should be the same
                        // as that stored in the ref textbox.
                        refLong = refCodes[attributes.name];
                    } else {
                        // Single: replacement code must not include the name,
                        // at least not if the citation was untouched.
                        // (We don't want to add unnecessary autonames)
                        refLong = cleanRefLong(refCodes[attributes.name]);
                    }
                } else {
                    // No: the replacement code should be the same
                    // as that stored in the ref textbox.
                    // (We want to preserve all human-generated names)
                    refLong = refCodes[attributes.name];
                }
                
                // Replace the short code with the long code
                scanner.wikiText = setSlice(scanner.wikiText, refLong,
                    scanner.refScanRegex.lastIndex - ref.length,
                    scanner.refScanRegex.lastIndex);
                // Update lastIndex accordingly
                scanner.refScanRegex.lastIndex += refLong.length - ref.length;
                
                // Delete the name from the replacement list
                delete refCodes[attributes.name];
            }
        }
    }
    // Return both the combined output and the ref codes that were not used.
    return {wikiText: scanner.wikiText, unusedRefs: refCodes};
}

// Clears the undo history of a textarea by removing it
// from the DOM and then inserting it again.
function clearUndoHistory(ta) {
    var pn = ta.parentNode, ns = ta.nextSibling;
    pn.insertBefore(pn.removeChild(ta), ns);
}

function unloadHandler(evt) {
    // Local variables
    var result, refName, unusedRefNamesQuoted = [];
    
    // wikEd compatibility (frame -> textarea)
    if(typeof wikEdUseWikEd != "undefined" && wikEdUseWikEd) {
        WikEdUpdateTextarea();
    }
    
    // Do the actual integration work
    result = integrateRefs(mainTextbox.value, refsTextbox.value,
        randPrefix, complete);
    
    
    // Find all unused ref names
    for(refName in result.unusedRefs) {
        if(has(result.unusedRefs, refName)) {
            unusedRefNamesQuoted.push(htmlQuote(refName));
        }
    }
    // If any refs are unused, warn and allow the user to cancel;
    // we do not do this on unload because it is not really possible.
    if(evt.type == "submit" && unusedRefNamesQuoted.length) {
        if(!window.confirm(messages.integrateWarning +
        unusedRefNamesQuoted.join(", "))) {
            // Don't submit form
            evt.preventDefault();
            return false;
        }
    }
    
    // Otherwise, update the textbox.
    mainTextbox.value = result.wikiText;
    
    // wikEd compatibility (textarea -> frame)
    if(typeof wikEdUseWikEd != "undefined" && wikEdUseWikEd) {
        WikEdUpdateFrame();
    }
    
    // Deactivate this event handler
    window.removeEventListener("submit", unloadHandler, false);
    window.removeEventListener("unload", unloadHandler, false);
    unloadHandlerRegistered = false;
    
    // We can delete the header and refs textbox now
    refsDiv.removeChild(refsH2);
    refsDiv.removeChild(refsTextbox);
    
    return true;
}

function refsButtonHandler() { // Called when script activated by button click
    
    // Both buttons should disappear
    if(convertButton.parentNode){
        convertButton.parentNode.removeChild(convertButton);   
    }
    if(refsButton.parentNode) {
        refsButton.parentNode.removeChild(refsButton);
    }
    
    // Allow for disabling usage of the complete search mode
    // when segregating refs for editing.
    if(typeof SegregateRefsJsCompleteSearch != "undefined" &&
    !SegregateRefsJsCompleteSearch) {
        complete = false;
    } else {
        complete = true;
    }
    
    // wikEd compatibility (frame -> textarea)
    if(typeof wikEdUseWikEd != "undefined" && wikEdUseWikEd) {
        WikEdUpdateTextarea();
    }
    
    // Do the actual segregation work and save the random prefix
    var segFormat = segregateRefs(mainTextbox.value, complete, "", complete);
    if(!segFormat) {
        return false;
    }
    randPrefix = segFormat.randPrefix;
    
    // Update the textbox
    mainTextbox.value = segFormat.wikiText;
    clearUndoHistory(mainTextbox);
    
    // wikEd compatibility (textarea -> frame)
    if(typeof wikEdUseWikEd != "undefined" && wikEdUseWikEd) {
        WikEdUpdateFrame();
    }
    
    // Inline refs header
    refsH2 = document.createElement("h2");
    refsH2.appendChild(document.createTextNode(messages.refsHeader));
    
    refsH2.style.borderColor = "silver";
    refsH2.style.borderStyle = "solid";
    refsH2.style.borderWidth = "1px 0";
    refsH2.style.fontSize = "100%";
    refsH2.style.fontWeight = "100%";
    refsH2.style.lineHeight = "normal";
    refsH2.style.margin = "0";
    refsH2.style.padding = "0.5em 0 0";
    refsH2.style.textAlign = "center";
    
    // Inline refs textbox
    refsTextbox = document.createElement("textarea");
    refsTextbox.id = "PsRefsTextbox";
    if(!complete) {
        refsTextbox.value = messages.refsCommentIncomplete +
            segFormat.refCodes.join("\n\n");
    } else {
        refsTextbox.value = segFormat.refCodes.join("\n\n");
    }
    refsTextbox.rows = Math.floor(mainTextbox.rows / 2);
    refsTextbox.cols = mainTextbox.cols;
    
    refsTextbox.style.border = "none";
    refsTextbox.style.lineHeight = "1.5em";
    refsTextbox.style.margin = "0";
    refsTextbox.style.resize = "vertical";
    refsTextbox.style.width = "100%";

    // Add to document
    refsDiv.appendChild(refsH2);
    refsDiv.appendChild(refsTextbox);
    
    // Set up the submit handler (to integrate refs when done editing)
    window.addEventListener("submit", unloadHandler, false);
    window.addEventListener("unload", unloadHandler, false);
    unloadHandlerRegistered = true;
    
    // Don't submit form
    return false;
}

function convertButtonHandler() { // Called when script activated by button click
    // Display warning
    if(!window.confirm(messages.convertRefsWarning)) {
        return false;
    }
    
    // Which group?
    var group = window.prompt(messages.groupPrompt, "");
    if(group === null) {
        return false;
    }
    group = htmlUnquote(group);
    
    // The first button should disappear
    if(refsButton.parentNode) {
        refsButton.parentNode.removeChild(refsButton);
    }
    
    // Do the actual segregation work and save the random prefix
    var segFormat = segregateRefs(mainTextbox.value, true, group, false);
    if(!segFormat) {
        return false;
    }
    randPrefix = segFormat.randPrefix;
    
    // wikEd compatibility (frame -> textarea)
    if(typeof wikEdUseWikEd != "undefined" && wikEdUseWikEd) {
        WikEdUpdateTextarea();
    }
    
    // Update the textbox
    mainTextbox.value = segFormat.wikiText;
    clearUndoHistory(mainTextbox);
    
    // wikEd compatibility (textarea -> frame)
    if(typeof wikEdUseWikEd != "undefined" && wikEdUseWikEd) {
        WikEdUpdateFrame();
    }
    
    // Inline refs header
    refsH2 = document.createElement("h2");
    refsH2.appendChild(document.createTextNode(messages.convertHeader));
    
    refsH2.style.borderColor = "silver";
    refsH2.style.borderStyle = "solid";
    refsH2.style.borderWidth = "1px 0";
    refsH2.style.fontSize = "100%";
    refsH2.style.fontWeight = "100%";
    refsH2.style.lineHeight = "normal";
    refsH2.style.margin = "0";
    refsH2.style.padding = "0.5em 0 0";
    refsH2.style.textAlign = "center";
    
    // Inline refs textbox
    if(!refsTextbox) {
        // Does not exist; creating
        refsTextbox = document.createElement("textarea");
        refsTextbox.id = "PsRefsTextbox";
        refsTextbox.value = messages.refsCommentComplete +
            segFormat.refCodes.join("\n");
        refsTextbox.rows = Math.floor(mainTextbox.rows / 2);
        refsTextbox.cols = mainTextbox.cols;

        refsTextbox.style.border = "none";
        refsTextbox.style.lineHeight = "1.5em";
        refsTextbox.style.margin = "0";
        refsTextbox.style.resize = "vertical";
        refsTextbox.style.width = "100%";
        
        // Add to document
        refsDiv.appendChild(refsH2);
        refsDiv.appendChild(refsTextbox);
    } else {
        // Already exists
        refsTextbox.value = messages.refsCommentComplete +
            segFormat.refCodes.join("\n");
    }
    
    // Set a default edit summary.
    document.getElementById("wpSummary").value = messages.convertSummary;
    
    // Show the further instructions.
    window.alert(messages.convertFurther);
    
    // Don't submit form
    return false;
}

function getEditboxContents() { // ajaxPreview compatibility
    if(unloadHandlerRegistered) {
        // wikEd compatibility (frame -> textarea)
        if(typeof wikEdUseWikEd != "undefined" && wikEdUseWikEd) {
            WikEdUpdateTextarea();
        }
        return integrateRefs(mainTextbox.value, refsTextbox.value,
            randPrefix, complete).wikiText;
    } else {
        return mainTextbox.value;
    }
}

// Leave a global for ajaxPreview to use.
window.getEditboxContents = getEditboxContents;


function loadHandler() { // This function is called on page load
    try {

        if( !window.addEventListener ) {
            return;
        }
        
        // Handle message translations
        messages = (typeof SegregateRefsJsL10n == "object" &&
                    typeof SegregateRefsJsL10n.version != "undefined" &&
                    SegregateRefsJsL10n.version == 1.11 ? SegregateRefsJsL10n :
                    SegregateRefsJsMsgs);
        
        // Only activate on edit pages (that are not section edit pages)
        if(!document.getElementById("editform") ||
        document.getElementById("editform").wpSection.value.length) {
            return;
        }
        
        // Get the edit form
        editForm = document.getElementById("editform");
        // Get the edit box
        mainTextbox = document.getElementById("wpTextbox1");
        
        // Make the "segregate" button
        refsButton = document.createElement("input");
        refsButton.type = "button";
        refsButton.value = messages.buttonText;
        refsButton.setAttribute("style", messages.buttonStyle);
        refsButton.onclick = refsButtonHandler;
        
        // Make the "convert" button
        convertButton = document.createElement("input");
            convertButton.type = "button";
            convertButton.value = messages.buttonConvertText;
            convertButton.setAttribute("style", messages.buttonConvertStyle);
            convertButton.onclick = convertButtonHandler;
        
        if(typeof SegregateRefsJsAllowConversion == "undefined" ||
        !SegregateRefsJsAllowConversion) {
            convertButton.setAttribute("style", "display: none;");
        }
        
        // Add the refs div
        refsDiv = document.createElement("div");
        refsDiv.appendChild(refsButton);
        refsDiv.appendChild(convertButton);
        mainTextbox.parentNode.insertBefore(refsDiv, mainTextbox.nextSibling);
    } catch(e) {
    }
}


// Register document ready handler
$(loadHandler);

})();

//</nowiki></pre>