Jump to content

MediaWiki:Gadget-FileUploader.js

From Appropedia

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 );
Cookies help us deliver our services. By using our services, you agree to our use of cookies.