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.
/* =====================================================================
* Bharatpedia Gadget: RefGenVe (hidden)
* VisualEditor plugin for the Citation generator gadget.
*
* Adds a "Citation generator" tool to VE's Insert menu (visual mode
* and the 2017 wikitext editor). The tool opens a dialog: paste a URL,
* fetch metadata (via mw.libs.refGen from ext.gadget.RefGen), and
* insert the result as a proper <ref> citation at the cursor.
*
* Loaded via mw.libs.ve.addPlugin( 'ext.gadget.RefGenVe' ).
* All user-facing text is in English.
* ===================================================================== */
( function () {
'use strict';
/* ---------------- Dialog ---------------- */
function RefGenDialog( config ) {
RefGenDialog.super.call( this, config );
this.surface = config.surface || null;
this.params = null;
}
OO.inheritClass( RefGenDialog, OO.ui.ProcessDialog );
RefGenDialog.static.name = 'refgen';
RefGenDialog.static.title = 'Citation generator';
RefGenDialog.static.size = 'large';
RefGenDialog.static.actions = [
{ action: 'insert', label: 'Insert citation', flags: [ 'primary', 'progressive' ] },
{ action: 'cancel', label: 'Cancel', flags: [ 'safe' ] }
];
RefGenDialog.prototype.initialize = function () {
RefGenDialog.super.prototype.initialize.call( this );
this.urlInput = new OO.ui.TextInputWidget( {
placeholder: 'Paste a URL (e.g. https://www.bbc.com/news/...)'
} );
this.fetchButton = new OO.ui.ButtonWidget( { label: 'Fetch' } );
this.statusLabel = new OO.ui.LabelWidget();
this.typeLabel = new OO.ui.LabelWidget();
this.pageInput = new OO.ui.TextInputWidget( { placeholder: 'e.g. 42' } );
this.quoteInput = new OO.ui.MultilineTextInputWidget( {
rows: 2, placeholder: 'Exact quote from the source (optional)'
} );
this.refPreview = new OO.ui.MultilineTextInputWidget( {
rows: 4, readOnly: true, placeholder: 'The generated reference will appear here.'
} );
this.fetchButton.on( 'click', this.onFetch.bind( this ) );
this.urlInput.on( 'enter', this.onFetch.bind( this ) );
this.pageInput.on( 'change', this.refreshPreview.bind( this ) );
this.quoteInput.on( 'change', this.refreshPreview.bind( this ) );
var fieldset = new OO.ui.FieldsetLayout( {
label: 'Citation generator',
icon: 'reference'
} );
fieldset.addItems( [
new OO.ui.FieldLayout( this.urlInput, { label: 'URL', align: 'top' } ),
new OO.ui.FieldLayout( this.fetchButton, { align: 'top' } ),
new OO.ui.FieldLayout( this.statusLabel, { align: 'top' } ),
new OO.ui.FieldLayout( this.typeLabel, { align: 'top' } ),
new OO.ui.FieldLayout( this.pageInput, { label: 'Page(s)', align: 'top' } ),
new OO.ui.FieldLayout( this.quoteInput, { label: 'Quote', align: 'top' } ),
new OO.ui.FieldLayout( this.refPreview, { label: 'Generated reference', align: 'top' } )
] );
this.$body.append( fieldset.$element );
};
RefGenDialog.prototype.getSetupProcess = function ( data ) {
return RefGenDialog.super.prototype.getSetupProcess.call( this, data )
.next( function () {
this.surface = ( data && data.surface ) || this.surface;
this.params = null;
this.urlInput.setValue( '' );
this.pageInput.setValue( '' );
this.quoteInput.setValue( '' );
this.refPreview.setValue( '' );
this.typeLabel.setLabel( '' );
this.statusLabel.setLabel( '' );
}, this );
};
RefGenDialog.prototype.onFetch = function () {
var self = this,
RefGen = mw.libs.refGen;
if ( !RefGen ) {
this.statusLabel.setLabel( 'Citation generator library not loaded.' );
return;
}
this.fetchButton.setDisabled( true ).setLabel( 'Loading…' );
this.statusLabel.setLabel( '' );
RefGen.fetchCitation( this.urlInput.getValue() ).done( function ( item ) {
self.params = RefGen.mapToParams( item );
self.typeLabel.setLabel( 'Detected type: {{' + self.params._template + '}}' );
self.refreshPreview();
} ).fail( function ( msg ) {
self.statusLabel.setLabel( String( msg ) );
} ).always( function () {
self.fetchButton.setDisabled( false ).setLabel( 'Fetch' );
} );
};
RefGenDialog.prototype.refreshPreview = function () {
if ( !this.params || !mw.libs.refGen ) {
return;
}
this.refPreview.setValue(
mw.libs.refGen.buildRef(
this.params,
this.pageInput.getValue(),
this.quoteInput.getValue()
)
);
};
RefGenDialog.prototype.getActionProcess = function ( action ) {
if ( action === 'insert' ) {
return new OO.ui.Process( function () {
this.insertCitation();
this.close( { action: action } );
}, this );
}
return RefGenDialog.super.prototype.getActionProcess.call( this, action );
};
/**
* Insert the generated citation as a proper VE reference node
* at the current cursor position.
*/
RefGenDialog.prototype.insertCitation = function () {
var params = this.params;
if ( !params || !this.surface ) {
return;
}
var page = this.pageInput.getValue().trim();
var quote = this.quoteInput.getValue().trim();
// Build the cite template as VE transclusion data
// (same params/order/guards as mw.libs.refGen.buildRef).
var mwParams = {};
var dropWebsite = params._template === 'cite news' &&
String( params.newspaper || '' ).trim() &&
String( params.website || '' ).trim();
[ 'url', 'title', 'author', 'date', 'website', 'newspaper', 'journal',
'publisher', 'volume', 'issue', 'pages', 'isbn', 'doi', 'accessdate'
].forEach( function ( k ) {
if ( k === 'website' && dropWebsite ) {
return;
}
var v = String( params[ k ] == null ? '' : params[ k ] ).trim();
if ( !v ) {
return;
}
mwParams[ k === 'accessdate' ? 'access-date' : k ] = { wt: v };
} );
if ( page ) {
mwParams.page = { wt: page };
}
if ( quote ) {
mwParams.quote = { wt: quote };
}
var names = {
'cite web': 'Cite web',
'cite book': 'Cite book',
'cite journal': 'Cite journal',
'cite news': 'Cite news',
'cite magazine': 'Cite magazine'
};
var tName = names[ params._template ] || 'Cite web';
var ns = mw.config.get( 'wgFormattedNamespaces' )[ '10' ];
var surfaceModel = this.surface.getModel();
var doc = surfaceModel.getDocument();
var ref = ve.dm.MWReferenceModel.static.newEmptyRef( doc );
ref.setDocument( doc.cloneWithData( [
{ type: 'paragraph' },
{
type: 'mwTransclusionInline',
attributes: {
mw: {
parts: [ {
template: {
target: { href: ns + ':' + tName, wt: tName },
params: mwParams
}
} ]
}
}
},
{ type: '/mwTransclusionInline' },
{ type: '/paragraph' },
{ type: 'internalList' },
{ type: '/internalList' }
] ) );
ref.setGroup( '' );
ref.insertIntoFragment( surfaceModel.getFragment().collapseToEnd() );
};
/* ---------------- Toolbar tool ---------------- */
function RefGenVeTool( toolGroup, config ) {
OO.ui.Tool.call( this, toolGroup, config );
}
OO.inheritClass( RefGenVeTool, OO.ui.Tool );
RefGenVeTool.static.name = 'refgen';
RefGenVeTool.static.group = 'insert';
RefGenVeTool.static.autoAddToGroup = 'insert';
RefGenVeTool.static.title = 'Ref-Gen';
RefGenVeTool.static.icon = 'code';
RefGenVeTool.prototype.onSelect = function () {
this.setActive( false );
var surface = this.toolbar.getSurface();
// Use the global window manager with a pre-created dialog instance:
// surface.getDialogs() does not reliably open plain OOUI dialogs.
ve.ui.windowManager.openWindow( refGenDialogInstance, { surface: surface } );
};
RefGenVeTool.prototype.onUpdateState = function () {
this.setActive( false );
};
ve.ui.windowFactory.register( RefGenDialog );
ve.ui.toolFactory.register( RefGenVeTool );
// Pre-create the dialog and attach it to the global window manager.
var refGenDialogInstance = new RefGenDialog();
ve.ui.windowManager.addWindows( [ refGenDialogInstance ] );
}() );