jenkins-bot has submitted this change and it was merged.
Change subject: second source field mapping dissapears
......................................................................
second source field mapping dissapears
the main issue here was that in step 2 of the upload process, when adding
metadata mappings,
categories or item specific categories with the + button; they were added with
javascript. if the
user stepped back in the upload process, e.g., from step 3 back to step 2,
those added fields
would be lost.
the solution implemented was to use javascript and cookies to maintain the
state of those added
fields and re-apply them if the user comes back to step 2.
* includes/Config.php
- added resource jquery.json so that it can be used in the js createCookie()
method
* includes/Forms/MetadataMappingForm.php
- added ids to form tables for quicker js access to the individual tables
* resources/js/ext.gwtoolset.js
- added line breaks to code that is > 100 characters
- added logic to handle cookies
+ createCookie()
+ removeCookies()
+ restoreJsFormFields()
+ storeJsFormFields()
- alphabatized initial gwtoolset variables
- attempted to improve the option search while still using jQuery
- changed .html() to .append() when adding jQuery objectsto an html element
- fixed an issue where the restore of js fields did not always correspond
with field/values
previously present in the form
- re-worked the logic of handleButtonAddClick() and handleFormSubmit() so
that they work
in conjunction with the new cookie handling methods
* re: assembla/169 - Second source field mapping disappears
Change-Id: I7afe3d2fb01becccd586afed2ead490dbcd01784
---
M includes/Forms/PreviewForm.php
M resources/js/ext.gwtoolset.js
2 files changed, 246 insertions(+), 42 deletions(-)
Approvals:
BryanDavis: Looks good to me, approved
MarkTraceur: Looks good to me, but someone else must approve
jenkins-bot: Verified
diff --git a/includes/Forms/PreviewForm.php b/includes/Forms/PreviewForm.php
index a90974b..ca88ff8 100644
--- a/includes/Forms/PreviewForm.php
+++ b/includes/Forms/PreviewForm.php
@@ -91,7 +91,7 @@
array(
'type' => 'hidden',
'name' => 'gwtoolset-form',
- 'value' => 'metadata-mapping'
+ 'value' => 'metadata-preview'
)
) .
diff --git a/resources/js/ext.gwtoolset.js b/resources/js/ext.gwtoolset.js
index 9b06547..8c7a938 100644
--- a/resources/js/ext.gwtoolset.js
+++ b/resources/js/ext.gwtoolset.js
@@ -1,6 +1,6 @@
-/*global jQuery, mw */
-/*jslint browser: true, white: true, devel: true, regexp: true */
-(function ( $ ) {
+/*global jQuery, mediaWiki */
+/*jslint browser: true, plusplus: true, regexp: true, white: true */
+(function ( mw, $ ) {
'use strict';
var gwtoolset,
@@ -86,6 +86,29 @@
gwtoolset = {
+ $ajaxLoader: $( '<div>' )
+ .attr( 'id', 'gwtoolset-loader' )
+ .append(
+ $( '<p>' )
+ .text( mw.message( 'gwtoolset-loading'
).text() )
+ .append( $.createSpinner( { size:
'large', type: 'block' } ) )
+ ),
+ $backText: $( '#back-text' ),
+ $buttons: {
+ $add: $( '<img>' )
+ .attr(
+ 'src',
+ mw.config.get( 'wgExtensionAssetsPath'
) + '/GWToolset/resources/images/b_snewtbl.png'
+ )
+ .addClass( 'gwtoolset-metadata-button' ),
+ $subtract: $( '<img>' )
+ .attr(
+ 'src',
+ mw.config.get( 'wgExtensionAssetsPath'
) + '/GWToolset/resources/images/b_drop.png'
+ )
+ .addClass( 'gwtoolset-metadata-button' )
+ },
+ cookieName: 'gwtoolset.cookie',
$dialog: $( '<div>' )
.attr( 'id', 'dialog' )
.dialog( {
@@ -97,20 +120,19 @@
}
} ),
$form: $( '#gwtoolset-form' ),
- $ajaxLoader: $( '<div>' )
- .attr( 'id', 'gwtoolset-loader' )
- .html(
- $( '<p>' )
- .text( mw.message( 'gwtoolset-loading'
).text() )
- .append( $.createSpinner( { size:
'large', type: 'block' } ) )
- ),
- $templateTableTbody: $( '#template-table > tbody' ),
+ formName: $( 'input[name=gwtoolset-form]' ).val(),
+ $globalCategoriesTableTbody: $( '#global-categories-table')
+ .children( 'tbody' )
+ .eq( 0 ),
+ $itemSpecificCategoriesTableTbody: $(
'#item-specific-categories-table' )
+ .children( 'tbody' )
+ .eq( 0 ),
$saveMappingButton: $( '<tr>' )
- .html(
+ .append(
$( '<td>' )
.attr( 'colspan', 3 )
.css( 'text-align', 'right' )
- .html(
+ .append(
$( '<span>' )
.attr( {
id:
'save-mapping',
@@ -119,16 +141,8 @@
.text( mw.message(
'gwtoolset-save-mapping' ).text() )
)
),
- $buttons: {
- $add: $( '<img>' )
- .attr( 'src',
mw.config.get('wgExtensionAssetsPath') +
'/GWToolset/resources/images/b_snewtbl.png' )
- .addClass( 'gwtoolset-metadata-button' ),
- $subtract: $( '<img>' )
- .attr( 'src',
mw.config.get('wgExtensionAssetsPath') +
'/GWToolset/resources/images/b_drop.png' )
- .addClass( 'gwtoolset-metadata-button' )
- },
- $backText: $( '#back-text' ),
$step2Link: $( '#step2-link' ),
+ $templateTableTbody: $( '#template-table' ).children( 'tbody'
).eq( 0 ),
addAjaxLoader: function () {
this.$ajaxLoader.hide();
@@ -136,13 +150,21 @@
},
addBackLinks: function () {
- this.$backText.replaceWith( this.createBackLink( {
title: mw.message( 'gwtoolset-back-text-link' ).text() } ) );
- this.$step2Link.replaceWith( this.createBackLink( {
title: mw.message( 'gwtoolset-step-2-heading' ).text() } ) );
+ this.$backText
+ .replaceWith(
+ this.createBackLink( { title:
mw.message( 'gwtoolset-back-text-link' ).text() } )
+ );
+ this.$step2Link
+ .replaceWith(
+ this.createBackLink( { title:
mw.message( 'gwtoolset-step-2-heading' ).text() } )
+ );
},
addButtons: function () {
- $( '.button-add' ).html( this.$buttons.$add.clone().on(
'click', this.handleButtonAddClick ) );
- $( '.button-subtract' ).html(
this.$buttons.$subtract.clone().on( 'click', this.handleButtonSubtractClick ) );
+ $( '.button-add' )
+ .append( this.$buttons.$add.clone().on(
'click', this.handleButtonAddClick ) );
+ $( '.button-subtract' )
+ .append( this.$buttons.$subtract.clone().on(
'click', this.handleButtonSubtractClick ) );
},
addFormListener: function () {
@@ -188,6 +210,88 @@
} );
},
+ /**
+ * creates/adds to the document.cookie
+ *
+ * @param {Object} options
+ *
+ * @param {string} options.name
+ * name of the cookie
+ *
+ * @param {Object} options.options
+ * $.cookie, cookie options
+ *
+ * @param {mixed} options.value
+ */
+ createCookie: function ( options ) {
+ var optionsDefault = {
+ name: this.cookieName,
+ options: {
+ path: '/'
+ }
+ };
+
+ options = $.extend( true, {}, optionsDefault, options );
+
+ $.cookie(
+ options.name,
+ ( typeof options.value === 'object' ) ?
$.toJSON( options.value ) : options.value,
+ options.options
+ );
+ },
+
+ /**
+ * @param {Object} $elm
+ * a jQuery object
+ *
+ * @returns {Object}
+ */
+ findTarget: function ( $elm ) {
+ if ( $elm.next().children( 'td.button-subtract'
).length > 0 ) {
+ return this.findTarget( $elm.next() );
+ }
+
+ return $elm;
+ },
+
+ /**
+ * creates an Object that contains the form section fields the
application tracks
+ *
+ * @returns {Object}
+ */
+ getFieldsOnForm: function () {
+ return {
+ $globalCategoriesTableTbody:
+ this.getFormSectionValues(
this.$globalCategoriesTableTbody, 'input' ),
+ $itemSpecificCategoriesTableTbody:
+ this.getFormSectionValues(
this.$itemSpecificCategoriesTableTbody, 'input, select' ),
+ $templateTableTbody:
+ this.getFormSectionValues(
this.$templateTableTbody, 'select' )
+ };
+ },
+
+ /**
+ * given a jQuery element representing a section within the
html, finds and returns
+ * the fields and values serialized and deparamed
+ *
+ * @param {Object} $elm
+ * a jQuery object representing a section that contains the
fields and values to be
+ * serialized and deparamed
+ *
+ * @param {string} find
+ * the specific element(s) to find within the $elm, e.g.,
'input, select'
+ *
+ * @returns {string}
+ */
+ getFormSectionValues: function ( $elm, find ) {
+ var result;
+
+ result = $elm.find( find ).serialize();
+ result = $.String.deparam( result );
+
+ return result;
+ },
+
handleAjaxError: function () {
gwtoolset.openDialog( { msg: mw.message(
'gwtoolset-developer-issue' ).text() } );
mw.log( arguments );
@@ -208,28 +312,51 @@
/**
* @param {Event} evt
+ * @param {Object} data
*/
- handleButtonAddClick: function ( evt ) {
- var $target = $( this ).closest( 'tr' ),
+ handleButtonAddClick: function ( evt, data ) {
+ var $target = gwtoolset.findTarget( $( this ).closest(
'tr' ) ),
$tdButton = $( '<td>' )
.addClass( 'button-subtract' )
- .html(
gwtoolset.$buttons.$subtract.clone().on( 'click',
gwtoolset.handleButtonSubtractClick ) ),
+ .append(
gwtoolset.$buttons.$subtract.clone()
+ .on( 'click',
gwtoolset.handleButtonSubtractClick )
+ ),
$row = $( '<tr>' );
evt.preventDefault();
$target.children().each( function () {
var $tdElm,
- $elm = $( this );
+ $elm = $( this );
if ( $elm.find('label').length === 1 ) {
$row.append( $( '<td>' ) );
- } else if ( $elm.hasClass( 'button-add' ) ) {
+ } else if ( $elm.hasClass( 'button-add' ) ||
$elm.hasClass( 'button-subtract' ) ) {
$row.append( $tdButton );
} else {
$tdElm = $elm.clone();
- $tdElm.find( 'input' ).val( '' );
- $tdElm.find( 'option' ).prop(
'selected', false );
+
+ if ( data && data.value ) {
+ $tdElm.find( 'input' ).val(
data.value );
+ } else {
+ $tdElm.find( 'input' ).val( ''
);
+ }
+
+ if ( data && data.option ) {
+ $.each( $tdElm.find( 'option'
), function () {
+ var $optionElm = $(
this );
+
+ if ( $optionElm.text()
=== data.option ) {
+
$optionElm.prop( 'selected', true );
+ return false;
+ }
+
+ return true;
+ } );
+ } else {
+ $tdElm.find( 'option' ).prop(
'selected', false );
+ }
+
$row.append( $tdElm );
}
});
@@ -245,7 +372,19 @@
$( this ).closest( 'tr' ).remove();
},
+ /**
+ * remove cookies on step-1 submit, we don’t want previously
stored values to be used.
+ * store cookies on step-2 submit
+ */
handleFormSubmit: function () {
+ if ( gwtoolset.formName === 'metadata-detect' ) {
+ gwtoolset.removeCookies();
+ } else if ( gwtoolset.formName === 'metadata-mapping' )
{
+ gwtoolset.createCookie(
+ { value: gwtoolset.getFieldsOnForm() }
+ );
+ }
+
gwtoolset.$ajaxLoader.fadeIn();
},
@@ -288,10 +427,77 @@
},
init: function () {
- gwtoolset.addBackLinks();
- gwtoolset.addFormListener();
- gwtoolset.addSaveMappingButton();
- gwtoolset.addButtons();
+ this.addBackLinks();
+ this.addFormListener();
+ this.addSaveMappingButton();
+ this.addButtons();
+ this.restoreJsFormFields();
+ },
+
+ removeCookies: function () {
+ $.cookie( this.cookieName, null );
+ },
+
+ /**
+ * restores js added input and select fields using the
document.cookie
+ * - the document.cookie should contain a cookie value named
this.cookieName
+ * - that cookie should be a JSON stringified
+ */
+ restoreJsFormFields: function () {
+ var buttonAdd,
+ fieldsInCookie,
+ fieldsOnForm,
+ formSectionFieldIndex;
+
+ if ( this.formName !== 'metadata-mapping' ) {
+ return;
+ }
+
+ fieldsOnForm = this.getFieldsOnForm();
+ fieldsInCookie = $.secureEvalJSON( $.cookie(
this.cookieName ) );
+
+ if ( !fieldsInCookie ) {
+ return;
+ }
+
+ $.each( fieldsInCookie, function ( section,
cookieSectionFields ) {
+ $.each( cookieSectionFields, function (
cookieSectionField ) {
+ if (
fieldsOnForm[section][cookieSectionField].length !==
+
cookieSectionFields[cookieSectionField].length
+ ) {
+ formSectionFieldIndex =
fieldsOnForm[section][cookieSectionField].length - 1;
+ $.each(
cookieSectionFields[cookieSectionField],
+ function(
cookieSectionFieldIndex, value
+ ) {
+ // when this is true
the cookie contains a field and value that was added with js
+ if (
cookieSectionFieldIndex > formSectionFieldIndex ) {
+ switch (
section ) {
+ case
'$globalCategoriesTableTbody':
+
buttonAdd = gwtoolset[section].find( '.button-add img' );
+
buttonAdd.trigger( 'click', { value: value } );
+
break;
+ case
'$templateTableTbody':
+
buttonAdd = $( '#' + cookieSectionField.replace( ' ', '_' ) )
+
.closest( 'tr' )
+
.find('.button-add img');
+
buttonAdd.trigger( 'click', { option: value } );
+
break;
+ case
'$itemSpecificCategoriesTableTbody':
+
// only want to trigger buttonAdd once
+
if ( cookieSectionField === 'category-metadata' ) {
+
buttonAdd = gwtoolset[section].find( '.button-add img' );
+
buttonAdd.trigger( 'click', {
+
option:
cookieSectionFields['category-metadata'][cookieSectionFieldIndex],
+
value:
cookieSectionFields['category-phrase'][cookieSectionFieldIndex]
+
} );
+
}
+
break;
+ }
+ }
+ } );
+ }
+ } );
+ } );
},
/**
@@ -316,14 +522,12 @@
var mappingNameToUse = $( '#mapping-name-to-use'
).val(),
mediawikiTemplateName = $(
'#mediawiki-template-name' ).val(),
wpEditToken = mw.user.tokens.get( 'editToken' ),
- metadataMappings = gwtoolset.$form.find(
'select' ).serialize();
+ metadataMappings =
gwtoolset.getFormSectionValues( gwtoolset.$templateTableTbody, 'select' );
if ( evt ) {
gwtoolset.$dialog.dialog( 'close' );
evt.preventDefault();
}
-
- metadataMappings = $.String.deparam( metadataMappings );
if ( mappingNameToUse === null ||
mappingNameToUse.length < 3 ) {
return;
@@ -350,4 +554,4 @@
gwtoolset.init();
-}( jQuery ));
+}( mediaWiki, jQuery ));
--
To view, visit https://gerrit.wikimedia.org/r/90041
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I7afe3d2fb01becccd586afed2ead490dbcd01784
Gerrit-PatchSet: 11
Gerrit-Project: mediawiki/extensions/GWToolset
Gerrit-Branch: master
Gerrit-Owner: Dan-nl <[email protected]>
Gerrit-Reviewer: BryanDavis <[email protected]>
Gerrit-Reviewer: Dan-nl <[email protected]>
Gerrit-Reviewer: MarkTraceur <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits