# மீடியாவிக்கி:FileUploadWizard.js

/*  
- ===============================================================
- FileUploadWizard.js
- Script for uploading files through a dynamic questionnaire.
- This is the code to accompany .
- ===============================================================
- /

var fuwTesting = false;  
var fuwDefaultTextboxLength = 60;  
var fuwDefaultTextarea;  
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&action=raw&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 = "fuwScriptForm";  
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 = "TargetForm";  
frm.method = "post";  
frm.enctype = "multipart/form-data";  
// "enctype" doesn't work properly on IE; need "encoding" instead:  
frm.encoding = "multipart/form-data";  
// 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 = "TargetIFrame";  
//testing:  
//frm.target = "_blank";  
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 = "fuwTestForm";  
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') + "/sandbox", '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 = "TargetIFrame";  
ifr.name = "TargetIFrame";  
//ifr.setAttribute('style', 'float:;width:;height:;');  
ifr.style.display = "";  
ifr.src = "";  

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.;  
btn.onclick = fuwSubmitSandbox;  
fuwAppendInput('SandboxButton', btn);  

}  

// create the real submit button  
btn = document.createElement('input');  
btn.id = "SubmitButton";  
btn.value = "Upload";  
btn.name = "Upload";  
btn.disabled = true;  
btn.type = "button";  
btn.onclick = fuwSubmitUpload;  
btn.style.;  
fuwAppendInput('SubmitButton', btn);  

// create the Commons submit button  
btn = document.createElement('input');  
btn.id = "CommonsButton";  
btn.value = "Upload on Commons";  
btn.name = "Upload_on_Commons";  
btn.disabled = true;  
btn.type = "button";  
btn.onclick = fuwSubmitCommons;  
btn.style.;  
fuwAppendInput('CommonsButton', btn);  

// create reset buttons  
for (i = 1; i<=2; i++) {  
btn = document.createElement('input');  
btn.id = 'ResetButton' + i;  
btn.value = "Reset form";  
btn.name = "Reset form";  
btn.type = "button";  
btn.onclick = fuwReset;  
btn.style.;  
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<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<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<activeTextareas.length; i++) {  
fuwMakeTextarea(activeTextareas[i]);  
};  

var checkboxes = [  
'NFCoverCheckDedicated','NFLogoCheckDedicated','NFPortraitCheckDedicated'  
];  
for (i=0; i<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' :  
[  
[*, *],  
['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="disabled";  
fuwGet('SandboxText').disabled="disabled";  
fuwGet('SandboxText').rows = 12;  
}  

// set links to "_blank" 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 < widgets.length; i++) {  
var w = widgets[i];  
if (w.type == "radio") {  
var nm = w.name;  
var id = w.id;  
var vl = w.checked && !w.disabled && fuwIsVisible(w);  
opts[id] = vl;  
if (vl) opts[nm] = id;  
}  
else {  
var id = w.id;  
var active = !w.disabled && 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 "Own Work".  
// (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 "Own Work".  
// (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 "Logo", 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 && 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 "used in" 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 && opts.OverwriteSame));  
fuwSetVisible('UploadScriptStep3', !(warn.ImageExists && 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 < widgets.length; i++) {  
var w = widgets[i];  
var type = w.type;  

if (type != "radio") {  
var id = w.id;  
var active = !w.disabled && 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 && opts.OptionFree && !(opts.OverwriteSame || opts.OverwriteDifferent)  
&& !opts.ThirdPartyEvidenceOptionNone;  
fuwSetVisible('sendToCommons', opts.OptionFree);  
fuwSetEnabled('CommonsButton', validForCommons);  
fuwGet('fuwSubmitText').innerHTML = opts.OptionFree ?  
("<b>No</b>, I want to upload this file here on this wiki only.  
" +  
"<small>This way it can be used only on the English Wikipedia. However, somebody " +  
"else might still decide to copy it to Commons or use it elsewhere later. If you " +  
"do not want your file to be copied to Commons and deleted locally, consider adding " +  
".</small>") :  
"Upload this file.";  
fuwGet('SubmitButton').value = validForCommons ? "Upload locally" : "Upload";  
fuwSetEnabled('EditSummary', true);  
fuwSetEnabled('SubmitButton', valid && (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 &&  
opts.InputFilename &&  
!warn.BadFilename &&  
!warn.ImageOnCommons &&  
// if image exists on enwiki, accept only if user has confirmed overwrite:  
!(warn.ImageExists && !(opts.OverwriteSame || opts.OverwriteDifferent));  
//alert("HasValidFilename: " + 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("HasValidCommonFreeInput: " + 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 &&  
opts.InputDesc &&  
opts.NFArticle &&  
opts.Source &&  
opts.NFMinimality &&  
!warn.NFArticleNotFound &&  
!warn.NFArticleNotMainspace &&  
!warn.NFArticleDab;  
//alert("hasValidCommonNFInput: " + 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  
&&  
(! (opts.OverwriteDifferent && ! opts.EditSummary))  
&&  
(  
( // overwriting is okay if there is an edit summary  
opts.OverwriteSame && opts.EditSummary  
( // free options  
this.hasValidCommonFreeInput &&  
(  
(opts.OptionOwnWork &&  
opts.Date &&  
opts.OwnWorkLicense)  
(opts.OptionThirdParty &&  
opts.Author &&  
opts.Source &&  
opts.Permission &&  
(opts.ThirdPartyOtherLicense || opts.ThirdPartyLicense) &&  
((opts.ThirdPartyEvidenceOptionLink && opts.ThirdPartyEvidenceLink) ||  
opts.ThirdPartyEvidenceOptionOTRS ||  
opts.ThirdPartyEvidenceOptionOTRSForthcoming ||  
opts.ThirdPartyEvidenceOptionNone))  
(opts.OptionFreeWebsite &&  
opts.Author &&  
opts.Source &&  
(opts.FreeWebsiteOtherLicense || opts.FreeWebsiteLicense) &&  
opts.Permission)  
(opts.OptionPDOld &&  
opts.Author &&  
opts.PDOldAuthorLifetime &&  
opts.Publication &&  
opts.Date &&  
opts.Source &&  
opts.PDOldOptions &&  
(! (opts.PDOldOther && ! opts.PDOldPermission)))  
(opts.OptionPDOther &&  
opts.Author &&  
opts.Source &&  
((opts.PDOtherUSGov && opts.USGovLicense) ||  
(opts.PDOtherOfficial && opts.PDOfficialPermission) ||  
(opts.PDOtherSimple && opts.IneligibleLicense) ||  
(opts.PDOtherOther && opts.PDOtherPermission)))  
) // end of free options  
( // non-free options  
this.hasValidCommonNFInput &&  
(  
(opts.OptionNFSubject &&  
opts.NFSubjectLicense &&  
opts.Author &&  
(opts.NFSubjectCheckDedicated ||  
(opts.NFSubjectCheckDiscussed && opts.NFSubjectPurpose)))  
(opts.OptionNF3D &&  
opts.NF3DLicense &&  
opts.NF3DCreator &&  
opts.Author &&  
(opts.NF3DOptionSame ||  
(opts.NF3DOptionFree || opts.NF3DPermission)) &&  
(opts.NF3DCheckDedicated ||  
(opts.NF3DCheckDiscussed && opts.NF3DPurpose)))  
(opts.OptionNFExcerpt &&  
opts.NFExcerptLicense &&  
opts.Author &&  
opts.NFPurpose)  
(opts.OptionNFCover &&  
opts.NFCoverLicense &&  
opts.Author &&  
opts.NFCoverCheckDedicated  
(opts.OptionNFLogo &&  
opts.NFLogoLicense &&  
opts.NFLogoCheckDedicated  
(opts.OptionNFPortrait &&  
opts.Publication &&  
opts.NFPortraitDeceased &&  
opts.Author &&  
opts.NFPortraitCheckDedicated &&  
opts.NFReplaceable &&  
opts.NFCommercial)  
(opts.OptionNFMisc &&  
opts.NFMiscLicense &&  
opts.Author &&  
opts.Publication &&  
opts.NFPurpose &&  
opts.NFReplaceableText &&  
opts.NFReplaceable &&  
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 "Information" template for free files:  
if (this.opts.OptionFree) return "Information";  
// experimental new version of fair-use rationale template,  
// designed to fit the fields used in the wizard  
else if (this.opts.OptionNonFree) return "Non-free use rationale 2";  
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 = '';  
}  
}  
else {  
license.special =  
opts.ThirdPartyOtherLicense ||  
opts.FreeWebsiteOtherLicense ||  
(opts.PDOtherOfficial ? ('') : null) ||  
(opts.OptionNFPortrait ? ('') : 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);  

// "PD-author" needs parameter, at least on Commons  
if (simpleLicense == 'PD-author') {  
license.special = '';  
}  
else if (this.knownCommonsLicenses[simpleLicense]) {  
// make sure we send only those licenses as "standard" licenses  
// that exist in the Commons license dropdown box  
license.standard = simpleLicense;  
}  
else {  
license.special = '\{\{' + simpleLicense + '\}\}';  
}  
}  
return license;  
};  

function fuwSubst(template) {  
return '';  
}  

// ===================================================================  
// Produce code for local tracking categories  
// ===================================================================  
fuwGlobal.prototype.getTrackingCategory = function {  
var opts = this.opts;  
var cat = "";  
if (opts.OptionFreeWebsite) { cat = "Files from freely licensed external sources"; }  
else if (opts.OptionThirdParty) { cat = "Files licensed by third parties"; }  
else if (opts.PDOtherOther || opts.PDOldOther) { cat = "Files with non-standard public domain statements"; }  
else if (opts.OptionNFSubject || opts.OptionNF3D) { cat = "Non-free files uploaded as object of commentary"; }  
if (cat) {  
cat = "\n\{\{Category ordered by date|" + cat + "|" +  
fuwSubst("CURRENTYEAR") + "|" + fuwSubst("CURRENTMONTH") + "|" + fuwSubst("CURRENTDAY2") + "\}\}";  
}  
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 + ' (File Upload Wizard)') : null)||  
("Uploading " +  
(  
(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 ' : "")  
+  
("using File Upload Wizard")  
));  
};  

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 ":en" + p1 + "";  
}  
// 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 ":en:" + p1 + "";  
}  
// introduce a pipe  
else {  
return "" + p1 + "";  
}  
}  
);  
return "";  
} 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  
};  
// "other information" (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 "source" field for optional "how created?" and  
// "previously published" input fields.  
descFields.Source = fuwAppendLines([  
(opts.OwnWorkCreation || ""),  
"  
\n",  
fuwSurroundString("**Previously published:** ", opts.OwnWorkPublication)]);  
var username = mw.user.getName;  
descFields.Author = * + username + *;  
break;  

case 'OptionThirdParty':  

// use standard "permission" field for a compilation of the  
// "permission" input field and the various "evidence" options  
var evidence = (  
opts.ThirdPartyEvidenceOptionLink ?  
("The license statement can be found online at: " + opts.ThirdPartyEvidenceLink) :  
(opts.ThirdPartyEvidenceOptionOTRS ?  
("The license agreement has been forwarded to OTRS." +  
fuwSurroundString(" Ticket: ", opts.ThirdPartyOTRSTicket) + "\{\{OTRS pending|year=" + fuwSubst("CURRENTYEAR") +  
"|month=" + fuwSubst("CURRENTMONTH") +  
"|day=" + fuwSubst("CURRENTDAY2") + "\}\}") :  
(opts.ThirdPartyEvidenceOptionOTRSForthcoming ?  
"The license agreement will be forwarded to OTRS shortly. \{\{OTRS pending|year=" + fuwSubst("CURRENTYEAR") +  
"|month=" + fuwSubst("CURRENTMONTH") +  
"|day=" + fuwSubst("CURRENTDAY2") + "\}\}" :  
(opts.ThirdPartyEvidenceOptionNone ?  
"Will be provided on request." : null))));  
descFields.Permission = fuwAppendLines([  
opts.ThirdPartyPermission,  
"  
\n",  
fuwSurroundString("**Evidence:** ", evidence)]);  
break;  

case 'OptionFreeWebsite':  
descFields.Permission = opts.Permission;  
break;  

case 'OptionPDOld':  
// add "lifetime" input to "author" field  
descFields.Author = fuwAppendLines([  
opts.Author,  
"  
\n",  
fuwSurroundString("(Life time: ", opts.PDOldAuthorLifetime, ")")  
]);  

// combine original and direct source into standard "source" field:  
descFields.Source = fuwAppendLines([  
fuwSurroundString("**Original publication**: ", opts.Publication),  
"  
\n",  
fuwSurroundString("**Immediate source**: ", opts.Source)  
]);  

// no standard tag available for "lack-of-registration" PD-US. Need  
// to put this into the "permission" field  
if (opts.PDFormality)  
descFields.Permission =  
"Copyright expired because the work was published without a copyright " +  
"notice and/or without the necessary copyright registration.";  

// add optional "explanation" input to "permission" field  
if (opts.PDOldPermission) {  
descFields.Permission = fuwAppendLines([  
descFields.Permission,  
"\n\n",  
opts.PDOldPermission  
]);  
}  
break;  

case 'OptionPDOther':  
// Need "permission" field in case of "official item" option  
if (opts.PDOtherOfficial)  
descFields.Permission = opts.PDOfficialPermission;  
break;  

case 'OptionNFSubject':  
// most FUR elements can be automatically provided:  
descFields.Purpose = (  
opts.NFSubjectCheckDedicated ?  
("For visual identification of the object of the article. " +  
"The article as a whole is dedicated specifically to a discussion of this work.") :  
(opts.NFSubjectCheckDiscussed ?  
("To support encyclopedic discussion of this work in this article. " +  
"The illustration is specifically needed to support the following point(s): " +  
"  
\n" + 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 = "n.a.";  
descFields.Commercial = "n.a.";  
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("**Original work:** ", opts.NF3DCreator),  
"  
\n",  
fuwSurroundString("**Depiction:** ", opts.Author)  
]);  
descFields.Date = fuwAppendLines([  
fuwSurroundString("**Original work:** ", opts.NF3DOrigDate),  
"  
\n",  
fuwSurroundString("**Depiction:** ", opts.Date)  
]);  
descFields.Purpose = (  
opts.NF3DCheckDedicated ?  
("For visual identification of the object of the article. " +  
"The article as a whole is dedicated specifically to a discussion of this work.") :  
(opts.NF3DCheckDiscussed ?  
("To support encyclopedic discussion of this work in this article. " +  
"The illustration is specifically needed to support the following point(s): " +  
"  
\n" + opts.NF3DPurpose) : null)  
);  
descFields.Replaceability = "n.a.";  
descFields.Commercial = "n.a.";  
descFields["Other information"] = (  
opts.NF3DOptionSame ?  
("The image was created and published by the same author who also " +  
"holds the rights to the original object, and no alternative depiction " +  
"could be suitably created.") :  
("The author of the image has released the photographic work under a " +  
"free license, or it is in the public domain: " + 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 = "n.a.";  
descFields.Commercial = "n.a.";  
break;  

case 'OptionNFCover':  
// cover art gets standard rationales.  
descFields.Purpose =  
"to serve as the primary means of visual identification " +  
"at the top of the article dedicated to the work in question.";  
descFields.Replaceability = "n.a.";  
descFields.Commercial = "n.a.";  
break;  

case 'OptionNFLogo':  
// logos get standard rationales.  
descFields.Purpose =  
"to serve as the primary means of visual identification " +  
"at the top of the article dedicated to the entity in question.";  
descFields.Replaceability = "n.a.";  
descFields.Commercial = "n.a.";  
break;  

case 'OptionNFPortrait':  
// as with other historic photographs, it is useful to have both  
// original publication and direct source  
descFields.Source = fuwAppendLines([  
fuwSurroundString("**Original publication**: ", opts.Publication),  
"  
\n",  
fuwSurroundString("**Immediate source**: ", opts.Source)  
]);  
descFields.Purpose =  
"for visual identification of the person in question, " +  
"at the top of his/her biographical article";  
descFields.Replaceability = opts.NFReplaceable;  
descFields.Commercial = opts.NFCommercial;  
descFields['Other information'] =  
"The subject of the photograph has been deceased since: " + opts.NFPortraitDeceased;  
break;  

case 'OptionNFMisc':  
descFields.Source = fuwAppendLines([  
fuwSurroundString(  
"**Original publication**: ",  
opts.Publication,  
"  
\n**Immediate source:** "),  
"",  
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 "extra license" selector and "AnyOther" fields  
// to "Other information" field:  
descFields['Other information'] = fuwAppendLines([  
descFields['Other information'],  
"  
\n",  
fuwSurroundString('\{\{', opts.NFExtraLicense, '\}\}'),  
"  
\n",  
opts.AnyOther  
]);  
}  
else {  
// common stuff for all free files:  
descFields.Other_versions = ''  
this.otherInfo = fuwAppendLines([this.otherInfo, "\n\n", 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 = "\n";  
if (otherInfo) {  
summary += "\n;Other information:\n" + fuwPackInfo(otherInfo, forCommons) + "\n";  
}  

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("Upload marker added by en.wp UW") + "\n" + summary;  
summary = summary.replace(/\{\{OTRS pending\}\}/g, fuwSubst("OP"));  

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 + "\n\n" + license.special;  
}  
return (fuwGetCommonsURL +  
"?title=Special:Upload" +  
"&wpUploadDescription=" +  
encodeURIComponent(summary) +  
(license.standard ?  
("&wpLicense=" + encodeURIComponent(license.standard)) : '') +  
"&wpDestFile=" +  
encodeURIComponent(opts.InputName));  
}  
else {  
// pack all description into a single "text" parameter to be submitted  
// to the local api.php upload.  
summary = "==Summary==\n" +  
summary +  
"\n==Licensing==\n" +  
(license.standard ? ("\{\{" + license.standard + "\}\}") : 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 "this.TargetForm.filename.value".  
($('#TargetForm [name="filename"]')[0]).value = opts.InputName;  
($('#TargetForm [name="text"]' )[0]).value = summary;  
($('#TargetForm [name="comment"]' )[0]).value = editSummary;  
($('#TargetForm [name="token"]' )[0]).value = mw.user.tokens.get('csrfToken');  

}  

};  

function fuwHasUserGroup(group) {  
// workaround because old IE versions don't have array.indexOf :-(  
for (i = 0; i < 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 < 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 < 100) {  
fuw.userStatus = 'newbie';  
}  
}  
var revs = data.getElementsByTagName('rev');  
var countWarn = 0;  
for (i = 0; i < 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)/) >= 0)) {  
countWarn += 1;  
}  
}  
if (countWarn >= 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 "https://commons.wikimedia.org/w/index.php";  
else  
return "http://commons.wikimedia.org/w/index.php";  
}  

// ==================================================================  
// functions for building form elements  
// ==================================================================  
fuwMakeRadiobutton = function(group, option, checked, event) {  
// Stupid IE7 doesn't get "value" attribute unless it's created in this convoluted way.  
// Annoying.  
var node = $('<input type="radio" id="' + option + '" name="' + group + '" value="' + option + '"></input>')[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= "_blank";  
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<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', '');  
entry.innerHTML = line[1];  
if (line.length > 2) {  
entry.setAttribute('selected', 'selected');  
}  
current.appendChild(entry);  
}  
}  
} catch (e) { alert("Name: " + name + ", i=" + 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="placeholderXYZ"  
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 && target) {  
var parent = move.parentNode;  
if (! (target===parent)) {  
parent.removeChild(move);  
if (toStart) {  
target.insertBefore(move, target.firstChild);  
}  
else {  
target.appendChild(move);  
}  
}  
}  
else {  
alert("Can't find elements: move=" + mv + "(" + move + "), target=" + tg + "(" + target + ")");  
}  
}  
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("Element not found: " + ((!!tg && !!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<elements.length; i++) {  
if (elements[i].tagName.match(/^(input|textarea|select|button|a)$/i)) {  
elements[i].disabled = (condition ? null : "disabled");  
}  
}  
} catch (e) { alert("Element not found: " + ((!!tg && !!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 == "") {  
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, "");  
// strip accidentally added "File:" prefix  
name = name.replace(/^(File|Image):/, "");  
// replace underscores with spaces  
name = name.replace(/_/g, " ");  
// 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(/\&[a-z]+;/g, fuwHtmlEntityDecode);  
name = name.replace(/(\%[A-F0-9]{2,2})/g, decodeURI);  
// remove illegal characters # < > [ ] | { } /:  
// using a best guess for an acceptable replacement  
name = name.replace(/[<\[\{]/g, "(");  
name = name.replace(/[>\]\}]/g, ")");  
name = name.replace(/[#:\|]/g, ",");  
name = name.replace(/\//g, "-");  
// remove sequences of tildes  
name = name.replace(/\~{3,}/g, "---");  
// remove initial slash  
name = name.replace(/^\//, "");  
}  

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(/</g,'&lt;').replace(/>/g,'&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, "");  

// name should be at least 10 characters long, excluding file type extension  
var tooShort = (name.length < 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 && !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 = {  
"png" : "image/png",  
"gif" : "image/gif",  
"jpg" : "image/jpeg",  
"jpeg" : "image/jpeg",  
"xcf" : "image/x-xcf",  
"pdf" : "application/pdf",  
"mid" : "audio/rtp-midi",  
"ogg" : "audio/ogg",  
"ogv" : "video/ogg",  
"svg" : "image/svg+xml",  
"djvu" : "image/vnd.djvu",  
"tiff" : "image/tiff",  
"tif" : "image/tiff",  
"oga" : "video/ogg"  
};  

var found = extensions.exec(file);  
var fileExt = found ? found[1].toLowerCase : "";  
found = extensions.exec(name);  
var nameExt = found ? found[1].toLowerCase : "";  
var mime = mimetypes[fileExt];  

if (fileExt && mime && (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 >= 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 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/, "commons.wikimedia.org");  
descURL = descURL.replace(/\/\/secure\.wikimedia\.org\/wikipedia\/en/, "commons.wikimedia.org");  
}  

// 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<thumbA.length; i++) {  
thumbA[i].setAttribute('href', descURL);  
}  
// insert the image itself:  
var thumbImg = thumbDiv.getElementsByTagName('img');  
if (thumbImg.length > 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 && isCommons;  
warn.ImageExists = exists && !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 &&  
fuwCheckPoorFilename &&  
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, "");  
// automatically fix article names entered as full urls:  
name = name.replace(/^https?:\/\/en\.wikipedia\.org\/wiki\//, "");  
name = name.replace(/^https?:\/\/en\.wikipedia\.org\/w\/index\.php\?title=/, "");  
name = name.replace(/_/g, " ");  
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("User( talk)?:" + mw.config.get('wgUserName')))) {  
userspace = true;  
}  
}  
else if (rd != null) {  
// redirect page  
// API returns an empty redirect="" attribute if  
// the page is a redirect  
var targets = pg.getElementsByTagName('pl');  
for (i=0; i<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<cats.length; i++) {  
var cat = cats[i];  
if (cat.getAttribute('title') == "Category:All disambiguation pages") {  
errorType = 4;  
break;  
}  
}  
}  
}  
warn = window.fuw.warn;  
warn.NFArticleNotFound = (errorType==1);  
warn.NFArticleNotMainspace = (errorType==2);  
warn.UserspaceDraft = ((errorType==2) && 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 + " is a redirect. Follow it to " + target + "?")) {  
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 < 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 = "";  
for (var i = 0; i < 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 : "") + content + (suffix ? suffix : "");  
else return "";  
}  

// ========================================================  
// 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>=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 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 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 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 = "";  
for (i = 0; i < details.length; i++) {  
if (add.length > 0) add += ", ";  
add += details[i].textContent;  
}  
if (add) {  
info = info + " (" + add + ")";  
}  
alert("Upload failed: " + info);  
}  
else {  
alert("Unknown error: upload may have failed.");  
}  
}  
}  
}  

// ========================================================  
// 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("onload", 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="text"]')[0]).value  

}  
});  
}  
}  

// =======================================================  
// Event handler for the Commons submit button  
// =======================================================  
function fuwSubmitCommons {  
var fuw = window.fuw;  
fuw.collectInput;  
var url = fuw.formatOutput(true);  
alert("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.");  
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') + "/sandbox",  
token : mw.user.tokens.get('csrfToken'),  
recreate : 1,  
summary : frm.SandboxSummary.value,  
text : frm.SandboxText.value  
},  
success: function(resp) {  
alert("Sandbox page edited!");  
}  
});  
}  

// ========================================================  
// convenience wrapper function to replace calls to  
// document.getElementById  
// to avoid browser incompatibility  
// ========================================================  
function fuwGet(target) {  
if (!!target && !!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;  
}  
});