User:Dario (WMF)/veCiteFromURL.js

From Meta, a Wikimedia project coordination wiki

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)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/*!
 * VE Cite From URL
 * A VisualEditor Citoid gadget
 * https://www.mediawiki.org/wiki/Citoid#Install_and_configure_Citoid_gadgets
 * By [[User:Mvolz]]
 * Includes code cannabilized from [[User:Eran]] and Zotero translators!
 * @license The MIT License (MIT)
 */
 
//necessary because mwreference loaded after ext.visualEditor.viewPageTarget.init
mw.loader.using( 'ext.visualEditor.mwreference', function () { 

/* Message Definitions */
if (!mw.messages.exists( 'citoid-citeFromURLDialog-search-placeholder' )) {
	mw.messages.set({
		'citoid-citeFromURLDialog-search-placeholder':'Enter URL (i.e. http://mediawiki.org)',
		'citoid-citeFromURLDialog-search-label':'URL:',
		'citoid-citeFromURLTool-title': 'Cite from URL'
	});
}

//---------- CiteFromURL Dialog ------------------

	ve.ui.CiteFromURLDialog = function VeUiCiteFromURLDialog( manager, config ) {
		// Parent constructor
		config = ve.extendObject( { 'size': 'medium' }, config );
		ve.ui.CiteFromURLDialog.super.call( this, manager, config );
	};

	/* Inheritance */
	OO.inheritClass( ve.ui.CiteFromURLDialog, ve.ui.MWCitationDialog );

	/* Static Properties */
	ve.ui.CiteFromURLDialog.static.name = 'citefromurl';
	ve.ui.CiteFromURLDialog.static.title = mw.msg( 'citoid-citeFromURLDialog-title' );

	/* Returns full template given search results */
	ve.ui.CiteFromURLDialog.prototype.getPlainObject = function ( url, searchResults ) {

		var content, plainObject, d, templateHref, templateName,
			citation = JSON.parse( JSON.stringify( searchResults ) )[0], //uses the first citation result for the time being

		templateTypeMap = {
			book: 'Cite book',
			bookSection: 'Cite book',
			journalArticle: 'Cite journal',
			magazineArticle: 'Cite news',
			newspaperArticle: 'Cite news',
			thesis: 'Cite journal',
			letter: 'Citation',
			manuscript: 'Cite book',
			interview: 'Citation',
			film: 'Citation',
			artwork: 'Citation',
			webpage: 'Cite web',
			report: 'Cite journal',
			bill: 'Citation',
			hearing: 'Citation',
			patent: 'Citation',
			statute: 'Citation',
			email: 'Cite web',
			map: 'Citation',
			blogPost: 'Cite web',
			instantMessage: 'Citation',
			forumPost: 'Cite web',
			audioRecording: 'Citation',
			presentation: 'Cite journal',
			videoRecording: 'Citation',
			tvBroadcast: 'Citation',
			radioBroadcast: 'Citation',
			podcast: 'Citation',
			computerProgram: 'Citation',
			conferencePaper: 'Cite journal',
			'document': 'Citation',
			encyclopediaArticle: 'Cite journal',
			dictionaryEntry: 'Cite journal'
		},

			//Parameter map for Template:Citation on en-wiki
			//In the format citation-template-field:citoid-field
			citationParams = {
				'first1': 'author1-first',
				'last1': 'author1-last',
				'first2': 'author2-first',
				'last2': 'author2-last',
				'first3': 'author3-first',
				'last3': 'author3-last',
				'first4': 'author4-first',
				'last4': 'author4-last',
			//	'accessdate': 'accessDate',
				'title': 'title',
				'url': 'url',
				'publisher': 'publisher',
				//a large number of Zotero types have the field publicationTitle
				//however, in setting journal to publicationTitle, the citation
				//will be formatted as a journal article, which may not always be
				//desirable.
				'journal': 'publicationTitle',
			//	'newspaper': 'publicationTitle',
				'date': 'date',
				'location': 'place',
				'issn': 'ISSN',
				'isbn': 'ISBN',
				'pages': 'pages',
				'volume': 'volume',
				'series': 'series',
				'issue': 'issue',
				'doi': 'DOI'
			},

			webParams = {
				'first1': 'author1-first',
				'last1': 'author1-last',
				'first2': 'author2-first',
				'last2': 'author2-last',
				'first3': 'author3-first',
				'last3': 'author3-last',
				'first4': 'author4-first',
				'last4': 'author4-last',
			//	'accessdate': 'accessDate',
				'title': 'title',
				'url': 'url',
				'date': 'date',
				'publisher': 'publisher',
				'website': 'publicationTitle'
			},

			newsParams = {
				'first1': 'author1-first',
				'last1': 'author1-last',
				'first2': 'author2-first',
				'last2': 'author2-last',
				'first3': 'author3-first',
				'last3': 'author3-last',
				'first4': 'author4-first',
				'last4': 'author4-last',
			//	'accessdate': 'accessDate',
				'title': 'title',
				'url': 'url',
				'publisher': 'publisher',
				'newspaper': 'publicationTitle',
				'date': 'date',
				'location': 'place',
				'issn': 'ISSN',
				'isbn': 'ISBN',
				'pages': 'pages',
				'volume': 'volume',
				'series': 'series',
				'issue': 'issue',
				'doi': 'DOI'
			},

			bookParams = {
				'first1': 'author1-first',
				'last1': 'author1-last',
				'first2': 'author2-first',
				'last2': 'author2-last',
				'first3': 'author3-first',
				'last3': 'author3-last',
				'first4': 'author4-first',
				'last4': 'author4-last',
			//	'accessdate': 'accessDate',
				'title': 'title',
				'url': 'url',
				'publisher': 'publisher',
				'journal': 'publicationTitle',
				'date': 'date',
				'location': 'place',
				'issn': 'ISSN',
				'isbn': 'ISBN',
				'pages': 'pages',
				'volume': 'volume',
				'series': 'series',
				'issue': 'issue',
				'doi': 'DOI'
			},

			journalParams = {
				'first1': 'author1-first',
				'last1': 'author1-last',
				'first2': 'author2-first',
				'last2': 'author2-last',
				'first3': 'author3-first',
				'last3': 'author3-last',
				'first4': 'author4-first',
				'last4': 'author4-last',
			//	'accessdate': 'accessDate',
				'title': 'title',
				'url': 'url',
				'publisher': 'publisher',
				'journal': 'publicationTitle',
				'date': 'date',
				'location': 'place',
				'issn': 'ISSN',
				'isbn': 'ISBN',
				'pages': 'pages',
				'volume': 'volume',
				'series': 'series',
				'issue': 'issue',
				'doi': 'DOI'
			},

			//format 'template name':parameter obj name
			templateParamMap = {
				'Citation': citationParams,
				'Cite web': webParams,
				'Cite news': newsParams,
				'Cite journal': journalParams,
				'Cite book': bookParams
			},

			//This will contain the correct template with the fields filled out
			paramObj = {};

		templateName = templateTypeMap[citation.itemType];

		templateHref = 'Template:' + templateName;
		
		//hack for now- set citation url to supplied url if not given
		if (!citation.url) {citation.url =  url;}

		$.each( templateParamMap[templateName], function ( key, value ) {
			if (citation[value] !== undefined) {
				paramObj[key] = { 'wt': citation[value] };
			}
		} );

		d = new Date();
		paramObj.accessdate = { 'wt': d.toISOString().split('T')[0] }; //discard time

		plainObject = { //before paren put get plain object
			'parts': [ {

				'template': {
					'target': {
						'href': templateHref,
						'wt': templateName.toLowerCase()
					},
					'params': paramObj
				}
			} ]
		};

		content = [
			{
				'type': 'mwTransclusionInline',
				'attributes': {
					'mw': plainObject
				}
			},
			{ 'type': '/mwTransclusionInline' }
		];
		return content;
	};

	ve.ui.CiteFromURLDialog.prototype.initialize = function () {
		ve.ui.CiteFromURLDialog.super.super.super.prototype.initialize.call( this );

		//not actually using this//hack for inheriting from mwtemplatedialog
		this.bookletLayout = new OO.ui.BookletLayout(
			ve.extendObject(
				{ '$': this.$ },
				this.constructor.static.bookletLayoutConfig
			)
		);

		this.searchInput = new OO.ui.TextInputWidget( {
			'$': this.$,
			'multiline': false,
			'placeholder': mw.msg( 'citoid-citeFromURLDialog-search-placeholder' )
		} );
		var panel = new OO.ui.PanelLayout( { '$': this.$, 'scrollable': true, 'padded': true } ),
			inputsFieldset = new OO.ui.FieldsetLayout( {
				'$': this.$
			} ),
			//input search

			searchField = new OO.ui.FieldLayout( this.searchInput, {
				'$': this.$,
				'label': mw.msg( 'citoid-citeFromURLDialog-search-label' )
			} );

		inputsFieldset.$element.append(
			searchField.$element
		);
		panel.$element.append( inputsFieldset.$element );
		this.$body.append( panel.$element );

	};

	ve.ui.CiteFromURLDialog.prototype.getActionProcess = function ( action ) {
		if ( action === 'apply' || action === 'insert' ) {
			return new OO.ui.Process( function () {

				this.pushPending();
				var citoidService,
					that = this;
					
				citoidService = "https://citoid.wmflabs.org/url";

				$.ajax( {
					beforeSend: function (request) {
						request.setRequestHeader('Content-Type', 'application/json');
					},
					url: citoidService,
					type: 'POST',
					data: JSON.stringify( { url: this.searchInput.getValue() } ),
					dataType: 'json',
					success: function ( result ) {
						that.close();

						var item, linsel,
							surfaceModel = that.getFragment().getSurface(),
							doc = surfaceModel.getDocument(),
							internalList = doc.getInternalList();

						//sets up referencemodel with blank stuff
						if ( !that.referenceModel ) {
							// Collapse returns a new fragment, so update this.fragment
							that.fragment = that.getFragment().collapseToEnd();
							that.referenceModel = new ve.dm.MWReferenceModel();
							that.referenceModel.insertInternalItem( surfaceModel );
							that.referenceModel.insertReferenceNode( that.getFragment() );
						}
						//gets bank stuff again
						item = that.referenceModel.findInternalItem( surfaceModel );
						if ( item ) {
							linsel = that.getFragment().clone( new ve.dm.LinearSelection( doc, item.getChildren()[0].getRange() ) );
							//actually inserts full transclusion model here!
							linsel.insertContent(that.getPlainObject( that.searchInput.getValue(), result ) );
						}

						// HACK: Scorch the earth - this is only needed because without it, the reference list won't
						// re-render properly, and can be removed once someone fixes that
						that.referenceModel.setDocument(
							doc.cloneFromRange(
								internalList.getItemNode( that.referenceModel.getListIndex() ).getRange()
							)
						);

						that.referenceModel.updateInternalItem( surfaceModel );

						//hack- doesn't seem to be working in always
						that.popPending();
					},
					error: function ( XMLHttpRequest, textStatus, errorThrown) {
						that.popPending();
						mw.notify( 'Status:'  + textStatus +  'Error: ' + errorThrown );
						that.popPending();
					},
					always: function () {
						that.popPending();
					}
				} );
			}, this );
		}

		// Parent method
		return ve.ui.CiteFromURLDialog.super.super.prototype.getActionProcess.call( this, action );
	};

	ve.ui.CiteFromURLDialog.prototype.onTransclusionReady = function () {
		// Parent method
		ve.ui.CiteFromURLDialog.super.prototype.onTransclusionReady.call( this );
		//hack- always enabled for now
		this.actions.setAbilities( { 'apply': true, 'insert': true } );
	};

	//hack for inheriting from template dialog
	//Sets the title of the dialog correctly
	ve.ui.CiteFromURLDialog.prototype.getTemplatePartLabel = function ( part ) {
		return ve.msg( 'citoid-citeFromURLTool-title' );
	};

	ve.ui.windowFactory.register( ve.ui.CiteFromURLDialog );

//---------- CiteFromURL tool ------------------
 
function CiteFromURLTool( toolGroup, config ) {
	OO.ui.Tool.call( this, toolGroup, config );
 
}
OO.inheritClass( CiteFromURLTool, OO.ui.Tool );
 
CiteFromURLTool.static.name = 'citefromurl';
CiteFromURLTool.static.icon = 'ref-cite-web';
CiteFromURLTool.static.group = 'cite';
CiteFromURLTool.static.autoAddToCatchall = false;
CiteFromURLTool.static.title = mw.msg('citoid-citeFromURLTool-title');
 
CiteFromURLTool.prototype.onSelect = function () {
	this.toolbar.getSurface().execute( 'window', 'open', 'citefromurl', null );
};
 
CiteFromURLTool.prototype.onUpdateState = function () {
	this.setActive( false );
};
 
ve.ui.toolFactory.register( CiteFromURLTool );

});