MediaWiki:Gadget-ProveIt.js
Apariencia
Nota: Después de guardar, debes refrescar la caché de tu navegador para ver los cambios. Internet Explorer: mantén presionada Ctrl mientras pulsas Actualizar. Firefox: mientras presionas Mayús pulsas el botón Actualizar, (o presiona Ctrl-Shift-R). Los usuarios de Google Chrome y Safari pueden simplemente pulsar el botón Recargar. Para más detalles e instrucciones acerca de otros exploradores, véase Ayuda:Cómo limpiar la caché.
/**
* ProveIt is a powerful GUI tool for viewing, editing, and inserting references on Wikipedia
*
* Copyright 2008-2011 Georgia Tech Research Corporation, Atlanta, GA 30332-0415
* Copyright 2011-? Matthew Flaschen
* Rewritten and internationalized by Luis Felipe Schenone in 2014
*
* ProveIt is available under the GNU Free Documentation License (http://www.gnu.org/copyleft/fdl.html),
* Creative Commons Attribution/Share-Alike License 3.0 (http://creativecommons.org/licenses/by-sa/3.0/),
* and the GNU General Public License 2 (http://www.gnu.org/licenses/gpl-2.0.html)
*/
( function ( mw, $ ) {
/**
* Second parameter (pre-existing proveit object, if any) passed to extend overrides first.
* Gives users the option to easily override initial constants, such as shouldAddSummary.
* If proveit is unintentionally imported more than once, the first import will take precedence.
*/
var proveit = window.proveit = $.extend({
LANGUAGE: 'es',
LOGO: '//proveit-js.googlecode.com/hg/static/logo.png',
ICON: '/media/wikipedia/commons/thumb/1/19/ProveIt_logo_for_user_boxes.svg/22px-ProveIt_logo_for_user_boxes.svg.png',
//Should ProveIt start visible?
startVisible: true,
//Should ProveIt start maximized?
startMaximized: false,
//Should ProveIt add an edit summary?
shouldAddSummary: true,
//Convenience function that returns the message for the given key in the current language
getMessage: function( key ) {
return this['i18n'][ this.LANGUAGE ]['messages'][ key ];
},
//Convenience function that returns all the registered templates
getRegisteredTemplates: function() {
return this['i18n'][ this.LANGUAGE ]['templates'];
},
//Convenience function that returns the edit textarea
getTextbox: function() {
return $( '#wpTextbox1' );
},
//Convenience function that returns the text in the edit textarea
getTextboxText: function() {
return this.getTextbox().val();
},
/**
* Initializes ProveIt
*/
start: function() {
//Initialize only when editing
if ( wgAction == 'edit' || wgAction == 'submit' ) {
var dependencies = [
'jquery.ui.tabs',
'jquery.ui.button',
'jquery.effects.highlight',
'jquery.textSelection'
];
mw.loader.using( dependencies, function() {
//If the user is using WikiEditor, add the ProveIt button to the toolbar
var textbox = proveit.getTextbox();
textbox.bind( 'wikiEditor-toolbar-buildSection-main', function( event, section ) {
section.groups.insert.tools.proveit = {
label: 'ProveIt',
type: 'button',
icon: proveit.ICON,
action: {
type: 'callback',
execute: function() {
$( '#proveit' ).toggle();
}
}
};
delete section.groups.insert.tools.reference; //Also delete the references button
});
proveit.createGUI();
//Only show the gadget on pages that are likely to contain references
if ( wgCanonicalNamespace == '' || wgCanonicalNamespace == 'User' ) {
if ( proveit.startVisible ) {
$( '#proveit' ).show();
}
if ( proveit.startMaximized ) {
$( '#proveit-logo' ).click();
}
}
});
}
},
/**
* Provides the x (left) and y (top) offsets to a given element.
* From QuirksMode (http://www.quirksmode.org/js/findpos.html), a freely available site by Peter-Paul Koch
* @param {Node} node any HTML node
* @return {Object} offsets to node, as object with left and top properties.
*/
getOffset: function( node ) {
var left = 0, top = 0;
do {
left += node.offsetLeft;
top += node.offsetTop;
} while ( node = node.offsetParent );
return { 'left': left, 'top': top };
},
/**
* Highlights a given length of text, starting at a particular index
* @param {Number} startInd start index in Wikipedia edit textbox
* @param {Number} length length of string to highlight
* @return {Boolean} always true
*/
highlightLengthAtIndex: function( startIndex, length ) {
var textbox = this.getTextbox()[0];
var referenceStringText = textbox.value;
var editTop = this.getOffset( textbox ).top;
textbox.value = referenceStringText.substring( 0, startIndex );
textbox.focus();
textbox.scrollTop = 1000000; //Larger than any real textarea (hopefully)
var curScrollTop = textbox.scrollTop;
textbox.value += referenceStringText.substring( startIndex );
if ( curScrollTop > 0 ) {
textbox.scrollTop = curScrollTop + 200;
}
$( textbox ).focus().textSelection( 'setSelection', {
start: startIndex,
end: startIndex + length
});
editTop = this.getOffset( textbox ).top;
window.scroll( 0, editTop );
return true;
},
/**
* Highlights the first instance of a given string in the MediaWiki edit textbox
* @param {String} targetStr the string in the edit textbox to highlight
* @return {Boolean} true if successful, false otherwise
*/
highlightTargetString: function( targetString ) {
var referenceStringText = this.getTextboxText();
var startIndex = referenceStringText.indexOf( targetString );
if ( startIndex == -1 ) {
return false;
}
return this.highlightLengthAtIndex( startIndex, targetString.length );
},
/**
* Adds the ProveIt edit summary to the edit summary field
*/
addSummary: function() {
if ( ! this.shouldAddSummary ) {
return false;
}
var summary = $( '#wpSummary' ).val()
if ( summary ) { //If the user has already added a summary, don't screw it up
return false;
}
summary = proveit.getMessage( 'summary' );
$( '#wpSummary' ).val( summary );
return true;
},
/**
* Populates the edit pane with the data of the selected reference
* @param {TemplateReference} the selected reference
*/
fillEditPane: function( reference ) {
//Remove all the fields
var editFields = $( '#proveit-edit-fields' );
editFields.children().remove( '.input-row' );
var refNameRow = $( '<div/>', { 'class': 'ref-name-row input-row' } );
var refNameLabel = $( '<label/>', { 'for': 'edit-ref-name', 'text': this.getMessage( 'ref_name_label' ) } );
var refNameInput = $( '<input/>', { id: 'edit-ref-name', 'class': 'param-value', 'value': reference.name } );
var deleteFieldButton = $( '<button/>', { 'class': 'delete-field-button', 'text': '×' } );
refNameRow.append( refNameLabel );
refNameRow.append( refNameInput );
refNameRow.append( deleteFieldButton );
editFields.append( refNameRow );
//Insert one row for each parameter, registered or not
//Hide the non-default parameters, unless they are filled
//Skip the delete button in the required parameters
var registeredParams = reference.getRegisteredParams();
var defaultParams = reference.getDefaultParams();
var requiredParams = reference.getRequiredParams();
for ( var paramName in registeredParams ) {
var paramLabel = reference.getParamLabel( paramName );
var paramValue = reference.params[ paramName ];
var row = $( '<div/>', { 'class': 'input-row param-row' } );
if ( ! ( paramName in defaultParams ) && ! paramValue ) {
row.addClass( 'hidden' );
}
var label = $( '<label/>', { 'for': paramName, 'text': paramLabel } );
var nameInput = $( '<input/>', { 'type': 'hidden', 'class': 'param-name', 'value': paramName } );
var valueInput = $( '<input/>', { 'id': paramName, 'class': 'param-value', 'value': paramValue } );
row.append( label );
row.append( nameInput );
row.append( valueInput );
if ( ! ( paramName in requiredParams ) ) {
row.append( deleteFieldButton.clone() );
}
editFields.append( row );
}
$( '.update-button' ).click( function() {
reference.update();
});
$( '#proveit-edit-buttons .params-button' ).click( function() {
$( this ).hide();
$( '#proveit-edit-buttons .add-field-button' ).show();
$( '#proveit-edit-fields .param-row' ).show();
});
$( '.delete-field-button' ).click( function() {
//First hide the row with a quick animation, then remove it
$( this ).parent().hide( 'fast', function() {
$( this ).remove();
});
});
},
addCustomField: function( fields ) {
var row = $( '<div/>', { 'class': 'input-row param-row' } );
var nameInput = $( '<input/>', { 'class': 'param-name' } );
var valueInput = $( '<input/>', { 'class': 'param-value' } );
var deleteFieldButton = $( '<button/>', { 'class': 'delete-field-button', 'text': '×' } );
row.append( nameInput );
row.append( valueInput );
row.append( deleteFieldButton );
fields.append( row );
deleteFieldButton.click( function() {
$( this ).parent().hide( 'fast', function() {
$( this ).remove();
});
});
},
/**
* Cross-browser implementation of ECMAScript String.prototype.split function 1.0.1
* (c) Steven Levithan <stevenlevithan.com>; MIT License
* http://blog.stevenlevithan.com/archives/cross-browser-split
*
* @param {String} str input string to split
* @param separator separator to split on, as RegExp or String
* @param {Number} limit limit on number of splits. If the parameter is absent, no limit is imposed.
* @return {Array} array resulting from split
*/
_compliantExecNpcg: /()??/.exec( '' )[1] === undefined, //NPCG: non-participating capturing group
_nativeSplit: String.prototype.split,
split: function( str, separator, limit ) {
//If 'separator' is not a regex, use the native 'split'
if ( Object.prototype.toString.call( separator ) !== "[object RegExp]" ) {
return proveit._nativeSplit.call( str, separator, limit );
}
var output = [],
lastLastIndex = 0,
flags = ( separator.ignoreCase ? "i" : "" ) + ( separator.multiline ? "m" : "" ) + ( separator.sticky ? "y" : "" ),
separator = RegExp( separator.source, flags + "g" ), //Make 'global' and avoid 'lastIndex' issues by working with a copy
separator2,
match,
lastIndex,
lastLength;
str = str + ""; //type conversion
if ( ! proveit._compliantExecNpcg ) {
separator2 = RegExp( "^" + separator.source + "$(?!\\s)", flags ); //Doesn't need /g or /y, but they don't hurt
}
/**
* Behavior for 'limit'. If it's...
* - undefined: no limit
* - NaN or zero: return an empty array
* - a positive number: use Math.floor(limit)
* - a negative number: no limit
* - other: type-convert, then use the above rules
*/
if ( limit === undefined || +limit < 0 ) {
limit = Infinity;
} else {
limit = Math.floor( +limit );
if ( ! limit) {
return [];
}
}
while ( match = separator.exec( str ) ) {
lastIndex = match.index + match[0].length; //separator.lastIndex is not reliable cross-browser
if ( lastIndex > lastLastIndex ) {
output.push( str.slice( lastLastIndex, match.index ) );
//fix browsers whose `exec` methods don't consistently return `undefined` for nonparticipating capturing groups
if ( ! proveit._compliantExecNpcg && match.length > 1 ) {
match[0].replace( separator2, function () {
for ( var i = 1; i < arguments.length - 2; i++ ) {
if ( arguments[ i ] === undefined ) {
match[ i ] = undefined;
}
}
});
}
if ( match.length > 1 && match.index < str.length ) {
Array.prototype.push.apply( output, match.slice(1) );
}
lastLength = match[0].length;
lastLastIndex = lastIndex;
if ( output.length >= limit ) {
break;
}
}
if ( separator.lastIndex === match.index ) {
separator.lastIndex++; //Avoid an infinite loop
}
}
if ( lastLastIndex === str.length ) {
if ( lastLength || ! separator.test("") ) {
output.push("");
}
} else {
output.push( str.slice( lastLastIndex ) );
}
return output.length > limit ? output.slice( 0, limit ) : output;
},
//TODO: Remove the split code, and just use a regular regex (with two main groups for key and value), iteratively.
//Regex.find? Make key and value indices match, and rework calling code as needed.
//Also, check how this was done in the original code.
/**
* Overly clever regex to parse template string (e.g. |last=Smith|first=John|title=My Life Story) into key and value pairs
* @param {String} templateString template string to parse.
* @return {Object} object with two properties, keys and values.
*/
splitKeysAndValues: function( templateString ) {
var split = {};
//The first component is "ordinary" text (no pipes), while the second is a correctly balanced wikilink, with optional pipe. Any combination of the two can appear.
split.keys = proveit.split( templateString.substring( templateString.indexOf( '|' ) + 1 ), /=(?:[^|]*?(?:\[\[[^|\]]*(?:\|(?:[^|\]]*))?\]\])?)+(?:\||\}\})/ );
split.keys.length--; //Remove single empty element at end
split.values = proveit.split( templateString.substring( templateString.indexOf( '=' ) + 1, templateString.indexOf( '}}' ) ), /\|[^|=]*=/ );
return split;
},
/**
* Scan for references in the MWEditBox, and create a reference object and refBoxRow for each.
*/
scanForReferences: function() {
$( '#proveit-view-pane' ).children().remove();
//First look for all the citations
var text = this.getTextboxText();
var citations = [];
//Three possibilities: <ref name="foo" />, <ref name='bar' /> or <ref name=baz />
var citationsRegExp = /<\s*ref\s+name\s*=\s*["|']?\s*([^"'\s]+)\s*["|']?\s*\/\s*>/gi;
//Then create an object for each and store it for later
while ( match = citationsRegExp.exec( text ) ) {
citations.push({
'string': match[0],
'index': match['index'],
'name': match[1]
})
}
//Next, look for all the raw references and template references
var referencesRegExp = new RegExp( '<\s*ref.*?<\s*\/\s*ref\s*>', 'gi' );
var matches = text.match( referencesRegExp );
if ( ! matches ) {
console.log( this.getMessage( 'no_references' ) );
var noReferencesMessage = $( '<div/>', { 'id': 'proveit-no-references-message', 'text': this.getMessage( 'no_references' ) } );
$( '#proveit-view-pane' ).append( noReferencesMessage );
return;
}
for ( var i = 0; i < matches.length; i++ ) {
var reference = this.makeReference( matches[ i ] );
//For each reference, check if there are any citations to it
for ( var j = 0; j < citations.length; j++ ) {
var citation = citations[ j ];
//And if there are, add the citation to the reference
if ( reference.name == citation.name ) {
reference.citations.push( citation );
}
}
//Finally, insert all the references into the view pane
var referenceRow = this.makeReferenceRow( reference );
$( '#proveit-view-pane' ).append( referenceRow );
}
},
makeReference: function( referenceString ) {
var registeredTemplates = proveit.getRegisteredTemplates();
var registeredTemplatesArray = [];
for ( var registeredTemplate in registeredTemplates ) {
registeredTemplatesArray.push( registeredTemplate );
}
var registeredTemplatesDisjunction = registeredTemplatesArray.join( '|' );
var regExp = new RegExp( '{{(' + registeredTemplatesDisjunction + ').*}}', 'i' );
var match = referenceString.match( regExp );
var reference = match ? new this.TemplateReference({}) : new this.RawReference({});
//Extract the name of the template
if ( reference.type == 'TemplateReference' ) {
var templateString = match[0];
var regExp = new RegExp( registeredTemplatesDisjunction, 'i' );
var template = templateString.match( regExp )[0];
//Normalize the uppercase and lowercase letters
for ( var registeredTemplate in registeredTemplates ) {
if ( template.toLowerCase() == registeredTemplate.toLowerCase() ) {
template = registeredTemplate;
}
}
reference.template = template;
}
//Extract the name of the reference, if any
//There are three possibilities: <ref name="foo">, <ref name='bar'>, and <ref name=baz>
var regExp = /<[\s]*ref[\s]*name[\s]*=[\s]*(?:(?:\"(.*?)\")|(?:\'(.*?)\')|(?:(.*?)))[\s]*\/?[\s]*>/i;
var match = referenceString.match( regExp );
if ( match ) {
reference.name = match[1] || match[2] || match[3];
}
reference.string = referenceString;
//Extract the parameters
if ( reference.type == 'TemplateReference' ) {
var split = this.splitKeysAndValues( templateString );
var keys = split.keys;
var values = split.values;
for ( var i = 0; i < keys.length; i++ ) {
var key = keys[ i ];
var value = values[ i ];
//Drop blank space, and |'s without params, which are never correct for citation templates
key = $.trim( key ).replace( /(?:\s*\|)*(.*)/, "$1" );
value = $.trim( value );
//TODO: Should there be a setParam function?
//It could handle empty values, and even drop (siliently or otherwise) invalid parameters
//Alternatively, should params be passed in the constructor?
if ( value ) {
reference.params[ key ] = value;
}
}
}
return reference;
},
/**
* Generates refbox row and all children, to be used by scanForReferences
* @param {AbstractReference} ref reference to generate from
* @return {Node} new row for refbox
*/
makeReferenceRow: function( reference ) {
//Create an empty row
//Right now this rows only contain one td, so they could be replaced by divs, but in the near future they may not
var row = $( '<div/>', { 'class': 'reference-row' } );
//Fill the row
if ( reference.type == 'RawReference' ) {
var rowContent = reference.string;
} else if ( reference.type == 'TemplateReference' ) {
var rowContent = '<span class="template">' + reference.template + '</span>';
//TODO: Display the first few params, not the required ones
var requiredParams = reference.getRequiredParams();
for ( var requiredParam in requiredParams ) {
var label = reference.getParamLabel( requiredParam );
var value = reference.params[ requiredParam ];
rowContent += '<span class="label">' + label + '</span>: <span class="value">' + value + '</span>';
}
}
rowContent += '<span class="citations">';
for ( var i = 0; i < reference.citations.length; i++ ) {
var citationIndex = i + 1;
rowContent += '<a href="#" class="citation">' + citationIndex + '</a>';
}
rowContent += '</span>';
row.html( rowContent );
//Event handlers
$( row ).click( function() {
proveit.highlightTargetString( reference.string );
if ( reference.type == 'TemplateReference' ) {
proveit.fillEditPane( reference );
$( '#proveit-view-pane' ).hide();
$( '#proveit-edit-pane' ).show();
}
});
$( 'a.citation', row ).click( function( event ) {
event.stopPropagation();
var i = $( this ).text() - 1;
var citation = reference.citations[ i ];
//TODO: If the user edits the textbox manually, the following will cease to highlight correctly
proveit.highlightLengthAtIndex( citation.index, citation.string.length );
return false;
});
return row;
},
/**
* Constructs a reference out of the contents of the add tab and inserts it into the textbox
*/
insertReference: function() {
var addTab = $( '#proveit-add-tab' );
var referenceName = $( '#add-ref-name' ).val();
var referenceTemplate = $( '#add-template' ).val();
var reference = new this.TemplateReference( { 'name': referenceName, 'template': referenceTemplate } );
var paramRows = $( 'div.param-row', addTab );
var paramRow, paramName, paramValue;
for ( var i = 0; i < paramRows.length; i++ ) {
paramRow = paramRows[ i ];
paramName = $( '.param-name', paramRow ).val();
paramValue = $( '.param-value', paramRow ).val();
if ( paramName != '' && paramValue != '' ) { //Non-blank
reference.params[ paramName ] = paramValue;
}
}
reference.string = reference.toString();
//Replace existing selection (if any), then scroll
var textbox = proveit.getTextbox();
textbox.textSelection( 'encapsulateSelection', {
peri: reference.string,
replace: true
});
var caretPos = textbox.textSelection( 'getCaretPosition', { startAndEnd: true } );
this.addSummary();
//Update the view pane by scanning the references again
proveit.scanForReferences()
},
/**
* Changes the params in the add panel according to the template selected
* @param {string} template selected from the dropdown menu
*/
changeAddPane: function( template ) {
var reference = new this.TemplateReference( { 'template': template } );
var addFields = $( '#proveit-add-fields' );
//Remove all the fields except the <ref> name and the dropdown menu
addFields.children().remove( '.param-row' );
//Insert one row for each parameter, registered or not
//Hide the non-default parameters, unless they are filled
//Skip the delete button in the required parameters
var registeredParams = reference.getRegisteredParams();
var defaultParams = reference.getDefaultParams();
var requiredParams = reference.getRequiredParams();
for ( var paramName in registeredParams ) {
var paramLabel = reference.getParamLabel( paramName );
var paramValue = reference.params[ paramName ];
var row = $( '<div/>', { 'class': 'input-row param-row' } );
if ( ! ( paramName in defaultParams ) && ! paramValue ) {
row.addClass( 'hidden' );
}
var label = $( '<label/>', { 'for': paramName, 'text': paramLabel } );
var nameInput = $( '<input/>', { 'type': 'hidden', 'class': 'param-name', 'value': paramName } );
var valueInput = $( '<input/>', { 'id': paramName, 'class': 'param-value', 'value': paramValue } );
var deleteFieldButton = $( '<button/>', { 'class': 'delete-field-button', 'text': '×' } );
row.append( label );
row.append( nameInput );
row.append( valueInput );
if ( ! ( paramName in requiredParams ) ) {
row.append( deleteFieldButton );
}
addFields.append( row );
}
},
createGUI: function() {
//TODO: There should be no need for this check
if ( $( '#proveit' ).length > 0 ) {
return false; //GUI already created
}
var gui = $( '<div/>', { id: 'proveit' } );
var tabs = $( '<div/>', { id: 'proveit-tabs' } );
//Logo
var logo = $( '<img/>', { id: 'proveit-logo', src: proveit.LOGO, alt: 'ProveIt' } );
tabs.append( logo );
/* Tab list */
var list = $( '<ul/>' );
//View tab link
var viewItem = $( '<li/>' );
var viewLink = $( '<a/>', { id: 'view-link', 'class': 'tab-link', href: '#proveit-view-tab', 'text': this.getMessage( 'edit_tab' ) } );
viewItem.append( viewLink );
list.append( viewItem );
//Add tab link
var addItem = $( '<li/>' );
var addLink = $( '<a/>', { id: 'add-link', 'class': 'tab-link', href: '#proveit-add-tab', 'text': this.getMessage( 'add_tab' ) } );
addItem.append( addLink );
list.append( addItem );
tabs.append( list );
/* View tab */
var viewTab = $( '<div/>', { id: 'proveit-view-tab', 'class': 'hidden' } );
//View pane
var viewPane = $( '<div/>', { id: 'proveit-view-pane' } );
viewTab.append( viewPane );
//Edit pane
var editPane = $( '<div/>', { id: 'proveit-edit-pane', 'class': 'hidden scroll' } );
//Edit fields
var editFields = $( '<div/>', { id: 'proveit-edit-fields' } );
editPane.append( editFields );
//Edit buttons
var editButtons = $( '<div/>', { id: 'proveit-edit-buttons' } );
var addFieldButton = $( '<button/>', { 'class': 'add-field-button', 'text': this.getMessage( 'add_field_button' ) } );
var paramsButton = $( '<button/>', { 'class': 'params-button', 'text': this.getMessage( 'params_button' ) } );
var updateButton = $( '<button/>', { 'class': 'update-button', 'text': this.getMessage( 'update_button' ) } );
editButtons.append( addFieldButton );
editButtons.append( paramsButton );
editButtons.append( updateButton );
editPane.append( editButtons );
viewTab.append( editPane );
tabs.append( viewTab );
/* Add tab */
var addTab = $( '<div/>', { id: 'proveit-add-tab' } );
var addFields = $( '<div/>', { id: 'proveit-add-fields' } );
//First insert the row for the <ref> name
var refNameRow = $( '<div/>', { 'class': 'ref-name-row input-row' } );
var refNameLabel = $( '<label/>', { 'for': 'add-ref-name', 'text': this.getMessage( 'ref_name_label' ) } );
var refNameInput = $( '<input/>', { id: 'add-ref-name', 'class': 'param-value' } );
var deleteFieldButton = $( '<button/>', { 'class': 'delete-field-button', 'text': '×' } );
refNameRow.append( refNameLabel );
refNameRow.append( refNameInput );
refNameRow.append( deleteFieldButton );
addFields.append( refNameRow );
//Then insert the row for the dropdown menu
var templateRow = $( '<div/>', { id: 'cite', 'class': 'input-row' } );
var templateLabel = $( '<label/>', { 'for': 'add-template', 'text': this.getMessage( 'template_label' ) } );
var templateSelect = $( '<select/>', { id: 'add-template' } );
var templates = proveit.getRegisteredTemplates();
for ( var templateName in templates ) {
var templateOption = $( '<option/>', { 'value': templateName, 'text': templateName } );
templateSelect.append( templateOption );
}
templateRow.append( templateLabel );
templateRow.append( templateSelect );
addFields.append( templateRow );
addTab.append( addFields );
//After the fields, insert the buttons
var addButtons = $( '<div/>', { id: 'proveit-add-buttons' } );
var insertButton = $( '<button/>', { 'class': 'insert-button', 'text': this.getMessage( 'insert_button' ) } );
var paramsButton = $( '<button/>', { 'class': 'params-button', 'text': this.getMessage( 'params_button' ) } );
addButtons.append( addFieldButton.clone() );
addButtons.append( paramsButton );
addButtons.append( insertButton );
addTab.append( addButtons );
//Fourth, add everything to the DOM
tabs.append( addTab );
gui.append( tabs );
$( document.body ).prepend( gui );
//Now that everything is on the DOM, we can call this method to fill the rest of the add tab
this.changeAddPane( templateSelect.val() );
//Set up tabs
$( '#proveit-tabs' ).tabs();
/* Event handlers */
logo.click( function() {
viewTab.toggle();
addTab.toggle();
});
viewLink.click( function() {
if ( viewTab.is( ':visible' ) ) {
viewPane.show();
editPane.hide();
} else {
viewTab.show();
}
});
addLink.click( function() {
addTab.show();
});
insertButton.click( function() {
proveit.insertReference();
$( '#proveit-tabs' ).tabs( { selected: '#proveit-view-tab' } );
$( 'div.scroll, #proveit-view-pane' ).scrollTop( 100000 ); //Scroll to the new reference
});
$( '#proveit-add-buttons .add-field-button' ).click( function() {
proveit.addCustomField( $( '#proveit-add-fields' ) );
});
$( '#proveit-edit-buttons .add-field-button' ).click( function() {
proveit.addCustomField( $( '#proveit-edit-fields' ) );
});
templateSelect.change( function() {
proveit.changeAddPane( templateSelect.val() );
});
$( '#proveit-add-buttons .params-button' ).click( function() {
$( this ).hide();
$( '#proveit-add-buttons .add-field-button' ).show();
$( '#proveit-add-fields .param-row' ).show();
});
$( '.delete-field-button' ).click( function() {
//First hide the row with a quick animation, then remove it
$( this ).parent().hide( 'fast', function() {
$( this ).remove();
});
});
this.scanForReferences();
},
RawReference: function( argObj ) {
this.type = 'RawReference';
this.name = argObj.name ? argObj.name : '';
this.string = argObj.string ? argObj.string : '';
this.citations = [];
this.toString = function() {
return this.string;
};
this.updateInTextbox = function() {
var textbox = proveit.getTextbox();
textbox[0].focus();
var text = proveit.getTextboxText();
text = text.replace( this.string, this.toString() );
//Do replacement in textarea
textbox.val( text );
//Baseline for future modifications
this.string = this.toString();
this.save = true;
proveit.highlightTargetString( this.toString() );
};
},
TemplateReference: function( argObj ) {
//Extend RawReference
proveit.RawReference.call( this, argObj );
//Override
this.type = 'TemplateReference';
this.params = {};
this.template = argObj.template ? argObj.template : '';
this.update = function() {
var editPane = $( '#proveit-edit-pane' );
var name = $( '#edit-ref-name' ).val();
this.name = name ? name : null; //Save blank names as null
//Clear old params
this.params = {};
var paramRows = $( 'div.param-row', editPane );
var paramRow, paramName, paramValue;
for ( var i = 0; i < paramRows.length; i++ ) {
paramRow = paramRows[ i ];
paramName = $( '.param-name', paramRow ).val();
paramValue = $( '.param-value', paramRow ).val();
if ( paramName != '' && paramValue != '' ) {
this.params[ paramName ] = paramValue;
}
}
this.updateInTextbox();
proveit.scanForReferences();
proveit.addSummary();
$( '#proveit-logo' ).click();
return this;
}
//Override
this.toString = function() {
var string;
if ( this.name ) {
string = '<ref name="' + this.name + '">';
} else {
string = '<ref>';
}
string += '{{' + this.template;
for ( var name in this.params ) {
string += ' |' + name + '=' + this.params[ name ];
}
string += '}}</ref>';
return string;
};
this.getRegisteredParams = function() {
return proveit.getRegisteredTemplates()[ this.template ];
};
this.getParamLabel = function( param ) {
return this.getRegisteredParams()[ param ][ 'label' ];
};
this.getRequiredParams = function() {
var requiredParams = {};
var registeredParams = this.getRegisteredParams();
for ( var registeredParam in registeredParams ) {
if ( registeredParams[ registeredParam ][ 'required' ] === true ) {
requiredParams[ registeredParam ] = registeredParams[ registeredParam ];
}
}
return requiredParams;
};
this.getDefaultParams = function() {
var defaultParams = {};
var registeredParams = this.getRegisteredParams();
for ( var registeredParam in registeredParams ) {
if ( registeredParams[ registeredParam ][ 'default' ] === true ) {
defaultParams[ registeredParam ] = registeredParams[ registeredParam ];
}
}
return defaultParams;
};
}
}, window.proveit );
$( proveit.start );
}( mediaWiki, jQuery ) );