User:Sophivorus/FileUploader.js
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
// <nowiki>
const FileUploader = {
userAgent: 'FileUploader/1.0 (User:Sophivorus)',
// @todo i18n
messages: {
'FileUploader-file-name-exists': 'A file with that name already exists.',
},
async init( $content ) {
const $instances = $content.find( '.FileUploader' );
if ( !$instances.length ) {
return;
}
await mw.loader.using( 'mediawiki.api' );
FileUploader.api = new mw.Api( { userAgent: FileUploader.userAgent } );
mw.messages.set( FileUploader.messages );
$instances.each( FileUploader.makeApp );
},
async makeApp() {
const require = await mw.loader.using( [ '@wikimedia/codex', 'mediawiki.Upload' ] );
const Vue = require( 'vue' );
const Codex = require( '@wikimedia/codex' );
const app = Vue.createMwApp( FileUploader.component, this.dataset );
app.component( 'cdx-button', Codex.CdxButton );
app.component( 'cdx-card', Codex.CdxCard );
app.component( 'cdx-field', Codex.CdxField );
app.component( 'cdx-select', Codex.CdxSelect );
app.component( 'cdx-text-input', Codex.CdxTextInput );
app.mount( this );
},
component: {
props: [ 'licenses' ],
template: `
<cdx-button @click="selectFiles">Select files</cdx-button>
<input type="file" ref="fileInput" multiple hidden @change="onFileInputChange" />
<cdx-card v-for="file in files" :force-thumbnail="true" :thumbnail="file.thumb">
<template #title>
<a v-if="file.status === 'uploaded'" :href="file.url">{{ file.name }}</a>
<cdx-field v-else :status="file.nameStatus" :messages="file.nameMessages">
<template #label>Title</template>
<cdx-text-input v-model="file.name" @change="validateFile( file )" />
</cdx-field>
</template>
<template #description>
<cdx-field v-if="file.status === 'selected'">
<template #label>License</template>
<cdx-select v-model:selected="file.license" :menu-items="licenseItems" default-label="Select a license" />
</cdx-field>
</template>
</cdx-card>
<cdx-button v-if="files.length" action="progressive" weight="primary" @click="uploadFiles" :disabled="uploadDisabled">Upload</cdx-button>
`,
data() {
const licenseItems = []
for ( const license of this.licenses.split( ',' ) ) {
const trimmed = license.trim();
const item = {
value: trimmed,
label: trimmed
};
licenseItems.push( item );
}
return {
files: [],
licenseItems: licenseItems,
uploadDisabled: false
};
},
methods: {
selectFiles() {
this.$refs.fileInput.click();
},
async onFileInputChange( event ) {
//console.log( event.target.files );
const files = [];
for ( const fileObject of event.target.files ) {
const upload = new mw.Upload( FileUploader.api );
upload.setFile( fileObject );
upload.uploadToStash();
const file = {
upload: upload,
status: 'selected',
thumb: fileObject.type.startsWith( 'image/' ) && { url: URL.createObjectURL( fileObject ) },
name: fileObject.name,
nameStatus: 'default',
nameMessages: { warning: mw.msg( 'FileUploader-file-name-exists' ) },
license: null
};
files.push( file );
}
this.files = files;
},
async validateFile( file ) {
// Validate the file name
file.nameStatus = 'default';
const title = new mw.Title( file.name, 6 );
const data = await FileUploader.api.get( {
action: 'query',
titles: title.getPrefixedText(),
formatversion: 2
} );
const page = data.query.pages[0];
if ( !page.missing ) {
file.nameStatus = 'warning';
}
},
uploadFiles() {
this.uploadDisabled = true;
for ( const file of this.files ) {
let wikitext = '{{File data';
if ( file.license ) {
wikitext += '\n| license = ' + file.license
}
wikitext += '\n}}';
file.upload.setFilename( file.name );
file.upload.setText( wikitext );
file.upload.finishStashUpload()
.done( response => this.onFileUploadDone( response, file ) )
.fail( ( _, response ) => this.onFileUploadFail( response, file ) );
}
},
onFileUploadDone( response, file ) {
//console.log( 'onFileUploadDone', response, file );
const title = new mw.Title( file.name, 6 );
const url = title.getUrl();
file.url = url;
file.status = 'uploaded';
},
onFileUploadFail( response, file ) {
console.log( 'onFileUploadFail', response, file );
}
}
}
};
mw.hook( 'wikipage.content' ).add( FileUploader.init );