woocommerce/assets/js/admin/settings-views-html-setting...

419 lines
14 KiB
JavaScript
Raw Normal View History

2015-08-14 15:10:55 +00:00
/* global htmlSettingsTaxLocalizeScript, ajaxurl */
/**
* Used by woocommerce/includes/admin/settings/views/html-settings-tax.php
*/
(function($, data, wp, ajaxurl){
$(function() {
2015-08-10 21:22:03 +00:00
if ( ! String.prototype.trim ) {
String.prototype.trim = function () {
return this.replace( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '' );
};
}
2015-08-08 14:57:22 +00:00
var rowTemplate = wp.template( 'wc-tax-table-row' ),
2015-08-12 19:29:17 +00:00
rowTemplateEmpty = wp.template( 'wc-tax-table-row-empty' ),
paginationTemplate = wp.template( 'wc-tax-table-pagination' ),
2015-08-08 18:45:37 +00:00
$table = $( '.wc_tax_rates' ),
2015-08-08 14:57:22 +00:00
$tbody = $( '#rates' ),
$unsaved_msg = $( '#unsaved-changes' ),
$pagination = $( '#rates-pagination' ),
2015-08-12 18:30:26 +00:00
$search_field = $( '#rates-search .wc-tax-rates-search-field' ),
$submit = $( '.submit .button-primary[type=submit]' ),
WCTaxTableModelConstructor = Backbone.Model.extend({
2015-08-10 22:54:25 +00:00
changes : {},
setRateAttribute : function( rateID, attribute, value ) {
var rates = _.indexBy( this.get( 'rates' ), 'tax_rate_id' ),
changes = {};
if ( rates[ rateID ][ attribute ] !== value ) {
changes[ rateID ] = {};
changes[ rateID ][ attribute ] = value;
rates[ rateID ][ attribute ] = value;
}
this.logChanges( changes );
},
logChanges : function( changedRows ) {
var changes = this.changes || {};
_.each( changedRows, function( row, id ) {
changes[ id ] = _.extend( changes[ id ] || { tax_rate_id : id }, row );
2015-08-12 21:18:32 +00:00
} );
this.changes = changes;
this.trigger( 'change:rates' );
2015-08-12 21:18:32 +00:00
},
getFilteredRates : function() {
var rates = this.get( 'rates' ),
search = $search_field.val().toLowerCase();
if ( search.length ) {
rates = _.filter( rates, function( rate ) {
2015-08-12 18:41:52 +00:00
var search_text = _.toArray( rate ).join( ' ' ).toLowerCase();
return ( -1 !== search_text.indexOf( search ) );
} );
}
rates = _.sortBy( rates, function( rate ) {
return parseInt( rate.tax_rate_order, 10 );
} );
2015-08-12 19:29:33 +00:00
return rates;
},
save : function() {
$.post( ajaxurl + '?action=woocommerce_tax_rates_save_changes', {
current_class : data.current_class,
wc_tax_nonce : data.wc_tax_nonce,
changes : this.changes
}, this.onSaveResponse, 'json' );
},
onSaveResponse : function( response, textStatus ) {
2015-08-13 21:54:31 +00:00
if ( 'success' === textStatus ) {
WCTaxTableModelInstance.set( 'rates', response.data.rates );
2015-08-13 21:54:31 +00:00
WCTaxTableModelInstance.trigger( 'change:rates' );
WCTaxTableModelInstance.changes = {};
WCTaxTableModelInstance.trigger( 'saved:rates' );
}
}
} ),
WCTaxTableViewConstructor = Backbone.View.extend({
rowTemplate : rowTemplate,
per_page : data.limit,
page : data.page,
2015-08-13 17:01:42 +00:00
initialize : function() {
this.qty_pages = Math.ceil( _.toArray( this.model.get( 'rates' ) ).length / this.per_page );
this.page = this.sanitizePage( data.page );
this.listenTo( this.model, 'change:rates', this.setUnloadConfirmation );
this.listenTo( this.model, 'saved:rates', this.clearUnloadConfirmation );
2015-08-13 17:01:42 +00:00
$tbody.on( 'change', { view : this }, this.updateModelOnChange );
$tbody.on( 'sortupdate', { view : this }, this.updateModelOnSort );
$search_field.on( 'keyup search', { view : this }, this.onSearchField );
$pagination.on( 'click', 'a', { view : this }, this.onPageChange );
$pagination.on( 'change', 'input', { view : this }, this.onPageChange );
$(window).on( 'beforeunload', { view : this }, this.unloadConfirmation );
$submit.on( 'click', { view : this }, this.onSubmit );
// Can bind these directly to the buttons, as they won't get overwritten.
$table.find('.insert').on( 'click', { view : this }, this.onAddNewRow );
$table.find('.remove_tax_rates').on( 'click', { view : this }, this.onDeleteRow );
$table.find('.export').on( 'click', { view : this }, this.onExport );
2015-08-13 17:01:42 +00:00
},
2015-08-13 17:07:00 +00:00
render : function() {
2015-08-12 18:43:48 +00:00
var rates = this.model.getFilteredRates(),
qty_rates = _.size( rates ),
qty_pages = Math.ceil( qty_rates / this.per_page ),
first_index = this.per_page * ( this.page - 1),
last_index = this.per_page * this.page,
2015-08-12 18:43:48 +00:00
paged_rates = _.toArray( rates ).slice( first_index, last_index ),
view = this;
// Blank out the contents.
this.$el.empty();
2015-08-12 19:29:17 +00:00
if ( paged_rates.length ) {
// Populate $tbody with the current page of results.
$.each( paged_rates, function ( id, rowData ) {
view.$el.append( view.rowTemplate( rowData ) );
} );
} else {
view.$el.append( rowTemplateEmpty() );
}
// Initialize autocomplete for countries.
this.$el.find( 'td.country input' ).autocomplete({
source: data.countries,
minLength: 2
});
// Initialize autocomplete for states.
this.$el.find( 'td.state input' ).autocomplete({
source: data.states,
minLength: 3
});
// Postcode and city don't have `name` values by default. They're only created if the contents changes, to save on database queries (I think)
this.$el.find( 'td.postcode input, td.city input' ).change(function() {
$(this).attr( 'name', $(this).data( 'name' ) );
});
if ( qty_pages > 1 ) {
// We've now displayed our initial page, time to render the pagination box.
$pagination.html( paginationTemplate( {
qty_rates : qty_rates,
current_page : this.page,
qty_pages : qty_pages
} ) );
}
2015-08-13 16:13:05 +00:00
// Disable sorting if there is a search term filtering the items.
if ( $search_field.val() ) {
$tbody.sortable( 'disable' );
} else {
$tbody.sortable( 'enable' );
}
},
updateUrl : function() {
if ( ! window.history.replaceState ) {
return;
}
var url = data.base_url,
search = $search_field.val();
if ( 1 < this.page ) {
url += '&p=' + encodeURIComponent( this.page );
}
if ( search.length ) {
url += '&s=' + encodeURIComponent( search );
}
window.history.replaceState( {}, '', url );
},
onSubmit : function( event ) {
event.data.view.model.save();
event.preventDefault();
},
onAddNewRow : function( event ) {
var view = event.data.view,
model = view.model,
rates = _.indexBy( model.get('rates'), 'tax_rate_id' ),
changes = {},
size = _.size( rates ),
newRow = _.extend( {}, data.default_rate, {
tax_rate_id : 'new-' + size + '-' + Date.now(),
newRow : true
} ),
2015-08-13 18:27:50 +00:00
$current, current_id, current_order, rates_to_reorder, reordered_rates;
$current = $tbody.children( '.current' );
if ( $current.length ) {
current_id = $current.last().data( 'id' );
current_order = parseInt( rates[ current_id ].tax_rate_order, 10 );
newRow.tax_rate_order = 1 + current_order;
rates_to_reorder = _.filter( rates, function( rate ) {
if ( parseInt( rate.tax_rate_order, 10 ) > current_order ) {
return true;
}
return false;
} );
reordered_rates = _.map( rates_to_reorder, function( rate ) {
rate.tax_rate_order++;
changes[ rate.tax_rate_id ] = _.extend( changes[ rate.tax_rate_id ] || {}, { tax_rate_order : rate.tax_rate_order } );
return rate;
} );
} else {
newRow.tax_rate_order = 1 + _.max(
_.pluck( rates, 'tax_rate_order' ),
function ( val ) {
// Cast them all to integers, because strings compare funky. Sighhh.
return parseInt( val, 10 );
}
);
}
rates[ newRow.tax_rate_id ] = newRow;
changes[ newRow.tax_rate_id ] = newRow;
model.set( 'rates', rates );
model.logChanges( changes );
view.render();
},
onDeleteRow : function( event ) {
var view = event.data.view,
model = view.model,
rates = _.indexBy( model.get('rates'), 'tax_rate_id' ),
changes = {},
2015-08-13 18:27:50 +00:00
$current, current_id, current_order, rates_to_reorder, reordered_rates;
event.preventDefault();
if ( $current = $tbody.children( '.current' ) ) {
$current.each(function(){
current_id = $( this ).data('id');
current_order = parseInt( rates[ current_id ].tax_rate_order, 10 );
rates_to_reorder = _.filter( rates, function( rate ) {
if ( parseInt( rate.tax_rate_order, 10 ) > current_order ) {
return true;
}
return false;
} );
reordered_rates = _.map( rates_to_reorder, function( rate ) {
rate.tax_rate_order--;
changes[ rate.tax_rate_id ] = _.extend( changes[ rate.tax_rate_id ] || {}, { tax_rate_order : rate.tax_rate_order } );
return rate;
} );
delete rates[ current_id ];
changes[ current_id ] = _.extend( changes[ current_id ] || {}, { deleted : 'deleted' } );
});
model.set( 'rates', rates );
model.logChanges( changes );
view.render();
} else {
window.alert( data.strings.no_rows_selected );
}
},
2015-08-12 19:01:27 +00:00
onSearchField : function( event ){
event.data.view.updateUrl();
event.data.view.render();
},
onPageChange : function( event ) {
var $target = $( event.currentTarget );
event.preventDefault();
event.data.view.page = $target.data('goto') ? $target.data('goto') : $target.val();
event.data.view.render();
event.data.view.updateUrl();
2015-08-12 19:01:27 +00:00
},
onExport : function( event ) {
var csv_data = 'data:application/csv;charset=utf-8,' + data.strings.csv_data_cols.join(',') + '\n';
$.each( event.data.view.model.rates, function( id, rowData ) {
var row = '';
row += rowData.tax_rate_country + ',';
row += rowData.tax_rate_state + ',';
row += ( rowData.postcode ? rowData.postcode.join( '; ' ) : '' ) + ',';
row += ( rowData.city ? rowData.city.join( '; ' ) : '' ) + ',';
row += rowData.tax_rate + ',';
row += rowData.tax_rate_name + ',';
row += rowData.tax_rate_priority + ',';
row += rowData.tax_rate_compound + ',';
row += rowData.tax_rate_shipping + ',';
row += data.current_class;
csv_data += row + '\n';
});
$(this).attr( 'href', encodeURI( csv_data ) );
return true;
},
setUnloadConfirmation : function() {
this.needsUnloadConfirm = true;
$unsaved_msg.show();
$unsaved_msg.find( 'pre' ).text( JSON.stringify( this.model.changes, null, '\t' ) );
},
clearUnloadConfirmation : function() {
this.needsUnloadConfirm = false;
$unsaved_msg.hide();
},
unloadConfirmation : function(event) {
if ( event.data.view.needsUnloadConfirm ) {
event.returnValue = data.strings.unload_confirmation_msg;
window.event.returnValue = data.strings.unload_confirmation_msg;
return data.strings.unload_confirmation_msg;
}
},
updateModelOnChange : function( event ) {
var model = event.data.view.model,
$target = $( event.target ),
id = $target.closest('tr').data('id'),
attribute = $target.data('attribute'),
val = $target.val();
if ( 'city' === attribute || 'postcode' === attribute ) {
val = val.split(';');
val = $.map( val, function( thing ) {
return thing.trim();
});
}
if ( 'tax_rate_compound' === attribute || 'tax_rate_shipping' === attribute ) {
if ( $target.is(':checked') ) {
val = 1;
} else {
val = 0;
}
}
model.setRateAttribute( id, attribute, val );
},
2015-08-12 21:18:32 +00:00
updateModelOnSort : function( event, ui ) {
var view = event.data.view,
model = view.model,
$tr = ui.item,
tax_rate_id = $tr.data( 'id' ),
rates = _.indexBy( model.get('rates'), 'tax_rate_id' ),
old_position = rates[ tax_rate_id ].tax_rate_order,
new_position = $tr.index() + ( ( view.page - 1 ) * view.per_page ),
which_way = ( new_position > old_position ) ? 'higher' : 'lower',
changes = {},
2015-08-12 21:18:32 +00:00
rates_to_reorder, reordered_rates;
rates_to_reorder = _.filter( rates, function( rate ) {
var order = parseInt( rate.tax_rate_order, 10 ),
limits = [ old_position, new_position ];
if ( parseInt( rate.tax_rate_id, 10 ) === parseInt( tax_rate_id, 10 ) ) {
return true;
} else if ( order > _.min( limits ) && order < _.max( limits ) ) {
return true;
} else if ( 'higher' === which_way && order === _.max( limits ) ) {
return true;
} else if ( 'lower' === which_way && order === _.min( limits ) ) {
return true;
}
return false;
} );
reordered_rates = _.map( rates_to_reorder, function( rate ) {
var order = parseInt( rate.tax_rate_order, 10 );
if ( parseInt( rate.tax_rate_id, 10 ) === parseInt( tax_rate_id, 10 ) ) {
rate.tax_rate_order = new_position;
} else if ( 'higher' === which_way ) {
rate.tax_rate_order = order - 1;
} else if ( 'lower' === which_way ) {
rate.tax_rate_order = order + 1;
}
changes[ rate.tax_rate_id ] = _.extend( changes[ rate.tax_rate_id ] || {}, { tax_rate_order : rate.tax_rate_order } );
2015-08-12 21:18:32 +00:00
return rate;
} );
2015-08-12 21:26:10 +00:00
if ( reordered_rates.length ) {
model.logChanges( changes );
2015-08-12 21:26:10 +00:00
view.render(); // temporary, probably should get yanked.
}
2015-08-12 21:18:32 +00:00
},
sanitizePage : function( page_num ) {
page_num = parseInt( page_num, 10 );
if ( page_num < 1 ) {
page_num = 1;
} else if ( page_num > this.qty_pages ) {
page_num = this.qty_pages;
}
return page_num;
}
} ),
WCTaxTableModelInstance = new WCTaxTableModelConstructor({
2015-08-10 20:02:32 +00:00
rates : data.rates
} ),
WCTaxTableInstance = new WCTaxTableViewConstructor({
model : WCTaxTableModelInstance,
// page : data.page, // I'd prefer to have these two specified down here in the instance,
// per_page : data.limit, // but it doesn't seem to recognize them in render if I do. :\
el : '#rates'
} );
2015-08-07 15:42:49 +00:00
WCTaxTableInstance.render();
2015-08-07 15:42:49 +00:00
});
})(jQuery, htmlSettingsTaxLocalizeScript, wp, ajaxurl);