installed plugin Easy Digital Downloads
version 3.1.0.3
This commit is contained in:
@ -0,0 +1,76 @@
|
||||
/* global eddEmailTagsInserter, tb_remove, tb_position, send_to_editor, _, window, document */
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import { searchItems } from './utils.js';
|
||||
|
||||
/**
|
||||
* Make tags clickable and send them to the email content (wp_editor()).
|
||||
*/
|
||||
function setupEmailTags() {
|
||||
// Find all of the buttons.
|
||||
const insertButtons = document.querySelectorAll( '.edd-email-tags-list-button' );
|
||||
if ( ! insertButtons ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen for clicks on tag buttons.
|
||||
*
|
||||
* @param {object} node Button node.
|
||||
*/
|
||||
_.each( insertButtons, function( node ) {
|
||||
/**
|
||||
* Listen for clicks on tag buttons.
|
||||
*/
|
||||
node.addEventListener( 'click', function() {
|
||||
// Close Thickbox.
|
||||
tb_remove();
|
||||
|
||||
window.send_to_editor( node.dataset.to_insert );
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter tags.
|
||||
*/
|
||||
function filterEmailTags() {
|
||||
const filterInput = document.querySelector( '.edd-email-tags-filter-search' );
|
||||
const tagItems = document.querySelectorAll( '.edd-email-tags-list-item' );
|
||||
|
||||
if ( ! filterInput ) {
|
||||
return;
|
||||
}
|
||||
|
||||
filterInput.addEventListener( 'keyup', function( event ) {
|
||||
const searchTerm = event.target.value;
|
||||
const foundTags = searchItems( eddEmailTagsInserter.items, searchTerm );
|
||||
|
||||
_.each( tagItems, function( node ) {
|
||||
const found = _.findWhere( foundTags, { tag: node.dataset.tag } );
|
||||
|
||||
node.style.display = ! found ? 'none' : 'block';
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* DOM ready.
|
||||
*/
|
||||
document.addEventListener( 'DOMContentLoaded', function() {
|
||||
// Resize Thickbox when media button is clicked.
|
||||
const mediaButton = document.querySelector( '.edd-email-tags-inserter' );
|
||||
if ( ! mediaButton ) {
|
||||
return;
|
||||
}
|
||||
|
||||
mediaButton.addEventListener( 'click', tb_position );
|
||||
|
||||
// Clickable tags.
|
||||
setupEmailTags();
|
||||
|
||||
// Filterable tags.
|
||||
filterEmailTags();
|
||||
} );
|
@ -0,0 +1,40 @@
|
||||
/* global _ */
|
||||
|
||||
/**
|
||||
* Filters an item list given a search term.
|
||||
*
|
||||
* @param {Array} items Item list
|
||||
* @param {string} searchTerm Search term.
|
||||
*
|
||||
* @return {Array} Filtered item list.
|
||||
*/
|
||||
export const searchItems = function( items, searchTerm ) {
|
||||
const normalizedSearchTerm = normalizeTerm( searchTerm );
|
||||
|
||||
const matchSearch = function( string ) {
|
||||
return normalizeTerm( string ).indexOf( normalizedSearchTerm ) !== -1;
|
||||
};
|
||||
|
||||
return _.filter( items, function( item ) {
|
||||
return matchSearch( item.title ) || _.some( item.keywords, matchSearch );
|
||||
} );
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts the search term into a normalized term.
|
||||
*
|
||||
* @param {string} term The search term to normalize.
|
||||
*
|
||||
* @return {string} The normalized search term.
|
||||
*/
|
||||
export const normalizeTerm = function( term ) {
|
||||
// Lowercase.
|
||||
// Input: "MEDIA"
|
||||
term = term.toLowerCase();
|
||||
|
||||
// Strip leading and trailing whitespace.
|
||||
// Input: " media "
|
||||
term = term.trim();
|
||||
|
||||
return term;
|
||||
};
|
@ -0,0 +1,75 @@
|
||||
/* global EDDExtensionManager, ajaxurl */
|
||||
|
||||
; ( function ( document, $ ) {
|
||||
'use strict';
|
||||
|
||||
$( '.edd-extension-manager__action' ).on( 'click', function ( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
var $btn = $( this ),
|
||||
action = $btn.attr( 'data-action' ),
|
||||
plugin = $btn.attr( 'data-plugin' ),
|
||||
type = $btn.attr( 'data-type' ),
|
||||
ajaxAction = '';
|
||||
|
||||
if ( $btn.attr( 'disabled' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( action ) {
|
||||
case 'activate':
|
||||
ajaxAction = 'edd_activate_extension';
|
||||
$btn.text( EDDExtensionManager.activating );
|
||||
break;
|
||||
|
||||
case 'install':
|
||||
ajaxAction = 'edd_install_extension';
|
||||
$btn.text( EDDExtensionManager.installing );
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
$btn.removeClass( 'button-primary' ).attr( 'disabled', true ).addClass( 'updating-message' );
|
||||
|
||||
var data = {
|
||||
action: ajaxAction,
|
||||
nonce: EDDExtensionManager.extension_manager_nonce,
|
||||
plugin: plugin,
|
||||
type: type,
|
||||
pass: $btn.attr( 'data-pass' ),
|
||||
id: $btn.attr( 'data-id' ),
|
||||
product: $btn.attr( 'data-product' ),
|
||||
};
|
||||
|
||||
$.post( ajaxurl, data )
|
||||
.done( function ( res ) {
|
||||
console.log( res );
|
||||
var thisStep = $btn.closest( '.edd-extension-manager__step' );
|
||||
if ( res.success ) {
|
||||
var nextStep = thisStep.next();
|
||||
if ( nextStep.length ) {
|
||||
thisStep.fadeOut();
|
||||
nextStep.prepend( '<div class="notice inline-notice notice-success"><p>' + res.data.message + '</p></div>' );
|
||||
nextStep.fadeIn();
|
||||
}
|
||||
} else {
|
||||
thisStep.fadeOut();
|
||||
var message = res.data.message;
|
||||
/**
|
||||
* The install class returns an array of error messages, and res.data.message will be undefined.
|
||||
* In that case, we'll use the standard failure messages.
|
||||
*/
|
||||
if ( ! message ) {
|
||||
if ( 'plugin' !== type ) {
|
||||
message = EDDExtensionManager.extension_install_failed;
|
||||
} else {
|
||||
message = EDDExtensionManager.plugin_install_failed;
|
||||
}
|
||||
}
|
||||
thisStep.after( '<div class="notice inline-notice notice-warning"><p>' + message + '</p></div>' );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
} )( document, jQuery );
|
@ -0,0 +1,130 @@
|
||||
jQuery( document ).ready( function ( $ ) {
|
||||
/**
|
||||
* Connect to PayPal
|
||||
*/
|
||||
$( '#edd-paypal-commerce-connect' ).on( 'click', function ( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
// Clear errors.
|
||||
var errorContainer = $( '#edd-paypal-commerce-errors' );
|
||||
errorContainer.empty().removeClass( 'notice notice-error' );
|
||||
|
||||
var button = document.getElementById( 'edd-paypal-commerce-connect' );
|
||||
button.classList.add( 'updating-message' );
|
||||
button.disabled = true;
|
||||
|
||||
$.post( ajaxurl, {
|
||||
action: 'edd_paypal_commerce_connect',
|
||||
_ajax_nonce: $( this ).data( 'nonce' )
|
||||
}, function( response ) {
|
||||
if ( ! response.success ) {
|
||||
console.log( 'Connection failure', response.data );
|
||||
button.classList.remove( 'updating-message' );
|
||||
button.disabled = false;
|
||||
|
||||
// Set errors.
|
||||
errorContainer.html( '<p>' + response.data + '</p>' ).addClass( 'notice notice-error' );
|
||||
return;
|
||||
}
|
||||
|
||||
var paypalLinkEl = document.getElementById( 'edd-paypal-commerce-link' );
|
||||
paypalLinkEl.href = response.data.signupLink + '&displayMode=minibrowser';
|
||||
|
||||
paypalLinkEl.click();
|
||||
} );
|
||||
} );
|
||||
|
||||
/**
|
||||
* Checks the PayPal connection & webhook status.
|
||||
*/
|
||||
function eddPayPalGetAccountStatus() {
|
||||
var accountInfoEl = document.getElementById( 'edd-paypal-commerce-connect-wrap' );
|
||||
if ( accountInfoEl ) {
|
||||
$.post( ajaxurl, {
|
||||
action: 'edd_paypal_commerce_get_account_info',
|
||||
_ajax_nonce: accountInfoEl.getAttribute( 'data-nonce' )
|
||||
}, function( response ) {
|
||||
var newHtml = '<p>' + eddPayPalConnectVars.defaultError + '</p>';
|
||||
|
||||
if ( response.success ) {
|
||||
newHtml = response.data.account_status;
|
||||
|
||||
if ( response.data.actions && response.data.actions.length ) {
|
||||
newHtml += '<p class="edd-paypal-connect-actions">' + response.data.actions.join( ' ' ) + '</p>';
|
||||
}
|
||||
} else if ( response.data && response.data.message ) {
|
||||
newHtml = response.data.message;
|
||||
}
|
||||
|
||||
accountInfoEl.innerHTML = newHtml;
|
||||
|
||||
// Remove old status messages.
|
||||
accountInfoEl.classList.remove( 'notice-success', 'notice-warning', 'notice-error' );
|
||||
|
||||
// Add new one.
|
||||
var newClass = response.success && response.data.status ? 'notice-' + response.data.status : 'notice-error';
|
||||
accountInfoEl.classList.add( newClass );
|
||||
} );
|
||||
}
|
||||
}
|
||||
eddPayPalGetAccountStatus();
|
||||
|
||||
/**
|
||||
* Create webhook
|
||||
*/
|
||||
$( document ).on( 'click', '.edd-paypal-connect-action', function ( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
var button = $( this );
|
||||
button.prop( 'disabled', true );
|
||||
button.addClass( 'updating-message' );
|
||||
|
||||
var errorWrap = $( '#edd-paypal-commerce-connect-wrap' ).find( '.edd-paypal-actions-error-wrap' );
|
||||
if ( errorWrap.length ) {
|
||||
errorWrap.remove();
|
||||
}
|
||||
|
||||
$.post( ajaxurl, {
|
||||
action: button.data( 'action' ),
|
||||
_ajax_nonce: button.data( 'nonce' )
|
||||
}, function( response ) {
|
||||
button.prop( 'disabled', false );
|
||||
button.removeClass( 'updating-message' );
|
||||
|
||||
if ( response.success ) {
|
||||
button.addClass( 'updated-message' );
|
||||
|
||||
// Refresh account status.
|
||||
eddPayPalGetAccountStatus();
|
||||
} else {
|
||||
button.parent().after( '<p class="edd-paypal-actions-error-wrap">' + response.data + '</p>' );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
||||
window.eddPayPalOnboardingCallback = function eddPayPalOnboardingCallback( authCode, shareId ) {
|
||||
var connectButton = document.getElementById( 'edd-paypal-commerce-connect' );
|
||||
var errorContainer = document.getElementById( 'edd-paypal-commerce-errors' );
|
||||
|
||||
jQuery.post( ajaxurl, {
|
||||
action: 'edd_paypal_commerce_get_access_token',
|
||||
auth_code: authCode,
|
||||
share_id: shareId,
|
||||
_ajax_nonce: connectButton.getAttribute( 'data-nonce' )
|
||||
}, function( response ) {
|
||||
connectButton.classList.remove( 'updating-message' );
|
||||
|
||||
if ( ! response.success ) {
|
||||
connectButton.disabled = false;
|
||||
|
||||
errorContainer.innerHTML = '<p>' + response.data + '</p>';
|
||||
errorContainer.classList.add( 'notice notice-error' );
|
||||
return;
|
||||
}
|
||||
|
||||
connectButton.classList.add( 'updated-message' );
|
||||
|
||||
window.location.reload();
|
||||
} );
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
import { recaptureRemoteInstall } from './recapture';
|
||||
import './gateways/paypal';
|
||||
|
||||
/**
|
||||
* Settings screen JS
|
||||
*/
|
||||
const EDD_Settings = {
|
||||
init: function() {
|
||||
this.general();
|
||||
this.misc();
|
||||
this.gateways();
|
||||
this.emails();
|
||||
},
|
||||
|
||||
general: function() {
|
||||
const edd_color_picker = $( '.edd-color-picker' );
|
||||
|
||||
if ( edd_color_picker.length ) {
|
||||
edd_color_picker.wpColorPicker();
|
||||
}
|
||||
|
||||
// Settings Upload field JS
|
||||
if ( typeof wp === 'undefined' || '1' !== edd_vars.new_media_ui ) {
|
||||
// Old Thickbox uploader
|
||||
const edd_settings_upload_button = $( '.edd_settings_upload_button' );
|
||||
if ( edd_settings_upload_button.length > 0 ) {
|
||||
window.formfield = '';
|
||||
|
||||
$( document.body ).on( 'click', edd_settings_upload_button, function( e ) {
|
||||
e.preventDefault();
|
||||
window.formfield = $( this ).parent().prev();
|
||||
window.tbframe_interval = setInterval( function() {
|
||||
jQuery( '#TB_iframeContent' ).contents().find( '.savesend .button' ).val( edd_vars.use_this_file ).end().find( '#insert-gallery, .wp-post-thumbnail' ).hide();
|
||||
}, 2000 );
|
||||
tb_show( edd_vars.add_new_download, 'media-upload.php?TB_iframe=true' );
|
||||
} );
|
||||
|
||||
window.edd_send_to_editor = window.send_to_editor;
|
||||
window.send_to_editor = function( html ) {
|
||||
if ( window.formfield ) {
|
||||
imgurl = $( 'a', '<div>' + html + '</div>' ).attr( 'href' );
|
||||
window.formfield.val( imgurl );
|
||||
window.clearInterval( window.tbframe_interval );
|
||||
tb_remove();
|
||||
} else {
|
||||
window.edd_send_to_editor( html );
|
||||
}
|
||||
window.send_to_editor = window.edd_send_to_editor;
|
||||
window.formfield = '';
|
||||
window.imagefield = false;
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// WP 3.5+ uploader
|
||||
var file_frame;
|
||||
window.formfield = '';
|
||||
|
||||
$( document.body ).on( 'click', '.edd_settings_upload_button', function( e ) {
|
||||
e.preventDefault();
|
||||
|
||||
const button = $( this );
|
||||
|
||||
window.formfield = $( this ).parent().prev();
|
||||
|
||||
// If the media frame already exists, reopen it.
|
||||
if ( file_frame ) {
|
||||
//file_frame.uploader.uploader.param( 'post_id', set_to_post_id );
|
||||
file_frame.open();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the media frame.
|
||||
file_frame = wp.media.frames.file_frame = wp.media( {
|
||||
title: button.data( 'uploader_title' ),
|
||||
library: { type: 'image' },
|
||||
button: { text: button.data( 'uploader_button_text' ) },
|
||||
multiple: false,
|
||||
} );
|
||||
|
||||
file_frame.on( 'menu:render:default', function( view ) {
|
||||
// Store our views in an object.
|
||||
const views = {};
|
||||
|
||||
// Unset default menu items
|
||||
view.unset( 'library-separator' );
|
||||
view.unset( 'gallery' );
|
||||
view.unset( 'featured-image' );
|
||||
view.unset( 'embed' );
|
||||
|
||||
// Initialize the views in our view object.
|
||||
view.set( views );
|
||||
} );
|
||||
|
||||
// When an image is selected, run a callback.
|
||||
file_frame.on( 'select', function() {
|
||||
const selection = file_frame.state().get( 'selection' );
|
||||
selection.each( function( attachment, index ) {
|
||||
attachment = attachment.toJSON();
|
||||
window.formfield.val( attachment.url );
|
||||
} );
|
||||
} );
|
||||
|
||||
// Finally, open the modal
|
||||
file_frame.open();
|
||||
} );
|
||||
|
||||
// WP 3.5+ uploader
|
||||
var file_frame;
|
||||
window.formfield = '';
|
||||
}
|
||||
},
|
||||
|
||||
misc: function() {
|
||||
const downloadMethod = $( 'select[name="edd_settings[download_method]"]' ),
|
||||
symlink = downloadMethod.parent().parent().next();
|
||||
|
||||
// Hide Symlink option if Download Method is set to Direct
|
||||
if ( downloadMethod.val() === 'direct' ) {
|
||||
symlink.css( 'opacity', '0.4' );
|
||||
symlink.find( 'input' ).prop( 'checked', false ).prop( 'disabled', true );
|
||||
}
|
||||
|
||||
// Toggle download method option
|
||||
downloadMethod.on( 'change', function() {
|
||||
if ( $( this ).val() === 'direct' ) {
|
||||
symlink.css( 'opacity', '0.4' );
|
||||
symlink.find( 'input' ).prop( 'checked', false ).prop( 'disabled', true );
|
||||
} else {
|
||||
symlink.find( 'input' ).prop( 'disabled', false );
|
||||
symlink.css( 'opacity', '1' );
|
||||
}
|
||||
} );
|
||||
},
|
||||
|
||||
gateways: function() {
|
||||
$( '#edd-payment-gateways input[type="checkbox"]' ).on( 'change', function() {
|
||||
const gateway = $( this ),
|
||||
gateway_key = gateway.data( 'gateway-key' ),
|
||||
default_gateway = $( '#edd_settings\\[default_gateway\\]' ),
|
||||
option = default_gateway.find( 'option[value="' + gateway_key + '"]' );
|
||||
|
||||
// Toggle enable/disable based
|
||||
option.prop( 'disabled', function( i, v ) {
|
||||
return ! v;
|
||||
} );
|
||||
|
||||
// Maybe deselect
|
||||
if ( option.prop( 'selected' ) ) {
|
||||
option.prop( 'selected', false );
|
||||
}
|
||||
|
||||
default_gateway.trigger( 'chosen:updated' );
|
||||
} );
|
||||
},
|
||||
|
||||
emails: function() {
|
||||
$('#edd-recapture-connect').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
$(this).html( edd_vars.wait + ' <span class="edd-loading"></span>' );
|
||||
document.body.style.cursor = 'wait';
|
||||
recaptureRemoteInstall();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
jQuery( document ).ready( function( $ ) {
|
||||
EDD_Settings.init();
|
||||
} );
|
@ -0,0 +1,18 @@
|
||||
export const recaptureRemoteInstall = () => {
|
||||
var data = {
|
||||
'action': 'edd_recapture_remote_install',
|
||||
};
|
||||
|
||||
jQuery.post( ajaxurl, data, function( response ) {
|
||||
|
||||
if( ! response.success ) {
|
||||
|
||||
if( confirm( response.data.error ) ) {
|
||||
location.reload();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
window.location.href = 'https://recapture.io/register';
|
||||
});
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/* global Backbone */
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import TaxRate from './../models/tax-rate.js';
|
||||
|
||||
/**
|
||||
* A collection of multiple tax rates.
|
||||
*/
|
||||
const TaxRates = Backbone.Collection.extend( {
|
||||
// Map the model.
|
||||
model: TaxRate,
|
||||
|
||||
/**
|
||||
* Set initial state.
|
||||
*/
|
||||
initialize: function() {
|
||||
this.showAll = false;
|
||||
this.selected = [];
|
||||
},
|
||||
} );
|
||||
|
||||
export default TaxRates;
|
@ -0,0 +1,47 @@
|
||||
/* global _, eddTaxRates */
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import TaxRate from './models/tax-rate.js';
|
||||
import TaxRates from './collections/tax-rates.js';
|
||||
import Manager from './views/manager.js';
|
||||
import { jQueryReady } from 'utils/jquery.js';
|
||||
|
||||
/**
|
||||
* DOM ready.
|
||||
*/
|
||||
jQueryReady( () => {
|
||||
// Show notice if taxes are not enabled.
|
||||
const noticeEl = document.getElementById( 'edd-tax-disabled-notice' );
|
||||
|
||||
if ( noticeEl ) {
|
||||
noticeEl.classList.add( 'notice' );
|
||||
noticeEl.classList.add( 'notice-warning' );
|
||||
}
|
||||
|
||||
// Start manager with a blank collection.
|
||||
const manager = new Manager( {
|
||||
collection: new TaxRates(),
|
||||
} );
|
||||
|
||||
const rates = [];
|
||||
|
||||
// Normalize rate data.
|
||||
_.each( eddTaxRates.rates, ( rate ) => rates.push( {
|
||||
id: rate.id,
|
||||
country: rate.name,
|
||||
region: rate.description,
|
||||
global: 'country' === rate.scope,
|
||||
amount: rate.amount,
|
||||
status: rate.status,
|
||||
} ) );
|
||||
|
||||
// Add initial rates.
|
||||
manager.collection.set( rates, {
|
||||
silent: true,
|
||||
} );
|
||||
|
||||
// Render manager.
|
||||
manager.render();
|
||||
} );
|
@ -0,0 +1,34 @@
|
||||
/* global Backbone */
|
||||
|
||||
/**
|
||||
* Model a tax rate.
|
||||
*/
|
||||
const TaxRate = Backbone.Model.extend( {
|
||||
defaults: {
|
||||
id: '',
|
||||
country: '',
|
||||
region: '',
|
||||
global: true,
|
||||
amount: 0,
|
||||
status: 'active',
|
||||
unsaved: false,
|
||||
selected: false,
|
||||
},
|
||||
|
||||
/**
|
||||
* Format a rate amount (adds a %)
|
||||
*
|
||||
* @todo This should support dynamic decimal types.
|
||||
*/
|
||||
formattedAmount: function() {
|
||||
let amount = 0;
|
||||
|
||||
if ( this.get( 'amount' ) ) {
|
||||
amount = parseFloat( this.get( 'amount' ) ).toFixed( 2 );
|
||||
}
|
||||
|
||||
return `${ amount }%`;
|
||||
},
|
||||
} );
|
||||
|
||||
export default TaxRate;
|
@ -0,0 +1,55 @@
|
||||
/* global wp, _ */
|
||||
|
||||
/**
|
||||
* Apply bulk actions.
|
||||
*/
|
||||
const BulkActions = wp.Backbone.View.extend( {
|
||||
// See https://codex.wordpress.org/Javascript_Reference/wp.template
|
||||
template: wp.template( 'edd-admin-tax-rates-table-bulk-actions' ),
|
||||
|
||||
// Watch events.
|
||||
events: {
|
||||
'click .edd-admin-tax-rates-table-filter': 'filter',
|
||||
'change .edd-admin-tax-rates-table-hide input': 'showHide',
|
||||
},
|
||||
|
||||
/**
|
||||
* Bulk actions for selected items.
|
||||
*
|
||||
* Currently only supports changing the status.
|
||||
*
|
||||
* @param {Object} event Event.
|
||||
*/
|
||||
filter: function( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
// @hack - need to access the DOM directly here because the dropdown is not tied to the button event.
|
||||
const status = document.getElementById( 'edd-admin-tax-rates-table-bulk-actions' );
|
||||
|
||||
_.each( this.collection.selected, ( cid ) => {
|
||||
const model = this.collection.get( {
|
||||
cid: cid,
|
||||
} );
|
||||
|
||||
model.set( 'status', status.value );
|
||||
} );
|
||||
|
||||
this.collection.trigger( 'filtered' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggle show active/inactive rates.
|
||||
*
|
||||
* @param {Object} event Event.
|
||||
*/
|
||||
showHide: function( event ) {
|
||||
this.collection.showAll = event.target.checked;
|
||||
|
||||
// @hack -- shouldn't access this table directly.
|
||||
document.getElementById( 'edd_tax_rates' ).classList.toggle( 'has-inactive', this.collection.showAll );
|
||||
|
||||
this.collection.trigger( 'filtered' );
|
||||
},
|
||||
} );
|
||||
|
||||
export default BulkActions;
|
@ -0,0 +1,65 @@
|
||||
/* global wp */
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import Table from './table.js';
|
||||
import BulkActions from './bulk-actions.js';
|
||||
|
||||
/**
|
||||
* Manage tax rates.
|
||||
*/
|
||||
const Manager = wp.Backbone.View.extend( {
|
||||
// Append to this element.
|
||||
el: '#edd-admin-tax-rates',
|
||||
|
||||
/**
|
||||
* Set bind changes to collection.
|
||||
*/
|
||||
initialize: function() {
|
||||
this.listenTo( this.collection, 'add change', this.makeDirty );
|
||||
|
||||
// Clear unload confirmation when submitting parent form.
|
||||
document.querySelector( '.edd-settings-form #submit' ).addEventListener( 'click', this.makeClean );
|
||||
},
|
||||
|
||||
/**
|
||||
* Output the manager.
|
||||
*/
|
||||
render: function() {
|
||||
this.views.add( new BulkActions( {
|
||||
collection: this.collection,
|
||||
} ) );
|
||||
|
||||
this.views.add( new Table( {
|
||||
collection: this.collection,
|
||||
} ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Collection has changed so warn the user before exiting.
|
||||
*/
|
||||
makeDirty: function() {
|
||||
window.onbeforeunload = this.confirmUnload;
|
||||
},
|
||||
|
||||
/**
|
||||
* When submitting the main form remove the dirty check.
|
||||
*/
|
||||
makeClean: function() {
|
||||
window.onbeforeunload = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Confirm page unload.
|
||||
*
|
||||
* @param {Object} event Close event.
|
||||
*/
|
||||
confirmUnload: function( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
return '';
|
||||
},
|
||||
} );
|
||||
|
||||
export default Manager;
|
@ -0,0 +1,38 @@
|
||||
/* global wp, _ */
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import { getChosenVars } from 'utils/chosen.js';
|
||||
|
||||
const RegionField = wp.Backbone.View.extend( {
|
||||
/**
|
||||
* Bind passed arguments.
|
||||
*
|
||||
* @param {Object} options Extra options passed.
|
||||
*/
|
||||
initialize: function( options ) {
|
||||
_.extend( this, options );
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a list of options.
|
||||
*/
|
||||
render: function() {
|
||||
if ( this.global ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'nostates' === this.states ) {
|
||||
this.setElement( '<input type="text" id="tax_rate_region" />' );
|
||||
} else {
|
||||
this.$el.html( this.states );
|
||||
this.$el.find( 'select' ).each( function() {
|
||||
const el = $( this );
|
||||
el.chosen( getChosenVars( el ) );
|
||||
} );
|
||||
}
|
||||
},
|
||||
} );
|
||||
|
||||
export default RegionField;
|
@ -0,0 +1,236 @@
|
||||
/* global wp */
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import TaxRate from './../models/tax-rate.js';
|
||||
import RegionField from './../views/region-field.js';
|
||||
import { getChosenVars } from 'utils/chosen.js';
|
||||
|
||||
/**
|
||||
* Add a new rate "form".
|
||||
*/
|
||||
const TableAdd = wp.Backbone.View.extend( {
|
||||
// Use <tfoot>
|
||||
tagName: 'tfoot',
|
||||
|
||||
// Set class.
|
||||
className: 'add-new',
|
||||
|
||||
// See https://codex.wordpress.org/Javascript_Reference/wp.template
|
||||
template: wp.template( 'edd-admin-tax-rates-table-add' ),
|
||||
|
||||
// Watch events.
|
||||
events: {
|
||||
'click button': 'addTaxRate',
|
||||
'keypress': 'maybeAddTaxRate',
|
||||
|
||||
'change #tax_rate_country': 'setCountry',
|
||||
|
||||
// Can be select or input.
|
||||
'keyup #tax_rate_region': 'setRegion',
|
||||
'change #tax_rate_region': 'setRegion',
|
||||
|
||||
'change input[type="checkbox"]': 'setGlobal',
|
||||
|
||||
// Can be click increase or keyboard.
|
||||
'keyup #tax_rate_amount': 'setAmount',
|
||||
'change #tax_rate_amount': 'setAmount',
|
||||
},
|
||||
|
||||
/**
|
||||
* Set initial state and bind changes to model.
|
||||
*/
|
||||
initialize: function() {
|
||||
this.model = new TaxRate( {
|
||||
global: true,
|
||||
unsaved: true,
|
||||
} );
|
||||
|
||||
this.listenTo( this.model, 'change:country', this.updateRegion );
|
||||
this.listenTo( this.model, 'change:global', this.updateRegion );
|
||||
},
|
||||
|
||||
/**
|
||||
* Render. Only overwritten so we can reinit chosen once cleared.
|
||||
*/
|
||||
render: function() {
|
||||
wp.Backbone.View.prototype.render.apply( this, arguments );
|
||||
|
||||
this.$el.find( 'select' ).each( function() {
|
||||
const el = $( this );
|
||||
el.chosen( getChosenVars( el ) );
|
||||
} );
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Show a list of states or an input field.
|
||||
*/
|
||||
updateRegion: function() {
|
||||
const self = this;
|
||||
|
||||
const data = {
|
||||
action: 'edd_get_shop_states',
|
||||
country: this.model.get( 'country' ),
|
||||
nonce: eddTaxRates.nonce,
|
||||
field_name: 'tax_rate_region',
|
||||
};
|
||||
|
||||
$.post( ajaxurl, data, function( response ) {
|
||||
self.views.set( '#tax_rate_region_wrapper', new RegionField( {
|
||||
states: response,
|
||||
global: self.model.get( 'global' ),
|
||||
} ) );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a country value.
|
||||
*
|
||||
* @param {Object} event Event.
|
||||
*/
|
||||
setCountry: function( event ) {
|
||||
let country = event.target.options[ event.target.selectedIndex ].value;
|
||||
let regionGlobalCheckbox = document.getElementById( "tax_rate_region_global" );
|
||||
if ( 'all' === country ) {
|
||||
country = '*';
|
||||
regionGlobalCheckbox.checked = true;
|
||||
this.model.set( 'region', '' );
|
||||
this.model.set( 'global', true );
|
||||
regionGlobalCheckbox.readOnly = true;
|
||||
regionGlobalCheckbox.disabled = true;
|
||||
} else {
|
||||
regionGlobalCheckbox.disabled = false;
|
||||
regionGlobalCheckbox.readOnly = false;
|
||||
}
|
||||
|
||||
this.model.set( 'country', country );
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a region value.
|
||||
*
|
||||
* @param {Object} event Event.
|
||||
*/
|
||||
setRegion: function( event ) {
|
||||
let value = false;
|
||||
|
||||
if ( event.target.value ) {
|
||||
value = event.target.value;
|
||||
} else {
|
||||
value = event.target.options[ event.target.selectedIndex ].value;
|
||||
}
|
||||
|
||||
this.model.set( 'region', value );
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a global scope.
|
||||
*
|
||||
* @param {Object} event Event.
|
||||
*/
|
||||
setGlobal: function( event ) {
|
||||
let isChecked = event.target.checked;
|
||||
this.model.set( 'global', isChecked );
|
||||
if ( true === isChecked ) {
|
||||
this.model.set( 'region', '' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set an amount value.
|
||||
*
|
||||
* @param {Object} event Event.
|
||||
*/
|
||||
setAmount: function( event ) {
|
||||
this.model.set( 'amount', event.target.value );
|
||||
},
|
||||
|
||||
/**
|
||||
* Monitors keyepress for "Enter" key.
|
||||
*
|
||||
* We cannot use the `submit` event because we cannot nest <form>
|
||||
* elements inside the settings API.
|
||||
*
|
||||
* @param {Object} event Keypress event.
|
||||
*/
|
||||
maybeAddTaxRate: function( event ) {
|
||||
if ( 13 !== event.keyCode ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.addTaxRate( event );
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a single rate when the "form" is submitted.
|
||||
*
|
||||
* @param {Object} event Event.
|
||||
*/
|
||||
addTaxRate: function( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
const { i18n } = eddTaxRates;
|
||||
|
||||
if ( ! this.model.get( 'country' ) ) {
|
||||
alert( i18n.emptyCountry );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let addingRegion = this.model.get( 'region' );
|
||||
let addingCountry = this.model.get( 'country' );
|
||||
let addingGlobal = '' === this.model.get( 'region' );
|
||||
|
||||
// For the purposes of this query, the * is really an empty query.
|
||||
if ( '*' === addingCountry ) {
|
||||
addingCountry = '';
|
||||
addingRegion = '';
|
||||
addingGlobal = false;
|
||||
}
|
||||
|
||||
const existingCountryWide = this.collection.where( {
|
||||
region: addingRegion,
|
||||
country: addingCountry,
|
||||
global: addingGlobal,
|
||||
status: 'active',
|
||||
} );
|
||||
|
||||
if ( existingCountryWide.length > 0 ) {
|
||||
const countryString = '' === addingCountry
|
||||
? '*'
|
||||
: addingCountry;
|
||||
|
||||
const regionString = '' === addingRegion
|
||||
? ''
|
||||
: ': ' + addingRegion;
|
||||
|
||||
const taxRateString = countryString + regionString;
|
||||
|
||||
alert( i18n.duplicateRate.replace( '%s', `"${ taxRateString }"` ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this.model.get( 'amount' ) <= 0 ) {
|
||||
alert( i18n.emptyTax );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Merge cid as ID to make this a unique model.
|
||||
this.collection.add( _.extend(
|
||||
this.model.attributes,
|
||||
{
|
||||
id: this.model.cid,
|
||||
}
|
||||
) );
|
||||
|
||||
this.render();
|
||||
this.initialize();
|
||||
},
|
||||
} );
|
||||
|
||||
export default TableAdd;
|
@ -0,0 +1,33 @@
|
||||
/* global wp, _ */
|
||||
|
||||
/**
|
||||
* Output a table header and footer.
|
||||
*/
|
||||
const TableMeta = wp.Backbone.View.extend( {
|
||||
// See https://codex.wordpress.org/Javascript_Reference/wp.template
|
||||
template: wp.template( 'edd-admin-tax-rates-table-meta' ),
|
||||
|
||||
// Watch events.
|
||||
events: {
|
||||
'change [type="checkbox"]': 'selectAll',
|
||||
},
|
||||
|
||||
/**
|
||||
* Select all items in the collection.
|
||||
*
|
||||
* @param {Object} event Event.
|
||||
*/
|
||||
selectAll: function( event ) {
|
||||
const checked = event.target.checked;
|
||||
|
||||
_.each( this.collection.models, ( model ) => {
|
||||
// Check individual models.
|
||||
model.set( 'selected', checked );
|
||||
|
||||
// Add to global selection.
|
||||
this.collection.selected.push( model.cid );
|
||||
} );
|
||||
},
|
||||
} );
|
||||
|
||||
export default TableMeta;
|
@ -0,0 +1,17 @@
|
||||
/* global wp */
|
||||
|
||||
/**
|
||||
* Empty tax rates table.
|
||||
*/
|
||||
const TableRowEmpty = wp.Backbone.View.extend( {
|
||||
// Insert as a <tr>
|
||||
tagName: 'tr',
|
||||
|
||||
// Set class.
|
||||
className: 'edd-tax-rate-row edd-tax-rate-row--is-empty',
|
||||
|
||||
// See https://codex.wordpress.org/Javascript_Reference/wp.template
|
||||
template: wp.template( 'edd-admin-tax-rates-table-row-empty' ),
|
||||
} );
|
||||
|
||||
export default TableRowEmpty;
|
@ -0,0 +1,119 @@
|
||||
/* global wp, _ */
|
||||
|
||||
/**
|
||||
* A row inside a table of rates.
|
||||
*/
|
||||
const TableRow = wp.Backbone.View.extend( {
|
||||
// Insert as a <tr>
|
||||
tagName: 'tr',
|
||||
|
||||
// Set class.
|
||||
className: function() {
|
||||
return 'edd-tax-rate-row edd-tax-rate-row--' + this.model.get( 'status' );
|
||||
},
|
||||
|
||||
// See https://codex.wordpress.org/Javascript_Reference/wp.template
|
||||
template: wp.template( 'edd-admin-tax-rates-table-row' ),
|
||||
|
||||
// Watch events.
|
||||
events: {
|
||||
'click .remove': 'removeRow',
|
||||
'click .activate': 'activateRow',
|
||||
'click .deactivate': 'deactivateRow',
|
||||
'change [type="checkbox"]': 'selectRow',
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind model to view.
|
||||
*/
|
||||
initialize: function() {
|
||||
this.listenTo( this.model, 'change', this.render );
|
||||
},
|
||||
|
||||
/**
|
||||
* Render
|
||||
*/
|
||||
render: function() {
|
||||
this.$el.html( this.template( {
|
||||
...this.model.toJSON(),
|
||||
formattedAmount: this.model.formattedAmount(),
|
||||
} ) );
|
||||
|
||||
// Ensure the wrapper class has the new name.
|
||||
this.$el.attr( 'class', _.result( this, 'className' ) );
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a rate (can only be done if it has not been saved to the database).
|
||||
*
|
||||
* Don't use this.model.destroy() to avoid sending a DELETE request.
|
||||
*
|
||||
* @param {Object} event Event.
|
||||
*/
|
||||
removeRow: function( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
this.collection.remove( this.model );
|
||||
},
|
||||
|
||||
/**
|
||||
* Activate a rate.
|
||||
*
|
||||
* @param {Object} event Event.
|
||||
*/
|
||||
activateRow: function( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
const { i18n } = eddTaxRates;
|
||||
const existingCountryWide = this.collection.where( {
|
||||
region: this.model.get( 'region' ),
|
||||
country: this.model.get( 'country' ),
|
||||
global: '' === this.model.get( 'region' ),
|
||||
status: 'active',
|
||||
} );
|
||||
|
||||
if ( existingCountryWide.length > 0 ) {
|
||||
const regionString = '' === this.model.get( 'region' )
|
||||
? ''
|
||||
: ': ' + this.model.get( 'region' );
|
||||
|
||||
const taxRateString = this.model.get( 'country' ) + regionString;
|
||||
|
||||
alert( i18n.duplicateRate.replace( '%s', `"${ taxRateString }"` ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.model.set( 'status', 'active' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Deactivate a rate.
|
||||
*
|
||||
* @param {Object} event Event.
|
||||
*/
|
||||
deactivateRow: function( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
this.model.set( 'status', 'inactive' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Select or deselect for bulk actions.
|
||||
*
|
||||
* @param {Object} event Event.
|
||||
*/
|
||||
selectRow: function( event ) {
|
||||
const checked = event.target.checked;
|
||||
|
||||
if ( ! checked ) {
|
||||
this.collection.selected = _.reject( this.collection.selected, ( cid ) => {
|
||||
return cid === this.model.cid;
|
||||
} );
|
||||
} else {
|
||||
this.collection.selected.push( this.model.cid );
|
||||
}
|
||||
},
|
||||
} );
|
||||
|
||||
export default TableRow;
|
@ -0,0 +1,65 @@
|
||||
/* global wp, _ */
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import TableRowEmpty from './table-row-empty.js';
|
||||
import TableRow from './table-row.js';
|
||||
|
||||
/**
|
||||
* A bunch of rows inside a table of rates.
|
||||
*/
|
||||
const TableRows = wp.Backbone.View.extend( {
|
||||
// Insert as a <tbody>
|
||||
tagName: 'tbody',
|
||||
|
||||
/**
|
||||
* Bind events to collection.
|
||||
*/
|
||||
initialize: function() {
|
||||
this.listenTo( this.collection, 'add', this.render );
|
||||
this.listenTo( this.collection, 'remove', this.render );
|
||||
this.listenTo( this.collection, 'filtered change', this.filtered );
|
||||
},
|
||||
|
||||
/**
|
||||
* Render a collection of rows.
|
||||
*/
|
||||
render: function() {
|
||||
// Clear to handle sorting.
|
||||
this.views.remove();
|
||||
|
||||
// Show empty placeholder.
|
||||
if ( 0 === this.collection.models.length ) {
|
||||
return this.views.add( new TableRowEmpty() );
|
||||
}
|
||||
|
||||
// Add items.
|
||||
_.each( this.collection.models, ( rate ) => {
|
||||
this.views.add( new TableRow( {
|
||||
collection: this.collection,
|
||||
model: rate,
|
||||
} ) );
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Show an empty state if all items are deactivated.
|
||||
*/
|
||||
filtered: function() {
|
||||
const disabledRates = this.collection.where( {
|
||||
status: 'inactive',
|
||||
} );
|
||||
|
||||
// Check if all rows are invisible, and show the "No Items" row if so
|
||||
if ( disabledRates.length === this.collection.models.length && ! this.collection.showAll ) {
|
||||
this.views.add( new TableRowEmpty() );
|
||||
|
||||
// Possibly re-render the view
|
||||
} else {
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
} );
|
||||
|
||||
export default TableRows;
|
@ -0,0 +1,50 @@
|
||||
/* global wp */
|
||||
|
||||
/**
|
||||
* Internal dependencies.
|
||||
*/
|
||||
import TableMeta from './table-meta.js';
|
||||
import TableRows from './table-rows.js';
|
||||
import TableAdd from './table-add.js';
|
||||
|
||||
/**
|
||||
* Manage the tax rate rows in a table.
|
||||
*/
|
||||
const Table = wp.Backbone.View.extend( {
|
||||
// Render as a <table> tag.
|
||||
tagName: 'table',
|
||||
|
||||
// Set class.
|
||||
className: 'wp-list-table widefat fixed tax-rates',
|
||||
|
||||
// Set ID.
|
||||
id: 'edd_tax_rates',
|
||||
|
||||
/**
|
||||
* Output a table with a header, body, and footer.
|
||||
*/
|
||||
render: function() {
|
||||
this.views.add( new TableMeta( {
|
||||
tagName: 'thead',
|
||||
collection: this.collection,
|
||||
} ) );
|
||||
|
||||
this.views.add( new TableRows( {
|
||||
collection: this.collection,
|
||||
} ) );
|
||||
|
||||
this.views.add( new TableAdd( {
|
||||
collection: this.collection,
|
||||
} ) );
|
||||
|
||||
this.views.add( new TableMeta( {
|
||||
tagName: 'tfoot',
|
||||
collection: this.collection,
|
||||
} ) );
|
||||
|
||||
// Trigger the `filtered` action to show/hide rows accordingly
|
||||
this.collection.trigger( 'filtered' );
|
||||
},
|
||||
} );
|
||||
|
||||
export default Table;
|
Reference in New Issue
Block a user