மீடியாவிக்கி:FileUploadWizard.js
/*
 * ===============================================================
 *                    FileUploadWizard.js
 * Script for uploading files through a dynamic questionnaire.
 * This is the code to accompany [[Wikipedia:File Upload Wizard]].
 * ===============================================================
 */
 
 var fuwTesting = false;
 var fuwDefaultTextboxLength = 60;
 var fuwDefaultTextareaWidth = '90%';
 var fuwDefaultTextareaLines = 3;
 
 // ================================================================
 // Constructor function of global fuw (= File Upload Wizard) object
 // ================================================================
 function fuwGlobal() {
 
    // Loading the accompanying .css
    mw.loader.load( mw.config.get('wgServer') + mw.config.get('wgScriptPath') +
       '/index.php?title=MediaWiki:FileUploadWizard.css&amp;action=raw&amp;ctype=text/css', 
       'text/css'  );
 
    // see if user is logged in, autoconfirmed, experienced etc.
    this.getUserStatus();
 
    fuwSetVisible('warningLoggedOut', (this.userStatus == 'anon'));
    fuwSetVisible('warningNotConfirmed', (this.userStatus == 'notAutoconfirmed'));
    if ((this.userStatus == 'anon') || (this.userStatus == 'notAutoconfirmed')) {
       return;
    }
    fuwSetVisible('fuwStartScriptLink', false);
 
    // create the form element to wrap the main ScriptForm area
    // containing input elements of Step2 and Step3
    var frm = fuwGet('fuwScriptForm');
    if (! frm) {
       frm = document.createElement('form');
       frm.id = &quot;fuwScriptForm&quot;;
       var area = fuwGet('placeholderScriptForm');
       var parent = area.parentNode;
       parent.insertBefore(frm, area);
       parent.removeChild(area);
       frm.appendChild(area);
    }
    this.ScriptForm = frm;
 
    // create the TargetForm element that contains the filename
    // input box, together with hidden input controls.
    // This is the form that is actually submitted to the api.php.
    frm = fuwGet('TargetForm');
    if (! frm) {
       frm = document.createElement('form');
       frm.id = &quot;TargetForm&quot;;
       frm.method = &quot;post&quot;;
       frm.enctype = &quot;multipart/form-data&quot;;
       // &quot;enctype&quot; doesn't work properly on IE; need &quot;encoding&quot; instead:
       frm.encoding = &quot;multipart/form-data&quot;; 
       // we'll submit via api.php, not index.php, mainly because that
       // allows us to use a proper edit summary different from the page content
       frm.action = mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/api.php';
 
       // However, since api.php sends back a response page that humans won't want to read,
       // we'll have to channel that response away and discard it. We'll use a hidden iframe
       // for that purpose.
       // Unfortunately, it doesn't seem possible to submit file upload content through an 
       // Xmlhtml object via Ajax.
  
       frm.target = &quot;TargetIFrame&quot;;
       //testing:
       //frm.target = &quot;_blank&quot;;
       var area = fuwGet('placeholderTargetForm');
       var parent = area.parentNode;
       parent.insertBefore(frm, area);
       parent.removeChild(area);
       frm.appendChild(area);
    }
    this.TargetForm = frm;
 
    // For the testing version, create a third form that will display
    // the contents to be submitted, at the bottom of the page
    if (fuwTesting) {
       frm = fuwGet('fuwTestForm');
       if (! frm) {
          frm = document.createElement('form');
          frm.id = &quot;fuwTestForm&quot;;
          var area = fuwGet('placeholderTestForm');
          var parent = area.parentNode;
          parent.insertBefore(frm, area);
          parent.removeChild(area);
          frm.appendChild(area);
       }
       this.TestForm = frm;
    }
 
    // objects to hold cached results during validation and processing
    this.opts = { };
    this.warn = { };
 
    // create the input filename box
    var filebox  = document.createElement('input');
    filebox.id   = 'file';
    filebox.name = 'file';
    filebox.type = 'file';
    filebox.size = fuwDefaultTextboxLength;
    filebox.onchange = fuwValidateFile;
    filebox.accept = 'image/png,image/jpeg,image/gif,image/svg+xml,image/tiff,image/x-xcf,application/pdf,image/vnd.djvu,audio/ogg,video/ogg,audio/rtp-midi';
    fuwAppendInput('file', filebox);
 
    // create hidden controls for sending the remaining API parameters:
    fuwMakeHiddenfield('action', 'upload', 'apiAction');
    fuwMakeHiddenfield('format', 'xml', 'apiFormat');
    fuwMakeHiddenfield('filename', '', 'apiFilename');
    fuwMakeHiddenfield('text', '', 'apiText');
    fuwMakeHiddenfield('comment', '', 'apiComment');
    fuwMakeHiddenfield('token', mw.user.tokens.get('csrfToken'), 'apiToken');
    fuwMakeHiddenfield('ignorewarnings', 1, 'apiIgnorewarnings');
    fuwMakeHiddenfield('watch', 1, 'apiWatch');
 
    if (fuwTesting) {
       fuwMakeHiddenfield('title', mw.config.get('wgPageName') + &quot;/sandbox&quot;, 'SandboxTitle');
       fuwMakeHiddenfield('token', mw.user.tokens.get('csrfToken'), 'SandboxToken');
       fuwMakeHiddenfield('recreate', 1, 'SandboxRecreate');
    }
 
    // create a hidden IFrame to send the api.php response to
    var ifr = document.createElement('iframe');
    ifr.id   = &quot;TargetIFrame&quot;;
    ifr.name = &quot;TargetIFrame&quot;;
    //ifr.setAttribute('style', 'float:right;width:150px;height:150px;');
    ifr.style.display = &quot;none&quot;;
    ifr.src = &quot;&quot;;
 
    fuwAppendInput('TargetIFrame', ifr);
 
    if (fuwTesting) {
 
       // create the sandbox submit button
       btn = document.createElement('input');
       btn.id = 'SandboxButton';
       btn.value = 'Sandbox';
       btn.name  = 'Sandbox';
       btn.disabled = true;
       btn.type = 'button';
       btn.style.width = '12em';
       btn.onclick = fuwSubmitSandbox;
       fuwAppendInput('SandboxButton', btn);
 
    }
 
    // create the real submit button
    btn = document.createElement('input');
    btn.id = &quot;SubmitButton&quot;;
    btn.value = &quot;Upload&quot;;
    btn.name = &quot;Upload&quot;;
    btn.disabled = true;
    btn.type = &quot;button&quot;;
    btn.onclick = fuwSubmitUpload;
    btn.style.width = '12em';
    fuwAppendInput('SubmitButton', btn);
 
    // create the Commons submit button
    btn = document.createElement('input');
    btn.id = &quot;CommonsButton&quot;;
    btn.value = &quot;Upload on Commons&quot;;
    btn.name  = &quot;Upload_on_Commons&quot;;
    btn.disabled = true;
    btn.type = &quot;button&quot;;
    btn.onclick = fuwSubmitCommons;
    btn.style.width = '12em';
    fuwAppendInput('CommonsButton', btn);
 
    // create reset buttons
    for (i = 1; i&lt;=2; i++) {
       btn = document.createElement('input');
       btn.id = 'ResetButton' + i;
       btn.value = &quot;Reset form&quot;;
       btn.name  = &quot;Reset form&quot;;
       btn.type  = &quot;button&quot;;
       btn.onclick = fuwReset;
       btn.style.width = '12em';
       fuwAppendInput('ResetButton' + i, btn);
    }
 
    // names of radio button fields
    var optionRadioButtons = {
       // top-level copyright status choice
       'FreeOrNonFree' : ['OptionFree','OptionNonFree','OptionNoGood'],
       // main subsections under OptionFree
       'FreeOptions'   : ['OptionOwnWork', 'OptionThirdParty', 'OptionFreeWebsite',
                          'OptionPDOld', 'OptionPDOther'],
       // main subsections under OptionNonFree
       'NonFreeOptions': ['OptionNFSubject','OptionNF3D','OptionNFExcerpt',
                          'OptionNFCover','OptionNFLogo','OptionNFPortrait',
                          'OptionNFMisc'],
       // response options inside warningFileExists
       'FileExistsOptions': 
                         ['NoOverwrite','OverwriteSame','OverwriteDifferent'],
       // choice of evidence in OptionThirdParty subsection
       'ThirdPartyEvidenceOptions' : 
                         ['ThirdPartyEvidenceOptionLink',
                          'ThirdPartyEvidenceOptionOTRS',
                          'ThirdPartyEvidenceOptionOTRSForthcoming',
                          'ThirdPartyEvidenceOptionNone'],
       // choice of PD status in OptionPDOld subsection
       'PDOldOptions'  : ['PDUS1923','PDURAA','PDFormality','PDOldOther'],
       // choice of PD status in OptionPDOther subsection
       'PDOtherOptions': ['PDOtherUSGov','PDOtherOfficial','PDOtherSimple',
                          'PDOtherOther'],
       // whether target article is wholly or only partly dedicated to discussing non-free work:
       'NFSubjectCheck': ['NFSubjectCheckDedicated','NFSubjectCheckDiscussed'],
       'NF3DCheck'     : ['NF3DCheckDedicated','NF3DCheckDiscussed'],
       // choice about copyright status of photograph in OptionNF3D
       'NF3DOptions'   : ['NF3DOptionFree','NF3DOptionSame']
    };
    for (var group in optionRadioButtons) {
       var op = optionRadioButtons[group];
       for (i=0; i&lt;op.length; i++) {
          fuwMakeRadiobutton(group, op[i]);
       }
    }
    this.ScriptForm.NoOverwrite.checked = true;
    
    // input fields that trigger special
    // onchange() event handlers for validation:
    fuwMakeTextfield('InputName', fuwValidateFilename);
    fuwMakeTextfield('NFArticle', fuwValidateNFArticle);
 
    // names of input fields that trigger normal
    // validation event handler
    var activeTextfields = [
       'Artist3D','Country3D',
       'Date','OwnWorkCreation','OwnWorkPublication',
       'Author','Source',
       'Permission','ThirdPartyOtherLicense',
       'ThirdPartyEvidenceLink','ThirdPartyOTRSTicket',
       'FreeWebsiteOtherLicense',
       'PDOldAuthorLifetime','Publication',
       'PDOldCountry','PDOldPermission',
       'PDOfficialPermission','PDOtherPermission',
       'NFSubjectPurpose', 'NF3DOrigDate', 'NF3DPurpose',
       'NF3DCreator',
       'NFPortraitDeceased',
       'EditSummary'
    ];
    for (i=0; i&lt;activeTextfields.length; i++) {
       fuwMakeTextfield(activeTextfields[i]);
    }
 
    // names of multiline textareas
    var activeTextareas = [
       'InputDesc','NF3DPermission',
       'NFCommercial','NFPurpose','NFReplaceableText',
       'NFReplaceable','NFCommercial','NFMinimality','AnyOther'
    ];
    for (i=0; i&lt;activeTextareas.length; i++) {
       fuwMakeTextarea(activeTextareas[i]);
    };
 
    var checkboxes = [
       'NFCoverCheckDedicated','NFLogoCheckDedicated','NFPortraitCheckDedicated'
    ];
    for (i=0; i&lt;checkboxes.length; i++) {
       fuwMakeCheckbox(checkboxes[i]);
    };
 
    var licenseLists = {
       'OwnWorkLicense' : 
         // array structure as expected for input to fuwMakeSelection() function.
         // any entry that is a two-element array will be turned into an option
         // (first element is the value, second element is the display string).
         // Entries that are one-element arrays will be the label of an option group.
         // Zero-element arrays mark the end of an option group.
         [
         ['Allow all use as long as others credit you and share it under similar conditions'],
         ['self|GFDL|cc-by-sa-3.0|migration=redundant', 
          'Creative Commons Attribution-Share Alike 3.0 + GFDL (recommended)',
          true],
         ['self|cc-by-sa-3.0',
          'Creative Commons Attribution-Share Alike 3.0'],
         [],
         ['Allow all use as long as others credit you'],
         ['self|cc-by-3.0',
          'Creative Commons Attribution 3.0'],
         [],
         ['Reserve no rights'],
         ['cc-zero',
          'CC-zero Universal Public Domain Dedication'],
         []
         ],   
       'ThirdPartyLicense' :
         [
         ['', 'please select the correct license...'],
         ['Freely licensed:'],
         ['cc-by-sa-3.0', 'Creative Commons Attribution-Share Alike (cc-by-sa-3.0)'],
         ['cc-by-3.0', 'Creative Commons Attribution (cc-by-3.0)'],
         ['GFDL', 'GNU Free Documentation License (GFDL)'],
         [],
         ['No rights reserved:'],
         ['PD-author', 'Public domain'],
         [],
         ['Other (see below)'],
         []
         ],   
       'FreeWebsiteLicense' :
         [
         ['', 'please select the correct license...'],
         ['Freely licensed:'],
         ['cc-by-sa-3.0', 'Creative Commons Attribution-Share Alike (cc-by-sa-3.0)'],
         ['cc-by-3.0', 'Creative Commons Attribution (cc-by-3.0)'],
         ['GFDL', 'GNU Free Documentation License (GFDL)'],
         [],
         ['No rights reserved:'],
         ['PD-author', 'Public domain'],
         [],
         ['Other (see below)'],
         []
         ],   
       'USGovLicense' :
        [
        ['PD-USGov', 'US Federal Government'],
        ['PD-USGov-NASA','NASA'],
        ['PD-USGov-Military-Navy','US Navy'],
        ['PD-USGov-NOAA','US National Oceanic and Atmospheric Administration'],
        ['PD-USGov-Military-Air_Force','US Air Force'],
        ['PD-USGov-Military-Army','US Army'],
        ['PD-USGov-CIA-WF','CIA World Factbook'],
        ['PD-USGov-USGS','United States Geological Survey']
        ],
       'IneligibleLicense' :
        [
        ['', 'please select one...'],
        ['PD-shape','Item consists solely of simple geometric shapes'],
        ['PD-text','Item consists solely of a few individual words or letters'],
        ['PD-textlogo','Logo or similar item consisting solely of letters and simple geometric shapes'],
        ['PD-chem','Chemical structural formula'],
        ['PD-ineligible','Other kind of item that contains no original authorship']
        ],
       'NFSubjectLicense' :
        [
        ['', 'please select one...'],
        ['Non-free 2D art', '2-dimensional artwork (painting, drawing etc.)'], 
        ['Non-free historic image', 'Unique historic photograph'], 
        ['Non-free fair use in', 'something else (please describe in description field on top)']
        ],
       'NF3DLicense' :
        [
        ['', 'please select one...'],
        ['Non-free architectural work', 'Architectural work'], 
        ['Non-free 3D art', 'Other 3-dimensional creative work (sculpture etc.)']
        ],
       'NFCoverLicense' :
          [
          ['', 'please select one...'],
          ['Non-free book cover', 'Cover page of a book'], 
          ['Non-free album cover', 'Cover of a sound recording (album, single, song, CD)'], 
          ['Non-free game cover', 'Cover of a video/computer game'], 
          ['Non-free magazine cover', 'Cover page of a magazine'], 
          ['Non-free video cover', 'Cover of a video'], 
          ['Non-free software cover', 'Cover of a software product'], 
          ['Non-free product cover', 'Cover of some commercial product'], 
          ['Non-free title-card', 'Title screen of a TV programme'], 
          ['Non-free movie poster', 'Movie poster'], 
          ['Non-free poster', 'Official poster of an event'], 
          ['Non-free fair use in', 'something else (please describe in description field on top)']
          ],
       'NFExcerptLicense' :
          [
          ['', 'please select one...'],
          ['Non-free television screenshot', 'Television screenshot'], 
          ['Non-free film screenshot', 'Movie screenshot'], 
          ['Non-free game screenshot', 'Game screenshot'], 
          ['Non-free video screenshot', 'Video screenshot'], 
          ['Non-free music video screenshot', 'Music video screenshot'], 
          ['Non-free software screenshot', 'Software screenshot'], 
          ['Non-free web screenshot', 'Website screenshot'], 
          ['Non-free speech', 'Audio excerpt from a speech'], 
          ['Non-free audio sample', 'Sound sample of an audio recording'], 
          ['Non-free video sample', 'Sample extract from a video'], 
          ['Non-free sheet music', 'Sheet music representing a musical piece'], 
          ['Non-free comic', 'Panel from a comic, graphic novel, manga etc.'], 
          ['Non-free computer icon', 'Computer icon'], 
          ['Non-free newspaper image', 'Page from a newspaper'], 
          ['Non-free fair use in', 'something else (please describe in description field on top)']
          ],      
       'NFLogoLicense' :
          [
          ['Non-free logo', 'Logo of a company, organization etc.'], 
          ['Non-free seal', 'Official seal, coat of arms etc'], 
          ['Non-free symbol', 'Other official symbol']
          ],
       'NFMiscLicense' :
          [
          ['Non-free fair use in', 'something else (please describe in description field on top)'], 
          ['Non-free historic image', 'Historic photograph'], 
          ['Non-free 2D art', '2-dimensional artwork (painting, drawing etc.)'], 
          ['Non-free currency', 'Depiction of currency (banknotes, coins etc.)'], 
          ['Non-free architectural work', 'Architectural work'], 
          ['Non-free 3D art', 'Other 3-dimensional creative work (sculpture etc.)'], 
          ['Non-free book cover', 'Cover page of a book'], 
          ['Non-free album cover', 'Cover of a sound recording(album, single, song, CD)'], 
          ['Non-free game cover', 'Cover of a video/computer game'], 
          ['Non-free magazine cover', 'Cover page of a magazine'], 
          ['Non-free video cover', 'Cover of a video'], 
          ['Non-free software cover', 'Cover of a software product'], 
          ['Non-free product cover', 'Cover of some commercial product'], 
          ['Non-free title-card', 'Title screen of a TV programme'], 
          ['Non-free movie poster', 'Movie poster'], 
          ['Non-free poster', 'Official poster of an event'], 
          ['Non-free television screenshot', 'Television screenshot'], 
          ['Non-free film screenshot', 'Movie screenshot'], 
          ['Non-free game screenshot', 'Game screenshot'], 
          ['Non-free video screenshot', 'Video screenshot'], 
          ['Non-free music video screenshot', 'Music video screenshot'], 
          ['Non-free software screenshot', 'Software screenshot'], 
          ['Non-free web screenshot', 'Website screenshot'], 
          ['Non-free speech', 'Audio excerpt from a speech'], 
          ['Non-free audio sample', 'Sound sample of an audio recording'], 
          ['Non-free video sample', 'Sample extract from a video'], 
          ['Non-free sheet music', 'Sheet music representing a musical piece'], 
          ['Non-free comic', 'Panel from a comic, graphic novel, manga etc.'], 
          ['Non-free computer icon', 'Computer icon'], 
          ['Non-free newspaper image', 'Page from a newspaper'], 
          ['Non-free logo', 'Logo of a company, organization etc.'], 
          ['Non-free seal', 'Official seal, coat of arms etc'], 
          ['Non-free symbol', 'Other official symbol'], 
          ['Non-free sports uniform', 'Sports uniform'], 
          ['Non-free stamp', 'Stamp'] 
          ],
       'NFExtraLicense' :
          [
          ['', 'none'],
          ['Crown copyright and other governmental sources'],
          ['Non-free Crown copyright', 'UK Crown Copyright'],
          ['Non-free New Zealand Crown Copyright', 'NZ Crown Copyright'],
          ['Non-free Canadian Crown Copyright', 'Canadian Crown Copyright'],
          ['Non-free AUSPIC', 'AUSPIC (Australian Parliament image database'],
          ['Non-free Philippines government', 'Philippines government'],
          ['Non-free Finnish Defence Forces', 'Finnish Defence Forces'],
          [],
          ['Other individual sources'],
          ['Non-free Denver Public Library', 'Denver Public Library'],
          ['Non-free ESA media', 'ESA (European Space Agency)'],
          [],
          ['Possibly public domain in other countries'],
          ['Non-free Old-50', 'Author died more than 50 years ago.'],
          ['Non-free Old-70', 'Author died more than 70 years ago.'],
          [],
          ['Some permissions granted, but not completely free'],
          ['Non-free promotional', 'From promotional press kit'],
          ['Non-free with NC', 'Permission granted, but only for educational and/or non-commercial purposes'],
          ['Non-free with ND', 'Permission granted, but no derivative works allowed'],
          ['Non-free with permission', 'Permission granted, but only for Wikipedia'],
          []
          ]
    };
    for (var group in licenseLists) {
       fuwMakeSelection(group, licenseLists[group]);
    }
 
 
    this.knownCommonsLicenses = {
       'self|GFDL|cc-by-sa-all|migration=redundant' : 1,
       'self|Cc-zero' : 1,
       'PD-self' : 1,
       'self|GFDL|cc-by-sa-3.0|migration=redundant' : 1,
       'self|GFDL|cc-by-3.0|migration=redundant' : 1,
       'self|cc-by-sa-3.0' : 1,
       'cc-by-sa-3.0' : 1,
       'cc-by-sa-2.5' : 1,
       'cc-by-3.0' : 1,
       'cc-by-2.5' : 1,
       'FAL' : 1,
       'PD-old-100' : 1,
       'PD-old' : 1,
       'PD-Art' : 1,
       'PD-US' : 1,
       'PD-USGov' : 1,
       'PD-USGov-NASA' : 1,
       'PD-USGov-Military-Navy' : 1,
       'PD-ineligible' : 1,
       'Attribution' : 1,
       'Copyrighted free use' : 1
    };
 
 
    // textfields that don't react directly
    // to user input and are used only for assembling stuff:
    if (fuwTesting) {
       fuwMakeTextfield('SandboxSummary', function(){void(0);});
       fuwMakeTextarea('SandboxText', function(){void(0);});
       fuwGet('SandboxSummary').disabled=&quot;disabled&quot;;
       fuwGet('SandboxText').disabled=&quot;disabled&quot;;
       fuwGet('SandboxText').rows = 12;
    }
 
    // set links to &quot;_blank&quot; target, so we don't accidentally leave the page,
    // because on some browsers that would destroy all the input the user has already entered
    $('.fuwOutLink a').each(function() {
       this.target = '_blank';
    });
 
    // make main area visible
    fuwSetVisible('UploadScriptArea', true);
 
 }
 // ====================================== 
 // end of fuwGlobal constructor function
 // ======================================
 
 
 
 function fuwRadioClick(e) {
    var ev = e || event;
    var src = ev.target || ev.srcElement;
    //alert('onclick event from ' + src + ' (' + src.value + ')');
    fuwUpdateOptions();
    return true;
 }
 
 /* 
 * =============================================================
 * function fuwUpdateOptions
 * =============================================================
 * This is the onchange event handler for most of the input
 * elements in the main form. It changes visibility and disabled
 * status for the various sections of the input form in response
 * to which options are chosen.
 */
 function fuwUpdateOptions() {
 
    var fuw = window.fuw;
    var warn = fuw.warn;
    var opts = fuw.opts = { };
    opts.InputFilename = $('#TargetForm input#file').val();
 
    var widgets = fuw.ScriptForm.elements;
    for (i = 0; i &lt; widgets.length; i++) {
       var w = widgets[i];
       if (w.type == &quot;radio&quot;) {
          var nm = w.name;
          var id = w.id;
          var vl = w.checked &amp;&amp; !w.disabled &amp;&amp; fuwIsVisible(w);
          opts[id] = vl;
          if (vl) opts[nm] = id;
       }
       else {
          var id = w.id;
          var active = !w.disabled &amp;&amp; fuwIsVisible(w);
          if (active) {
             var value = ((type == 'checkbox') ? w.checked : w.value);
             opts[id] = value;         
          }
       }
    };
    opts.MainOption = opts.FreeOptions || opts.NonFreeOptions;
    
    // some parts of the input form are re-used across sections
    // and must be moved into the currently active input section:
 
    // minimality section is shared between all NF sections
    fuwMove('NFMinimalitySection', 'detailsNFSubject', (opts.OptionNFSubject)) ||
    fuwMove('NFMinimalitySection', 'detailsNF3D', (opts.OptionNF3D)) ||
    fuwMove('NFMinimalitySection', 'detailsNFExcerpt', (opts.OptionNFExcerpt)) ||
    fuwMove('NFMinimalitySection', 'detailsNFCover', (opts.OptionNFCover)) ||
    fuwMove('NFMinimalitySection', 'detailsNFLogo', (opts.OptionNFLogo)) ||
    fuwMove('NFMinimalitySection', 'detailsNFPortrait', (opts.OptionNFPortrait)) ||
    fuwMove('NFMinimalitySection', 'detailsNFMisc', true);
 
    // AnyOtherInfo section is shared between all
    fuwMove('AnyOtherInfo', 'detailsOwnWork', opts.OptionOwnWork) ||
    fuwMove('AnyOtherInfo', 'detailsThirdParty', opts.OptionThirdParty) ||
    fuwMove('AnyOtherInfo', 'detailsFreeWebsite', opts.OptionFreeWebsite) ||
    fuwMove('AnyOtherInfo', 'detailsPDOld', opts.OptionPDOld) ||
    fuwMove('AnyOtherInfo', 'detailsPDOther', opts.OptionPDOther) ||
    fuwMove('AnyOtherInfo', 'detailsNFSubject', opts.OptionNFSubject) ||
    fuwMove('AnyOtherInfo', 'detailsNF3D', opts.OptionNF3D) ||
    fuwMove('AnyOtherInfo', 'detailsNFExcerpt', opts.OptionNFExcerpt) ||
    fuwMove('AnyOtherInfo', 'detailsNFCover', opts.OptionNFCover) ||
    fuwMove('AnyOtherInfo', 'detailsNFLogo', opts.OptionNFLogo) ||
    fuwMove('AnyOtherInfo', 'detailsNFPortrait', opts.OptionNFPortrait) ||
    fuwMove('AnyOtherInfo', 'detailsNFMisc', opts.OptionNFMisc);
 
    // author input field is shared between all sections except &quot;Own Work&quot;.
    // (will serve for the immediate/photographic author, in those cases where there
    // are two author fields)
    fuwMove('Author', 'placeholderFreeWebsiteAuthor', (opts.OptionFreeWebsite)) ||
    fuwMove('Author', 'placeholderPDOldAuthor', (opts.OptionPDOld)) ||
    fuwMove('Author', 'placeholderPDOtherAuthor', (opts.OptionPDOther)) ||
    fuwMove('Author', 'placeholderNFSubjectAuthor', (opts.OptionNFSubject)) ||
    fuwMove('Author', 'placeholderNF3DAuthor', (opts.OptionNF3D)) ||
    fuwMove('Author', 'placeholderNFExcerptAuthor', (opts.OptionNFExcerpt)) ||
    fuwMove('Author', 'placeholderNFCoverAuthor', (opts.OptionNFCover)) ||
    fuwMove('Author', 'placeholderNFPortraitAuthor', (opts.OptionNFPortrait)) ||
    fuwMove('Author', 'placeholderNFMiscAuthor', (opts.OptionNFMisc)) ||
    fuwMove('Author', 'placeholderAuthor', true);
 
    // source input field is shared between all sections except &quot;Own Work&quot;.
    // (will serve for immediate/web source, in those cases where there are two
    // source fields involved)
    fuwMove('Source', 'placeholderFreeWebsiteSource', (opts.OptionFreeWebsite)) ||
    fuwMove('Source', 'placeholderPDOldSource', (opts.OptionPDOld)) ||
    fuwMove('Source', 'placeholderPDOtherSource', (opts.OptionPDOther)) ||
    fuwMove('Source', 'placeholderNFSubjectSource', (opts.OptionNFSubject)) ||
    fuwMove('Source', 'placeholderNF3DSource', (opts.OptionNF3D)) ||
    fuwMove('Source', 'placeholderNFExcerptSource', (opts.OptionNFExcerpt)) ||
    fuwMove('Source', 'placeholderNFCoverSource', (opts.OptionNFCover)) ||
    fuwMove('Source', 'placeholderNFLogoSource', (opts.OptionNFLogo)) ||
    fuwMove('Source', 'placeholderNFPortraitSource', (opts.OptionNFPortrait)) ||
    fuwMove('Source', 'placeholderNFMiscSource', (opts.OptionNFMisc)) ||
    fuwMove('Source', 'placeholderSource', true);
 
    // date input field is shared between all sections except &quot;Logo&quot;, which doesn't need it.
    // will serve for derived/photographic date in the case of 3D items
    fuwMove('Date', 'placeholderFreeWebsiteDate', (opts.OptionFreeWebsite)) ||
    fuwMove('Date', 'placeholderThirdPartyDate', (opts.OptionThirdParty)) ||
    fuwMove('Date', 'placeholderPDOldDate', (opts.OptionPDOld)) ||
    fuwMove('Date', 'placeholderPDOtherDate', (opts.OptionPDOther)) ||
    fuwMove('Date', 'placeholderNFSubjectDate', (opts.OptionNFSubject)) ||
    fuwMove('Date', 'placeholderNF3DDate', (opts.OptionNF3D)) ||
    fuwMove('Date', 'placeholderNFExcerptDate', (opts.OptionNFExcerpt)) ||
    fuwMove('Date', 'placeholderNFCoverDate', (opts.OptionNFCover)) ||
    fuwMove('Date', 'placeholderNFPortraitDate', (opts.OptionNFPortrait)) ||
    fuwMove('Date', 'placeholderNFMiscDate', (opts.OptionNFMisc)) ||
    fuwMove('Date', 'placeholderDate', true);
    
    // permission field is shared between ThirdParty and FreeWebsite sections
    fuwMove('Permission', 'placeholderFreeWebsitePermission', (opts.OptionFreeWebsite)) ||
    fuwMove('Permission', 'placeholderPermission', true);
 
    // publication field is shared between PDOld, NFPortrait and NFMisc
    fuwMove('Publication', 'placeholderNFPortraitPublication', (opts.OptionNFPortrait)) ||
    fuwMove('Publication', 'placeholderNFMiscPublication', (opts.OptionNFMisc)) ||
    fuwMove('Publication', 'placeholderPublication', true);
 
    // Purpose, Commercial, Replaceable and ReplaceableText FUR fields are shared
    // between some but not all of the non-free sections
    fuwMove('NFPurpose', 'placeholderNFExcerptPurpose', (opts.OptionNFExcerpt)) ||
    fuwMove('NFPurpose', 'placeholderNFPurpose');
    fuwMove('NFCommercial', 'placeholderNFPortraitCommercial', (opts.OptionNFPortrait)) ||
    fuwMove('NFCommercial', 'placeholderNFCommercial');
    fuwMove('NFReplaceable', 'placeholderNFPortraitReplaceable', (opts.OptionNFPortrait)) ||
    fuwMove('NFReplaceable', 'placeholderNFReplaceable');
    fuwMove('NFReplaceableText', 'placeholderNFExcerptReplaceable', (opts.OptionNFExcerpt)) ||
    fuwMove('NFReplaceableText', 'placeholderNFReplaceableText', true);
 
    // submit button goes to Step1 if user has chosen a plain overwrite of an existing file,
    // and to the active section of Step3 if otherwise
    fuwMove('fuwSubmit', 'UploadScriptStep1', (warn.ImageExists &amp;&amp; opts.OverwriteSame)) ||
    fuwMove('fuwSubmit', 'detailsOwnWork', opts.OptionOwnWork) ||
    fuwMove('fuwSubmit', 'detailsThirdParty', opts.OptionThirdParty) ||
    fuwMove('fuwSubmit', 'detailsFreeWebsite', opts.OptionFreeWebsite) ||
    fuwMove('fuwSubmit', 'detailsPDOld', opts.OptionPDOld) ||
    fuwMove('fuwSubmit', 'detailsPDOther', opts.OptionPDOther) ||
    fuwMove('fuwSubmit', 'detailsNFSubject', opts.OptionNFSubject) ||
    fuwMove('fuwSubmit', 'detailsNF3D', opts.OptionNF3D) ||
    fuwMove('fuwSubmit', 'detailsNFExcerpt', opts.OptionNFExcerpt) ||
    fuwMove('fuwSubmit', 'detailsNFCover', opts.OptionNFCover) ||
    fuwMove('fuwSubmit', 'detailsNFLogo', opts.OptionNFLogo) ||
    fuwMove('fuwSubmit', 'detailsNFPortrait', opts.OptionNFPortrait) ||
    fuwMove('fuwSubmit', 'fuwSubmitHost', true);
 
 
    // Show and hide warnings:
 
    // filename-related warnings:
    fuwSetVisible('warningIllegalChars', warn.IllegalChars);
    fuwSetVisible('warningBadFilename',  warn.BadFilename);
    fuwSetVisible('warningImageOnCommons', warn.ImageOnCommons);
    fuwSetVisible('warningImageExists', warn.ImageExists);
    fuwMove('warningImageThumb', 'warningImageOnCommons', warn.ImageOnCommons, true) ||
    fuwMove('warningImageThumb', 'warningImageExists', true, true);
 
 
    // notices related to the top-level options:
    fuwSetVisible('warningWhyNotCommons', opts.OptionFree);
    fuwSetVisible('warningNF', opts.OptionNonFree);
    fuwSetVisible('warningNoGood', opts.OptionNoGood);
 
    // warnings related to non-free &quot;used in&quot; article
    fuwSetVisible('warningNFArticleNotFound', warn.NFArticleNotFound);
    fuwSetVisible('warningNFArticleNotMainspace', warn.NFArticleNotMainspace);
    fuwSetVisible('warningUserspaceDraft', warn.UserspaceDraft);
    fuwSetVisible('warningNFArticleDab', warn.NFArticleDab);
    fuwSetVisible('NFArticleOK', warn.NFArticleOK);
 
    // warnings depending on user status:
    if (fuw.userStatus.match(/problem|newbie|notAutoconfirmed/)) {
       fuwSetVisible('warningFreeWebsite', opts.OptionFreeWebsite);
       fuwSetVisible('warningOwnWork', opts.OptionOwnWork);
       fuwSetVisible('warningPDOther', opts.OptionPDOther);
       fuwSetVisible('warningNFSubject', opts.OptionNFSubject);
    }
 
    // hide main sections in case of intended plain overwrite:   
    fuwSetVisible('UploadScriptStep2', !(warn.ImageExists &amp;&amp; opts.OverwriteSame));
    fuwSetVisible('UploadScriptStep3', !(warn.ImageExists &amp;&amp; opts.OverwriteSame));
 
    // show/hide top-level options
    fuwSetVisible('detailsFreeStatus', opts.OptionFree);
    fuwSetVisible('sendToCommons', opts.OptionFree);
 
    // show/hide details sections
    fuwSetVisible('detailsNFArticle', opts.OptionNonFree);
    fuwSetVisible('detailsNFWorkType', opts.OptionNonFree);
    fuwSetVisible('detailsOwnWork', opts.OptionOwnWork);
    fuwSetVisible('detailsThirdParty', opts.OptionThirdParty);
    fuwSetVisible('detailsFreeWebsite', opts.OptionFreeWebsite);
    fuwSetVisible('detailsPDOld', opts.OptionPDOld);
    fuwSetVisible('detailsPDOther', opts.OptionPDOther);
    fuwSetVisible('detailsNFSubject', opts.OptionNFSubject);
    fuwSetVisible('detailsNF3D', opts.OptionNF3D);
    fuwSetVisible('detailsNFExcerpt', opts.OptionNFExcerpt);
    fuwSetVisible('detailsNFCover', opts.OptionNFCover);
    fuwSetVisible('detailsNFLogo', opts.OptionNFLogo);
    fuwSetVisible('detailsNFPortrait', opts.OptionNFPortrait);
    fuwSetVisible('detailsNFMisc', opts.OptionNFMisc);
 
    fuwSetVisible('EditSummaryDiv', opts.OverwriteSame || opts.OverwriteDifferent);
 
    // set enabled/disabled
    // It might be useful to adapt this to be more liberal about
    // the order of input, at least for experienced users.
 
    //fuwSetEnabled('Artist3D', opts.PD3D);
    //fuwSetEnabled('Country3D', opts.FOP3D);
    fuwSetEnabled('ThirdPartyEvidenceLink', opts.ThirdPartyEvidenceOptionLink);
    fuwSetEnabled('ThirdPartyOTRSTicket', opts.ThirdPartyEvidenceOptionOTRS);
    fuwSetEnabled('NFSubjectPurpose', opts.NFSubjectCheckDiscussed);
    fuwSetEnabled('NF3DPurpose', opts.NF3DCheckDiscussed);
    fuwSetEnabled('NF3DPermission', opts.NF3DOptionFree);
    fuwSetEnabled('USGovLicense', opts.PDOtherUSGov);
    fuwSetEnabled('PDOfficialPermission', opts.PDOtherOfficial);
    fuwSetEnabled('IneligibleLicense', opts.PDOtherSimple);
    fuwSetEnabled('PDOtherPermission', opts.PDOtherOther);
    fuwSetEnabled('AnyOther', true);
 
    // need to re-collect the remaining (non-radiobutton) input into the opts object again,
    // preparing for validation:
    for (i = 0; i &lt; widgets.length; i++) {
       var w = widgets[i];
       var type = w.type;
 
       if (type != &quot;radio&quot;) {
          var id = w.id;
          var active = !w.disabled &amp;&amp; fuwIsVisible(w);
          if (active) {
             var value = ((type == 'checkbox') ? w.checked : w.value);
             opts[id] = value;         
          }
       }
    };
 
    // final step of validation: check if input is sufficient for
    // setting the submit buttons active
    var valid = fuw.validateInput();
    var validForCommons = valid &amp;&amp; opts.OptionFree &amp;&amp; !(opts.OverwriteSame || opts.OverwriteDifferent)
          &amp;&amp; !opts.ThirdPartyEvidenceOptionNone;
    fuwSetVisible('sendToCommons', opts.OptionFree);
    fuwSetEnabled('CommonsButton', validForCommons);
    fuwGet('fuwSubmitText').innerHTML = opts.OptionFree ? 
          (&quot;&lt;b&gt;No&lt;/b&gt;, I want to upload this file here on this wiki only.&lt;br/&gt;&quot; + 
           &quot;&lt;small&gt;This way it can be used only on the English Wikipedia. However, somebody &quot; +
           &quot;else might still decide to copy it to Commons or use it elsewhere later. If you &quot; +
           &quot;do not want your file to be copied to Commons and deleted locally, consider adding &quot; +
           &quot;{{tl|Keep local}}.&lt;/small&gt;&quot;) :
          &quot;Upload this file.&quot;;
    fuwGet('SubmitButton').value = validForCommons ? &quot;Upload locally&quot; : &quot;Upload&quot;;   
    fuwSetEnabled('EditSummary', true);
    fuwSetEnabled('SubmitButton', valid &amp;&amp; (fuw.userStatus != 'notAutoconfirmed'));
    if (fuwTesting) {
       fuwSetEnabled('SandboxButton', valid);
    }
 
    // if we're in testing mode, update the Sandbox display fields
    // after each input change. In normal mode, collectInput() will
    // only be needed on submit.
    if (fuwTesting) {
       fuw.collectInput();
       fuw.formatOutput(false);
       fuwSetVisible('placeholderTestForm', true);
    }  
 }
 
 // ============================================================
 // methods of the global fuw object
 // ============================================================
 
 // ============================================================
 // report validation status of filename information
 // ============================================================
 // This is called from within fuw.validateInput(), i.e. every
 // time anything in the whole form is changed. It only reports
 // results that have previously been cached in the opts and warn
 // objects. The actual checking is done in the event handler
 // of the file input boxes.
 fuwGlobal.prototype.hasValidFilename = function() {
    var opts = this.opts;
    var warn = this.warn;
    var valid =   
       opts.InputName &amp;&amp;
       opts.InputFilename &amp;&amp;
       !warn.BadFilename &amp;&amp;
       !warn.ImageOnCommons &amp;&amp;
       // if image exists on enwiki, accept only if user has confirmed overwrite:
       !(warn.ImageExists &amp;&amp; !(opts.OverwriteSame || opts.OverwriteDifferent));
    //alert(&quot;HasValidFilename: &quot; + valid);
    return valid;
 };
 
 // ============================================================
 // validation status for common input elements for all free
 // options
 // ============================================================
 fuwGlobal.prototype.hasValidCommonFreeInput = function() {
    var opts = this.opts;
    var warn = this.warn;
    var valid = opts.InputDesc;
    //alert(&quot;HasValidCommonFreeInput: &quot; + valid);
    return valid;
 };
 // ============================================================
 // validation status for common input elements for all non-free
 // options
 // ============================================================
 fuwGlobal.prototype.hasValidCommonNFInput = function() {
    var opts = this.opts;
    var warn = this.warn;
    var valid =
       opts.OptionNonFree &amp;&amp;
       opts.InputDesc &amp;&amp; 
       opts.NFArticle &amp;&amp;
       opts.Source &amp;&amp;
       opts.NFMinimality &amp;&amp;
       !warn.NFArticleNotFound &amp;&amp;
       !warn.NFArticleNotMainspace &amp;&amp;
       !warn.NFArticleDab;
    //alert(&quot;hasValidCommonNFInput: &quot; + valid);
    return valid;
 };
 // ============================================================
 // Main validation routine. Modify this to tweak which fields
 // are to be considered obligatory for each case group
 // ============================================================
 fuwGlobal.prototype.validateInput = function() {
    var opts = this.opts;
    var warn = this.warn;
    var valid = (
       this.hasValidFilename()
       &amp;&amp;
       (! (opts.OverwriteDifferent &amp;&amp; ! opts.EditSummary))
       &amp;&amp;
       (
        ( // overwriting is okay if there is an edit summary
         opts.OverwriteSame &amp;&amp; opts.EditSummary
        )
        ||
        ( // free options
          this.hasValidCommonFreeInput() &amp;&amp;
          (
           (opts.OptionOwnWork &amp;&amp;
            opts.Date &amp;&amp;
            opts.OwnWorkLicense)
           ||
           (opts.OptionThirdParty &amp;&amp;
            opts.Author &amp;&amp;
            opts.Source &amp;&amp;
            opts.Permission &amp;&amp;
            (opts.ThirdPartyOtherLicense || opts.ThirdPartyLicense) &amp;&amp;
            ((opts.ThirdPartyEvidenceOptionLink &amp;&amp; opts.ThirdPartyEvidenceLink) ||
             opts.ThirdPartyEvidenceOptionOTRS ||
             opts.ThirdPartyEvidenceOptionOTRSForthcoming ||
             opts.ThirdPartyEvidenceOptionNone))
           ||
           (opts.OptionFreeWebsite &amp;&amp;
            opts.Author &amp;&amp;
            opts.Source &amp;&amp;
            (opts.FreeWebsiteOtherLicense || opts.FreeWebsiteLicense) &amp;&amp;
            opts.Permission)
           ||
           (opts.OptionPDOld &amp;&amp;
            opts.Author &amp;&amp;
            opts.PDOldAuthorLifetime &amp;&amp;
            opts.Publication &amp;&amp;
            opts.Date &amp;&amp;
            opts.Source &amp;&amp;
            opts.PDOldOptions &amp;&amp; 
            (! (opts.PDOldOther &amp;&amp; ! opts.PDOldPermission)))
           ||
           (opts.OptionPDOther &amp;&amp;
            opts.Author &amp;&amp;
            opts.Source &amp;&amp;
            ((opts.PDOtherUSGov &amp;&amp; opts.USGovLicense) ||
             (opts.PDOtherOfficial &amp;&amp; opts.PDOfficialPermission) ||
             (opts.PDOtherSimple &amp;&amp; opts.IneligibleLicense) ||
             (opts.PDOtherOther &amp;&amp; opts.PDOtherPermission)))
         )
        ) // end of free options
        ||
        ( // non-free options
          this.hasValidCommonNFInput() &amp;&amp;
          (
           (opts.OptionNFSubject &amp;&amp;
            opts.NFSubjectLicense &amp;&amp;
            opts.Author &amp;&amp;
            (opts.NFSubjectCheckDedicated ||
            (opts.NFSubjectCheckDiscussed &amp;&amp; opts.NFSubjectPurpose)))
           ||
           (opts.OptionNF3D &amp;&amp;
            opts.NF3DLicense &amp;&amp;
            opts.NF3DCreator &amp;&amp;
            opts.Author &amp;&amp;
            (opts.NF3DOptionSame ||
            (opts.NF3DOptionFree || opts.NF3DPermission)) &amp;&amp; 
            (opts.NF3DCheckDedicated ||
             (opts.NF3DCheckDiscussed &amp;&amp; opts.NF3DPurpose)))
           ||
           (opts.OptionNFExcerpt &amp;&amp;
            opts.NFExcerptLicense &amp;&amp;
            opts.Author &amp;&amp;
            opts.NFPurpose)
           ||
           (opts.OptionNFCover &amp;&amp;
            opts.NFCoverLicense &amp;&amp;
            opts.Author &amp;&amp;
            opts.NFCoverCheckDedicated 
           )
           ||
           (opts.OptionNFLogo &amp;&amp;
            opts.NFLogoLicense &amp;&amp;
            opts.NFLogoCheckDedicated
           )
           ||
           (opts.OptionNFPortrait &amp;&amp;
            opts.Publication &amp;&amp;
            opts.NFPortraitDeceased &amp;&amp;
            opts.Author &amp;&amp;
            opts.NFPortraitCheckDedicated &amp;&amp;
            opts.NFReplaceable &amp;&amp;
            opts.NFCommercial)
           ||
           (opts.OptionNFMisc &amp;&amp;
            opts.NFMiscLicense &amp;&amp;
            opts.Author &amp;&amp;
            opts.Publication &amp;&amp;
            opts.NFPurpose &amp;&amp;
            opts.NFReplaceableText &amp;&amp;
            opts.NFReplaceable &amp;&amp;
            opts.NFCommercial)
          )
        ) // end of non-free options
       )
    );
    return valid;
 };
 
 // =============================================================
 // return which template name will be used as the main
 // description template
 // =============================================================
 fuwGlobal.prototype.getDescriptionTemplateName = function() {
    // standard &quot;Information&quot; template for free files:
    if (this.opts.OptionFree) return &quot;Information&quot;;
    // experimental new version of fair-use rationale template,
    // designed to fit the fields used in the wizard
    else if (this.opts.OptionNonFree) return &quot;Non-free use rationale 2&quot;;
    return undefined;
 };
 
 // =============================================================
 // get the license tag code from the appropriate input element
 // =============================================================
 
 fuwGlobal.prototype.getStandardLicense = function() {
    var opts = this.opts;
    
 }
 
 fuwGlobal.prototype.getLicense = function() {
    var opts = this.opts;
       // ThirdParty and FreeWebsite have alternative input fields
       // for manual entry of other licenses:
    var license = {};
    if (opts.PDOtherOther || opts.PDOldOther) {
       license.special = opts.PDOtherOther ? opts.PDOtherPermission : opts.PDOldPermission;
       if (! (license.special.match(/^\s*\{\{.+\}\}\s*$/))) {
          license.special = '{{PD-because|' + license.special + '}}';
       }
    }
    else {
       license.special = 
          opts.ThirdPartyOtherLicense || 
          opts.FreeWebsiteOtherLicense ||
          (opts.PDOtherOfficial ? ('{{PD-because|official item legally exempt from copyright in its country of origin}}') : null) ||
          (opts.OptionNFPortrait ? ('{{Non-free biog-pic|' + opts.NFArticle + '}}') : null);
    }   
    if (! license.special) {
       // standard, non-parametrized tag licenses from dropdownbox.
       var simpleLicense = (opts.OptionOwnWork ? opts.OwnWorkLicense : null) ||
           (opts.OptionThirdParty ? opts.ThirdPartyLicense : null) ||
           (opts.OptionFreeWebsite ? opts.FreeWebsiteLicense : null) ||
           (opts.OptionNFSubject ? opts.NFSubjectLicense : null) ||
           (opts.OptionNF3D ? opts.NF3DLicense : null) ||
           (opts.OptionNFExcerpt ? opts.NFExcerptLicense : null) ||
           (opts.OptionNFCover ? opts.NFCoverLicense : null) ||
           (opts.OptionNFLogo ? opts.NFLogoLicense : null) ||
           (opts.OptionNFMisc ? opts.NFMiscLicense : null) ||
           (opts.PDOtherUSGov ? opts.USGovLicense : null) ||
           (opts.PDOtherSimple ? opts.IneligibleLicense : null) ||
           (opts.PDUS1923 ? 'PD-US-1923' : null) ||
           (opts.PDURAA   ? 'PD-URAA' : null) ||
           (opts.PDFormality ? 'PD-US' : null);
 
        // &quot;PD-author&quot; needs parameter, at least on Commons
        if (simpleLicense == 'PD-author') {
           license.special = '{{PD-author|' + opts.Author + '}}';
        }
        else if (this.knownCommonsLicenses[simpleLicense]) {
        // make sure we send only those licenses as &quot;standard&quot; licenses
        // that exist in the Commons license dropdown box
           license.standard = simpleLicense;
        }
        else {
           license.special = '\{\{' + simpleLicense + '\}\}';
        }
    }
    return license;
 };
 
 function fuwSubst(template) {
    return '{{subst:' + template + '}}';
 }
 
 // ===================================================================
 // Produce code for local tracking categories
 // ===================================================================
 fuwGlobal.prototype.getTrackingCategory = function() {
    var opts = this.opts;
    var cat = &quot;&quot;;
    if (opts.OptionFreeWebsite) { cat = &quot;Files from freely licensed external sources&quot;; }
    else if (opts.OptionThirdParty) { cat = &quot;Files licensed by third parties&quot;; }
    else if (opts.PDOtherOther || opts.PDOldOther) { cat = &quot;Files with non-standard public domain statements&quot;; }
    else if (opts.OptionNFSubject || opts.OptionNF3D) { cat = &quot;Non-free files uploaded as object of commentary&quot;; }
    if (cat) {
       cat = &quot;\n\{\{Category ordered by date|&quot; + cat + &quot;|&quot; + 
       fuwSubst(&quot;CURRENTYEAR&quot;) + &quot;|&quot; + fuwSubst(&quot;CURRENTMONTH&quot;) + &quot;|&quot; + fuwSubst(&quot;CURRENTDAY2&quot;) + &quot;\}\}&quot;;
    }
    return cat;
 };
 
 // ===================================================================
 // Get or create an edit summary for the upload
 // ===================================================================
 // Note: if we work with the api.php interface, we can have separate
 // data for the edit summary and the description page, which is far
 // better than the way the index.php interface does it.
 // TO DO: need to actually define an input element for a manually
 // entered edit summary. Must be obligatory when overwriting files.
 // In other cases we'll use an automatic edit summary.
 // ===================================================================
 fuwGlobal.prototype.getEditSummary = function() {
    var opts = this.opts;
    return (
       (opts.EditSummary ? (opts.EditSummary + ' ([[' + mw.config.get('wgPageName') + '|File Upload Wizard]])') : null)||
       (&quot;Uploading &quot; +
        (
         (opts.OptionOwnWork ? 'a self-made file ' : false) ||
         (opts.OptionThirdParty ? 'a free file from somebody else ' : false) ||
         (opts.OptionFreeWebsite ? 'a file from a free published source ' : false) ||
         (opts.OptionPDOld       ? 'an old public-domain work ' : false) ||
         (opts.OptionPDOther     ? 'a public-domain item ' : false) ||
         (opts.OptionNFSubject   ? 'a non-free work, as object of commentary ' : false) ||
         (opts.OptionNF3D        ? 'a depiction of a non-free 3D artwork ' : false) ||
         (opts.OptionNFExcerpt   ? 'an excerpt from a non-free work ' : false) ||
         (opts.OptionNFCover     ? 'a piece of non-free cover art ' : false) ||
         (opts.OptionNFLogo      ? 'a non-free logo ' : false) ||
         (opts.OptionNFPortrait    ? 'a non-free historic portrait ' : false) ||
         (opts.OptionNFMisc      ? 'a non-free file ' : &quot;&quot;)
        )
        + 
        (&quot;using [[&quot; + mw.config.get('wgPageName') + &quot;|File Upload Wizard]]&quot;)
       ));
 };
 
 
 function fuwPackInfo(text, forCommons) {
    if (forCommons) {
       // reformat wikilinks embedded in description fields to adapt them for Commons
       text = text.replace(/\[\[([^\]]+)\]\]/g, 
          function(str, p1, offset, s) {
 
             // mark File links as local
             if (p1.match(/^:(File|Image):/)) {
                return &quot;[[:en&quot; + p1 + &quot;]]&quot;;
             }      
             // leave prefixed links unchanged:
             else if (p1.match(/^:[\w\-]+:/)) {
                return str;
             }
             // if the link is piped, add a prefix only
             else if (p1.match(/.+\|/)) {
                return &quot;[[:en:&quot; + p1 + &quot;]]&quot;;
             }
             // introduce a pipe
             else {
                return &quot;[[:en:&quot; + p1 + &quot;|&quot; + p1 + &quot;]]&quot;;
             }
          }
       );
       return &quot;{{en|&quot; + text + &quot;}}&quot;;
    } else return text;
 }
 
 // ================================================================
 // This is the main method called by the event handler for the 
 // (experimental) submit button. Its main task is to collect the 
 // input into a single string of wikitext for the description page.
 // ================================================================
 fuwGlobal.prototype.collectInput = function() {
    var opts = this.opts;
 
    // object representing template fields for filling in
    // the description template. Pre-loaded with some
    // standard settings:
    var descFields = this.descFields = { 
       'Description' : opts.InputDesc,
       'Author'      : opts.Author,
       'Date'        : opts.Date,
       'Source'      : opts.Source
    };
    // &quot;other information&quot; (outside the template)
    this.otherInfo = null;
    
    if (opts.OptionNonFree) {
       descFields.Article = opts.NFArticle;
    }
    
    // add/modify option-specific fields:
    switch (opts.MainOption) {
       case 'OptionOwnWork':
       
          // use standard &quot;source&quot; field for optional &quot;how created?&quot; and 
          // &quot;previously published&quot; input fields.
          descFields.Source = fuwAppendLines([
             (opts.OwnWorkCreation || &quot;{{own}}&quot;), 
             &quot;&lt;br/&gt;\n&quot;, 
             fuwSurroundString(&quot;'''Previously published:''' &quot;, opts.OwnWorkPublication)]);
          var username = mw.user.getName();
          descFields.Author = '[[User:' + username + '|' + username + ']]';
          break;
 
       case 'OptionThirdParty':
       
          // use standard &quot;permission&quot; field for a compilation of the
          // &quot;permission&quot; input field and the various &quot;evidence&quot; options
          var evidence = (
             opts.ThirdPartyEvidenceOptionLink ? 
                (&quot;The license statement can be found online at: &quot; + opts.ThirdPartyEvidenceLink) :
                (opts.ThirdPartyEvidenceOptionOTRS ? 
                (&quot;The license agreement has been forwarded to OTRS.&quot; + 
                   fuwSurroundString(&quot; Ticket: &quot;, opts.ThirdPartyOTRSTicket) + &quot;\{\{OTRS pending|year=&quot; + fuwSubst(&quot;CURRENTYEAR&quot;) + 
                                                                               &quot;|month=&quot; + fuwSubst(&quot;CURRENTMONTH&quot;) + 
                                                                               &quot;|day=&quot; + fuwSubst(&quot;CURRENTDAY2&quot;) + &quot;\}\}&quot;) :
                (opts.ThirdPartyEvidenceOptionOTRSForthcoming ? 
                &quot;The license agreement will be forwarded to OTRS shortly. \{\{OTRS pending|year=&quot; + fuwSubst(&quot;CURRENTYEAR&quot;) + 
                                                                               &quot;|month=&quot; + fuwSubst(&quot;CURRENTMONTH&quot;) + 
                                                                               &quot;|day=&quot; + fuwSubst(&quot;CURRENTDAY2&quot;) + &quot;\}\}&quot; :
                (opts.ThirdPartyEvidenceOptionNone ?
                &quot;Will be provided on request.&quot; : null))));
          descFields.Permission = fuwAppendLines([
             opts.ThirdPartyPermission,
             &quot;&lt;br/&gt;\n&quot;,
             fuwSurroundString(&quot;'''Evidence:''' &quot;, evidence)]);
          break;
          
       case 'OptionFreeWebsite':
          descFields.Permission = opts.Permission;
          break;
          
       case 'OptionPDOld':
          // add &quot;lifetime&quot; input to &quot;author&quot; field
          descFields.Author = fuwAppendLines([
             opts.Author,
             &quot;&lt;br/&gt;\n&quot;,
             fuwSurroundString(&quot;(Life time: &quot;, opts.PDOldAuthorLifetime, &quot;)&quot;)
          ]);
          
          // combine original and direct source into standard &quot;source&quot; field: 
          descFields.Source = fuwAppendLines([
             fuwSurroundString(&quot;'''Original publication''': &quot;, opts.Publication),
             &quot;&lt;br/&gt;\n&quot;,
             fuwSurroundString(&quot;'''Immediate source''': &quot;, opts.Source)
          ]);
          
          // no standard tag available for &quot;lack-of-registration&quot; PD-US. Need
          // to put this into the &quot;permission&quot; field
          if (opts.PDFormality) 
             descFields.Permission = 
                &quot;Copyright expired because the work was published without a copyright &quot; +
                &quot;notice and/or without the necessary copyright registration.&quot;;
       
          // add optional &quot;explanation&quot; input to &quot;permission&quot; field
          if (opts.PDOldPermission) {
             descFields.Permission = fuwAppendLines([
                descFields.Permission,
                &quot;\n\n&quot;,
                opts.PDOldPermission
             ]);
          }
          break;
          
       case 'OptionPDOther':
          // Need &quot;permission&quot; field in case of &quot;official item&quot; option
          if (opts.PDOtherOfficial) 
             descFields.Permission = opts.PDOfficialPermission;
          break; 
 
       case 'OptionNFSubject':
          // most FUR elements can be automatically provided:
          descFields.Purpose = (
             opts.NFSubjectCheckDedicated ? 
              (&quot;For visual identification of the object of the article. &quot; +
               &quot;The article as a whole is dedicated specifically to a discussion of this work.&quot;) :
             (opts.NFSubjectCheckDiscussed ?
              (&quot;To support encyclopedic discussion of this work in this article. &quot; +
               &quot;The illustration is specifically needed to support the following point(s): &quot; +
               &quot;&lt;br/&gt;\n&quot; + opts.NFSubjectPurpose) : null)
          );
          // I hate FURs filled with trivial/predictable/redundant verbiage,
          // so we'll just cut it short. And don't anybody dare complain that
          // that's not a valid FUR.
          descFields.Replaceability = &quot;n.a.&quot;;
          descFields.Commercial     = &quot;n.a.&quot;;
          break;
 
       case 'OptionNF3D':
          // complex case: we need to assemble attribution and FUR both for the 
          // original 3D work and for the photographic depiction. Both might be 
          // non-free.
          descFields.Author = fuwAppendLines([
             fuwSurroundString(&quot;'''Original work:''' &quot;, opts.NF3DCreator),
             &quot;&lt;br/&gt;\n&quot;,
             fuwSurroundString(&quot;'''Depiction:''' &quot;, opts.Author)
          ]);
          descFields.Date = fuwAppendLines([
             fuwSurroundString(&quot;'''Original work:''' &quot;, opts.NF3DOrigDate),
             &quot;&lt;br/&gt;\n&quot;,
             fuwSurroundString(&quot;'''Depiction:''' &quot;, opts.Date)
          ]);
          descFields.Purpose = (
             opts.NF3DCheckDedicated ? 
              (&quot;For visual identification of the object of the article. &quot; +
               &quot;The article as a whole is dedicated specifically to a discussion of this work.&quot;) :
             (opts.NF3DCheckDiscussed ? 
              (&quot;To support encyclopedic discussion of this work in this article. &quot; +
               &quot;The illustration is specifically needed to support the following point(s): &quot; +
               &quot;&lt;br/&gt;\n&quot; + opts.NF3DPurpose) : null)
          );
          descFields.Replaceability = &quot;n.a.&quot;;
          descFields.Commercial    = &quot;n.a.&quot;;
          descFields[&quot;Other information&quot;] = (
             opts.NF3DOptionSame ?
             (&quot;The image was created and published by the same author who also &quot; +
              &quot;holds the rights to the original object, and no alternative depiction &quot; +
              &quot;could be suitably created.&quot;) :
             (&quot;The author of the image has released the photographic work under a &quot; +
              &quot;free license, or it is in the public domain: &quot; + opts.NF3DPermission)
          );
          break; 
          
       case 'OptionNFExcerpt':
          // FURs for screenshots etc. don't normally need to bother
          // about replaceability (with free images) and with commercial role,
          // but do need to bother about purpose and about replaceability with text.
          descFields.Purpose        = opts.NFPurpose;
          descFields.Replaceability_text = opts.NFReplaceableText;
          descFields.Replaceability = &quot;n.a.&quot;;
          descFields.Commercial     = &quot;n.a.&quot;;
          break;
          
       case 'OptionNFCover':
          // cover art gets standard rationales.
          descFields.Purpose = 
             &quot;to serve as the primary means of visual identification &quot; +
             &quot;at the top of the article dedicated to the work in question.&quot;;
          descFields.Replaceability = &quot;n.a.&quot;;
          descFields.Commercial     = &quot;n.a.&quot;;
          break;
  
       case 'OptionNFLogo':
          // logos get standard rationales.
          descFields.Purpose = 
             &quot;to serve as the primary means of visual identification &quot; +
             &quot;at the top of the article dedicated to the entity in question.&quot;;
          descFields.Replaceability = &quot;n.a.&quot;;
          descFields.Commercial     = &quot;n.a.&quot;;
          break;
 
       case 'OptionNFPortrait':
          // as with other historic photographs, it is useful to have both
          // original publication and direct source
          descFields.Source = fuwAppendLines([
             fuwSurroundString(&quot;'''Original publication''': &quot;, opts.Publication),
             &quot;&lt;br/&gt;\n&quot;,
             fuwSurroundString(&quot;'''Immediate source''': &quot;, opts.Source)
          ]);   
          descFields.Purpose = 
             &quot;for visual identification of the person in question, &quot; +
             &quot;at the top of his/her biographical article&quot;;
          descFields.Replaceability = opts.NFReplaceable;
          descFields.Commercial = opts.NFCommercial;
          descFields['Other information'] = 
             &quot;The subject of the photograph has been deceased since: &quot; + opts.NFPortraitDeceased;
          break;
          
       case 'OptionNFMisc':
          descFields.Source = fuwAppendLines([
             fuwSurroundString(
                &quot;'''Original publication''': &quot;, 
                opts.Publication,
                &quot;&lt;br/&gt;\n'''Immediate source:''' &quot;),
             &quot;&quot;,
             opts.Source
          ]);   
          descFields.Purpose = opts.NFPurpose;
          descFields.Replaceability = opts.NFReplaceable;
          descFields.Replaceability_text = opts.NFReplaceable_text;
          descFields.Commercial = opts.NFCommercial; 
          break;     
    };
 
    if (opts.OptionNonFree) {
       // common stuff for all non-free files:
       
       // Minimality field (same for all NF options):
       descFields.Minimality = opts.NFMinimality;
       
       // append optional &quot;extra license&quot; selector and &quot;AnyOther&quot; fields
       // to &quot;Other information&quot; field:
       descFields['Other information'] = fuwAppendLines([
          descFields['Other information'],
          &quot;&lt;br/&gt;\n&quot;,
          fuwSurroundString('\{\{', opts.NFExtraLicense, '\}\}'),
          &quot;&lt;br/&gt;\n&quot;,
          opts.AnyOther
       ]);
    }
    else {
       // common stuff for all free files:
       descFields.Other_versions = ''
       this.otherInfo = fuwAppendLines([this.otherInfo, &quot;\n\n&quot;, opts.AnyOther]);
    
    }
 
 };
 
 fuwGlobal.prototype.formatOutput = function(forCommons) {
    var baseForm = this.ScriptForm;
    var targetForm = this.TargetForm;
    if (fuwTesting) {
       var testForm   = this.TestForm;
    }
    var opts = this.opts;
    var otherInfo = this.otherInfo;
    var descFields = this.descFields;
 
    var summary = &quot;{{&quot; + this.getDescriptionTemplateName();
 
    // assemble all fields into the wikitext of the description page:
    var fieldOrder = [
       'Source', 'Date', 'Author', 'Permission', 'Other_versions',
       'Article', 'Purpose', 'Replaceability', 'Replaceability_text', 
       'Minimality', 'Commercial', 'Other information'
    ];
    summary += &quot;\n|Description = &quot; + fuwPackInfo(descFields['Description'], forCommons);
    for (var i = 0; i &lt; fieldOrder.length; i++) {
       if (descFields[fieldOrder[i]]) {
          summary += &quot;\n|&quot; + fieldOrder[i] + &quot; = &quot; + descFields[fieldOrder[i]];
       }
    }
    summary += &quot;\n}}\n&quot;;
    if (otherInfo) {
       summary += &quot;\n;Other information:\n&quot; + fuwPackInfo(otherInfo, forCommons) + &quot;\n&quot;;
    }
 
    var editSummary = this.getEditSummary();
    
    var license = this.getLicense();
    
    if (forCommons) {
       // pack our description info into an url pointing to the 
       // standard Commons Special:Upload
       // with pre-loaded description fields
 
       summary = fuwSubst(&quot;Upload marker added by en.wp UW&quot;) + &quot;\n&quot; + summary;
       summary = summary.replace(/\{\{OTRS pending\}\}/g, fuwSubst(&quot;OP&quot;));
 
       if (license.special) {
          // manually format the whole description page including the license tag, if it
          // isn't one of the bare standard licenses in the dropdown box. Otherwise,
          // submit description summary and license as two separate url parameters.
          summary = summary + &quot;\n\n&quot; + license.special;
       }
       return (fuwGetCommonsURL() +
          &quot;?title=Special:Upload&quot; +
          &quot;&amp;wpUploadDescription=&quot; +
          encodeURIComponent(summary) +
          (license.standard ? 
           (&quot;&amp;wpLicense=&quot; + encodeURIComponent(license.standard)) : '') +
          &quot;&amp;wpDestFile=&quot; + 
          encodeURIComponent(opts.InputName));
    }
    else {
       // pack all description into a single &quot;text&quot; parameter to be submitted
       // to the local api.php upload.
       summary = &quot;==Summary==\n&quot; + 
          summary + 
          &quot;\n==Licensing==\n&quot; + 
          (license.standard ? (&quot;\{\{&quot; + license.standard + &quot;\}\}&quot;) : license.special) +
          this.getTrackingCategory();
          
       if (fuwTesting) {
          // Testing mode: show our data in the dummy form
          // at the bottom of the page.
          fuwGet('placeholderSandboxFilename').innerHTML = opts.InputName;
          this.TestForm.SandboxSummary.value = editSummary;
          this.TestForm.SandboxText.value = summary;
          fuwSetVisible('placeholderTestForm', true);
       }
       // write output parameters into target form
       // I can't believe IE7 is too stupid to simply understand &quot;this.TargetForm.filename.value&quot;.
       ($('#TargetForm [name=&quot;filename&quot;]')[0]).value = opts.InputName;
       ($('#TargetForm [name=&quot;text&quot;]'    )[0]).value = summary;
       ($('#TargetForm [name=&quot;comment&quot;]' )[0]).value = editSummary;
       ($('#TargetForm [name=&quot;token&quot;]'   )[0]).value = mw.user.tokens.get('csrfToken');
 
    }
    
 };
 
 function fuwHasUserGroup(group) {
    // workaround because old IE versions don't have array.indexOf :-(
    for (i = 0; i &lt; mw.config.get('wgUserGroups').length; i++) {
       if (mw.config.get('wgUserGroups')[i] == group) {
          return true;
       }
    }
    return false
 }
 
 fuwGlobal.prototype.getUserStatus = function() {
    // function to determine the experience status and userrights of the current user:
    // 'anon': not logged in; can't use script.
    // 'notAutoconfirmed': can't use local upload, but may use script to prepare upload for Commons
    // 'newbie': autoconfirmed but editcount &lt; 100 
    //    (may be used in future to adapt instructions more to newbie needs)
    // 'problem': autoconfirmed but has 3 or more image-related warnings or deletion notifications among recent user talk entries
    //    (may be used in future to produce more strongly worded instructions)
    // 'autoconfirmed': regular user
    // 'sysop'
 
    if (mw.config.get('wgUserName')) {
       if (fuwHasUserGroup('sysop')) {
          this.userStatus = 'sysop';
       }
       else if (fuwHasUserGroup('autoconfirmed') || fuwHasUserGroup('confirmed')) {
          this.userStatus = 'autoconfirmed';
          $.ajax({
             url     : mw.util.wikiScript( 'api' ),
             type    : 'GET',
             dataType: 'xml',
             traditional : true,
             data:   {
                      format: 'xml',
                      action: 'query',
                      meta  : 'userinfo',
                      uiprop: 'editcount',
                      prop  : 'revisions',
                      titles: 'User talk' + mw.config.get('wgUserName'),
                      rvprop: 'comment|user',
                      rvlimit: 30
                     },      
             success: function(data) {
             // callback func     
                var fuw = window.fuw;
                if (data) {
                   var ui = data.getElementsByTagName('userinfo');
                   if (ui) {
                      var editcount = ui[0].getAttribute('editcount');
                      if (editcount &lt; 100) {
                         fuw.userStatus = 'newbie';
                      }
                   }
                   var revs = data.getElementsByTagName('rev');
                   var countWarn = 0;
                   for (i = 0; i &lt; revs.length; i++) {
                      var rev = revs[i];
                      var usr = rev.getAttribute('user');
                      var cmt = rev.getAttribute('comment');
                      if ((usr == 'ImageTaggingBot') ||
                          (cmt.search(/(tagging for deletion of \[\[File)|(Uploading files missing)|(File (source and )?copyright licensing problem)|(Speedy deletion nomination of \[\[File)|(Notification: listing at \[\[possibly unfree files)/) &gt;= 0)) {
                         countWarn += 1;   
                      }
                   }
                   if (countWarn &gt;= 3) {
                      fuw.userStatus = 'problem';
                   }
                }
             }
          });
       }
       else {
          this.userStatus = 'notAutoconfirmed';
       }
    }
    else {
       this.userStatus = 'anon';
    }
 };
 
 // =================================================================
 // Convenience function for getting the regular index.php
 // interface of Commons. Not very elegant.
 // =================================================================
 function fuwGetCommonsURL() {
    if (document.URL.match(/^https:/)) 
       return &quot;https://commons.wikimedia.org/w/index.php&quot;;
    else
       return &quot;http://commons.wikimedia.org/w/index.php&quot;;
 }  
 
 // ==================================================================
 // functions for building form elements
 // ==================================================================
 fuwMakeRadiobutton = function(group, option, checked, event) {
    // Stupid IE7 doesn't get &quot;value&quot; attribute unless it's created in this convoluted way.
    // Annoying.   
    var node = $('&lt;input type=&quot;radio&quot; id=&quot;' + option + '&quot; name=&quot;' + group + '&quot; value=&quot;' + option + '&quot;&gt;&lt;/input&gt;')[0];
    if (checked) node.checked = true;
    node.onclick = event || fuwRadioClick;
    node.onclick = event || fuwRadioClick;
    fuwAppendInput(option, node);
 };
 fuwMakeTextfield = function(label, event) {
    var node  = document.createElement('input');
    node.type = 'text';
    node.name = label;
    node.size = fuwDefaultTextboxLength;
    node.onchange = event || fuwUpdateOptions;
    // only for testing:
    //node.value = label;
    fuwAppendInput(label, node);
 };
 fuwMakeTextarea = function(label, event) {
    var node  = document.createElement('textarea');
    node.name = label;
    node.rows = fuwDefaultTextareaLines;
    node.style.width = fuwDefaultTextareaWidth;
    node.onchange = event || fuwUpdateOptions;
    //only for testing:
    //node.innerHTML = label;
    fuwAppendInput(label, node);
 };
 fuwMakeCheckbox = function(label, checked, event) {
    var node  = document.createElement('input');
    node.name = label;
    node.type = 'checkbox';
    //only for testing:
    //node.title= label;
    node.checked = checked;
    node.onchange = event || fuwUpdateOptions;
    fuwAppendInput(label, node);
 }
 fuwMakeHiddenfield = function(name, value, id) {
    var node   = document.createElement('input');
    node.name  = name;
    node.type  = 'hidden';
    node.value = value;
    fuwAppendInput((id || name), node);
 };
 fuwMakeAnchor = function(label, href, content) {
    var node   = document.createElement('a');
    node.name  = label;
    node.target= &quot;_blank&quot;;
    node.href  = href;
    node.innerHTML = content;
    fuwAppendInput(label, node);
 };
 fuwMakeSelection = function(name, values) {
    var root = document.createElement('select');
    var current = root;
    try {
       for (i=0; i&lt;values.length; i++) {
          var line = values[i];
          var entry;
          if (line.length == 0) {
             current = root;
          }
          else if (line.length == 1) {
             entry = document.createElement('optgroup');
             entry.setAttribute('label', line[0]);
             root.appendChild(entry);
             current = entry;
          }
          else {
             entry = document.createElement('option');
             entry.setAttribute('value', line[0]);
             entry.setAttribute('title', '{{' + line[0] + '}}');
             entry.innerHTML = line[1];
             if (line.length &gt; 2) {
                entry.setAttribute('selected', 'selected');
             } 
             current.appendChild(entry);
          }
       }
    } catch (e) { alert(&quot;Name: &quot; + name + &quot;, i=&quot; + i); }
    root.name = name;
    root.onchange = fuwUpdateOptions;
    fuwAppendInput(name, root);
 };
 function fuwMakeWikilink(place, target, redlink, display) {
    
    place = fuwGet(place);
    var id = place.id;
    var anchor;
    if (place.tagName == 'A') {
       anchor = place;
    }
    else {
       anchor = document.createElement('a');
       place.appendChild(anchor);
    }
    anchor.href = mw.util.getUrl(target);
    anchor.title = target;
    anchor.innerHTML = target;
    anchor.className = (redlink ? 'new' : null);
 }
 
 function fuwAppendInput(label, content) {
    // append a newly created input element to an existing
    // span element marked as id=&quot;placeholderXYZ&quot;
    var node = fuwGet('placeholder' + label);
    var old  = fuwGet(label);
    if (old) {
       old.parentNode.removeChild(old);
    }
    content.id = content.id || label;
    if (node) {
       while (node.hasChildNodes()) {
          node.removeChild(node.firstChild);
       }
       node.appendChild(content);
    }
 }
 
 // ======================================================
 // move an element away from its current position
 // and append it to a target element if condition is true
 // ======================================================
 function fuwMove(mv, tg, condition, toStart) {
    if (condition) {
       move   = fuwGet(mv);
       target = fuwGet(tg);
       if (move &amp;&amp; target) {
          var parent = move.parentNode;
          if (! (target===parent)) {
             parent.removeChild(move);
             if (toStart) {
                target.insertBefore(move, target.firstChild);
             }
             else {
                target.appendChild(move);
             }
          }
       }
       else {
          alert(&quot;Can't find elements: move=&quot; + mv + &quot;(&quot; + move + &quot;), target=&quot; + tg + &quot;(&quot; + target + &quot;)&quot;);
       } 
    }
    return condition;
 }
 
 // ===================================================
 // make an element visible/invisible
 // ===================================================
 function fuwSetVisible(tg, condition) {
    target = fuwGet(tg);
    if (target) {
       if (condition) {
          $(target).show();
       }
       else {
          $(target).hide();
       }
    }
    else {
       alert(&quot;Element not found: &quot; +  ((!!tg &amp;&amp; !!tg.nodeType) ? tg.id : tg));
    }
 }
 
 // ===================================================
 // set enabled/disabled status for an element and/or
 // all input controls contained in it.
 // ===================================================
 function fuwSetEnabled(tg, condition) {
    target = fuwGet(tg);
    try {
       var elements = (target.tagName.match(/^(input|textarea|select|button|a)$/i) ? 
          [target] :
          $('#' + target.id + ' *'));
       for (i = 0; i&lt;elements.length; i++) {
          if (elements[i].tagName.match(/^(input|textarea|select|button|a)$/i)) {
             elements[i].disabled = (condition ? null : &quot;disabled&quot;);
          }
       }
    } catch (e) { alert(&quot;Element not found: &quot; +  ((!!tg &amp;&amp; !!tg.nodeType) ? tg.id : tg)); }
 }
 
 // ===================================================
 // convenience function to check whether a given
 // element is currenly visible. Needs to check display
 // property of the element and its ancestors
 // ===================================================
 function fuwIsVisible(el) {
    element = fuwGet(el);
    if (!element) return false;
    el = element.id;
    
    var visible = true;
    while (! (element === document.body)) {
       if (element.style.display == &quot;none&quot;) {
          visible = false;
          break;
       }
       element = element.parentNode;
    }
    return visible;
 }
 
 // ===================================================
 // cleanup filename
 // ===================================================
 function fuwCleanFilename() {
    var nameBox = window.fuw.ScriptForm.InputName;
    var oldname = name = $.trim(nameBox.value);
 
    if (name) {
       // strip accidentally added [[   ]] or [[:  ]] brackets
       name = name.replace(/(^\[\[:?)|(\]\]$)/g, &quot;&quot;);
       // strip accidentally added &quot;File:&quot; prefix
       name = name.replace(/^(File|Image):/, &quot;&quot;);
       // replace underscores with spaces
       name = name.replace(/_/g, &quot; &quot;);
       // uppercase first letter
       name = name[0].toUpperCase() + name.slice(1);
    }
    if (oldname != name) {
       nameBox.value = name;
    }
    // always return true so the next validation step will proceed:
    return true;
 }
 
 
 // ==================================================
 // check filename for technically illegal 
 // characters, trying to fix them automatically
 // ==================================================
 function fuwCheckLegalFilename() {
    var nameBox = window.fuw.ScriptForm.InputName;
    var oldname = name = $.trim(nameBox.value);
 
    if (name) {
       // resolve accidentally entered html entities and URI-encoded %XX character codes
       name = name.replace(/\&amp;[a-z]+;/g, fuwHtmlEntityDecode);
       name = name.replace(/(\%[A-F0-9]{2,2})/g, decodeURI);
       // remove illegal characters # &lt; &gt; [ ] | { } /:
       // using a best guess for an acceptable replacement
       name = name.replace(/[&lt;\[\{]/g, &quot;(&quot;);
       name = name.replace(/[&gt;\]\}]/g, &quot;)&quot;);
       name = name.replace(/[#:\|]/g,  &quot;,&quot;);
       name = name.replace(/\//g, &quot;-&quot;);
       // remove sequences of tildes
       name = name.replace(/\~{3,}/g, &quot;---&quot;);
       // remove initial slash
       name = name.replace(/^\//, &quot;&quot;);
    }
    
    if (oldname != name) {
       window.fuw.warn.IllegalChars = true;
       nameBox.value = name;
       return false;
    }
    else {
       window.fuw.warn.IllegalChars = false;
       return true;
    }
 }
 function fuwHtmlEntityDecode(str) {
    // hack to translate accidentally entered html entity code
    // into actual characters
    var ta=document.createElement('textarea');
    ta.innerHTML=str.replace(/&lt;/g,'&amp;lt;').replace(/&gt;/g,'&amp;gt;');
    return ta.value;
 }
 
 // =======================================================
 // Check against various common patterns of poorly chosen
 // filenames (too short / too generic)
 // =======================================================
 function fuwCheckPoorFilename() {
    var nameBox = window.fuw.ScriptForm.InputName;
    var name = $.trim(nameBox.value);
 	name = name.replace(/\.(png|gif|jpg|jpeg|xcf|pdf|mid|ogg|ogv|svg|djvu|tiff|tif|oga)$/i, &quot;&quot;);
 
    // name should be at least 10 characters long, excluding file type extension
    var tooShort = (name.length &lt; 10);
    
    // common generic filename patterns: 
    // IMG......jpg
    // Image....jpg
    // DSC......jpg
    // Picture......jpg
    // Pic..........jpg
    // anything that has fewer than 3 alphabetic letters and then just numbers
    var pattern = /^(img|image|dsc|picture|pic)?(\\s*|\\_*|[a-z]{,3})?\\d+$/i;
    var auto = name.match(pattern);
 
    window.fuw.warn.BadFilename = (tooShort || auto);
    return !tooShort &amp;&amp; !auto;
 }
 
 // =======================================================
 // check if file extensions match between local filename
 // and target filename input box. Automatically append 
 // appropriate extension to target filename if they don't.
 // =======================================================
 function fuwCheckFileExtension() {
    var nameBox = window.fuw.ScriptForm.InputName;
    var name = $.trim(nameBox.value);
    var fileBox = window.fuw.TargetForm.file;
    var file = fileBox.value;
    
    // cancel check if no filename has been provided yet
    if (!file || !name) return true;
    
    var extensions = /.+\.(png|gif|jpg|jpeg|xcf|pdf|mid|ogg|ogv|svg|djvu|tiff|tif|oga)$/i;
    var mimetypes = {
       &quot;png&quot;  : &quot;image/png&quot;,
       &quot;gif&quot;  : &quot;image/gif&quot;,
       &quot;jpg&quot;  : &quot;image/jpeg&quot;,
       &quot;jpeg&quot; : &quot;image/jpeg&quot;,
       &quot;xcf&quot;  : &quot;image/x-xcf&quot;,
       &quot;pdf&quot;  : &quot;application/pdf&quot;,
       &quot;mid&quot;  : &quot;audio/rtp-midi&quot;,
       &quot;ogg&quot;  : &quot;audio/ogg&quot;,
       &quot;ogv&quot;  : &quot;video/ogg&quot;,
       &quot;svg&quot;  : &quot;image/svg+xml&quot;,
       &quot;djvu&quot; : &quot;image/vnd.djvu&quot;,
       &quot;tiff&quot; : &quot;image/tiff&quot;,
       &quot;tif&quot;  : &quot;image/tiff&quot;,
       &quot;oga&quot;  : &quot;video/ogg&quot;
    };   
 
    var found = extensions.exec(file);
    var fileExt = found ? found[1].toLowerCase() : &quot;&quot;;
    found = extensions.exec(name);
    var nameExt = found ? found[1].toLowerCase() : &quot;&quot;;
    var mime = mimetypes[fileExt]; 
    
    if (fileExt &amp;&amp; mime &amp;&amp; (mimetypes[nameExt] != mime)) {
       nameBox.value = name.replace(/\.?$/, ('.' + fileExt));
    }
    return true;
 }
 
 // ============================================================
 // Check if a file under the chosen name already exists,
 // either locally or on Commons.
 // Store results in the fuw.warn object, so warnings will
 // be displayed on the next fuwUpdateOptions() call
 // ============================================================
 function fuwCheckFileExists() {
    // this is an asynchronous AJAX function.
    // results won't yet be present when this function returns.
 
    var nameBox = window.fuw.ScriptForm.InputName;
    var name = $.trim(nameBox.value);
 
    // using the jQuery wrapper for the Ajax functionality:
    $.ajax({
       url     : mw.util.wikiScript( 'api' ),
       type    : 'GET',
       dataType: 'xml',
       traditional : true,
       data:   {
                format: 'xml',
                action: 'query',
                titles: 'File:' + name,
                prop  : 'imageinfo',
                iiprop: 'url|user',
                iiurlwidth: 120
               },      
       success: function(resp) {
       // callback function, called when API query has succeeded:
          // see if the request has returned info from an existing image:
          var foundlist = resp.getElementsByTagName('ii');
          var exists = (foundlist.length &gt;= 1);
          var isCommons = false;
          if (exists) {
 
             // extract description data from http response.
             // see https://www.mediawiki.org/wiki/API:Properties#imageinfo_.2F_ii 
             // for structure of API response
             var foundImg = foundlist[0];
             isCommons = (foundImg.parentNode.parentNode.getAttribute('imagerepository')=='shared');
 
             // need this data for creating our own image thumb link
             var width = foundImg.getAttribute('thumbwidth');
             var height = foundImg.getAttribute('thumbheight');
             var thumbURL = foundImg.getAttribute('thumburl');
             var lastUser = foundImg.getAttribute('user');
             var descURL = foundImg.getAttribute('descriptionurl');
 
             // API returns link to local description page even for Commons images.
             // However, we want a direct link to Commons.
             if (isCommons) {
                descURL = descURL.replace(/en\.wikipedia\.org/, &quot;commons.wikimedia.org&quot;);
                descURL = descURL.replace(/\/\/secure\.wikimedia\.org\/wikipedia\/en/, &quot;commons.wikimedia.org&quot;);
             }
 
             // build the image info into the warning section of our page:
             thumbDiv = fuwGet('warningImageThumb');
             if (thumbDiv) {
             
                // make all links point to description page:
                var thumbA = thumbDiv.getElementsByTagName('a');
                for (i = 0; i&lt;thumbA.length; i++) {
                   thumbA[i].setAttribute('href', descURL);
                }
                // insert the image itself:
                var thumbImg = thumbDiv.getElementsByTagName('img');
                if (thumbImg.length &gt; 0) {
                   thumbImg = thumbImg[0];
                   thumbImg.setAttribute('src', thumbURL);
                   thumbImg.setAttribute('width', width);
                   thumbImg.setAttribute('height', height);
                }
                // insert the name of the last uploader:
                var thumbSpan = fuwGet('existingImageUploader');
                // TO DO: turn this into a proper link
                if (thumbSpan) thumbSpan.innerHTML = lastUser;
             }
 
             
          }
          warn = window.fuw.warn;
          warn.ImageOnCommons = exists &amp;&amp; isCommons;
          warn.ImageExists    = exists &amp;&amp; !isCommons;
 
          fuwUpdateOptions();
       }
    });
 }
 
 // ===========================================================
 // onchange event handler for the local filename box
 // ===========================================================
 fuwValidateFile = function() {
    fuwCheckFileExtension();
    fuwUpdateOptions();
 }
 
 // ===========================================================
 // onchange event handler for the name input box
 // ===========================================================
 fuwValidateFilename = function() {
    fuwCleanFilename();
    if (
       fuwCheckLegalFilename() &amp;&amp;
       fuwCheckPoorFilename() &amp;&amp;
       fuwCheckFileExtension()) {
       // after fuwCheckFileExists(),
       // fuwUpdateOptions will be triggered
       // by the callback function after Ajax completion
       fuwCheckFileExists();
    }
    else {
       // if there's been no Ajax call.
       fuwUpdateOptions();
    }
 };
 
 // ==========================================================
 // function fuwValidateNFArticle()
 // ==========================================================
 // This is the validation routine for the obligatory
 // article-to-be-used-in field for non-free files. It queries
 // api.php about the target article through an Ajax call.
 // It will store error info in the fuw.warn object,
 // triggering the following error on the next updateOptions():
 // * warningNFArticleNotFound : target page doesn't exist.
 // * warningNFArticleNotMainspace : target is not an article. 
 // * warningNFArticleDab : target is a disambiguation page.
 // Redirects will automatically be substituted.
 // ==========================================================
 fuwValidateNFArticle = function() {
    
    var nameBox = window.fuw.ScriptForm.NFArticle;
    oldname = name = nameBox.value;
    
    // cleanup article name:
    // automatically fix accidentally added [[ ... ]] and
    // regularize underscores
    name = $.trim(name);
    name = name.replace(/(^\[\[)|(\]\]$)/g, &quot;&quot;);
    // automatically fix article names entered as full urls:
    name = name.replace(/^https?:\/\/en\.wikipedia\.org\/wiki\//, &quot;&quot;);
    name = name.replace(/^https?:\/\/en\.wikipedia\.org\/w\/index\.php\?title=/, &quot;&quot;);
    name = name.replace(/_/g, &quot; &quot;);
    if (name != oldname) nameBox.value = name;
    
    // do nothing more if field was blank
    if (!name) return;
 
    // using the jQuery wrapper for the Ajax functionality:
    $.ajax({
       url     : mw.util.wikiScript( 'api' ),
       type    : 'GET',
       dataType: 'xml',
       traditional : true,
       data:   {
                format: 'xml',
                action: 'query',
                titles: name,
                prop  : 'info|categories|links'
               },      
       success: function(resp) {
       // callback function, called when API query has succeeded:
          var errorType = 0;
          var pg = resp.getElementsByTagName('page')[0];
          var title = pg.getAttribute('title');
          var target = title;
          if (pg.getAttribute('missing') != null) {
             // no page found under this title.
             errorType = 1;
          }           
          else {
             var userspace = false;
             var ns = pg.getAttribute('ns');
             var rd = pg.getAttribute('redirect');
             if (ns != 0) {
                // not a mainspace page!
                errorType = 2;
 
                // try to detect if the target might be a user space draft:               
                if (title.match(new RegExp(&quot;User( talk)?:&quot; + mw.config.get('wgUserName')))) {
                   userspace = true;
                }
             }
             else if (rd != null) {
                // redirect page
                // API returns an empty redirect=&quot;&quot; attribute if
                // the page is a redirect
                var targets = pg.getElementsByTagName('pl');
                for (i=0; i&lt;targets.length; i++) {
                   var link = targets[i];
                   if (link.getAttribute('ns')==0) {
                      target = link.getAttribute('title');
                      errorType = 3;
                      break;
                   }
                }
             }
             else {
                // check for disambiguation categories
                var cats = pg.getElementsByTagName('cl');
                for (i=0; i&lt;cats.length; i++) {
                   var cat = cats[i];
                   if (cat.getAttribute('title') == &quot;Category:All disambiguation pages&quot;) {
                      errorType = 4;
                      break;
                   }
                }  
             }
          }
          warn = window.fuw.warn;
          warn.NFArticleNotFound = (errorType==1);
          warn.NFArticleNotMainspace = (errorType==2);
          warn.UserspaceDraft = ((errorType==2) &amp;&amp; userspace);
          warn.NFArticleDab = (errorType==4);
          warn.NFArticleOK  = (errorType==0);
 
          // fix links in error messages:
          if (warn.NFArticleNotFound) {
             fuwMakeWikilink(fuwGet('warningNFArticleNotFound').getElementsByTagName('A')[0], target, true);
          }
          else if (warn.NFArticleNotMainspace) {
             fuwMakeWikilink(fuwGet('warningNFArticleNotMainspace').getElementsByTagName('A')[0], target);
          }
          else if (warn.NFArticleDab) {
             fuwMakeWikilink(fuwGet('warningNFArticleDab').getElementsByTagName('A')[0], target);
          }
          else if (warn.NFArticleOK) {
             fuwMakeWikilink(fuwGet('NFArticleOK').getElementsByTagName('A')[0], target);
          }
                        
          if (errorType==3) {
             // automatically replace title with redirect target
             window.fuw.ScriptForm.NFArticle.value = target;
             // need to recursively call validation again now
             //if (confirm(name + &quot; is a redirect. Follow it to &quot; + target + &quot;?&quot;)) {
                fuwValidateNFArticle();
             //}
          }
          else {
             fuwUpdateOptions();
          }          
       }
    });
 };
 
 // ================================================
 // manually reload script (just for testing)
 // ================================================
 function fuwReload() {
    mw.loader.load( 'http://localhost/script/uploadscript.js' );
    fuwReset();
 }
 
 // ================================================
 // reset forms
 // TO DO: add a button that actually triggers this.
 // ================================================
 function fuwReset() {
    var forms = mw.util.$content[0].getElementsByTagName('form');
    for (i = 0; i &lt; forms.length; i++) {
       forms[i].reset();
       window.fuw.warn = { };
       window.fuw.opts = { };
    }
    fuwSetVisible('UploadScriptArea', true);
    fuwSetVisible('fuwSuccess', false);
    fuwSetVisible('fuwWaiting', false);
    fuwUpdateOptions();
 }
 
 // ===============================================
 // convenience functions for string handling
 // ===============================================
 function fuwAppendLines(parts) {
    // assemble a string from an array of strings.
    // treat every second element as a conditional
    // separator that will be included only if 
    // surrounding elements are non-empty.
    var build = &quot;&quot;;
    for (var i = 0; i &lt; parts.length; i += 2) {
       if (parts[i]) {
          if (build) build += parts[i - 1];
          build += parts[i];
       }
    }
    return build;
 }
 function fuwSurroundString(prefix, content, suffix) {
    // put a prefix and a suffix on a string, 
    // if the input string is non-empty.
    if (content) 
       return (prefix ? prefix : &quot;&quot;) + content + (suffix ? suffix : &quot;&quot;); 
    else return &quot;&quot;;
 }
 
 // ========================================================
 // convenience function for accessing the contents of the
 // dummy TargetIFrame
 // ========================================================
 function fuwGetDocumentFromIFrame(iframe) {
    var doc = (iframe.contentDocument ? iframe.contentDocument : iframe.contentWindow.document);
    if (doc.XMLDocument) {
       doc = doc.XMLDocument;
    }
    return doc;
 }
 // ========================================================
 // event handler for the dummy TargetIFrame's onload event.
 // TO DO: expand stub to add real notification of success,
 // link to new file page, instructions about how to include
 // file in articles, etc.
 // ========================================================
 function fuwUploadCompleted() {
    var doc = fuwGetDocumentFromIFrame(fuwGet('TargetIFrame'));
    if (doc) {
       //alert(doc);
       fuwSetVisible('successThumb', false);
 
       var fuw = window.fuw;
       var name = fuw.opts.InputName;
 
       var uploads = doc.getElementsByTagName('upload');
       var success = false;
       for (i = uploads.length-1; i&gt;=0; i--) {
          if (uploads[i].getAttribute('result') == 'Success') {
             success = true;
             // need to get the real resulting filename here; might be different from the requested one in some cases.
             name = uploads[i].getAttribute('filename');
             break;
          }
       }
       if (success) {
 
          // need another ajax call to check the file is actually there,
          // and to retrieve its direct thumb img url:
          $.ajax({
             url     : mw.util.wikiScript( 'api' ),
             type    : 'GET',
             dataType: 'xml',
             traditional : true,
             data:   {
                      format: 'xml',
                      action: 'query',
                      titles: 'File:' + name,
                      prop  : 'imageinfo',
                      iiprop: 'url',
                      iiurlwidth: 120
                     },      
             success: function(resp) {
                // callback function, called when API query has succeeded:
                // see if the request has returned info from an existing image:
 
                var foundImg = resp.getElementsByTagName('ii')[0];
                if (foundImg) {
 
                   // need this data for creating our own image thumb link
                   var width = foundImg.getAttribute('thumbwidth');
                   var height = foundImg.getAttribute('thumbheight');
                   var thumbURL = foundImg.getAttribute('thumburl');
                   var lastUser = foundImg.getAttribute('user');
                   var descURL = foundImg.getAttribute('descriptionurl');
 
                   // build the thumbnail in the success message:
                   thumbDiv = fuwGet('successThumb');
                   
                   // make link point to description page:
                   var thumbA = thumbDiv.getElementsByTagName('a')[0];
                   thumbA.href = descURL;
 
                   // insert the image itself:
                   var thumbImg = thumbDiv.getElementsByTagName('img')[0];
                   thumbImg.setAttribute('src', thumbURL);
                   thumbImg.setAttribute('width', width);
                   thumbImg.setAttribute('height', height);
                   
                   fuwSetVisible(thumbDiv, true);
                }
             }
          });
          fuwMakeWikilink(
             fuwGet('fuwSuccessLink2').getElementsByTagName('a')[0],
             'File:' + name);
          fuwGet('placeholderExFilename1').innerHTML = name;
          fuwGet('placeholderExFilename2').innerHTML = name;
          fuwSetVisible('fuwSuccess', true);
          fuwSetVisible('fuwWaiting', false);
       }
       else {
          var err = doc.getElementsByTagName('error');
          if (err) {
             var info = err[0].getAttribute('info');
             var details = err[0].getElementsByTagName('detail');
             var add = &quot;&quot;;
             for (i = 0; i &lt; details.length; i++) {
                if (add.length &gt; 0) add += &quot;, &quot;;
                add += details[i].textContent;
             }
             if (add) {
                info = info + &quot; (&quot; + add + &quot;)&quot;;
             }
             alert(&quot;Upload failed: &quot; + info);
          }
          else {
             alert(&quot;Unknown error: upload may have failed.&quot;);
          }
       }
    }
 }
 
 // ========================================================
 // clean out dummy IFrame before submitting a request
 // ========================================================
 function fuwResetTargetIFrame() {
    var doc = fuwGetDocumentFromIFrame(fuwGet('TargetIFrame'));
    if (doc) {
       while (doc.hasChildNodes()) {
          doc.removeChild(doc.firstChild);
       }
    }
 }
 
 // ========================================================
 // Event handler for the real submit button
 // ========================================================
 function fuwSubmitUpload() {
    
    var fuw = window.fuw;
    var frm = fuw.TargetForm;
 
    fuw.collectInput();
    fuw.formatOutput(false);
 
    // we will use the iframe's onload event to trigger a function that
    // adds success notification etc.
    fuwResetTargetIFrame();
    var ifr = fuwGet('TargetIFrame');
    if (ifr.attachEvent) {
       // workaround for IE, according to 
       // http://www.nczonline.net/blog/2009/09/15/iframes-onload-and-documentdomain/
       ifr.attachEvent(&quot;onload&quot;, fuwUploadCompleted);
    }
    else {
       // all other browsers
       ifr.onload = fuwUploadCompleted;
    }
 
    if (fuwTesting) {
       fuwSetVisible('placeholderTestForm', false);
    }
    fuwSetVisible('UploadScriptArea', false);
 
    fuwMakeWikilink(
      fuwGet('fuwSuccessLink').getElementsByTagName('a')[0], 'File:' + fuw.opts.InputName);
    fuwSetVisible('fuwWaiting', true);
 
    frm.submit();
    var opts = window.fuw.opts;
    // the API won't overwrite the description page text while overwriting
    // a file, which is really, really, really annoying and stupid.
    // So in the opts.OverwriteDifferent scenario, we need to edit
    // the description page through a separate ajax call. Dang.
    if (opts.OverwriteDifferent) {
       $.ajax({
          url   : mw.util.wikiScript('api'),
          type  : 'POST',
          dataType : 'xml',
          data  : {
                   format : 'xml',
                   action : 'edit',
                   title  : 'File:' + opts.InputName,
                   token  : mw.user.tokens.get('csrfToken'),
                   summary : opts.EditSummary,
                   text   : ($('#TargetForm .[name=&quot;text&quot;]')[0]).value
 
                  }
       });
    }
 }
 
 // =======================================================
 // Event handler for the Commons submit button
 // =======================================================
 function fuwSubmitCommons() {
    var fuw = window.fuw;
    fuw.collectInput();
    var url = fuw.formatOutput(true);
    alert(&quot;You will now be redirected to Commons. \nPlease use the Commons upload form to add categories to your file description, and then complete the upload.&quot;);
    window.location = url;
 }
 
 // =======================================================
 // Event handler for the test submit button
 // (write description string to sandbox only)
 // =======================================================
 function fuwSubmitSandbox() {
    var frm = window.fuw.TestForm;
    $.ajax({
       url     : mw.util.wikiScript( 'api' ),
       type    : 'POST',
       dataType: 'xml',
       data:   {
                format: 'xml',
                action: 'edit',
                title : mw.config.get('wgPageName') + &quot;/sandbox&quot;,
                token : mw.user.tokens.get('csrfToken'),
                recreate : 1,
                summary  : frm.SandboxSummary.value,
                text     : frm.SandboxText.value
               },      
       success: function(resp) {
          alert(&quot;Sandbox page edited!&quot;);
       }
    });
 }
 
 
 
 // ========================================================
 // convenience wrapper function to replace calls to
 // document.getElementById() 
 // to avoid browser incompatibility
 // ========================================================
 function fuwGet(target) {
    if (!!target &amp;&amp; !!target.nodeType) return target;
    else {
       var found = $('#' + target);
       if (found) return found[0];
    }
    return undefined;
 }
 
 // ========================================================
 // onload hook function, loading this script
 // ========================================================
 $(function() { 
    if (fuwGet('UploadScriptArea')) {
       window.fuw = new fuwGlobal();
       fuwUpdateOptions();
    }