Sophivorus has uploaded a new change for review. https://gerrit.wikimedia.org/r/314828
Change subject: Many improvements ...................................................................... Many improvements - Improved comments - Improved CSS class naming - Code pretification - Merged RawReference class with TemplateReference class - Allow to switch between templates without losing data - Allow to drag and resize widget - Bugfixes - All config options are now optional - Add button to delete references and all their citations - Add button to add a citation to a reference Change-Id: Id7ce3cf5776e30f7336e25c92a19746d3a363568 --- M proveit.css M proveit.js 2 files changed, 417 insertions(+), 336 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/wikipedia/gadgets/ProveIt refs/changes/28/314828/1 diff --git a/proveit.css b/proveit.css index 54b47e6..dc4762e 100755 --- a/proveit.css +++ b/proveit.css @@ -74,11 +74,11 @@ cursor: pointer; } -#proveit-reference-list .proveit-reference-item .proveit-template { +#proveit-reference-list .proveit-reference-item .proveit-reference-template { font-weight: bold; } -#proveit-reference-list .proveit-reference-item .proveit-required-value { +#proveit-reference-list .proveit-reference-item .proveit-required-param-value { margin-left: 10px; } @@ -134,7 +134,7 @@ } #proveit-reference-form textarea { - height: 100px; + height: 60px; resize: vertical; } @@ -158,6 +158,13 @@ border-radius: 3px; cursor: pointer; font: inherit; + margin-left: 10px; padding: 5px; pointer-events: all; +} + +#proveit-buttons #proveit-cite-button, +#proveit-buttons #proveit-remove-button, +#proveit-buttons #proveit-params-button { + background: none; } \ No newline at end of file diff --git a/proveit.js b/proveit.js index d8273f5..83e7a78 100755 --- a/proveit.js +++ b/proveit.js @@ -16,6 +16,11 @@ var proveit = { /** + * URL of the ProveIt icon hosted at Commons + */ + ICON: '//upload.wikimedia.org/wikipedia/commons/thumb/1/19/ProveIt_logo_for_user_boxes.svg/22px-ProveIt_logo_for_user_boxes.svg.png', + + /** * Interface messages */ messages: { @@ -23,20 +28,32 @@ 'proveit-edit-tab': 'Edit', 'proveit-add-tab': 'Add', 'proveit-reference-name-label': 'Reference name', - 'proveit-reference-text-label': 'Reference text', - 'proveit-template-label': 'Template', + 'proveit-reference-content-label': 'Reference content', + 'proveit-reference-template-label': 'Main template', + 'proveit-params-button': 'Show all parameters', + 'proveit-cite-button': 'Cite', + 'proveit-remove-button': 'Remove', 'proveit-insert-button': 'Insert', 'proveit-update-button': 'Update', + 'proveit-prompt-name': 'The reference needs a name in order to be cited:', + 'proveit-confirm-remove': 'This will remove the reference and all of its citations. Are you sure?', + 'proveit-no-template': 'No template', 'proveit-no-references': 'No references found' }, 'es': { 'proveit-edit-tab': 'Editar', 'proveit-add-tab': 'Agregar', 'proveit-reference-name-label': 'Nombre de la referencia', - 'proveit-reference-text-label': 'Texto de la referencia', - 'proveit-template-label': 'Plantilla', + 'proveit-reference-content-label': 'Contenido de la referencia', + 'proveit-reference-template-label': 'Plantilla principal', + 'proveit-params-button': 'Ver todos los parámetros', + 'proveit-cite-button': 'Citar', + 'proveit-remove-button': 'Borrar', 'proveit-insert-button': 'Insertar', 'proveit-update-button': 'Actualizar', + 'proveit-prompt-name': 'La referencia necesita un nombre para ser citada:', + 'proveit-confirm-remove': 'Esto borrará la referencia y todas sus citas. ¿Estás seguro?', + 'proveit-no-template': 'Sin plantilla', 'proveit-no-references': 'No se han encontrado referencias' } }, @@ -49,10 +66,9 @@ templates: {}, /** - * Interface language - * The default or fallback language is English + * Interface language (may be different from the content language) * - * @type {string} + * @type {string} defaults to English */ userLanguage: 'en', @@ -79,7 +95,7 @@ /** * Convenience method to get the edit textbox * - * @return {jQuery} Edit textbox + * @return {jQuery} edit textbox */ getTextbox: function () { return $( '#wpTextbox1' ); @@ -103,22 +119,47 @@ proveit.build(); // Get the template data from the wiki + var templates = proveit.getOption( 'templates' ); new mw.Api().get({ 'action': 'templatedata', - 'titles': proveit.getOption( 'templates' ).join( '|' ), + 'titles': templates ? templates.join( '|' ) : null, 'format': 'json' }).done( function ( data ) { //console.log( data ); for ( var page in data.pages ) { page = data.pages[ page ]; - proveit.templates[ page.title ] = page.params; // Set the template data + proveit.templates[ page.title ] = page.params; } proveit.scanForReferences(); + }); + + // Replace the reference button for the ProveIt button + proveit.getTextbox().wikiEditor( 'removeFromToolbar', { + 'section': 'main', + 'group': 'insert', + 'tool': 'reference' + }); + proveit.getTextbox().wikiEditor( 'addToToolbar', { + 'section': 'main', + 'group': 'insert', + 'tools': { + 'proveit': { + 'label': 'ProveIt', + 'type': 'button', + 'icon': proveit.ICON, + 'action': { + 'type': 'callback', + 'execute': function () { + $( '#proveit' ).toggle(); + } + } + } + } }); }, /** - * Build the GUI and insert it into the DOM + * Build the GUI and add it to the DOM * * @return {void} */ @@ -142,18 +183,20 @@ // Make the GUI draggable var dragged = false; - gui.draggable({ - handle: header, - containment: 'window', - start: function ( event ) { - if ( event.toElement.id !== 'proveit-header' ) { - dragged = true; + mw.loader.using( 'jquery.ui.draggable' ).then( function () { + gui.draggable({ + handle: header, + containment: 'window', + start: function ( event ) { + if ( event.toElement.id !== 'proveit-header' ) { + dragged = true; + } + gui.css({ + 'right': 'auto', + 'bottom': 'auto' + }); } - gui.css({ - 'right': 'auto', - 'bottom': 'auto' - }); - } + }); }); // Lastly, bind events @@ -188,27 +231,24 @@ dragged = false; // Reset the flag return; } - $( this ).addClass( 'active' ).siblings().removeClass( 'active' ); - - // Create an dummy reference and a dummy form out of it - var template = $.cookie( 'proveit-last-template' ); - if ( !template ) { - template = Object.keys( proveit.templates )[0]; - template = template.substring( template.indexOf( ':' ) + 1 ); - } - var dummyReference = new proveit.TemplateReference({ 'template': template }), + // Create a dummy reference and a dummy form out of it + var template = $.cookie( 'proveit-last-template' ), // Remember the user choice + dummyReference = new proveit.Reference({ 'template': template }), dummyForm = dummyReference.toForm(); content.html( dummyForm ); - $( '#proveit-update-button' ).hide(); + // Switch the GUI to add mode + $( this ).addClass( 'active' ).siblings().removeClass( 'active' ); + $( '#proveit-insert-button' ).show(); + $( '#proveit-cite-button, #proveit-remove-button, #proveit-update-button' ).hide(); }); }, /** * Scan for references in the textbox and display them * - * @return {boolean} Whether the scan succeeded and found at least one reference + * @return {void} */ scanForReferences: function () { @@ -218,7 +258,7 @@ // Second, look for all the citations in the wikitext and store them in an array for later var wikitext = proveit.getTextbox().val(), citations = [], - citationsRegExp = /<\s*ref\s+name\s*=\s*["|']?\s*([^"'\s]+)\s*["|']?\s*\/\s*>/ig, // Three possibilities: <ref name="foo" />, <ref name='foo' /> and <ref name=foo /> + citationsRegExp = /<\s*ref\s+name\s*=\s*["|']?\s*([^"'\s]+)\s*["|']?\s*\/\s*>/ig, // Three patterns: <ref name="foo" />, <ref name='foo' /> and <ref name=foo /> match, citation; @@ -228,65 +268,78 @@ } // Third, look for all the raw and template references - var matches = wikitext.match( /<\s*ref[^\/]*>[\s\S]*?<\s*\/\s*ref\s*>/ig ); + var matches = wikitext.match( /<\s*ref[^\/]*>[\s\S]*?<\s*\/\s*ref\s*>/ig ); // We use [\s\S]* instead of .* to match newlines - if ( !matches ) { - var noReferencesMessage = $( '<div>' ).attr( 'id', 'proveit-no-references-message' ).text( proveit.getMessage( 'no-references' ) ); - referenceList.append( noReferencesMessage ); - return false; - } + if ( matches ) { + var i, j, reference, referenceItem; + for ( i = 0; i < matches.length; i++ ) { + // Turn all the matches into reference objects + reference = proveit.makeReference( matches[ i ] ); - var i, j, reference, referenceItem; - for ( i = 0; i < matches.length; i++ ) { - // Turn all the matches into reference objects - reference = proveit.makeReference( matches[ i ] ); - - // For each reference, check the citations array for citations to it - for ( j = 0; j < citations.length; j++ ) { - citation = citations[ j ]; - if ( reference.name === citation.name ) { - reference.citations.push( citation ); + // For each reference, check the citations array for citations to it + for ( j = 0; j < citations.length; j++ ) { + citation = citations[ j ]; + if ( reference.name === citation.name ) { + reference.citations.push( citation ); + } } + + // Finally, turn all the references into list items and insert them into the reference list + referenceItem = reference.toListItem(); + referenceList.append( referenceItem ); } - // Finally, turn all the references into list items and insert them into the reference list - referenceItem = reference.toListItem(); - referenceList.append( referenceItem ); + $( '#proveit-content' ).html( referenceList ); + } else { + $( '#proveit-content' ).html( $( '<div>' ).attr( 'id', 'proveit-no-references-message' ).text( proveit.getMessage( 'no-references' ) ) ); } - - $( '#proveit-content' ).html( referenceList ); }, /** * Make a reference object out of a reference string * - * @param {string} Wikitext of the reference - * @return {Citation|RawReference|TemplateReference} Reference object of the appropriate class + * @param {string} wikitext of the reference + * @return {object} reference object */ makeReference: function ( referenceString ) { + // Extract the name, if any + // Three patterns: <ref name="foo">, <ref name='foo'> and <ref name=foo> + var referenceName = null, + match = referenceString.match( /<[\s]*ref[\s]*name[\s]*=[\s]*(?:(?:\"(.*?)\")|(?:\'(.*?)\')|(?:(.*?)))[\s]*>/i ); + if ( match ) { + referenceName = match[1] || match[2] || match[3]; + } - // First we need to determine what kind of reference we're dealing with - // So we get all the template names and search for a match - var registeredTemplate, - registeredTemplatesArray = []; - for ( registeredTemplate in proveit.templates ) { + // Extract the index + var referenceIndex = proveit.getTextbox().val().indexOf( referenceString ); + + // Extract the content + var referenceContent = referenceString.match( />([\s\S]*)<\s*\/\s*ref\s*>/i )[1]; // We use [\s\S]* instead of .* to match newlines + + // Build the basic reference + var reference = new proveit.Reference({ + 'name': referenceName, + 'index': referenceIndex, + 'string': referenceString, + 'content': referenceContent + }); + + // Determine if the reference uses a template by getting all the registered template names and searching for a match + var registeredTemplatesArray = []; + for ( var registeredTemplate in proveit.templates ) { registeredTemplate = registeredTemplate.substring( registeredTemplate.indexOf( ':' ) + 1 ); // Remove the namespace registeredTemplatesArray.push( registeredTemplate ); } var registeredTemplatesDisjunction = registeredTemplatesArray.join( '|' ), - regExp = new RegExp( '{{(' + registeredTemplatesDisjunction + ')([\\s\\S]*)}}', 'i' ), - match = referenceString.match( regExp ), - referenceText, - reference; + regExp = new RegExp( '{{(' + registeredTemplatesDisjunction + ')([\\s\\S]*)}}', 'i' ), // We use [\s\S]* instead of .* to match newlines + match = referenceContent.match( regExp ); + // If there's a match, add the template data to the reference if ( match ) { - referenceText = match[2]; - reference = new proveit.TemplateReference({ 'string': referenceString, 'text': referenceText }); + reference.templateString = match[0]; - // Extract the name of the template + // Extract and the template name and normalize it var template = match[1]; - - // Normalize it registeredTemplatesArray.forEach( function ( registeredTemplate ) { if ( template.toLowerCase() === registeredTemplate.toLowerCase() ) { template = registeredTemplate; @@ -294,11 +347,11 @@ }); reference.template = template; - // Next, extract the parameters - var paramsArray = referenceText.split( '|' ), + // Extract the parameters and normalize them + var paramsArray = match[2].split( '|' ), paramString, paramNameAndValue, paramName, paramValue; - paramsArray.shift(); // Remove everything before the fist pipe + paramsArray.shift(); // The first element is always empty for ( paramString in paramsArray ) { @@ -312,21 +365,6 @@ reference.params[ paramName ] = paramValue; } - } else { - referenceText = referenceString.match( />([\s\S]*)<\s*\/\s*ref\s*>/i )[1]; - reference = new proveit.RawReference({ 'string': referenceString, 'text': referenceText }); - } - - // Now set the starting index of the reference - var text = proveit.getTextbox().val(); - reference.index = text.indexOf( referenceString ); - - // Lastly, extract the name of the reference, if any - // Three possibilities: <ref name="foo">, <ref name='foo'> and <ref name=foo> - regExp = /<[\s]*ref[\s]*name[\s]*=[\s]*(?:(?:\"(.*?)\")|(?:\'(.*?)\')|(?:(.*?)))[\s]*>/i; - match = referenceString.match( regExp ); - if ( match ) { - reference.name = match[1] || match[2] || match[3]; } return reference; @@ -372,38 +410,49 @@ }, /** - * Class for citations: <ref name="some-reference" /> + * Citation class * - * The citation class is the base class. It has the properties and methods common to all references. - * - * @param {object} Data for constructing the object + * @param {object} data for constructing the object */ Citation: function ( data ) { /** - * Name of the class + * Citation name */ - this.type = 'Citation'; + this.name = data.name ? data.name : ''; /** - * Name of the reference + * Citation location in the edit textbox + */ + this.index = data.index ? data.index : 0; + + /** + * Citation wikitext * - * This is the value of the "name" parameter of the <ref> tag: <ref name="abc" /> + * Example: <ref name="abc" /> */ - this.name = data.name; + this.string = data.string ? data.string : ''; /** - * Location of this reference in the edit textbox + * Convert this citation to wikitext */ - this.index = data.index; + this.toString = function () { + return '<ref name="' + this.name + '" />'; + }; /** - * Wikitext for this reference. + * Insert this citation into the textbox */ - this.string = data.string; + this.insert = function () { + var textbox = proveit.getTextbox(); + textbox.textSelection( 'encapsulateSelection', { + 'peri': this.toString(), + 'replace': true + }); + }; /** - * Highlight the string in the textbox and scroll it to view + * Highlight the citation in the textbox and scroll it to view * * @return {void} */ @@ -429,12 +478,11 @@ }, /** - * Class for raw references: <ref>This is a raw reference, it uses no templates.</ref> + * Reference class * - * @extends Citation * @param {object} Data for constructing the object */ - RawReference: function ( data ) { + Reference: function ( data ) { /** * Extend the Citation class @@ -442,11 +490,11 @@ proveit.Citation.call( this, data ); /** - * Name of the class + * Reference content (without the <ref> tags) * - * Overrides the value inherited from the Citation class. + * Example: Second chapter of {{Cite book |first=Charles |last=Darwin |title=On the Origin of Species}} */ - this.type = 'RawReference'; + this.content = data.content ? data.content : ''; /** * Array of citations to this reference @@ -454,134 +502,144 @@ this.citations = []; /** - * String inside the <ref> tags + * Name of the main template of this reference, if any + * + * Example: Cite book */ - this.text = data.text; + this.template = data.template ? data.template : null; /** - * Convert this reference to wikitext + * Wikitext of the main template, if any * - * This method is trivial, but it needs to exist because it isn't trivial in the TemplateReference class, - * and sometimes we call it on a reference object without knowing if it's a raw reference or a template reference. - * - * @return {string} wikitext for this reference + * Example: {{Cite book |first=Charles |last=Darwin |title=On the Origin of Species}} */ - this.toString = function () { - var string = '<ref'; - - if ( this.name ) { - string += ' name="' + this.name + '"'; - } - - string += '>' + this.text + '</ref>'; - - return string; - }; + this.templateString = data.templateString ? data.templateString : ''; /** - * Convert this reference to a list item ready to be inserted into the reference list + * Object mapping the parameter names of this reference to their values * - * @return {jQuery} jQuery-wrapped <li> + * This object is constructed directly out of the wikitext, so it doesn't include + * any information about the parameters other than their names and values. */ - this.toListItem = function () { - - var item = $( '<li>' ).addClass( 'proveit-reference-item' ).text( this.text ), - citations = $( '<span>' ).addClass( 'proveit-citations' ); - - for ( var i = 0; i < this.citations.length; i++ ) { - citations.append( $( '<a>' ).addClass( 'proveit-citation' ).text( i + 1 ) ); - } - - item.append( citations ); - - // Bind events - var reference = this; - item.click( function () { - reference.highlight(); - var form = reference.toForm(); - $( '#proveit-content' ).html( form ); - $( '#proveit-insert-button' ).hide(); - }); - - item.find( 'a.proveit-citation' ).click( function ( event ) { - event.stopPropagation(); - var i = parseInt( $( this ).text(), 10 ) - 1, - citation = reference.citations[ i ]; - citation.highlight(); - return false; - }); - - return item; - }; + this.params = {}; /** - * Convert this reference into a HTML form filled with its data - * - * @return {jQuery} jQuery-wrapped <form> - */ - this.toForm = function () { - - var form = $( '<form>' ).attr( 'id', 'proveit-reference-form' ), - table = $( '<table>' ); - - // Insert the <ref> name field - var referenceNameRow = $( '<tr>' ), - referenceNameLabel = $( '<label>' ).text( proveit.getMessage( 'reference-name-label' ) ), - referenceNameInput = $( '<input>' ).attr( 'name', 'reference-name' ).val( this.name ); - referenceNameRow.append( referenceNameLabel, referenceNameInput ); - table.append( referenceNameRow ); - - // Insert the textarea - var referenceTextRow = $( '<tr>' ), - referenceTextLabel = $( '<label>' ).text( proveit.getMessage( 'reference-text-label' ) ), - referenceTextArea = $( '<textarea>' ).attr( 'name', 'reference-text' ).val( this.text ); - referenceTextRow.append( referenceTextLabel, referenceTextArea ); - table.append( referenceTextRow ); - - // Insert the buttons - var buttons = $( '<div>' ).attr( 'id', 'proveit-buttons' ), - updateButton = $( '<button>' ).attr( 'id', 'proveit-update-button' ).text( proveit.getMessage( 'update-button' ) ), - insertButton = $( '<button>' ).attr( 'id', 'proveit-insert-button' ).text( proveit.getMessage( 'insert-button' ) ); - buttons.append( updateButton, insertButton ); - form.append( table, buttons ); - - // Bind events - form.submit( false ); - - updateButton.click( this, this.update ); - - insertButton.click( this, this.insert ); - - return form; - }; - - /** - * Update the data of this reference with the content of the reference form + * Show all the hidden optional parameters * * @return {void} */ - this.loadFromForm = function () { - this.name = $( '#proveit-reference-form input[name="reference-name"]' ).val(); - this.text = $( '#proveit-reference-form textarea[name="reference-text"]' ).val(); - this.string = this.toString(); + this.showAllParams = function () { + var button = $( this ), + form = button.closest( 'form' ), + rows = $( 'tr', form ); + rows.show(); + button.hide(); + }; + + /** + * Insert a citation to this reference + * + * @return {void} + */ + this.cite = function ( event ) { + var reference = event.data; + + // If the reference has no name, ask the user for one + // @todo check if the name is unique? + // @todo autogenerate names? + if ( !reference.name ) { + reference.name = prompt( proveit.getMessage( 'prompt-name' ) ); + if ( !reference.name ) { + return; + } + var table = reference.toTable(); + $( '#proveit-reference-table' ).replaceWith( table ); + + var oldString = reference.string; + reference.loadFromForm(); + var newString = reference.string; + + // Replace the old reference + var textbox = proveit.getTextbox(), + text = textbox.val().replace( oldString, newString ); + textbox.val( text ); + } + + // Add the citation + var citation = new proveit.Citation({ 'name': reference.name }); + citation.insert(); + }; + + /** + * Remove this reference and all its citations + * + * @param {object} click event, with the reference as data + * @return {void} + */ + this.remove = function ( event ) { + var reference = event.data; + + // Make sure the user understands that the citations will also be removed + if ( confirm( proveit.getMessage( 'confirm-remove' ) ) ) { + + // Remove the reference + var textbox = proveit.getTextbox(), + text = textbox.val(); + text = text.replace( reference.string, '' ); + + // Remove all the citations + // @todo citation.remove() + reference.citations.forEach( function ( citation ) { + text = text.replace( citation.string, '' ); + }); + + // Update the textbox + textbox.val( text ); + + // Add the tag and summary + proveit.addTag(); + proveit.addSummary(); + + // Switch to add mode + $( '#proveit-add-tab' ).addClass( 'active' ).siblings().removeClass( 'active' ); + $( '#proveit-insert-button' ).show(); + $( '#proveit-cite-button, #proveit-remove-button, #proveit-update-button' ).hide(); + } }; /** * Update the wikitext in the textbox with the current data of this reference * + * @param {object} click event, with the reference as data * @return {void} */ this.update = function ( event ) { var reference = event.data; - var oldString = reference.string; + var oldName = reference.name, + oldString = reference.string; reference.loadFromForm(); - var newString = reference.string; + var newName = reference.name, + newString = reference.string; // Replace the old reference var textbox = proveit.getTextbox(), - text = textbox.val().replace( oldString, newString ); + text = textbox.val(); + text = text.replace( oldString, newString ); + // If the name changed, update the citations + // @todo citation.update() + if ( oldName !== newName && reference.citations ) { + var oldCitationString, newCitationString; + reference.citations.forEach( function ( citation ) { + oldCitationString = citation.toString(); + citation.name = newName; + newCitationString = citation.toString(); + text = text.replace( oldCitationString, newCitationString ); + }); + } + + // Update the textbox textbox.val( text ); // Update the index and highlight the reference @@ -589,7 +647,10 @@ reference.index = text.indexOf( newString ); reference.highlight(); - // Add the tag, the summary and rescan + // Update the GUI + $( '#proveit-reference-table' ).replaceWith( reference.toTable() ); + + // Add the tag and summary proveit.addTag(); proveit.addSummary(); }; @@ -597,6 +658,7 @@ /** * Insert this reference into the textbox * + * @param {object} click event, with the reference as data * @return {void} */ this.insert = function ( event ) { @@ -613,53 +675,23 @@ 'replace': true }); - // Update the index and highlight the reference + // Update the index reference.index = textbox.val().indexOf( reference.string ); - reference.highlight(); - // Add the tag, the summary and rescan + // Switch to edit mode + $( '#proveit-edit-tab' ).addClass( 'active' ).siblings().removeClass( 'active' ); + $( '#proveit-reference-table' ).replaceWith( reference.toTable() ); + $( '#proveit-insert-button' ).hide().siblings().show(); + + // Add the tag and summary proveit.addTag(); proveit.addSummary(); }; - }, - - /** - * Class for template references: <ref>{{Cite book |first=Charles |last=Darwin |title=The Origin of Species}}</ref> - * - * @extends RawReference - * @param {object} Data for constructing the object - */ - TemplateReference: function ( data ) { - - /** - * Extend the RawReference class - */ - proveit.RawReference.call( this, data ); - - /** - * Name of the class - * - * Overrides the value inherited from the RawReference class. - */ - this.type = 'TemplateReference'; - - /** - * Name of the template used by this reference. - */ - this.template = data.template; - - /** - * Object mapping the parameter names of this reference to their values - * - * This object is constructed directly out of the wikitext, so it doesn't include - * any information about the parameters other than their names and values, - */ - this.params = {}; /** * Get the registered parameters for this reference * - * @return {object} + * @return {object} TemplateData of the registered parameters */ this.getRegisteredParams = function () { var formattedNamespaces = mw.config.get( 'wgFormattedNamespaces' ), @@ -670,7 +702,7 @@ /** * Get the required parameters for this reference * - * @return {object} + * @return {object} TemplateData of the required parameters */ this.getRequiredParams = function () { var requiredParams = {}, @@ -686,7 +718,7 @@ /** * Get the suggested parameters for this reference * - * @return {object} + * @return {object} TemplateData of the suggested parameters */ this.getSuggestedParams = function () { var suggestedParams = {}, @@ -702,7 +734,7 @@ /** * Get the optional parameters for this reference * - * @return {object} + * @return {object} TemplateData of the optional parameters */ this.getOptionalParams = function () { var optionalParams = {}, @@ -718,7 +750,7 @@ /** * Get the registered params but sorted by required first, suggested later, optional last * - * @return {object} + * @return {object} TemplateData of the sorted parameters */ this.getSortedParams = function () { var requiredParams = this.getRequiredParams(), @@ -730,100 +762,116 @@ /** * Convert this reference to wikitext * - * Overrides the toString() method of the RawReference class. - * - * @return {string} Wikitext for this reference + * @return {string} wikitext for this reference */ this.toString = function () { + // Build the opening ref tag var string = '<ref'; - if ( this.name ) { string += ' name="' + this.name + '"'; } + string += '>'; - string += '>{{' + this.template; - - for ( var name in this.params ) { - string += ' |' + name + '=' + this.params[ name ]; + // Build the template string + if ( this.template ) { + var templateString = '{{' + this.template; + for ( var name in this.params ) { + templateString += ' |' + name + '=' + this.params[ name ]; + } + templateString += '}}'; + // Build the content string by replacing the old template string with the new + // By doing this we keep any content that before or after the template string + this.content = this.content.replace( this.templateString, templateString ); + this.templateString = templateString; } + // Add the content + string += this.content; - string += '}}</ref>'; - + // Close and return the reference + string += '</ref>'; return string; }; /** * Convert this reference to a list item * - * Overrides the toListItem() method of the RawReference class. - * - * @return {jQuery} jQuery-wrapped node for reference list + * @return {jQuery} list item */ this.toListItem = function () { - var item = $( '<li>' ).addClass( 'proveit-reference-item' ); - item.append( $( '<span>' ).addClass( 'proveit-template' ).text( this.template ) ); - var requiredParams = this.getRequiredParams(), - requiredParam, - requiredParamValue; - for ( requiredParam in requiredParams ) { - requiredParamValue = this.params[ requiredParam ]; - item.append( $( '<span>' ).addClass( 'proveit-required-value' ).text( requiredParamValue ) ); + // Add the main content + if ( this.template ) { + var templateSpan = $( '<span>' ).addClass( 'proveit-reference-template' ).text( this.template ), + requiredParams = this.getRequiredParams(), + requiredParamName, requiredParamValue, requiredParamSpan; + item.html( templateSpan ); + for ( requiredParamName in requiredParams ) { + requiredParamValue = this.params[ requiredParamName ]; + requiredParamSpan = $( '<span>' ).addClass( 'proveit-required-param-value' ).text( requiredParamValue ); + item.append( requiredParamSpan ); + } + } else { + item.text( this.content ); } + // Add the citations var citations = $( '<span>' ).addClass( 'proveit-citations' ); - - for ( var i = 0; i < this.citations.length; i++ ) { - citations.append( $( '<a>' ).addClass( 'proveit-citation' ).text( i + 1 ) ); + for ( var i = 1; i <= this.citations.length; i++ ) { + citations.append( $( '<a>' ).addClass( 'proveit-citation' ).text( i ) ); } - item.append( citations ); // Bind events - var reference = this; - item.click( function () { + item.click( this, function ( event ) { + var reference = event.data, + form = reference.toForm(); reference.highlight(); - var form = reference.toForm(); $( '#proveit-content' ).html( form ); - $( '#proveit-insert-button' ).hide(); + $( '#proveit-insert-button' ).hide().siblings().show(); }); - item.find( 'a.proveit-citation' ).click( function ( event ) { - event.stopPropagation(); - var i = parseInt( $( this ).text(), 10 ) - 1, + $( '.proveit-citation', item ).click( this, function ( event ) { + var reference = event.data, + i = parseInt( $( this ).text(), 10 ) - 1, citation = reference.citations[ i ]; citation.highlight(); - return false; + event.stopPropagation(); }); return item; }; /** - * Convert this reference into a HTML form filled with its data + * Convert this reference into a HTML table * - * @return {jQuery} jQuery-wrapped <form> + * @return {jQuery} table */ - this.toForm = function () { + this.toTable = function () { + var table = $( '<table>' ).attr( 'id', 'proveit-reference-table' ); - var form = $( '<form>' ).attr( 'id', 'proveit-reference-form' ), - table = $( '<table>' ); - - // Insert the <ref> name field + // Add the reference name field var referenceNameRow = $( '<tr>' ), referenceNameLabel = $( '<label>' ).text( proveit.getMessage( 'reference-name-label' ) ), referenceNameInput = $( '<input>' ).attr( 'name', 'reference-name' ).val( this.name ); referenceNameRow.append( referenceNameLabel, referenceNameInput ); table.append( referenceNameRow ); - // Insert the dropdown menu - var templateRow = $( '<tr>' ), - templateLabel = $( '<label>' ).text( proveit.getMessage( 'template-label' ) ), - templateSelect = $( '<select>' ).attr( 'name', 'template' ), - templateName, - templateOption; + // Add the reference content area + var referenceContentRow = $( '<tr>' ), + referenceContentLabel = $( '<label>' ).text( proveit.getMessage( 'reference-content-label' ) ), + referenceContentTextarea = $( '<textarea>' ).attr( 'name', 'reference-content' ).val( this.content ); + referenceContentRow.append( referenceContentLabel, referenceContentTextarea ); + table.append( referenceContentRow ); + // Add the template dropdown menu + var templateRow = $( '<tr>' ), + templateLabel = $( '<label>' ).text( proveit.getMessage( 'reference-template-label' ) ), + templateSelect = $( '<select>' ).attr( 'name', 'reference-template' ), + templateName = proveit.getMessage( 'no-template' ), + templateOption = $( '<option>' ).text( templateName ).val( '' ); + templateSelect.append( templateOption ); + templateRow.append( templateLabel, templateSelect ); for ( templateName in proveit.templates ) { templateName = templateName.substr( templateName.indexOf( ':' ) + 1 ); // Remove the namespace templateOption = $( '<option>' ).text( templateName ).val( templateName ); @@ -835,15 +883,15 @@ templateRow.append( templateLabel, templateSelect ); table.append( templateRow ); - // The insert all the other fields - var paramName, param, paramLabel, paramPlaceholder, paramDescription, paramValue, row, label, paramNameInput, paramValueInput, - sortedParams = this.getSortedParams(), + // Add the parameter fields + var sortedParams = this.getSortedParams(), requiredParams = this.getRequiredParams(), - optionalParams = this.getOptionalParams(); + optionalParams = this.getOptionalParams(), + paramName, paramData, paramLabel, paramPlaceholder, paramDescription, paramValue, row, label, paramNameInput, paramValueInput; for ( paramName in sortedParams ) { - param = sortedParams[ paramName ]; + paramData = sortedParams[ paramName ]; // Defaults paramLabel = paramName; @@ -852,63 +900,86 @@ paramValue = ''; // Override with template data - if ( param.label ) { - paramLabel = param.label[ proveit.userLanguage ]; + if ( paramData.label ) { + paramLabel = paramData.label[ proveit.userLanguage ]; } - if ( param.type === 'date' ) { + // If the parameter is a date, put the current date as a placeholder + // @todo find a better solution + if ( paramData.type === 'date' ) { var date = new Date(), yyyy = date.getFullYear(), mm = ( '0' + ( date.getMonth() + 1 ) ).slice( -2 ), dd = ( '0' + date.getDate() ).slice( -2 ); paramPlaceholder = yyyy + '-' + mm + '-' + dd; } - if ( param.description ) { - paramDescription = param.description[ proveit.userLanguage ]; + if ( paramData.description ) { + paramDescription = paramData.description[ proveit.userLanguage ]; } if ( paramName in this.params ) { paramValue = this.params[ paramName ]; } + // Build the table row row = $( '<tr>' ).addClass( 'proveit-param-pair' ); label = $( '<label>' ).attr( 'title', paramDescription ).text( paramLabel ); paramNameInput = $( '<input>' ).attr( 'type', 'hidden' ).addClass( 'proveit-param-name' ).val( paramName ); paramValueInput = $( '<input>' ).attr( 'placeholder', paramPlaceholder ).addClass( 'proveit-param-value' ).val( paramValue ); - // Mark the required parameters as such + // Mark the required parameters if ( paramName in requiredParams ) { row.addClass( 'proveit-required' ); } // Hide the optional parameters, unless they are filled if ( ( paramName in optionalParams ) && !paramValue ) { - row.addClass( 'proveit-optional' ); + row.hide(); } + // Put it all together and add it to the table row.append( label, paramValueInput, paramNameInput ); table.append( row ); } - // Insert the buttons + // Show the params button + $( '#proveit-params-button' ).show(); + + // Bind events + templateSelect.change( this, function ( event ) { + var reference = event.data; + reference.template = $( this ).val(); + $.cookie( 'proveit-last-template', reference.template ); // Remember the user choice + table.replaceWith( reference.toTable() ); + }); + + return table; + }; + + /** + * Convert this reference to an HTML form filled with its data + * + * @return {jQuery} form + */ + this.toForm = function () { + + var form = $( '<form>' ).attr( 'id', 'proveit-reference-form' ), + table = this.toTable(); + + // Add the buttons var buttons = $( '<div>' ).attr( 'id', 'proveit-buttons' ), + paramsButton = $( '<button>' ).attr( 'id', 'proveit-params-button' ).text( proveit.getMessage( 'params-button' ) ), + citeButton = $( '<button>' ).attr( 'id', 'proveit-cite-button' ).text( proveit.getMessage( 'cite-button' ) ), + removeButton = $( '<button>' ).attr( 'id', 'proveit-remove-button' ).text( proveit.getMessage( 'remove-button' ) ), updateButton = $( '<button>' ).attr( 'id', 'proveit-update-button' ).text( proveit.getMessage( 'update-button' ) ), insertButton = $( '<button>' ).attr( 'id', 'proveit-insert-button' ).text( proveit.getMessage( 'insert-button' ) ); - buttons.append( updateButton, insertButton ); + buttons.append( paramsButton, citeButton, removeButton, updateButton, insertButton ); form.append( table, buttons ); // Bind events - var reference = this; - templateSelect.change( function ( event ) { - reference.template = $( event.currentTarget ).val(); - $.cookie( 'proveit-last-template', reference.template ); // Remember the user choice - var form = reference.toForm(); - $( '#proveit-content' ).html( form ); - insertButton.hide(); - }); - form.submit( false ); - + paramsButton.click( this.showAllParams ); + citeButton.click( this, this.cite ); + removeButton.click( this, this.remove ); updateButton.click( this, this.update ); - insertButton.click( this, this.insert ); return form; @@ -920,21 +991,24 @@ * @return {void} */ this.loadFromForm = function () { + this.name = $( '#proveit-reference-form input[name="reference-name"]' ).val(); - this.template = $( '#proveit-reference-form select[name="template"]' ).val(); + + this.content = $( '#proveit-reference-form textarea[name="reference-content"]' ).val(); + + this.template = $( '#proveit-reference-form select[name="reference-template"]' ).val(); // Load all the parameter key-value pairs - this.params = {}; - var pairs = $( '#proveit-reference-form .proveit-param-pair' ), - pair, paramName, paramValue; - for ( var i = 0; i < pairs.length; i++ ) { - pair = pairs[ i ]; - paramName = $( 'input.proveit-param-name', pair ).val(); - paramValue = $( 'input.proveit-param-value', pair ).val(); - if ( paramName !== '' && paramValue !== '' ) { - this.params[ paramName ] = paramValue; + var params = {}, name, value; + $( '.proveit-param-pair' ).each( function () { + name = $( '.proveit-param-name', this ).val(); + value = $( '.proveit-param-value', this ).val(); + if ( name !== '' && value !== '' ) { + params[ name ] = value; } - } + }); + this.params = params; + this.string = this.toString(); }; } -- To view, visit https://gerrit.wikimedia.org/r/314828 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Id7ce3cf5776e30f7336e25c92a19746d3a363568 Gerrit-PatchSet: 1 Gerrit-Project: wikipedia/gadgets/ProveIt Gerrit-Branch: master Gerrit-Owner: Sophivorus <scheno...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits