File: /home/muoapartman/www/wp-content/plugins/motopress-hotel-booking-lite/assets/js/admin/admin.js
(function( $ ) {
$( function() {
MPHBAdmin.BookingsCalendar = can.Control.extend( {}, {
filtersForm: null,
customPeriodWrapper: null,
btnPeriodPrev: null,
btnPeriodNext: null,
periodEl: null,
popup: null,
init: function( el, args ) {
this.filtersForm = this.element.find( '#mphb-bookings-calendar-filters' );
this.customPeriodWrapper = this.filtersForm.find( '.mphb-custom-period-wrapper' );
this.btnPeriodPrev = this.filtersForm.find( '.mphb-period-prev' );
this.btnPeriodNext = this.filtersForm.find( '.mphb-period-next' );
this.periodEl = this.filtersForm.find( '#mphb-bookings-calendar-filter-period' );
this.searchDateFromEl = this.filtersForm.find( '.mphb-search-date-from' );
this.searchDateToEl = this.filtersForm.find( '.mphb-search-date-to' );
this.popup = new MPHBAdmin.CalendarPopup(this.element.find('#mphb-bookings-calendar-popup'), {
clickTargets: this.element.find('.mphb-link-to-booking, .mphb-silent-link-to-booking')
});
this.initDatepickers();
},
initDatepickers: function() {
var datepickers = this.filtersForm.find( '.mphb-datepick' );
datepickers.datepick( {
dateFormat: MPHBAdmin.Plugin.myThis.data.settings.dateFormat,
firstDay: MPHBAdmin.Plugin.myThis.data.settings.firstDay,
showSpeed: 0,
showOtherMonths: true,
monthsToShow: MPHBAdmin.Plugin.myThis.data.settings.numberOfMonthDatepicker,
pickerClass: MPHBAdmin.Plugin.myThis.data.settings.datepickerClass,
useMouseWheel: false
} );
},
'#mphb-bookings-calendar-filter-period change': function( el, e ) {
var period = $( el ).val();
if ( period === 'custom' ) {
this.customPeriodWrapper.removeClass( 'mphb-hide' );
this.btnPeriodNext.addClass( 'mphb-hide' );
this.btnPeriodPrev.addClass( 'mphb-hide' );
} else {
this.customPeriodWrapper.addClass( 'mphb-hide' );
this.btnPeriodNext.removeClass( 'mphb-hide' );
this.btnPeriodPrev.removeClass( 'mphb-hide' );
}
},
'#mphb-booking-calendar-search-room-availability-status change': function( el, e ) {
var status = $( el ).val();
if ( status === '' ) {
this.searchDateFromEl.addClass( 'mphb-hide' );
this.searchDateToEl.addClass( 'mphb-hide' );
} else {
this.searchDateFromEl.removeClass( 'mphb-hide' );
this.searchDateToEl.removeClass( 'mphb-hide' );
}
}
} );
MPHBAdmin.CalendarPopup = can.Control.extend(
{},
{
$title: null,
$status: null,
$preloader: null,
$content: null,
$editLink: null,
titleText: '',
errorText: '',
statuses: {},
ajaxUrl: '',
ajaxAction: 'mphb_get_booking_info',
ajaxNonce: '',
init: function (element, args) {
if (!element || element.length == 0 || args == undefined || args.clickTargets == undefined) {
return;
}
var pluginData = MPHBAdmin.Plugin.myThis.data;
var translations = pluginData.translations;
this.titleText = translations.bookingId;
this.errorText = translations.errorHasOccured;
this.statuses = translations.bookingStatuses;
this.ajaxUrl = pluginData.ajaxUrl;
this.ajaxNonce = pluginData.nonces[this.ajaxAction];
this.$title = element.find('.mphb-title');
this.$status = element.find('.mphb-status');
this.$preloader = element.find('.mphb-preloader');
this.$content = element.find('.mphb-content');
this.$editLink = element.find('.mphb-edit-button');
args.clickTargets.on('click', this.onClick.bind(this));
},
onClick: function (event) {
event.preventDefault();
// Get booking ID
var element = $(event.target);
var bookingId = parseInt(element.data('booking-id'));
if (isNaN(bookingId)) {
return;
}
// Update booking ID and edit URL
var editUrl = element.attr('href');
this.$title.text(this.titleText.replace('%s', bookingId));
this.$editLink.attr('href', editUrl);
// Update status
var bookingStatus = element.data('booking-status');
if (this.statuses.hasOwnProperty(bookingStatus)) {
this.$status.text(this.statuses[bookingStatus]);
this.$status.attr('class', 'mphb-status mphb-status-' + bookingStatus);
this.show(this.$status);
} else {
this.hide(this.$status);
}
// Show the popup
this.show();
this.loadBookingDetails(bookingId);
},
'.mphb-close-popup-button, .mphb-popup-backdrop click': function () {
this.hide();
},
loadBookingDetails: function (bookingId) {
this.beforeLoad();
var self = this;
$.ajax({
url: this.ajaxUrl,
type: 'GET',
dataType: 'json',
data: {
action: this.ajaxAction,
mphb_nonce: this.ajaxNonce,
bookingId: bookingId
},
success: function (response) {
// Push new HTML or error message
if (response.hasOwnProperty('success')) {
if (response.success) {
self.updateContent(response.data.bookingInfo);
} else {
self.setMessage(response.data.message);
}
} else {
self.setMessage(self.errorText);
}
},
error: function () {
self.setMessage(self.errorText);
},
complete: function () {
self.afterLoad();
}
});
},
updateContent: function (htmlContent) {
this.$content.html(htmlContent);
},
setMessage: function (message) {
this.updateContent('<p>' + message + '</p>');
},
beforeLoad: function () {
this.$content.empty();
this.show(this.$preloader);
},
afterLoad: function () {
this.hide(this.$preloader);
},
show: function (element) {
element = element || this.element;
element.removeClass('mphb-hide');
},
hide: function (element) {
element = element || this.element;
element.addClass('mphb-hide');
}
}
);
/**
* @since 3.5.0
*/
MPHBAdmin.ExportBookings = can.Control.extend(
{},
{
rooms: null, // select[name="room"]
statuses: null, // select[name="status"]
startDate: null, // input.mphb-export-start-date
endDate: null, // input.mphb-export-end-date
searchBy: null, // select[name="search_by"]
columnsFieldset: null, // fieldset.mphb-export-columns
exportColumns: null, // input[type="checkbox"]
submitButton: null, // button.submit-button
preloader: null, // span.mphb-preloader
progressBar: null, // div.mphb-progress
progressBack: null, // .mphb-progress__bar
progressText: null, // .mphb-progress__text
cancelButton: null, // button.cancel-button
errorsWrapper: null, // div.mphb-errors-wrapper
timeoutInterval: 1000,
shortInterval: 500,
checkTimer: null,
cancelTimer: null,
messages: {
error: '',
processing: '',
cancelling: ''
},
init: function (element, args) {
if (element.length == 0) {
return;
}
this.initMessages();
this.initElements(element);
this.initDatepickers();
// Did the previous process finished it's work?
if (MPHBAdmin.Plugin.myThis.data.settings.isExportingBookings) {
this.alreadyStarted();
this.checkTimer = setTimeout(this.checkExport.bind(this), 0);
}
},
initMessages: function () {
var translations = MPHBAdmin.Plugin.myThis.data.translations;
this.messages.error = translations.errorHasOccured;
this.messages.processing = translations.processing;
this.messages.cancelling = translations.cancelling;
},
initElements: function (root) {
this.rooms = root.find('select[name="room"]');
this.statuses = root.find('select[name="status"]');
this.startDate = root.find('.mphb-export-start-date');
this.endDate = root.find('.mphb-export-end-date');
this.searchBy = root.find('select[name="search_by"]');
this.columnsFieldset = root.find('.mphb-export-columns');
this.exportColumns = this.columnsFieldset.find('input[type="checkbox"]');
this.submitButton = root.find('.submit-button');
this.preloader = root.find('.mphb-preloader');
this.progressBar = root.find('.mphb-progress');
this.progressBack = this.progressBar.children('.mphb-progress__bar');
this.progressText = this.progressBar.children('.mphb-progress__text');
this.cancelButton = root.find('.cancel-button');
this.errorsWrapper = root.find('.mphb-errors-wrapper');
},
initDatepickers: function () {
var pluginSettings = MPHBAdmin.Plugin.myThis.data.settings;
var settings = {
dateFormat: pluginSettings.dateFormat,
firstDay: pluginSettings.firstDay,
showSpeed: 0,
showOtherMonths: true,
monthsToShow: pluginSettings.numberOfMonthDatepicker,
pickerClass: pluginSettings.datepickerClass,
useMouseWheel: false
};
this.startDate.datepick(settings);
this.endDate.datepick(settings);
},
".submit-button click": function (element, event) {
event.preventDefault();
this.beforeStart();
this.startExport();
},
".cancel-button click": function (element, event) {
event.preventDefault();
clearTimeout(this.checkTimer);
this.afterCancel();
this.cancelExport();
},
startExport: function () {
var action = 'mphb_export_bookings_csv',
data = MPHBAdmin.Plugin.myThis.data,
self = this;
$.ajax({
url: data.ajaxUrl,
type: 'POST',
dataType: 'json',
data: {
action: action,
mphb_nonce: data.nonces[action],
args: this.getValues()
},
success: function (response) {
if (response.hasOwnProperty('success') && response.success) {
self.afterStart();
self.checkTimer = setTimeout(self.checkExport.bind(self), self.shortInterval);
} else {
self.badResponse( response.success ? null : response.data.message );
}
},
error: this.badResponse.bind(this)
});
},
checkExport: function () {
var action = 'mphb_check_bookings_csv',
data = MPHBAdmin.Plugin.myThis.data,
self = this;
$.ajax({
url: data.ajaxUrl,
type: 'GET',
dataType: 'json',
data: {
action: action,
mphb_nonce: data.nonces[action]
},
success: function (response) {
if (response.hasOwnProperty('success') && response.success) {
if (response.data.finished) {
self.setProgress(100);
if (response.data.file) {
self.downloadFile(response.data.file);
} else {
self.setMessage(self.messages.error);
}
self.afterEnd();
} else {
self.setProgress(Math.floor(response.data.progress));
self.checkTimer = setTimeout(self.checkExport.bind(self), self.timeoutInterval);
}
} else {
self.badResponse();
}
},
error: this.badResponse.bind(this)
});
},
cancelExport: function () {
var action = 'mphb_cancel_bookings_csv',
data = MPHBAdmin.Plugin.myThis.data,
self = this;
$.ajax({
url: data.ajaxUrl,
type: 'POST',
dataType: 'json',
data: {
action: action,
mphb_nonce: data.nonces[action]
},
success: function (response) {
if (response.hasOwnProperty('success') && response.success) {
if (!response.data.cancelled) {
self.cancelTimer = setTimeout(self.cancelExport.bind(self), self.timeoutInterval);
} else {
self.afterEnd();
}
} else {
self.badResponse();
}
},
error: this.badResponse.bind(this)
});
},
badResponse: function (message) {
if (message == undefined) {
message = this.messages.error;
}
if (message != '') {
this.setMessage(message);
}
this.afterEnd();
},
downloadFile: function (file) {
window.location = file;
},
setProgress: function (progress, text) {
if (text == undefined) {
text = progress == 0 ? this.messages.processing : progress + '%';
}
this.progressBack.css('width', progress + '%');
this.progressText.text(text);
if (progress < 100) {
if (progress == 0) {
this.progressBar.addClass('mphb-wait');
} else {
this.progressBar.removeClass('mphb-wait');
}
}
},
setMessage: function (message) {
this.errorsWrapper.text(message).removeClass('mphb-hide');
},
beforeStart: function () {
this.submitButton.prop('disabled', true);
this.preloader.removeClass('mphb-hide');
this.errorsWrapper.addClass('mphb-hide').empty();
this.setProgress(0);
this.progressBar.removeClass('mphb-hide');
this.cancelButton.removeClass('mphb-hide');
},
afterStart: function () {
this.cancelButton.prop('disabled', false);
},
alreadyStarted: function () {
this.submitButton.prop('disabled', true);
this.preloader.removeClass('mphb-hide');
this.progressBar.removeClass('mphb-hide');
this.cancelButton.removeClass('mphb-hide').prop('disabled', false);
},
afterCancel: function () {
this.cancelButton.addClass('mphb-hide').prop('disabled', true);
this.progressBar.addClass('mphb-wait');
this.setProgress(100, this.messages.cancelling);
},
afterEnd: function () {
this.submitButton.prop('disabled', false);
this.preloader.addClass('mphb-hide');
this.progressBar.addClass('mphb-hide');
this.cancelButton.addClass('mphb-hide').prop('disabled', true);
},
getValues: function () {
var values = {};
values['room'] = this.rooms.val();
values['status'] = this.statuses.val();
values['start_date'] = this.startDate.val();
values['end_date'] = this.endDate.val();
values['search_by'] = this.searchBy.val();
values['columns'] = $.map(this.exportColumns.filter(':checked'), function (element) { return element.value; });
if (values.columns.length == 0) {
values.columns = 'none'; // Otherwise $.ajax() will lose the field
}
return values;
},
".mphb-toggle-export-columns click": function (element, event) {
event.preventDefault();
this.columnsFieldset.toggleClass('mphb-hide');
},
".mphb-checkbox-select-all click": function (element, event) {
event.preventDefault();
this.exportColumns.filter(':not(:checked)').prop('checked', true);
},
".mphb-checkbox-unselect-all click": function (element, event) {
event.preventDefault();
this.exportColumns.filter(':checked').prop('checked', false);
}
}
);
/**
* @see MPHBAdmin.format_price() in public/mphb.js
*/
MPHBAdmin.format_price = function( price, atts ) {
atts = atts || {};
var defaultAtts = MPHBAdmin.Plugin.myThis.data.settings.currency;
atts = $.extend( { 'trim_zeros': false }, defaultAtts, atts );
price = MPHBAdmin.number_format( price, atts['decimals'], atts['decimal_separator'], atts['thousand_separator'] );
var formattedPrice = atts['price_format'].replace( '%s', price );
if ( atts['trim_zeros'] ) {
var regex = new RegExp('\\' + atts['decimal_separator'] + '0+$|(\\' + atts['decimal_separator'] + '\\d*[1-9])0+$');
formattedPrice = formattedPrice.replace( regex, '$1' );
}
var priceHtml = '<span class="mphb-price">' + formattedPrice + '</span>';
return priceHtml;
};
MPHBAdmin.format_percentage = function( price, atts ) {
atts = atts || {};
var defaultAtts = MPHBAdmin.Plugin.myThis.data.settings.currency;
atts = $.extend( {}, defaultAtts, atts );
price = MPHBAdmin.number_format( price, atts['decimals'], atts['decimal_separator'], atts['thousand_separator'] );
var formattedPrice = price + '%';
var priceHtml = '<span class="mphb-percentage">' + formattedPrice + '</span>';
return priceHtml;
};
/**
* @see MPHBAdmin.number_format() in public/mphb.js
*/
MPHBAdmin.number_format = function( number, decimals, dec_point, thousands_sep ) {
// + Original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// + Improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + Bugfix by: Michael White (http://crestidg.com)
var sign = '', i, j, kw, kd, km;
// Input sanitation & defaults
decimals = decimals || 0
dec_point = dec_point || '.'
thousands_sep = thousands_sep || ','
if ( number < 0 ) {
sign = '-';
number *= -1;
}
i = parseInt( number = ( +number || 0 ).toFixed( decimals ) ) + '';
if ( ( j = i.length ) > 3 ) {
j = j % 3;
} else {
j = 0;
}
km = ( j ? i.substr( 0, j ) + thousands_sep : '' );
kw = i.substr( j ).replace( /(\d{3})(?=\d)/g, '$1' + thousands_sep );
kd = ( decimals ? dec_point + Math.abs( number - i ).toFixed( decimals ).replace( /-/, 0 ).slice( 2 ) : '' );
return sign + km + kw + kd;
};
/**
* @param {String} action Action name (without prefix "mphb_").
* @param {Object} data
* @param {Object} callbacks "success", "error", "complete".
* @returns {Object} The jQuery XMLHttpRequest object.
*
* @since 3.7.0
*/
MPHBAdmin.post = function (action, data, callbacks)
{
var pluginData = MPHBAdmin.Plugin.myThis.data;
if (action.substr(0, 4) !== 'mphb') {
action = 'mphb_' + action;
}
data = $.extend(
{
action: action,
mphb_nonce: pluginData.nonces[action]
},
data
);
var ajaxArgs = $.extend(
{
url: pluginData.ajaxUrl,
type: 'POST',
dataType: 'json',
data: data
},
callbacks
);
return $.ajax(ajaxArgs);
}
MPHBAdmin.Plugin = can.Construct.extend( {
myThis: null
}, {
data: null,
init: function( el, args ) {
MPHBAdmin.Plugin.myThis = this;
this.data = MPHBAdmin._data;
delete MPHBAdmin._data;
var ctrls = $( '.mphb-ctrl:not([data-inited])' );
this.setControls( ctrls );
},
getVersion: function() {
return this.data.version;
},
getPrefix: function() {
return this.data.prefix;
},
addPrefix: function( str, separator ) {
separator = (typeof separator !== 'undefined') ? separator : '-';
return this.getPrefix() + separator + str;
},
setControls: function( ctrls ) {
var ctrl, type;
$.each( ctrls, function() {
type = $( this ).attr( 'data-type' );
switch ( type ) {
case 'text':
break;
case 'number':
ctrl = new MPHBAdmin.NumberCtrl( $( this ) );
break;
case 'total-price':
ctrl = new MPHBAdmin.TotalPriceCtrl( $( this ) );
break;
case 'price-breakdown':
ctrl = new MPHBAdmin.PriceBreakdownCtrl( $( this ) );
break;
case 'media':
ctrl = new MPHBAdmin.MediaCtrl( $( this ) );
break;
case 'datepicker':
ctrl = new MPHBAdmin.DatePickerCtrl( $( this ) );
break;
case 'color-picker':
ctrl = new MPHBAdmin.ColorPickerCtrl( $( this ) );
break;
case 'complex':
ctrl = new MPHBAdmin.ComplexCtrl( $( this ) );
break;
case 'complex-vertical':
ctrl = new MPHBAdmin.ComplexVerticalCtrl( $( this ) );
break;
case 'dynamic-select':
ctrl = new MPHBAdmin.DynamicSelectCtrl( $( this ) );
break;
case 'multiple-checkbox':
ctrl = new MPHBAdmin.MultipleCheckboxCtrl( $( this ) );
break;
case 'amount':
ctrl = new MPHBAdmin.AmountCtrl( $( this ) );
break;
case 'rules-list':
ctrl = new MPHBAdmin.RulesListCtrl( $( this ) );
break;
case 'notes-list':
ctrl = new MPHBAdmin.NotesListCtrl( $( this ) );
break;
case 'variable-pricing':
ctrl = new MPHBAdmin.VariablePricingCtrl( $( this ) );
break;
case 'action-button':
ctrl = new MPHBAdmin.ActionButtonCtrl($(this));
break;
case 'install-plugin':
ctrl = new MPHBAdmin.InstallButtonCtrl($(this));
break;
}
$( this ).attr( 'data-inited', true );
} );
}
} );
/**
* @since 3.8
*/
MPHBAdmin.PopupForm = can.Control.extend(
{}, // Static
{
$popup: null,
$submitButton: null,
// States
isVisible: false,
isSubmitable: true, // Leave sentence "canSubmit" for the method
// Promise callbacks
resolve: null,
reject: null,
lastInput: {}, // Last input data from show()
init: function ($element, args) {
this.$popup = $element;
this.$submitButton = $element.find('.mphb-submit-popup-button');
},
/**
* @param {Object} inputData
*
* @private
*/
reset: function (inputData) {
this.canSubmit(true);
},
/**
* @param {Object} data Optional.
* @returns {Promise}
*
* @public
*/
show: function (data) {
if (this.isVisible) {
return;
}
this.lastInput = data || {};
// Make final preparations
this.reset(this.lastInput);
// Show popup
this.$popup.removeClass('mphb-hide');
this.isVisible = true;
// Create promise
var self = this;
return new Promise(function (resolve, reject) {
self.resolve = resolve;
self.reject = reject;
});
},
/**
* @private
*/
close: function () {
if (!this.isVisible) {
return;
}
// Hide popup
this.$popup.addClass('mphb-hide');
this.isVisible = false;
// Reject the promise
this.reject(new Error('Closed.'));
this.resolve = this.reject = null;
},
/**
* @private
*/
submit: function () {
if (!this.isVisible) {
return;
}
// Hide popup
this.$popup.addClass('mphb-hide');
this.isVisible = false;
// Fullfill the promise
if (this.canSubmit()) {
this.resolve(this.getData());
} else {
this.reject(new Error("Can't submit."));
}
this.resolve = this.reject = null;
},
/**
* @param {Boolean} isSubmitable Optional. New state to set.
* @returns {Boolean} The current state.
*
* @public
*/
canSubmit: function (isSubmitable) {
if (isSubmitable != undefined) {
this.isSubmitable = isSubmitable;
this.$submitButton.prop('disabled', !this.isSubmitable);
}
return this.isSubmitable;
},
/**
* @returns {Object}
*
* @public
*/
getData: function () {
return $.extend({}, this.lastInput);
},
".mphb-submit-popup-button click": function (element, event) {
this.submit();
},
".mphb-close-popup-button, .mphb-popup-backdrop click": function (element, event) {
this.close();
}
}
);
( function( $ ) {
$( '.mphb-remove-customer' ).on( 'click', function( e ) {
e.preventDefault();
e.stopPropagation();
var pluginData = MPHBAdmin.Plugin.myThis.data;
var translations = pluginData.translations;
var textOnDelete = translations.deleteConfirmation;
var nonce = pluginData.nonces.mphb_remove_customer;
var confirmDeleting = confirm(textOnDelete);
if(confirmDeleting) {
var customer = $( this );
$.ajax(
ajaxurl,
{
type: 'post',
data: {
action: 'mphb_remove_customer',
itemId: customer.attr( "data-item-key" ),
mphb_nonce: nonce
},
success: function( responce ) {
window.location.href = window.location.href;
}
}
);
}
} );
} )( jQuery );
// table.wp-list-table
MPHBAdmin.AttributesCustomOrder = can.Control.extend(
{},
{
ITEM_SELECTOR: 'tbody tr:not(.inline-edit-row)',
TERM_ID_SELECTOR: '.check-column input',
TERM_ID_CLASS: '.check-column',
COLUMN_HANDLE: '<td class="column-handle"></td>',
COLUMN_HANDLE_CLASS: '.column-handle',
/**
* @param {jQuery} element table.wp-list-table
* @param {Array} args
*/
init: function( element, args ) {
this._super( element, args );
// Add sortable handle to each item
element.find( 'tr:not(.inline-edit-row)' ).append( this.COLUMN_HANDLE );
element.find( this.COLUMN_HANDLE_CLASS ).show();
$( document ).ajaxComplete( this.onAjaxComplete.bind( this ) );
element.sortable( {
items: this.ITEM_SELECTOR,
cursor: 'move',
handle: this.COLUMN_HANDLE_CLASS,
axis: 'y',
opacity: 0.65,
scrollSensitivity: 40,
update: this.onUpdate.bind( this )
} );
},
onAjaxComplete: function( event, request, options ) {
if ( request && request.readyState === 4 && request.status === 200 && options.data && ( options.data.indexOf( '_inline_edit' ) >= 0 || options.data.indexOf( 'add-tag' ) >= 0 ) ) {
this.addMissingSortHandles();
$( document.body ).trigger( 'init_tooltips' );
}
},
onUpdate: function( event, ui ) {
var termId = ui.item.find( this.TERM_ID_SELECTOR ).val(); // This post ID
var nextTermId = ui.item.next().find( this.TERM_ID_SELECTOR ).val();
// Show spinner
ui.item.find( this.TERM_ID_SELECTOR ).hide();
ui.item.find( this.TERM_ID_CLASS ).append( '<span class="mphb-preloader"></span>' );
var self = this;
$.ajax( {
url: MPHBAdmin.Plugin.myThis.data.ajaxUrl,
type: 'POST',
dataType: 'json',
data: {
action: 'mphb_attributes_custom_ordering',
mphb_nonce: MPHBAdmin.Plugin.myThis.data.nonces.mphb_attributes_custom_ordering,
term_id: termId,
next_term_id: nextTermId,
taxonomy_name: MPHBAdmin.Plugin.myThis.data.settings.editTaxonomyName
},
complete: function( jqXHR, textStatus ) {
ui.item.find( self.TERM_ID_CLASS ).find( '.mphb-preloader' ).remove();
ui.item.find( self.TERM_ID_SELECTOR ).show();
}
} );
// Fix cell colors
this.element.find( 'tbody tr' ).each( function( index, element ) {
if ( index % 2 == 0 ) {
$( this ).addClass( 'alternate' );
} else {
$( this ).removeClass( 'alternate' );
}
} );
},
addMissingSortHandles: function() {
var allRows = this.element.find( 'tbody > tr' );
var handleRows = this.element.find( 'tbody > tr > td' + this.COLUMN_HANDLE_CLASS ).parent();
if ( allRows.length == handleRows.length ) {
return;
}
var self = this;
allRows.each( function( index, element ) {
if ( !handleRows.is( element ) ) {
$( element ).append( self.COLUMN_HANDLE );
}
} );
this.element.find( this.COLUMN_HANDLE_CLASS ).show();
}
}
);
MPHBAdmin.ServiceQuantity = can.Control.extend(
{},
{
$periodSelect: null,
$quantityRows: null,
$autoLimitCheckbox: null,
$maxQuantityInput: null,
init: function (element, args) {
if (element.length == 0) {
return;
}
this.$periodSelect = element.find('select[name="mphb_price_periodicity"]');
this.$quantityRows = element.find('.form-table tr:nth-of-type(n + 3):not(:last-of-type)');
this.$autoLimitCheckbox = element.find('input[name="mphb_is_auto_limit"][type="checkbox"]');
this.$maxQuantityInput = element.find('input[name="mphb_max_quantity"]');
// Add event listeners
var self = this;
this.$periodSelect.on('change', function (event) {
var newPeriod = self.$periodSelect.val();
self.onPeriodChange(newPeriod);
});
this.$autoLimitCheckbox.on('change', function (event) {
var isAutoLimit = self.$autoLimitCheckbox.prop('checked');
self.onAutoLimitChange(isAutoLimit);
});
// Init default state
this.onPeriodChange(this.$periodSelect.val());
this.onAutoLimitChange(this.$autoLimitCheckbox.prop('checked'));
},
onPeriodChange: function (newPeriod) {
if (newPeriod != 'flexible') {
this.$quantityRows.addClass('mphb-hide');
} else {
this.$quantityRows.removeClass('mphb-hide');
}
},
onAutoLimitChange: function (isAutoLimit) {
this.$maxQuantityInput.prop('readonly', isAutoLimit);
}
}
);
( function( $ ) {
$( document.body ).on( 'init_tooltips', function() {
$( '.mphb-help-tip' ).tipTip( {
'attribute': 'data-tip',
'fadeIn': 50,
'fadeOut': 50,
'delay': 200,
'keepAlive': true
} );
});
// Tooltips
$( document.body ).trigger( 'init_tooltips' );
})( jQuery );
MPHBAdmin.WPGallery = can.Construct.extend( {
myThis: null,
getInstance: function() {
if ( MPHBAdmin.WPGallery.myThis === null ) {
MPHBAdmin.WPGallery.myThis = new MPHBAdmin.WPGallery();
}
return MPHBAdmin.WPGallery.myThis;
}
},
{
frame: null,
ctrl: null,
init: function() {
var self = this;
MPHBAdmin.WPGallery.myThis = this;
Attachment = wp.media.model.Attachment;
wp.media.controller.MPHBGallery = wp.media.controller.FeaturedImage.extend( {
defaults: parent._.defaults( {
id: 'mphb-media-library-gallery',
title: MPHBAdmin.Plugin.myThis.data.translations.roomTypeGalleryTitle,
toolbar: 'main-insert',
filterable: 'uploaded',
library: wp.media.query( {type: 'image'} ),
multiple: 'add',
editable: true,
priority: 60,
syncSelection: false
}, wp.media.controller.Library.prototype.defaults ),
updateSelection: function() {
var selection = this.get( 'selection' ),
ids = MPHBAdmin.WPGallery.myThis.ctrl.getValue(),
attachments;
if ( '' !== ids && -1 !== ids ) {
attachments = parent._.map( ids.split( /,/ ), function( id ) {
return Attachment.get( id );
} );
}
selection.reset( attachments );
}
} );
wp.media.view.MediaFrame.MPHBGallery = wp.media.view.MediaFrame.Post.extend( {
// Define insert - MPHB state
createStates: function() {
var options = this.options;
// Add the default states
this.states.add( [
// Main states
new wp.media.controller.MPHBGallery()
] );
},
// Removing let menu from manager
bindHandlers: function() {
wp.media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
this.on( 'toolbar:create:main-insert', this.createToolbar, this );
var handlers = {
content: {
'embed': 'embedContent',
'edit-selection': 'editSelectionContent'
},
toolbar: {
'main-insert': 'mainInsertToolbar'
}
};
parent._.each( handlers, function( regionHandlers, region ) {
parent._.each( regionHandlers, function( callback, handler ) {
this.on( region + ':render:' + handler, this[ callback ], this );
}, this );
}, this );
},
// Changing main button title
mainInsertToolbar: function( view ) {
var controller = this;
this.selectionStatusToolbar( view );
view.set( 'insert', {
style: 'primary',
priority: 80,
text: MPHBAdmin.Plugin.myThis.data.translations.addGalleryToRoomType,
requires: {selection: true},
click: function() {
var state = controller.state(),
selection = state.get( 'selection' );
controller.close();
state.trigger( 'insert', selection ).reset();
}
} );
}
} );
this.frame = new wp.media.view.MediaFrame.MPHBGallery( parent._.defaults( {}, {
state: 'mphb-media-library-gallery',
library: {type: 'image'},
multiple: true
} ) );
this.frame.on( 'open', this.proxy( 'onOpen' ) );
this.frame.on( 'insert', this.proxy( 'setImage' ) );
},
open: function( ctrl ) {
this.ctrl = ctrl;
this.frame.open();
},
onOpen: function() {
var frame = this.frame;
frame.reset();
var ids = this.ctrl.getIds();
if ( ids.length ) {
var attachment = null;
ids.forEach( function( id ) {
attachment = wp.media.attachment( id );
attachment.fetch();
frame.state().get( 'selection' ).add( attachment );
} );
}
},
setImage: function() {
var ids = [ ];
var models = this.frame.state().get( 'selection' ).models;
$.each( models, function( key, model ) {
var attributes = model.attributes;
ids.push( attributes.id );
} );
this.ctrl.setValue( ids.join( ',' ) );
}
} );
MPHBAdmin.Ctrl = can.Control.extend( {
renderValue: function( control ) {
var type = control.attr( 'data-type' );
return control.find( 'input[type="' + type + '"]' ).val();
}
}, {
parentForm: null,
init: function( el, args ) {
this.parentForm = this.element.closest( 'form' );
}
} );
/**
* @requires ./ctrl.js
*
* @since 3.7.0
*/
MPHBAdmin.ActionButtonCtrl = MPHBAdmin.Ctrl.extend(
{},
{
// Elements
button: null,
preloader: null,
statusText: null,
// Input parameters
checkInterval: 1000,
reloadAfter: false,
redirectAfter: '',
// Request & progress parameters
actionName: '',
inProgress: false,
timeoutObject: null,
iteration: 1, // Current iteration number
undefinedError: '',
init: function (element, args) {
this._super(element, args);
this.button = element.find('button');
this.preloader = element.find('.mphb-preloader');
this.statusText = element.find('.status-text');
this.checkInterval = parseInt(this.button.data('check-interval'));
this.reloadAfter = this.button.data('reload-after') === 'yes';
this.redirectAfter = this.button.data('redirect-after');
this.actionName = this.button.attr('name');
this.undefinedError = MPHBAdmin.Plugin.myThis.data.translations.errorHasOccured;
if (this.button.prop('disabled')) {
// "Lock" the button if it was disabled from the beginning
this.inProgress = true;
}
if (this.button.data('is-in-progress') === 'yes') {
this.beforeStart();
// Some requests may use 1 as init stage and 2+ as "getStatus" stages
this.iteration = 2;
this.makeRequest();
}
this.button.on('click', this.onClick.bind(this));
},
onClick: function (event) {
event.preventDefault();
if (!this.inProgress) {
this.beforeStart();
this.makeRequest();
}
},
makeRequest: function () {
var self = this;
MPHBAdmin.post(
this.actionName,
{
iteration: this.iteration // Starts from 1
},
{
success: function (response) {
// Show message
if (response.data && response.data.message) {
self.setStatus(response.data.message, !response.success);
} else {
self.setStatus('', false);
}
// Wait for next iteration or end right now
if (response.success && response.data && response.data.inProgress) {
self.iteration++;
self.timeoutObject = setTimeout(self.makeRequest.bind(self), self.checkInterval);
} else {
self.afterEnd(response.success);
}
},
error: function (jqXHR) {
self.setStatus(self.undefinedError, true);
self.afterEnd(false);
}
}
);
},
beforeStart: function () {
this.inProgress = true;
this.iteration = 1;
this.button.prop('disabled', true);
this.preloader.removeClass('mphb-hide');
this.statusText.text('').removeClass('error');
},
/**
* @param {Boolean} succeeded
*/
afterEnd: function (succeeded) {
this.inProgress = false;
this.preloader.addClass('mphb-hide');
var enableButton = true;
if (succeeded) {
if (this.redirectAfter || this.reloadAfter) {
enableButton = false;
}
if (this.redirectAfter) {
window.location.href = this.redirectAfter;
} else if (this.reloadAfter) {
document.location.reload(true); // true - load new page from server
}
}
if (enableButton) {
this.button.prop('disabled', false);
}
},
/**
* @param {String} text
* @param {Boolean} isError
*/
setStatus: function (text, isError) {
this.statusText.text(text);
this.statusText.toggleClass('error', isError);
}
}
);
/**
*
* @requires ./ctrl.js
*/
MPHBAdmin.AmountCtrl = MPHBAdmin.Ctrl.extend( {
renderValue: function( control ) {
var inputs = control.find( 'input[type="number"]:not(:disabled)' );
var renderType = control.children( '.mphb-amount-inputs' ).attr( 'data-render-type' );
var formatFunction = renderType == 'price' ? MPHBAdmin.format_price : MPHBAdmin.format_percentage;
if ( inputs.length == 1 ) {
return formatFunction( inputs.val(), { decimals: 4 } );
} else {
var result = MPHBAdmin.Plugin.myThis.data.translations.adults;
result += formatFunction( $( inputs[0] ).val(), { decimals: 4 } );
result += '<br />' + MPHBAdmin.Plugin.myThis.data.translations.children;
result += formatFunction( $( inputs[1] ).val(), { decimals: 4 } );
return result;
}
}
}, {
mainWrapper: null,
singleInputGroup: null,
multipleInputsGroup: null,
commonAmountInput: null,
adultsAmountInput: null,
childrenAmountInput: null,
dependencyCtrl: null,
singleInputTriggers: [],
multipleInputsTriggers: [],
init: function( element, args ) {
this._super( element, args );
this.mainWrapper = this.element.children( '.mphb-amount-inputs' );
this.singleInputGroup = this.mainWrapper.children( '.mphb-amount-single-input-group' );
this.multipleInputsGroup = this.mainWrapper.children( '.mphb-amount-multiple-inputs-group' );
this.commonAmountInput = this.singleInputGroup.find( 'input.mphb-amount-common-input' );
this.adultsAmountInput = this.multipleInputsGroup.find( 'input.mphb-amount-adults-input' );
this.childrenAmountInput = this.multipleInputsGroup.find( 'input.mphb-amount-children-input' );
// Init dependency control
var dependencyName = this.mainWrapper.attr( 'data-dependency' );
if ( dependencyName ) {
var self = this;
this.dependencyCtrl = this.element.closest( 'form' ).find( '[name="' + dependencyName + '"]' );
this.dependencyCtrl.on( 'change', function( event ) {
var value = $( this ).val();
self.onTrigger( value );
} );
}
// Init triggers and flags
this.singleInputTriggers = this.mainWrapper.attr( 'data-single-triggers' ).split( ',' );
this.multipleInputsTriggers = this.mainWrapper.attr( 'data-multiple-triggers' ).split( ',' );
},
onTrigger: function( value ) {
var switchToSingle = this.singleInputTriggers.indexOf( value ) != -1;
var switchToMultiple = this.multipleInputsTriggers.indexOf( value ) != -1;
if ( value.indexOf( 'percent' ) != -1 ) {
this.mainWrapper.attr( 'data-render-type', 'percentage' );
} else {
this.mainWrapper.attr( 'data-render-type', 'price' );
}
if ( switchToSingle ) {
this.switchToSingleInput();
} else if ( switchToMultiple ) {
this.switchToMultipleInputs();
}
},
switchToSingleInput: function() {
this.adultsAmountInput.prop( 'disabled', true );
this.childrenAmountInput.prop( 'disabled', true );
this.commonAmountInput.prop( 'disabled', false );
this.multipleInputsGroup.addClass( 'mphb-hide' );
this.singleInputGroup.removeClass( 'mphb-hide' );
},
switchToMultipleInputs: function() {
this.commonAmountInput.prop( 'disabled', true );
this.adultsAmountInput.prop( 'disabled', false );
this.childrenAmountInput.prop( 'disabled', false );
this.singleInputGroup.addClass( 'mphb-hide' );
this.multipleInputsGroup.removeClass( 'mphb-hide' );
}
} );
/**
*
* @requires ./ctrl.js
*/
MPHBAdmin.ColorPickerCtrl = MPHBAdmin.Ctrl.extend( {}, {
input: null,
init: function( el, args ) {
this._super( el, args );
this.input = this.element.find( 'input' )
this.input.spectrum( {
allowEmpty: true,
preferredFormat: "hex",
showInput: true,
showInitial: true,
showAlpha: false
} );
}
} );
/**
*
* @requires ./ctrl.js
*/
MPHBAdmin.ComplexCtrl = MPHBAdmin.Ctrl.extend( {}, {
prototypeItem: null,
itemsHolder: null,
lastIndex: null,
uniqid: null,
itemSelector: 'tr',
metaName: null,
init: function( el, args ) {
this._super( el, args );
this.uniqid = this.element.children( 'table' ).attr( 'data-uniqid' );
this.metaName = this.element.children( 'input[type="hidden"]:first-of-type' ).attr( 'name' );
this.initItemsHolder();
this.initAddBtn();
this.initDeleteBtns();
this.preparePrototypeItem();
this.initLastIndex();
this.setKeys( this.itemsHolder.children( this.itemSelector ) );
},
makeItemsHolderSortable: function() {
if ( this.itemsHolder.parent().hasClass( 'mphb-separate-sortable-table' ) ) {
this.itemsHolder.sortable( {
handle: '.mphb-sortable-handle',
cursor: 'move'
} );
} else {
this.itemsHolder.sortable();
}
},
initLastIndex: function() {
this.lastIndex = 0;
var self = this;
this.itemsHolder.children( this.itemSelector ).each( function( index, item ){
self.lastIndex = Math.max( self.lastIndex, parseInt( $( item ).attr( 'data-id' ) ) );
} );
},
initItemsHolder: function() {
this.itemsHolder = this.element.children( 'table' ).children( 'tbody' );
if ( this.itemsHolder.hasClass( 'mphb-sortable' ) ) {
this.makeItemsHolderSortable();
}
},
initAddBtn: function() {
var self = this;
this.element.on( 'click', '.mphb-complex-add-item[data-id="' + this.uniqid + '"]', function( e ) {
e.preventDefault();
self.addItem();
} )
},
initDeleteBtns: function() {
var self = this;
this.itemsHolder.on( 'click', '.mphb-complex-delete-item[data-id="' + this.uniqid + '"]', function( e ) {
e.preventDefault();
self.deleteItem( $( this ).closest( self.itemSelector ) );
} );
},
preparePrototypeItem: function() {
var item = this.itemsHolder.children( '.mphb-complex-item-prototype' );
this.prototypeItem = item.clone();
this.prototypeItem.removeClass( 'mphb-hide mphb-complex-item-prototype' ).find( '[name]:not(.mphb-keep-disabled)' ).each( function() {
$( this ).removeAttr( 'disabled' );
} );
item.remove();
},
getIncIndex: function() {
return ++this.lastIndex;
},
setKeys: function( wrappers ) {
var self = this;
var name, id, forAttr, key, dependency, $wrapper;
var keyRegEx = new RegExp( '%key_' + this.uniqid + '%', 'g' );
var keyPlaceholder = '%key_' + this.uniqid + '%';
wrappers.each( function( index, wrapper ) {
$wrapper = $( wrapper );
key = $wrapper.attr( 'data-id' );
if ( key === keyPlaceholder ) {
key = self.getIncIndex();
$wrapper.attr( 'data-id', key );
}
$wrapper.find( '[name*="[%key_' + self.uniqid + '%]"]' ).each( function() {
name = $( this ).attr( 'name' ).replace( keyRegEx, key );
$( this ).attr( 'name', name )
if ( $( this ).attr( 'id' ) ) {
id = $( this ).attr( 'id' ).replace( keyRegEx, key ).replace( /\[|\]/g, '__' );
$( this ).attr( 'name', name ).attr( 'id', id );
}
} );
$wrapper.find( '[for*="[%key_' + self.uniqid + '%]"]' ).each( function() {
forAttr = $( this ).attr( 'for' ).replace( keyRegEx, key ).replace( /\[|\]/g, '__' );
$( this ).attr( 'for', forAttr );
} );
$wrapper.find( '[data-dependency*="%key_' + self.uniqid + '%"]' ).each( function() {
dependency = $( this ).attr( 'data-dependency' ).replace( keyRegEx, key );
$( this ).attr( 'data-dependency', dependency );
} );
} );
},
clonePrototypeItem: function() {
var clonedItem = this.prototypeItem.clone();
this.setKeys( clonedItem );
return clonedItem;
},
addItemToHolder: function( item ) {
this.itemsHolder.append( item );
},
deleteItem: function( item ) {
item.remove();
},
addItem: function() {
var item = this.clonePrototypeItem();
this.addItemToHolder( item );
var ctrls = item.find( '.mphb-ctrl:not([data-inited])' );
MPHBAdmin.Plugin.myThis.setControls( ctrls );
}
} );
/**
*
* @requires ./complex-ctrl.js
*/
MPHBAdmin.ComplexVerticalCtrl = MPHBAdmin.ComplexCtrl.extend( {}, {
itemSelector: 'tbody',
lastIndexInput: null,
minItemsCount: 0,
init: function( el, args ) {
this._super( el, args );
this.minItemsCount = this.itemsHolder.attr( 'data-min-items-count' );
},
initLastIndex: function() {
this.lastIndexInput = this.itemsHolder.find( '>tfoot .mphb-complex-last-index' );
this.lastIndex = this.lastIndexInput.val();
},
getIncIndex: function() {
var index = this._super();
this.lastIndexInput.val( index );
return index;
},
initItemsHolder: function() {
this.itemsHolder = this.element.children( 'table' );
},
addItemToHolder: function( item ) {
this.itemsHolder.children( 'tfoot' ).before( item );
},
disableDeleteButtons: function() {
var deleteButtons = this.itemsHolder.children( this.itemSelector ).children( '.mphb-complex-item-actions-holder' ).find( '.mphb-complex-delete-item' );
deleteButtons.attr( 'disabled', 'disabled' ).addClass( 'mphb-hide' );
},
enableDeleteButtons: function() {
var deleteButtons = this.itemsHolder.children( this.itemSelector ).children( '.mphb-complex-item-actions-holder' ).find( '.mphb-complex-delete-item' );
deleteButtons.removeAttr( 'disabled' ).removeClass( 'mphb-hide' );
},
updateItemActions: function() {
var itemCount = this.itemsHolder.children( this.itemSelector ).length;
if ( itemCount <= this.minItemsCount ) {
this.disableDeleteButtons();
} else {
this.enableDeleteButtons();
}
},
updateDefaultItem: function() {
var defaultRadio = this.itemsHolder.children( this.itemSelector ).find( '>.mphb-complex-item-actions-holder [name="' + this.metaName + '[default]"]' );
if ( !defaultRadio.filter( ':checked' ).length ) {
defaultRadio.first().attr( 'checked', 'checked' );
}
},
deleteItem: function( item ) {
this._super( item );
this.updateItemActions();
this.updateDefaultItem();
},
addItem: function() {
this._super();
this.updateItemActions();
this.updateDefaultItem();
}
} );
/**
*
* @requires ./ctrl.js
*/
MPHBAdmin.DatePickerCtrl = MPHBAdmin.Ctrl.extend( {
renderValue: function( control ) {
return control.find( 'input[type="text"]' ).val();
}
}, {
input: null,
hiddenInput: null,
init: function( el, args ) {
this._super( el, args );
this.input = this.element.find( 'input[type="text"]' );
this.hiddenInput = this.element.find( 'input[type="hidden"]' );
this.fixDate();
var self = this;
if( $( this.input ).data( 'dateMin' ) ) {
this.minDate = new Date( $( this.input ).data( 'dateMin' ) );
}
if( $( this.input ).data( 'dateMax' ) ) {
this.maxDate = new Date( $( this.input ).data( 'dateMax' ) );
}
if( $( this.input ).data( 'dependentAsMin' ) ) {
var dependentAsMin = $( this.input ).data( 'dependentAsMin' );
this.dependentAsMinInput = $( 'input[name="' + dependentAsMin + '"]' );
this.setDependentMinDate = true;
$( this.dependentAsMinInput ).each( function() {
$( this ).data( 'dateMin', self.hiddenInput.val() );
} );
}
if( $( this.input ).data( 'dependentAsMax' ) ) {
var dependentAsMax = $( this.input ).data( 'dependentAsMax' );
this.dependentAsMaxInput = $( 'input[name="' + dependentAsMax + '"]' );
this.setDependentMaxDate = true;
$( this.dependentAsMaxInput ).each( function() {
$( this ).data( 'dateMax', self.hiddenInput.val() );
} );
}
if ( !this.input.attr( 'readonly' ) ) {
this.input.datepick( {
dateFormat: MPHBAdmin.Plugin.myThis.data.settings.dateFormat,
firstDay: MPHBAdmin.Plugin.myThis.data.settings.firstDay,
altField: this.hiddenInput,
altFormat: MPHBAdmin.Plugin.myThis.data.settings.dateTransferFormat,
showSpeed: 0,
showOtherMonths: false,
monthsToShow: MPHBAdmin.Plugin.myThis.data.settings.numberOfMonthDatepicker,
pickerClass: MPHBAdmin.Plugin.myThis.data.settings.datepickerClass,
useMouseWheel: false,
minDate: this.minDate,
maxDate: this.maxDate,
onSelect: function( dates ) {
if( self.setDependentMinDate ) {
$.each( self.dependentAsMinInput, function( i, el ) {
$( el ).datepick( 'option', 'minDate', dates[0] );
} );
}
if( self.setDependentMaxDate ) {
$.each( self.dependentAsMaxInput, function( i, el ) {
$( el ).datepick( 'option', 'maxDate', dates[0] );
} );
}
}
} );
}
if ( !this.input.attr( 'required' ) ) {
var hiddenInput = this.hiddenInput;
this.input.on( 'change', function () {
var input = $( this );
var value = input.val();
if ( value == '' ) {
hiddenInput.val( '' );
}
} );
}
},
/**
* Fix date in customer date format
*
* @returns {undefined}
*/
fixDate: function() {
if ( !this.hiddenInput.val() ) {
// this.input.val( '' );
} else {
var date = $.datepick.parseDate( MPHBAdmin.Plugin.myThis.data.settings.dateTransferFormat, this.hiddenInput.val() );
var fixedValue = $.datepick.formatDate( MPHBAdmin.Plugin.myThis.data.settings.dateFormat, date );
this.input.val( fixedValue );
}
}
} );
/**
*
* @requires ./ctrl.js
*/
MPHBAdmin.DynamicSelectCtrl = MPHBAdmin.Ctrl.extend( {}, {
input: null,
dependencyCtrl: null,
ajaxAction: null,
ajaxNonce: null,
errorsWrapper: null,
preloader: null,
defaultValue: null,
defaultOption: null,
complexId: null,
group: '',
init: function( el, args ) {
this._super( el, args );
this.input = this.element.find( 'select' );
this.defaultValue = this.input.attr( 'data-default' );
this.defaultOption = this.input.find( 'option[value="' + this.defaultValue + '"]' ).clone();
this.errorsWrapper = this.element.find( '.mphb-errors-wrapper' );
this.preloader = this.element.find( '.mphb-preloader' );
this.ajaxAction = this.input.attr( 'data-ajax-action' );
this.ajaxNonce = this.input.attr( 'data-ajax-nonce' );
this.initDependencyCtrl();
this.initComplexId();
this.initGroup();
},
initDependencyCtrl: function() {
var dependencyName = this.input.attr( 'data-dependency' );
this.dependencyCtrl = this.element.closest( 'form' ).find( '[name="' + dependencyName + '"]' );
var self = this;
this.dependencyCtrl.on( 'change', function( e ) {
self.updateList();
} ).on( 'focus', function( e ) {
self.hideErrors();
} );
},
initComplexId: function() {
var complexRow = this.element.parents( 'tr[data-id]' );
if ( complexRow.length > 0 ) {
this.complexId = parseInt( complexRow.attr( 'data-id' ) );
}
},
initGroup: function() {
var complexWrapper = this.element.parents( '.mphb-ctrl-rules-list' );
if ( complexWrapper.length > 0 ) {
this.group = complexWrapper.attr( 'data-group' );
}
},
setOptions: function( source ) {
var self = this;
this.input.html( this.defaultOption.clone() );
$.each( source, function( value, label ) {
self.input.append( $( '<option />', {
'value': value,
'html': label
} ) );
} );
},
updateList: function() {
var self = this;
this.hideErrors();
this.showPreloader();
this.input.html( this.defaultOption.clone() );
var data = {
action: this.ajaxAction,
mphb_nonce: this.ajaxNonce,
formValues: this.parseFormToJSON()
};
$.ajax( {
url: MPHBAdmin.Plugin.myThis.data.ajaxUrl,
type: 'GET',
dataType: 'json',
"data": data,
success: function( response ) {
if ( response.hasOwnProperty( 'success' ) ) {
if ( response.success ) {
self.setOptions( response.data.options );
} else {
self.showError( response.data.message );
}
} else {
self.showError( MPHBAdmin.Plugin.myThis.data.translations.errorHasOccured );
}
},
error: function( jqXHR ) {
self.showError( MPHBAdmin.Plugin.myThis.data.translations.errorHasOccured );
},
complete: function( jqXHR ) {
self.hidePreloader();
}
} );
},
parseFormToJSON: function() {
var data = this.parentForm.serializeJSON();
if ( this.group != '' ) {
data = data[this.group];
}
if ( this.complexId != null ) {
data = data[this.complexId];
}
return data;
},
showPreloader: function() {
this.preloader.removeClass( 'mphb-hide' );
},
hidePreloader: function() {
this.preloader.addClass( 'mphb-hide' );
},
hideErrors: function() {
this.errorsWrapper.empty().addClass( 'mphb-hide' );
},
showError: function( message ) {
this.errorsWrapper.html( message ).removeClass( 'mphb-hide' );
}
} );
/**
* @requires ./ctrl.js
*
* @since 3.8.1
*/
MPHBAdmin.InstallButtonCtrl = MPHBAdmin.Ctrl.extend(
{}, // Static
{
$button: null,
$preloader: null,
$statusText: null,
pluginSlug: '',
pluginZipLink: '#',
redirect: '',
ajax: {
url: '',
action: 'mphb_install_plugin',
nonce: ''
},
i18n: {
unknownError: ''
},
init: function ($element, args) {
this._super($element, args);
// Find elements
this.$button = $element.find('.button-row > button');
this.$preloader = $element.find('.mphb-preloader');
this.$statusText = $element.find('.status-text');
// Ger parameters
this.pluginSlug = this.$button.data('plugin-slug');
this.pluginZipLink = this.$button.data('plugin-zip');
this.redirect = this.$button.data('redirect');
if (this.redirect === 'no') {
this.redirect = false;
} else if (this.redirect == undefined) {
this.redirect = '';
}
// Other settings
var pluginData = MPHBAdmin.Plugin.myThis.data;
this.ajax.url = pluginData.ajaxUrl;
this.ajax.nonce = pluginData.nonces[this.ajax.action];
this.i18n.unknownError = pluginData.translations.errorHasOccured;
// Add listeners
this.$button.on('click', this.triggerInstall.bind(this));
},
triggerInstall: function (event) {
event.preventDefault(); // Don't accidently submit the form
this.beforeRequest(); // Reset classes and elements visibility
var self = this;
$.ajax({
url: this.ajax.url,
type: 'POST',
dataType: 'json',
data: {
action: this.ajax.action,
mphb_nonce: this.ajax.nonce,
plugin_slug: this.pluginSlug,
plugin_zip: this.pluginZipLink
},
success: function (response) {
if (response.success) {
// Success
self.afterSuccess();
if (response.data && response.data.message) {
self.setMessage(response.data.message);
}
self.reloadOrRedirect();
} else {
// Failure
self.afterFailure();
if (response.data && response.data.message) {
self.setError(response.data.message);
} else {
self.setError(self.i18n.unknownError);
}
}
},
/**
* @param {Object} jqXHR
*
* @todo Somehow recognize the success response.
*/
error: function (jqXHR) {
// Here we got the logs like:
// ...
// <p>Unpacking the package...</p>
// <p>Installing the plugin...</p>
// <p>Plugin installed successfully.</p>
self.afterSuccess();
self.reloadOrRedirect();
}
});
},
beforeRequest: function () {
this.$button.prop('disabled', true);
this.$preloader.removeClass('mphb-hide');
this.$statusText.addClass('mphb-hide').removeClass('error').html('');
},
afterSuccess: function () {
this.$preloader.addClass('mphb-hide');
},
afterFailure: function () {
this.$button.prop('disabled', false);
this.$preloader.addClass('mphb-hide');
},
setMessage: function (message) {
this.$statusText.html(message).removeClass('error mphb-hide');
},
setError: function (message) {
this.$statusText.html(message).addClass('error').removeClass('mphb-hide');
},
reloadOrRedirect: function () {
// Reload current page or redirect to a new one
if (this.redirect !== false) {
if (this.redirect == '') {
document.location.reload(true); // TRUE - load new page from server
} else {
window.location.href = this.redirect;
}
}
}
}
);
/**
* @requires ./ctrl.js
*
* @since 3.8.6
*/
MPHBAdmin.MediaCtrl = MPHBAdmin.Ctrl.extend(
{},
{
$input: null,
$preview: null,
$addButton: null,
$removeButton: null,
isSingle: false,
thumbSize: 'full',
init: function ($element, args) {
this._super($element, args);
this.$input = this.element.find('input[type=hidden]');
this.$preview = this.element.find('img').on('click', this.proxy('addMedia'));
this.$addButton = this.element.find('.mphb-admin-organize-image-add').on('click', this.proxy('addMedia'));
this.$removeButton = this.element.find('.mphb-admin-organize-image-remove').on('click', this.proxy('removeMedia'));
this.isSingle = !!this.$input.attr('is-single');
this.thumbSize = this.$input.attr('image-size');
},
/**
* @return {String}
*
* @since 3.8.6
*/
getValue: function () {
return this.$input.val();
},
/**
* @return {Number[]}
*
* @since 3.8.6
*/
getIds: function () {
var value = this.getValue();
if (value === '') {
return [];
} else {
var ids = value.split(',');
return $.map(ids, function (id) { return parseInt(id); });
}
},
/**
* @param {String} value
*
* @since 3.8.6
*/
setValue: function (value) {
this.$input.val(value);
this.updatePreview();
this.updateButtons();
},
/**
* @since 3.8.6
*/
updateButtons: function () {
var value = this.getValue();
if (value === '') {
this.$addButton.removeClass('mphb-hide');
this.$removeButton.addClass('mphb-hide');
} else {
this.$addButton.addClass('mphb-hide');
this.$removeButton.removeClass('mphb-hide');
}
},
updatePreview: function () {
var value = this.getValue();
if (value === '') {
this.$preview.addClass('mphb-hide').attr('src', '');
} else {
var attachment = null;
if (this.isSingle) {
attachment = wp.media.attachment(value);
} else {
var previewId = parseInt(this.getIds().shift());
attachment = wp.media.attachment(previewId);
}
var previewSrc = attachment.attributes.sizes[this.thumbSize].url;
this.$preview.removeClass('mphb-hide').attr('src', previewSrc);
}
},
/**
* @param {Event} event
*
* @since 3.8.6
*
* @todo Select current attachment in isSingle=true mode.
*/
addMedia: function (event) {
event.preventDefault();
if (!this.isSingle) {
MPHBAdmin.WPGallery.getInstance().open(this);
} else {
var image = wp.media({
multiple: false
});
var self = this;
image.open().on('select', function (event) {
var uploadedImage = image.state().get('selection').first();
var imageId = uploadedImage.toJSON().id;
$('#image_url').val(imageId);
self.setValue(imageId);
});
}
},
/**
* @param {Event} event
*
* @since 3.8.6
*/
removeMedia: function (event) {
event.preventDefault();
this.setValue('');
}
}
);
/**
* @requires ./ctrl.js
*/
MPHBAdmin.MultipleCheckboxCtrl = MPHBAdmin.Ctrl.extend( {
renderValue: function( control ) {
var inputs = control.find( 'input[type="checkbox"]' );
var variantAll = inputs.filter( '.mphb-checkbox-all:checked' );
var checked = inputs.filter( ':checked' );
if ( variantAll.length > 0 || checked.length == inputs.length ) {
return MPHBAdmin.Plugin.myThis.data.translations.all;
} else {
var labels = [];
checked.each( function() {
var label = $( this ).parent().text();
labels.push( label );
} );
if ( labels.length > 0 ) {
return labels.join( ', ' );
} else {
return MPHBAdmin.Plugin.myThis.data.translations.none;
}
}
}
}, {
/**
* @type {Object[]} An array of checkbox input elements. "All" element is
* not included (see selectAllCheckbox).
*/
checkboxes: null,
/**
* @type {Object} "All" checkbox element (if exists).
*/
selectAllCheckbox: null,
init: function( element, args ) {
this._super( element, args );
this.checkboxes = this.element.find( 'input[type="checkbox"]:not(.mphb-checkbox-all)' );
this.selectAllCheckbox = this.element.find( 'input[type="checkbox"].mphb-checkbox-all' );
// Fix for complex inputs that removes all 'disabled="disabled"'
if ( this.selectAllCheckbox.prop( 'checked' ) ) {
this.disableCheckboxes();
}
},
".mphb-checkbox-all click": function() {
if ( this.selectAllCheckbox.prop( 'checked' ) ) {
this.disableCheckboxes();
this.selectCheckboxes();
} else {
this.enableCheckboxes();
}
},
/**
* @param {Object} element "Select all" button element.
* @param {Object} event
*/
".mphb-checkbox-select-all click": function( element, event ) {
event.preventDefault();
this.selectCheckboxes();
},
/**
* @param {Object} element "Unselect all" button element.
* @param {Object} event
*/
".mphb-checkbox-unselect-all click": function( element, event ) {
event.preventDefault();
this.unselectAll();
this.enableCheckboxes();
},
disableCheckboxes: function() {
this.checkboxes.prop( 'disabled', true );
},
enableCheckboxes: function() {
this.checkboxes.prop( 'disabled', false );
},
selectCheckboxes: function() {
this.checkboxes.prop( 'checked', true );
},
unselectCheckboxes: function() {
this.checkboxes.prop( 'checked', false );
},
unselectAll: function() {
this.selectAllCheckbox.prop( 'checked', false );
this.unselectCheckboxes();
}
} );
/**
* @requires ./ctrl.js
*/
MPHBAdmin.RulesListCtrl = MPHBAdmin.Ctrl.extend( {}, {
editClass: 'mphb-rules-list-editing',
editText: '',
doneText: '',
lastIndex: -1,
rulesCount: 0,
table: null,
tbody: null,
rulePrototype: null,
editingRule: null,
noRulesMessage: null,
prependNewItems: false, // ... instead of append
init: function( element, args ) {
this._super( element, args );
this.editText = MPHBAdmin.Plugin.myThis.data.translations.edit;
this.doneText = MPHBAdmin.Plugin.myThis.data.translations.done;
this.noRulesMessage = element.find( '.mphb-rules-list-empty-message' );
this.table = element.children( 'table' );
this.tbody = this.table.children( 'tbody' );
if ( this.tbody.hasClass( 'mphb-sortable' ) ) {
this.tbody.sortable();
this.prependNewItems = true;
}
// Prepare rule prototype
var prototypeElement = this.tbody.children( '.mphb-rules-list-prototype' );
var rulePrototype = prototypeElement.clone();
prototypeElement.remove();
rulePrototype.removeClass( 'mphb-rules-list-prototype mphb-hide' );
rulePrototype.find( '.mphb-ctrl:not(.mphb-keep-disabled) [name]:not(.mphb-keep-disabled)' ).each( function() {
// Enable all controls
$( this ).prop( 'disabled', false );
} );
this.rulePrototype = rulePrototype;
// Find max (last) index
var rules = this.tbody.children( 'tr' );
var maxIndex = this.lastIndex; // -1
rules.each( function() {
var ruleIndex = parseInt( $( this ).attr( 'data-id' ) );
maxIndex = Math.max( maxIndex, ruleIndex );
} );
this.lastIndex = maxIndex;
this.rulesCount = rules.length;
},
".mphb-rules-list-add-button click": function() {
this.addRule();
},
".mphb-rules-list-edit-button click": function( button, event ) {
var rule = this.getRuleByButton( button );
this.toggleEdit( rule );
},
".mphb-rules-list-delete-button click": function( button, event ) {
var rule = this.getRuleByButton( button );
this.deleteRule( rule );
},
addRule: function() {
var rule = this.rulePrototype.clone();
var nextIndex = this.nextIndex();
// Set ID for new rule
rule.attr( 'data-id', nextIndex );
// Change ID in all names
rule.find( '[name*="[$index$]"]' ).each( function() {
var element = $( this );
var name = element.attr( 'name' );
name = name.replace( '$index$', nextIndex );
element.attr( 'name', name );
var id = element.attr( 'id' );
if ( id ) {
id = id.replace( '$index$', nextIndex );
element.attr( 'id', id );
}
} );
rule.find( '[for*="[$index$]"]' ).each( function() {
var element = $( this );
var forProp = element.attr( 'for' );
forProp = forProp.replace( '$index$', nextIndex );
element.attr( 'for', forProp );
} );
// Change ID in dependencies
rule.find( '[data-dependency*="[$index$]"]' ).each( function() {
var element = $( this );
var dependency = element.attr( 'data-dependency' );
dependency = dependency.replace( '$index$', nextIndex );
element.attr( 'data-dependency', dependency );
} );
if ( this.prependNewItems ) {
this.tbody.prepend( rule );
} else {
this.tbody.append( rule );
}
this.increaseRulesCount();
// Init new controls
var newControls = rule.find( '.mphb-ctrl:not([data-inited])' );
MPHBAdmin.Plugin.myThis.setControls( newControls );
this.toggleEdit( rule );
},
/**
* @param {Object} rule <tr> element.
*/
toggleEdit: function( rule ) {
if ( this.editingRule != null ) {
// Toggle with active editing rule means maximize new rule or
// minimize the current one. In both cases current rule will be
// minimized
this.renderValues( this.editingRule );
this.editingRule.removeClass( this.editClass );
// Change text from "Done" to "Edit"
this.editingRule.find( '.mphb-rules-list-edit-button' ).text( this.editText );
}
if ( this.isEditingRule( rule ) ) {
this.editingRule = null; // Already removed the class
} else {
this.editingRule = rule;
rule.addClass( this.editClass );
// Change text from "Edit" to "Done"
rule.find( '.mphb-rules-list-edit-button' ).text( this.doneText );
}
},
/**
* @param {Object} rule <tr> element.
*/
deleteRule: function( rule ) {
if ( this.isEditingRule( rule ) ) {
this.editingRule = null;
}
rule.remove();
this.decreaseRulesCount();
},
/**
* @param {Object} rule <tr> element.
*/
isEditingRule: function( rule ) {
// rule.hasClass( this.editClass ) - at this time, the class can be
// removed, see toggleEdit()
return ( this.editingRule != null && rule[0] === this.editingRule[0] );;
},
/**
* @param {Object} button "Edit" or "Delete" button.
*/
getRuleByButton: function( button ) {
return button.closest( 'tr' );
},
increaseRulesCount: function() {
if ( this.rulesCount == 0 ) {
this.noRulesMessage.addClass( 'mphb-hide' );
this.table.removeClass( 'mphb-hide' );
}
this.rulesCount++;
},
decreaseRulesCount: function() {
this.rulesCount--;
if ( this.rulesCount == 0 ) {
this.table.addClass( 'mphb-hide' );
this.noRulesMessage.removeClass( 'mphb-hide' );
}
},
nextIndex: function() {
this.lastIndex++;
return this.lastIndex;
},
/**
* @param {Object} rule <tr> element.
*/
renderValues: function( rule ) {
var self = this;
rule.children( 'td' ).each( function() {
var td = $( this );
var control = td.children( '.mphb-ctrl' );
if ( control.length == 0 ) {
return;
}
var result = self.renderValue( control );
td.children( '.mphb-rules-list-rendered-value' ).html( result );
} );
},
/**
* @param {Object} control .mphb-ctrl element.
*
* @returns {String}
*/
renderValue: function( control ) {
var type = control.attr( 'data-type' );
var result = '';
switch ( type ) {
case 'text':
result = MPHBAdmin.Ctrl.renderValue( control );
break;
case 'datepicker':
result = MPHBAdmin.DatePickerCtrl.renderValue( control );
break;
case 'textarea':
result = control.find( 'textarea' ).val();
break;
case 'number':
result = MPHBAdmin.NumberCtrl.renderValue( control );
break;
case 'select':
case 'dynamic-select':
var select = control.children( 'select' );
var value = select.val();
if ( value != undefined ) {
var option = select.children( 'option[value="' + value + '"]' );
result = option.text();
} else {
result = MPHBAdmin.Plugin.myThis.data.translations.none;
}
break;
case 'single-checkbox':
result = MPHBAdmin.SingleCheckboxCtrl.renderValue( control );
break;
case 'multiple-checkbox':
result = MPHBAdmin.MultipleCheckboxCtrl.renderValue( control );
break;
case 'amount':
result = MPHBAdmin.AmountCtrl.renderValue( control );
break;
case 'placeholder':
result = '-';
break;
}
return result;
}
} );
/**
* @requires ./rules-list.js
*/
MPHBAdmin.NotesListCtrl = MPHBAdmin.RulesListCtrl.extend( {}, {
editClass: 'mphb-notes-list-editing',
editText: '',
doneText: '',
rulesCount: 0,
table: null,
tbody: null,
rulePrototype: null,
editingRule: null,
noRulesMessage: null,
prependNewItems: false, // ... instead of append
init: function( element, args ) {
this._super( element, args );
this.lastIndex = -1;
this.editText = MPHBAdmin.Plugin.myThis.data.translations.edit;
this.doneText = MPHBAdmin.Plugin.myThis.data.translations.done;
this.noRulesMessage = element.find( '.mphb-notes-list-empty-message' );
this.table = element.children( 'table' );
this.tbody = this.table.children( 'tbody' );
if ( this.tbody.hasClass( 'mphb-sortable' ) ) {
this.tbody.sortable();
this.prependNewItems = true;
}
// Prepare rule prototype
var prototypeElement = this.tbody.children( '.mphb-notes-list-prototype' );
var rulePrototype = prototypeElement.clone();
prototypeElement.remove();
rulePrototype.removeClass( 'mphb-notes-list-prototype mphb-hide' );
rulePrototype.find( '.mphb-ctrl:not(.mphb-keep-disabled) [name]:not(.mphb-keep-disabled)' ).each( function() {
// Enable all controls
$( this ).prop( 'disabled', false );
} );
this.rulePrototype = rulePrototype;
// Find max (last) index
var rules = this.tbody.children( 'tr' );
var maxIndex = this.lastIndex; // -1
rules.each( function() {
var ruleIndex = parseInt( $( this ).attr( 'data-id' ) );
maxIndex = Math.max( maxIndex, ruleIndex );
} );
this.lastIndex = maxIndex;
this.rulesCount = rules.length;
},
".mphb-notes-list-add-button click": function() {
this.addRule();
},
".mphb-notes-list-edit-button click": function( button, event ) {
var rule = this.getRuleByButton( button );
this.toggleEdit( rule );
},
".mphb-notes-list-delete-button click": function( button, event ) {
var rule = this.getRuleByButton( button );
this.deleteRule( rule );
},
addRule: function() {
var rule = this.rulePrototype.clone();
var nextIndex = this.nextIndex();
// Set ID for new rule
rule.attr( 'data-id', nextIndex );
// Change ID in all names
rule.find( '[name*="[$index$]"]' ).each( function() {
var element = $( this );
var name = element.attr( 'name' );
name = name.replace( '$index$', nextIndex );
element.attr( 'name', name );
var id = element.attr( 'id' );
if ( id ) {
id = id.replace( '$index$', nextIndex );
element.attr( 'id', id );
}
} );
// Change ID in dependencies
rule.find( '[data-dependency*="[$index$]"]' ).each( function() {
var element = $( this );
var dependency = element.attr( 'data-dependency' );
dependency = dependency.replace( '$index$', nextIndex );
element.attr( 'data-dependency', dependency );
} );
if ( this.prependNewItems ) {
this.tbody.prepend( rule );
} else {
this.tbody.append( rule );
}
this.increaseRulesCount();
// Init new controls
var newControls = rule.find( '.mphb-ctrl:not([data-inited])' );
MPHBAdmin.Plugin.myThis.setControls( newControls );
this.toggleEdit( rule );
},
/**
* @param {Object} rule <tr> element.
*/
toggleEdit: function( rule ) {
if ( this.editingRule != null ) {
// Toggle with active editing rule means maximize new rule or
// minimize the current one. In both cases current rule will be
// minimized
this.renderValues( this.editingRule );
this.editingRule.removeClass( this.editClass );
// Change text from "Done" to "Edit"
this.editingRule.find( '.mphb-notes-list-edit-button' ).text( this.editText );
}
if ( this.isEditingRule( rule ) ) {
this.editingRule = null; // Already removed the class
} else {
this.editingRule = rule;
rule.addClass( this.editClass );
// Change text from "Edit" to "Done"
rule.find( '.mphb-notes-list-edit-button' ).text( this.doneText );
}
},
/**
* @param {Object} rule <tr> element.
*/
deleteRule: function( rule ) {
if ( this.isEditingRule( rule ) ) {
this.editingRule = null;
}
rule.remove();
this.decreaseRulesCount();
},
/**
* @param {Object} rule <tr> element.
*/
isEditingRule: function( rule ) {
// rule.hasClass( this.editClass ) - at this time, the class can be
// removed, see toggleEdit()
return ( this.editingRule != null && rule[0] === this.editingRule[0] );;
},
/**
* @param {Object} button "Edit" or "Delete" button.
*/
getRuleByButton: function( button ) {
return button.closest( 'tr' );
},
increaseRulesCount: function() {
if ( this.rulesCount == 0 ) {
this.noRulesMessage.addClass( 'mphb-hide' );
this.table.removeClass( 'mphb-hide' );
}
this.rulesCount++;
},
decreaseRulesCount: function() {
this.rulesCount--;
if ( this.rulesCount == 0 ) {
this.table.addClass( 'mphb-hide' );
this.noRulesMessage.removeClass( 'mphb-hide' );
}
},
nextIndex: function() {
this.lastIndex++;
return this.lastIndex;
},
/**
* @param {Object} rule <tr> element.
*/
renderValues: function( rule ) {
var self = this;
rule.children( 'td' ).each( function() {
var td = $( this );
var control = td.children( '.mphb-ctrl' );
if ( control.length == 0 ) {
return;
}
var result = self.renderValue( control );
td.children( '.mphb-notes-list-rendered-value' ).html( result );
} );
},
renderValue: function( control ) {
var type = control.attr( 'data-type' );
var result = '';
switch ( type ) {
case 'text':
result = MPHBAdmin.Ctrl.renderValue( control );
break;
case 'username':
result = control.find( '.mphb-ctrl-user-name' ).text();
break;
case 'timestamp':
result = control.find( '.mphb-ctrl-date-val' ).text();
break;
case 'datepicker':
result = MPHBAdmin.DatePickerCtrl.renderValue( control );
break;
case 'textarea':
result = control.find( 'textarea' ).val();
break;
case 'number':
result = MPHBAdmin.NumberCtrl.renderValue( control );
break;
case 'select':
case 'dynamic-select':
var select = control.children( 'select' );
var value = select.val();
if ( value != undefined ) {
var option = select.children( 'option[value="' + value + '"]' );
result = option.text();
} else {
result = MPHBAdmin.Plugin.myThis.data.translations.none;
}
break;
case 'multiple-checkbox':
result = MPHBAdmin.MultipleCheckboxCtrl.renderValue( control );
break;
case 'amount':
result = MPHBAdmin.AmountCtrl.renderValue( control );
break;
case 'placeholder':
result = '-';
break;
}
return result;
}
} );
/**
*
* @requires ./ctrl.js
*/
MPHBAdmin.NumberCtrl = MPHBAdmin.Ctrl.extend( {
renderValue: function( control ) {
var input = control.children( 'input[type="number"]' );
return input.val() + input.parent().text(); // value + " inner label"
}
}, {
input: null,
disableOn: [],
init: function( element, args ) {
this._super( element, args );
this.input = this.element.children( '[name]' );
// Init dependency control
var dependencyName = this.input.attr( 'data-dependency' );
var disableOn = this.input.attr( 'data-disable-on' );
if ( dependencyName && disableOn ) {
this.disableOn = disableOn.split( ',' );
var self = this;
var dependencyCtrl = this.element.closest( 'form' ).find( '[name="' + dependencyName + '"]' );
dependencyCtrl.on( 'change', function( event ) {
var value = $( this ).val();
self.onDependencyChange( value );
} );
}
},
onDependencyChange: function( dependencyValue ) {
if ( this.disableOn.indexOf( dependencyValue ) != -1 ) {
this.input.prop( 'disabled', true );
} else {
this.input.prop( 'disabled', false );
}
}
} );
/**
*
* @requires ./ctrl.js
*/
MPHBAdmin.PriceBreakdownCtrl = MPHBAdmin.Ctrl.extend( {}, {
// See also assets/js/public/dev/checkout/checkout-form.js
".mphb-price-breakdown-expand click": function( element, event ) {
event.preventDefault();
$( element ).blur(); // Don't save a:focus style on last clicked item
var tr = $( element ).parents( 'tr.mphb-price-breakdown-group' );
tr.find( '.mphb-price-breakdown-rate' ).toggleClass( 'mphb-hide' );
tr.nextUntil( 'tr.mphb-price-breakdown-group' ).toggleClass( 'mphb-hide' );
$(element).children('.mphb-inner-icon').toggleClass('mphb-hide');
}
} );
/**
*
* @requires ./ctrl.js
*/
MPHBAdmin.SingleCheckboxCtrl = MPHBAdmin.Ctrl.extend( {
renderValue: function( control ) {
var input = control.children( 'input[type="checkbox"]' );
return input.prop('checked') ? $.trim( input.parent().text() ) : '';
}
}, {
input: null,
disableOn: [],
init: function( element, args ) {
this._super( element, args );
this.input = this.element.children( '[name]' );
}
} );
/**
*
* @requires ./ctrl.js
*/
MPHBAdmin.TotalPriceCtrl = MPHBAdmin.Ctrl.extend( {}, {
preloader: null,
input: null,
init: function( el, args ) {
this._super( el, args );
this.input = this.element.find( 'input' );
this.recalculateBtn = this.element.find( '#mphb-recalculate-total-price' );
this.errorsWrapper = this.element.find( '.mphb-errors-wrapper' );
this.preloader = this.element.find( '.mphb-preloader' );
},
set: function( value ) {
this.input.val( value );
},
hideErrors: function() {
this.errorsWrapper.empty().addClass( 'mphb-hide' );
},
'input focus': function() {
this.hideErrors();
},
showError: function( message ) {
this.errorsWrapper.html( message ).removeClass( 'mphb-hide' );
},
'#mphb-recalculate-total-price click': function( el, e ) {
var self = this;
this.hideErrors();
this.showPreloader();
var data = this.parseFormToJSON();
$.ajax( {
url: MPHBAdmin.Plugin.myThis.data.ajaxUrl,
type: 'POST',
dataType: 'json',
data: {
action: 'mphb_recalculate_total',
mphb_nonce: MPHBAdmin.Plugin.myThis.data.nonces.mphb_recalculate_total,
formValues: data
},
success: function( response ) {
if ( response.hasOwnProperty( 'success' ) ) {
if ( response.success ) {
self.set( response.data.total );
// Also update price breakdown
var breakdownInput = self.element.closest( 'form' ).find( '[name="_mphb_booking_price_breakdown"]' );
var breakdownWrapper = breakdownInput.siblings( '.mphb-price-breakdown-wrapper' );
breakdownInput.val( response.data.price_breakdown );
breakdownInput.prop( 'disabled', false );
breakdownWrapper.html( response.data.price_breakdown_html );
} else {
self.showError( response.data.message );
}
} else {
self.showError( MPHBAdmin.Plugin.myThis.data.translations.errorHasOccured );
}
},
error: function( jqXHR ) {
self.showError( MPHBAdmin.Plugin.myThis.data.translations.errorHasOccured );
},
complete: function( jqXHR ) {
self.hidePreloader();
}
} );
},
showPreloader: function() {
this.recalculateBtn.attr( 'disabled', 'disabled' );
this.preloader.removeClass( 'mphb-hide' );
},
hidePreloader: function() {
this.recalculateBtn.removeAttr( 'disabled' );
this.preloader.addClass( 'mphb-hide' );
},
parseFormToJSON: function() {
return this.parentForm.serializeJSON();
}
} );
/**
*
* @requires ./ctrl.js
*/
MPHBAdmin.VariablePricingCtrl = MPHBAdmin.Ctrl.extend( {}, {
MIN_PERIOD: 2, // See also \MPHB\Admin\Fields\VariablePricingField::MIN_PERIOD
name: '',
periodsTable: null, // Top table
variationsTable: null, // Bottom table
variationsTableBody: null,
variationsTableFooter: null,
afterPeriods: null, // Place for new period inputs
afterPrices: null, // Place for new price inputs (in top table)
pricesHeaders: null, // .mphb-pricing-price-per-night
template: null, // Template/prototype of variation
templateActions: null, // Place for new price inputs
lastIndex: -1,
lastPeriodIndex: -1,
periodsCount: 0,
removePeriodText: '',
upgradeToPremiumMessageHtml: '',
init: function( element, args ) {
this._super( element, args );
this.name = element.children( '.mphb-pricing-name-holder' ).attr( 'name' );
this.removePeriodText = MPHBAdmin.Plugin.myThis.data.translations.removePeriod;
this.upgradeToPremiumMessageHtml = MPHBAdmin.Plugin.myThis.data.settings.upgradeToPremiumMsgHtml;
this.periodsTable = element.children( '.mphb-pricing-periods-table' );
this.variationsTable = element.children( '.mphb-pricing-variations-table' );
this.variationsTableBody = this.variationsTable.children( 'tbody' );
this.variationsTableFooter = this.variationsTable.find( 'tfoot > tr > td' );
this.afterPeriods = this.periodsTable.find( '> tbody > tr:first-child > td:last-child' );
this.afterPrices = this.periodsTable.find( '> tbody > tr:last-child > td:last-child' );
this.pricesHeaders = element.find( '.mphb-pricing-price-per-night' );
// Prepare template
this.template = this.loadTemplate();
this.templateActions = this.template.children( 'td:last-child' );
// Find last/max indexes
this.lastIndex = this.findLastIndex();
this.lastPeriodIndex = this.findLastPeriodIndex();
this.periodsCount = this.findPeriodsCount();
// Watch checkbox "Enable variable pricing" to show/hide variable prices table
this.watchCheckbox();
},
loadTemplate: function() {
var templateElement = this.variationsTable.find( '.mphb-pricing-variation-template' );
var template = templateElement.clone();
templateElement.remove();
template.removeClass( 'mphb-pricing-variation-prototype mphb-hide' );
// Enable all controls
template.find( '[name]' ).each( function() {
if ( $( this ).attr( 'name' ).indexOf( '[prices]' ) == -1 )
$( this ).prop( 'disabled', false );
} );
return template;
},
addVariation: function () {
var variation = this.template.clone();
var index = this.nextIndex();
variation.attr( 'data-index', index );
// Change indexes in all names
variation.find( '[name*="[$index$]"]' ).each( function() {
var element = $( this );
var name = element.attr( 'name' );
name = name.replace( '$index$', index );
element.attr( 'name', name );
} );
this.variationsTableBody.append( variation );
},
removeVariation: function( element ) {
element.remove();
},
addPeriod: function() {
var index = this.nextPeriodIndex();
var periodInput = '<input type="number" name="' + this.name + '[periods][]" class="small-text" value="' + this.MIN_PERIOD + '" min="' + this.MIN_PERIOD + '" step="1" />';
periodInput += '<br /><span class="dashicons dashicons-trash mphb-pricing-action mphb-pricing-remove-period" title="' + this.removePeriodText + '"></span>';
periodInput = '<td data-period-index="' + index + '">' + periodInput + '</td>';
var pricesAtts = ' disabled="disabled"';
var afterPrices = '<br />' + this.upgradeToPremiumMessageHtml;
var priceInput = '<td data-period-index="' + index + '"><input type="text" name="' + this.name + '[prices][]" class="mphb-price-text" value=""' + pricesAtts + ' />' + afterPrices + '</td>';
var templateInput = '<td data-period-index="' + index + '"><input type="text" name="' + this.name + '[variations][$index$][prices][]" class="mphb-price-text" value=""' + pricesAtts + ' />' + afterPrices + '</td>';
this.afterPeriods.before( periodInput );
this.afterPrices.before( priceInput );
this.templateActions.before( templateInput );
this.variationsTableBody.children( 'tr' ).each( function( index, element ) {
var tr = $( element );
var index = parseInt( tr.attr( 'data-index' ) );
var afterPrices = tr.children( 'td:last-child' );
afterPrices.before( templateInput.replace( '$index$', index ) );
} );
this.increasePeriodsCount();
},
removePeriod: function( index ) {
this.template.find( '[data-period-index="' + index + '"]' ).remove();
this.element.find( '[data-period-index="' + index + '"]' ).remove();
this.decreasePeriodsCount();
},
nextIndex: function() {
this.lastIndex++;
return this.lastIndex;
},
nextPeriodIndex: function() {
this.lastPeriodIndex++;
return this.lastPeriodIndex;
},
findLastIndex: function() {
var variations = this.variationsTableBody.children( 'tr' );
var maxIndex = -1;
variations.each( function() {
var index = parseInt( $( this ).attr( 'data-index' ) );
maxIndex = Math.max( maxIndex, index );
} );
return maxIndex;
},
findLastPeriodIndex: function() {
var periods = this.periodsTable.find( '> tbody > tr:first-child > td[data-period-index]' );
var maxIndex = -1;
periods.each( function() {
var index = parseInt( $( this ).attr( 'data-period-index' ) );
maxIndex = Math.max( maxIndex, index );
} );
return maxIndex;
},
findPeriodsCount: function() {
var periods = this.periodsTable.find( '> tbody > tr:first-child > td[data-period-index]' );
return periods.length;
},
increasePeriodsCount: function() {
this.periodsCount++;
this.updateColspans();
},
decreasePeriodsCount: function() {
this.periodsCount--;
this.updateColspans();
},
updateColspans: function() {
this.pricesHeaders.attr( 'colspan', this.periodsCount );
this.variationsTableFooter.attr( 'colspan', this.periodsCount + 3 ); // 3 - adults, children and .mphb-pricing-remove-variation
},
watchCheckbox: function() {
var self = this;
this.element.find( '.mphb-pricing-enable-variations' ).on( 'change', function( event ) {
self.variationsTable.toggleClass( 'mphb-hide' );
} );
},
".mphb-pricing-add-variation click": function( target, event ) {
this.addVariation();
},
".mphb-pricing-remove-variation click": function( target, event ) {
var row = target.closest( 'tr' );
this.removeVariation( row );
},
".mphb-pricing-add-period click": function( target, event ) {
this.addPeriod();
},
".mphb-pricing-remove-period click": function( target, event ) {
var cell = target.closest( 'td' );
var periodIndex = cell.attr( 'data-period-index' );
this.removePeriod( periodIndex );
}
} );
/**
* @since 3.8
*/
MPHBAdmin.AddRoomPopup = MPHBAdmin.PopupForm.extend(
{}, // Static
{
$roomTypes: null,
$rooms: null,
availableRooms: {}, // {Room type ID: [Room IDs]}
reservedRooms: [],
selectedRoom: 0,
selectedRoomType: 0,
init: function ($element, args) {
this._super($element, args);
this.$roomTypes = $element.find('.mphb-room-type-select');
this.$rooms = $element.find('.mphb-room-select');
this.availableRooms = this.parseAvailableRooms(this.$rooms);
},
parseAvailableRooms: function ($select) {
var availableRooms = {};
$select.children().each(function (index, element) {
var roomId = parseInt(element.value);
if (!isNaN(roomId)) {
var roomTypeId = parseInt(element.getAttribute('data-room-type-id'));
if (!availableRooms[roomTypeId]) {
availableRooms[roomTypeId] = [];
}
availableRooms[roomTypeId].push(roomId);
}
});
return availableRooms;
},
reset: function (inputData) {
this._super(inputData);
// Disable submit button
this.canSubmit(false);
this.reservedRooms = inputData.reserved_rooms;
// Get presets
var selectRoom = inputData.room_id || '';
var selectRoomType = inputData.room_type_id || '';
if (this.availableRooms.hasOwnProperty(selectRoomType)) {
var roomIndex = this.reservedRooms.indexOf(selectRoom);
if (roomIndex >= 0) {
// Remove this room from reservedRooms and allow to use it
// again as a replacement
this.reservedRooms.splice(roomIndex, 1);
} else {
selectRoom = '';
}
} else {
selectRoom = selectRoomType = '';
}
// Reset selects
this.$rooms.val(selectRoom);
this.$roomTypes.val(selectRoomType);
this.selectedRoom = selectRoom || 0;
this.selectedRoomType = selectRoomType || 0;
this.filterRoomTypes(); // Once on reset()
this.filterRooms();
this.checkIfCanSubmit();
},
filterRoomTypes: function () {
var $options = this.$roomTypes.children('[value!=""]');
var availableRooms = this.availableRooms;
var reservedRooms = this.reservedRooms;
$options.show();
$options.each(function (index, option) {
var roomTypeId = parseInt(option.value);
var roomsList = availableRooms[roomTypeId];
var freeCount = 0;
for (var i = 0; i < roomsList.length; i++) {
if (reservedRooms.indexOf(roomsList[i]) == -1) {
freeCount++;
}
}
// Hide room type if no rooms left to select
if (freeCount == 0) {
$(option).hide();
// The room and the room type are not available for current dates
if (roomTypeId == this.selectedRoomType) {
this.selectedRoomType = this.selectedRoom = 0;
}
}
});
},
filterRooms: function () {
var roomTypeId = this.selectedRoomType;
var $options = this.$rooms.children('[value!=""]');
if (roomTypeId != 0) {
$options.show();
// Leave only options of the current room type
var reservedRooms = this.reservedRooms;
$options.each(function (index, option) {
var optionRoom = parseInt(option.value);
var optionRoomType = parseInt(option.getAttribute('data-room-type-id'));
if (optionRoomType != roomTypeId || reservedRooms.indexOf(optionRoom) >= 0) {
$(option).hide();
}
});
} else {
// Hide all room options (except for "- Select -")
$options.hide();
}
},
getData: function () {
var roomTypeId = this.selectedRoomType;
var roomTypeTitle = this.$roomTypes.children('option:selected').text().trim();
var roomId = this.selectedRoom;
var roomTitle = this.$rooms.children('option:selected').text().trim();
return $.extend({}, this._super(), {
room_type: {id: roomTypeId, title: roomTypeTitle},
room: {id: roomId, title: roomTitle}
});
},
checkIfCanSubmit: function () {
this.canSubmit(this.selectedRoom != 0 && this.selectedRoomType != 0);
},
".mphb-room-type-select change": function (element, event) {
var selectedRoomType = parseInt(this.$roomTypes.val()) || 0;
var roomTypeChanged = (this.selectedRoomType != selectedRoomType);
this.selectedRoomType = selectedRoomType;
// Reset the selected room if we changed the room type
if (roomTypeChanged) {
this.$rooms.val('');
this.selectedRoom = 0;
this.filterRooms();
this.checkIfCanSubmit();
}
},
".mphb-room-select change": function (element, event) {
this.selectedRoom = parseInt(this.$rooms.val()) || 0;
this.checkIfCanSubmit();
}
}
);
/**
* @since 3.8
*/
MPHBAdmin.BookingEditor = can.Control.extend(
{}, // Static
{
$editor: null,
$roomsTable: null, // .mphb-reserve-rooms-table > tbody (wrapper of the <tr>s)
$submitButton: null, // .mphb-reserve-rooms .mphb-submit-button-wrapper > .button
settings: {}, // MPHBAdmin.Plugin.myThis.data.settings
i18n: {}, // MPHBAdmin.Plugin.myThis.data.translations
rooms: {}, // {Room ID: {isAvailable, $element: Room jQuery element}}
popup: null,
init: function ($element, args) {
this.$editor = $element;
this.$roomsTable = $element.find('.mphb-reserve-rooms-table > tbody');
this.$submitButton = $element.find('.mphb-reserve-rooms .mphb-submit-button-wrapper > .button');
this.settings = MPHBAdmin.Plugin.myThis.data.settings;
this.i18n = MPHBAdmin.Plugin.myThis.data.translations;
this.popup = new MPHBAdmin.AddRoomPopup($element.find('.mphb-popup'));
this.initDatepickers();
this.initRooms();
this.toggleSubmit();
},
initDatepickers: function () {
this.$editor.find('.mphb-datepick').datepick({
dateFormat: this.settings.dateFormat,
firstDay: this.settings.firstDay,
showSpeed: 0,
showOtherMonths: true,
monthsToShow: this.settings.numberOfMonthDatepicker,
pickerClass: this.settings.datepickerClass + ' mphb-datepick-popup mphb-check-in-datepick',
useMouseWheel: false
});
},
initRooms: function () {
var $rooms = this.$roomsTable.children();
var self = this;
$rooms.each(function (index, node) {
var $room = $(node);
var roomId = parseInt($room.data('room-id'));
var roomTypeId = parseInt($room.data('room-type-id'));
if (!isNaN(roomId) && !isNaN(roomTypeId)) {
self.rooms[roomId] = {
$element: $room,
roomTypeId: roomTypeId,
isAvailable: $room.hasClass('mphb-available-room')
};
}
});
},
toggleSubmit: function () {
if (!this.hasRooms() || this.hasUnavailableRooms()) {
this.$submitButton.prop('disabled', true);
} else {
this.$submitButton.prop('disabled', false);
}
},
hasRooms: function () {
return !$.isEmptyObject(this.rooms);
},
hasUnavailableRooms: function () {
var hasUnavailable = false;
$.each(this.rooms, function (index, room) {
if (!room.isAvailable) {
hasUnavailable = true;
return false;
}
});
return hasUnavailable;
},
addRoom: function (room, roomType) {
var row = '<tr class="mphb-reserve-room mphb-available-room" data-room-id="' + room.id + '">'
+ '<td class="column-room-type">' + roomType.title + '</td>'
+ '<td class="column-room">' + room.title + '</td>'
+ '<td class="column-status">'
+ '<input type="hidden" name="add_rooms[]" value="' + room.id + '">'
+ '<span>' + this.i18n.available + '</span>'
+ '</td>'
+ '<td class="column-actions">'
+ '<button class="button mphb-remove-room-button">' + this.i18n.remove + '</button>'
+ ' <button class="button mphb-replace-room-button">' + this.i18n.replace + '</button>'
+ '</td>'
+ '</tr>';
this.$roomsTable.append(row);
this.rooms[room.id] = {
$element: this.$roomsTable.children('[data-room-id="' + room.id + '"]').first(),
roomTypeId: roomType.id,
isAvailable: true
};
this.toggleSubmit();
},
replaceRoom: function (replaceId, room, roomType) {
if (!this.rooms[replaceId]) {
return;
}
var $roomElement = this.rooms[replaceId]['$element'];
var $statusColumn = $roomElement.children('.column-status');
var $statusInput = $statusColumn.children('input').first();
// Update titles
$roomElement.children('.column-room-type').text(roomType.title);
$roomElement.children('.column-room').text(room.title);
// Updat inputs
$roomElement.data('room-id', room.id);
if ($statusInput.length == 1) {
$statusInput.val(room.id)
} else {
$roomElement.children('.column-status').prepend('<input type="hidden" name="replace_rooms[' + replaceId + ']" value="' + room.id + '">');
}
// Update status text
$statusColumn.children('span').text(this.i18n.available);
$roomElement.removeClass('mphb-unavailable-room').addClass('mphb-available-room');
this.rooms[room.id] = this.rooms[replaceId];
this.rooms[room.id]['roomTypeId'] = roomType.id;
this.rooms[room.id]['isAvailable'] = true;
delete(this.rooms[replaceId]);
// Enable submit button if all rooms are available
this.toggleSubmit();
},
getRoomIds: function () {
return Object.keys(this.rooms).map(function (roomId) { return parseInt(roomId); });
},
"#mphb-add-room-button click": function (element, event) {
event.preventDefault();
var self = this;
this.popup.show({reserved_rooms: this.getRoomIds()}).then(
function (data) {
self.addRoom(data.room, data.room_type);
},
function (error) {} // Catch errors. Don't trigger "Uncaught error"
);
},
".mphb-replace-room-button click": function (element, event) {
event.preventDefault();
var $room = element.parents('.mphb-reserve-room');
var roomId = parseInt($room.data('room-id'));
var self = this;
if (!isNaN(roomId)) {
var popupData = {
reserved_rooms: this.getRoomIds(),
room_id: roomId,
room_type_id: this.rooms[roomId]['roomTypeId']
};
this.popup.show(popupData).then(
function (data) {
self.replaceRoom(data.room_id, data.room, data.room_type);
},
function (error) {} // Catch errors. Don't trigger "Uncaught error"
);
}
},
".mphb-remove-room-button click": function (element, event) {
event.preventDefault();
var $room = element.parents('.mphb-reserve-room');
var roomId = parseInt($room.data('room-id'));
if (!isNaN(roomId) && this.rooms[roomId] != undefined) {
delete(this.rooms[roomId]);
}
$room.remove();
this.toggleSubmit();
},
".mphb-reserve-rooms .mphb-submit-button-wrapper > .button click": function (element, event) {
if (!this.hasRooms() || this.hasUnavailableRooms()) {
// Don't go to the next step
event.preventDefault();
}
}
}
);
new MPHBAdmin.Plugin();
$( function() {
if ( $( '.mphb-bookings-calendar-wrapper' ) ) {
new MPHBAdmin.BookingsCalendar( $( '.mphb-bookings-calendar-wrapper' ) );
}
if ( $('.mphb-edit-booking.edit' ).length > 0 ) {
new MPHBAdmin.BookingEditor( $( '.mphb-edit-booking' ) );
}
if ( MPHBAdmin.Plugin.myThis.data.settings.isAttributesCustomOrder ) {
new MPHBAdmin.AttributesCustomOrder( $( 'table.wp-list-table' ) );
}
new MPHBAdmin.ServiceQuantity('.post-type-mphb_room_service #mphb_price');
new MPHBAdmin.ExportBookings('#mphb-export-bookings-form');
// Add checkbox "Display imported bookings in this table" on bookings page
var pluginData = MPHBAdmin.Plugin.myThis.data;
if (pluginData.settings.displayImportCheckbox) {
var listTable = $('#posts-filter .wp-list-table');
if (listTable.length > 0) {
var checkboxLabel = pluginData.translations.displayImport;
var checkedAttr = pluginData.settings.displayImport ? 'checked="checked"' : '';
var appendHtml = '<p id="mphb-display-import-control"><label>'
+ '<input type="checkbox" id="mphb-display-imported-bookings" ' + checkedAttr + ' /> ' + checkboxLabel
+ '<span class="mphb-preloader mphb-hide"></span>'
+ '</label></p>';
$(appendHtml).insertBefore(listTable);
$('#mphb-display-imported-bookings').change(function () {
var self = $(this);
var value = self.prop('checked');
self.siblings('.mphb-preloader').removeClass('mphb-hide');
self.prop('disabled', true);
$.ajax({
url: pluginData.ajaxUrl,
type: 'POST',
dataType: 'json',
data: {
action: 'mphb_display_imported_bookings',
mphb_nonce: pluginData.nonces.mphb_display_imported_bookings,
new_value: value,
user_id: pluginData.settings.userId
},
complete: function () {
location.reload(true);
}
});
}); // On change
} // if (listTable.length > 0)
} // if (displayImportCheckbox)
} );
} );
})( jQuery );