uawdijnntqw1x1x1
IP : 216.73.216.109
Hostname : premium160.web-hosting.com
Kernel : Linux premium160.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
Disable Function : None :)
OS : Linux
PATH:
/
home
/
batcwwjx
/
www
/
wp-content
/
plugins
/
.
/
charitable
/
assets
/
js
/
campaign-builder
/
admin-builder.js
/
/
/* global charitable_builder, charitable_campaign_builder_field_conditionals, wpchar, jconfirm, charitable_panel_switch, Charitable, CharitableCampaignEmbedWizard, CharitableCampaignCongratsWizard, wpCookies, tinyMCE, CharitableUtils, CharitableOnboarding */ var CharitableCampaignBuilder = window.CharitableCampaignBuilder || ( function( document, window, $ ) { var s, $builder, $builderForm, elements = {}; /** * Whether to show the close confirmation dialog or not. * * @since 1.8.0 * * @type {boolean} */ var closeConfirmation = true; /** * A field is adding. * * @since 1.8.0 * * @type {boolean} */ var adding = false; var app = { settings: { spinner: '<i class="charitable-loading-spinner"></i>', spinnerInline: '<i class="charitable-loading-spinner charitable-loading-inline"></i>', tinymceDefaults: { tinymce: { toolbar1: 'bold,italic,underline,blockquote,strikethrough,bullist,numlist,alignleft,aligncenter,alignright,undo,redo,link' }, quicktags: true }, pagebreakTop: false, pagebreakBottom: false, upload_img_modal: false }, /** * Start the engine. * * @since 1.8.0 */ init: function() { var that = this; charitable_panel_switch = true; s = this.settings; // Document ready. $( app.ready ); // Page load. $( window ).on( 'load', function() { // In the case of jQuery 3.+, we need to wait for a ready event first. if ( typeof $.ready.then === 'function' ) { $.ready.then( app.load ); } else { app.load(); } } ); $( window ).on( 'beforeunload', function() { if ( ! that.formIsSaved() && closeConfirmation ) { return charitable_builder.are_you_sure_to_close; } } ); }, /** * Page load. * * @since 1.8.0 */ load: function() { // Trigger initial save for new forms. if ( wpchar.getQueryString( 'newcampaign' ) ) { app.formSave( false ); } // Allow callbacks to prevent making Campaign Builder ready... const event = CharitableUtils.triggerEvent( $builder, 'CharitableCampaignBuilderReady' ); // ...by triggering `event.preventDefault()`. if ( event.isDefaultPrevented() ) { return false; } // Hide loading overlay and make the Form Builder ready to use. app.hideLoadingOverlay(); // eslint-disable-line // if a textarea for a coded field is present, init the code editor. app.initCodeEditor(); }, /** * Document ready. * * @since 1.8.0 * @version 1.8.1.12 Added tooltip info for onboarding. * */ ready: function() { if ( app.isVisitedViaBackButton() ) { location.reload(); return; } app.showLoadingOverlay(); s.version = '1.8.4.3'; // Cache builder element. $builder = $( '#charitable-builder' ); $builderForm = $( '#charitable-builder-form' ); // Action buttons. elements.$helpButton = $( '#charitable-help' ); elements.$previewButton = $( '#charitable-preview-btn' ); elements.$viewCampaignButton = $( '#charitable-view-btn' ); elements.$embedButton = $( '#charitable-embed' ); elements.$statusButton = $( '#charitable-status-button' ); elements.$saveButton = $( '#charitable-save' ); elements.$exitButton = $( '#charitable-exit' ); elements.$templateButton = $( '.charitable-panel-template-button' ); elements.$designButton = $( '.charitable-panel-design-button' ); elements.$settingsButton = $( '.charitable-panel-settings-button' ); elements.$marketingButton = $( '.charitable-panel-marketing-button' ); elements.$paymentButton = $( '.charitable-panel-payment-button' ); // Cache other elements. elements.$noFieldsOptions = $( '.charitable-panel-fields .charitable-no-fields-holder .no-fields' ); elements.$noFieldsPreview = $( '.charitable-panel-fields .charitable-no-fields-holder .no-fields-preview' ); elements.$formPreview = $( '.charitable-panel-fields .charitable-preview-wrap' ); elements.$revisionPreview = $( '#charitable-panel-revisions .charitable-panel-content' ); elements.$focusOutTarget = null; elements.$preview = $( '.charitable-preview' ); elements.$panelDesign = $( '#charitable-panel-design'); elements.$nextFieldId = $( '#charitable-field-id' ); elements.$fieldOptions = $( '#charitable-field-options' ); elements.$fieldsPreviewWrap = $( '.charitable-panel-fields .charitable-panel-content-wrap' ), elements.$sortableFieldsWrap = $( '.charitable-panel-fields .charitable-field-wrap' ); elements.$sortableTabsWrap = $( '.charitable-panel-fields .charitable-tab-wrap' ); elements.$sortableTabNav = $( '.charitable-campaign-preview nav.charitable-campaign-preview-nav' ); elements.$sortableTabContent = $( '.charitable-campaign-preview .tab-content' ); elements.$addFieldsButtons = $( '.charitable-add-fields-button' ).not( '.not-draggable' ).not( '.warning-modal' ).not( '.charitable-not-available').not( '.charitable-not-installed' ).not( '.charitable-not-activated' ).not( '.charitable-installed-refresh' ).not( '.charitable-addon-file-missing').not( '.charitable-need-upgrade'); elements.$templatePanel = $( '#charitable-panel-template' ); elements.$templatePreview = $( '.charitable-template-preview' ); elements.$settingsPanel = $( '#charitable-panel-settings' ); elements.$campaignID = $( '#charitable-builder-form input[name="id"]' ); elements.$templateID = $( '#charitable-builder-form input[name="template_id"]' ); elements.$templateLabel = $( '#charitable-builder-form input[name="template_label"]' ); elements.$postStatus = $( '#charitable-builder-form input[name="post_status"]' ); elements.$primaryThemeColorBase = $( '#charitable-builder-form input[name="color_base_primary"]' ); elements.$secondaryThemeColorBase = $( '#charitable-builder-form input[name="color_base_secondary"]' ); elements.$tertiaryThemeColorBase = $( '#charitable-builder-form input[name="color_base_tertiary"]' ); elements.$buttonThemeColorBase = $( '#charitable-builder-form input[name="color_base_button"]' ); // Bind all actions. app.bindUIActions(); // Setup/cache some vars not available before s.formID = $builderForm.data( 'id' ); s.templateID = $builderForm.data( 'template-id' ); s.templateLabel = $builderForm.data( 'template-label' ); s.primaryThemeColorBase = s.primaryThemeColor = $( this ).closest('.charitable-template').data('template-primary'); s.secondaryThemeColorBase = s.secondaryThemeColor = $( this ).closest('.charitable-template').data('template-secondary'); s.tertiaryThemeColorBase = s.tertiaryThemeColor = $( this ).closest('.charitable-template').data('template-tertiary'); s.buttonThemeColorBase = s.buttonThemeColor = $( this ).closest('.charitable-template').data('template-button'); s.primaryThemeColorBase = elements.$primaryThemeColorBase.val().length > 0 ? elements.$primaryThemeColorBase.val() : ''; s.secondaryThemeColorBase = elements.$secondaryThemeColorBase.val().length > 0 ? elements.$secondaryThemeColorBase.val() : ''; s.tertiaryThemeColorBase = elements.$tertiaryThemeColorBase.val().length > 0 ? elements.$tertiaryThemeColorBase.val() : ''; s.buttonThemeColorBase = elements.$buttonThemeColorBase.val().length > 0 ? elements.$buttonThemeColorBase.val() : ''; s.primaryThemeColor = ''; s.secondaryThemeColor = ''; s.tertiaryThemeColor = ''; s.buttonThemeColor = ''; s.formSaved = $builderForm.find( '#charitable-form-saved' ).val(); s.formSavedStatus = $builderForm.find( '#charitable-form-post-status' ).val(); s.formSavedStatusLabel = $builderForm.find( '#charitable-form-post-status-label' ).val(); s.formStatus = s.formSavedStatus.length > 0 ? s.formSavedStatus : 'draft'; // this can change but draft is the default when a new campaign is created. s.formStatusLabel = s.formSavedStatusLabel.length > 0 ? s.formSavedStatusLabel : 'Draft'; // this can change but draft is the default when a new campaign is created. // Global variables for quick reference to campaign data like titles and descriptions. s.campaignTitle = $( 'input#charitable_settings_title' ).val(); s.campaignDescription = $( 'div[data-special-type="campaign_description"] .campaign-builder-htmleditor' ).first().html(); s.campaignOverview = $( 'div[data-special-type="campaign_overview"] .campaign-builder-htmleditor' ).length > 0 ? $( 'div[data-special-type="campaign_overview"] .campaign-builder-htmleditor' ).first().html() : ''; // Limit the number of tabs. s.maxNumberOfTabs = 4; s.denyList = { 'donation-form': { 'donate-button' : 0, 'donation-form' : 0, 'donate-amount' : 0 }, 'donate-button': { 'donation-form' : 0 }, 'donate-amount': { 'donation-form' : 0 } }; s.pagebreakTop = $( '.charitable-pagebreak-top' ).length; s.pagebreakBottom = $( '.charitable-pagebreak-bottom' ).length; s.didInitHTMLEditorFields = false; s.quilled = []; s.currentModal = false; // Disable implicit submission for every form inside the builder. // All form values are managed by JS and should not be submitted by pressing Enter. $builder.on( 'keypress', '#charitable-builder-form :input:not(textarea)', function( e ) { if ( e.keyCode === 13 ) { e.preventDefault(); } } ); // If there is a section configured, display it. // Otherwise, we show the first panel by default. $( '.charitable-panel' ).each( function( index, el ) { // eslint-disable-line var $this = $( this ), $configured = $this.find( '.charitable-panel-sidebar-section.configured' ).first(); if ( $configured.length ) { var section = $configured.data( 'section' ); $configured.addClass( 'active' ); $this.find( '.charitable-panel-content-section-' + section ).show().addClass( 'active' ); $this.find( '.charitable-panel-content-section-default' ).hide(); } else { $this.find( '.charitable-panel-content-section').hide().removeClass( 'active' ); $this.find( '.charitable-panel-content-section').first().show().addClass( 'active' ); $this.find( '.charitable-panel-sidebar-section:first-of-type' ).addClass( 'active' ); } } ); // Secret builder hotkeys. app.builderHotkeys(); if ( typeof jconfirm !== 'undefined' ) { // jquery-confirm defaults. jconfirm.defaults = { closeIcon: false, backgroundDismiss: false, escapeKey: true, animationBounce: 1, useBootstrap: false, theme: 'modern', boxWidth: '400px', animateFromElement: false, draggable: false, content: charitable_builder.something_went_wrong }; } // $('#charitable_settings_title').attr('disabled', true ); // Init all date pickers on the page. $( '.campaign-builder-datepicker' ).each( function() { app.initDatePicker( $( this ) ); }); // Init all unique UI tag fields on the page. $( '.campaign-tag-field' ).each( function() { app.initTagField( $( this ) ); }); // This handles the unique suggested donation area that creates dynamic rows. $( '.charitable-campaign-suggested-donations' ).each( function() { app.initSuggestedDonations( $( this ) ); }); $( '.charitable-campaign-suggested-donations-mini' ).each( function() { app.initSuggestedDonationsMini( $( this ) ); app.updateSuggestdDonationsMiniRowsFromSettings( $( this ) ); }); app.initColorPicker(); app.initTemplatePanel(); app.initStatusButton(); // Goal and End Date checks app.updateGoalRelatedItems(); app.updateEndDateRelatedItems(); // Refresh so that the campaign input box at the top can resize upon load of page. app.resizeTopCampaignTitleInputBox(); if ( false !== app.hasTemplate() ) { var panel = ( null !== wpCookies.get( 'charitable_panel' ) ) ? wpCookies.get( 'charitable_panel' ).trim() : false; // if there is a cookie saved with a particular panel, go to that by default. if ( typeof panel !== 'undefined' && panel.length > 0 && panel !== 'template' ) { app.panelSwitch( panel ); } else { app.panelSwitch( 'design' ); } // If there is a template, onload check the fields present on preview screen and disable the ones that are not allowed. app.checkFieldAllow(); // Cookies. app.redirectBasedOnCookies( panel ); } else { app.forceTemplateSelect(); // app.disableFormActions( false ); // 1.8.1.12 // temp: change mode to "new campaign mode". app.setCampaignTitleNotSet(); } // Lite Modal. app.openModalButtonClick(); app.confirmCampaignDeletion(); $('.education-buttons button').click(function() { window.open("https://www.wpcharitable.com/pricing/"); }); // Misc. $(".campaign-builder-campaign-creator-id select").select2({ templateResult: app.campaignCreatorFormatOptions }); $(".campaign-builder-campaign-creator-id-mini select").select2({ templateResult: app.campaignCreatorFormatOptions }); }, /** * Return a "row" in the select2 HTML for creator campaign dropdown. * * @since 1.8.0 * * @param {array} state The name of the panel. * */ campaignCreatorFormatOptions( state ) { if (!state.id) { return state.text; } var $state = $( '<span class="charitable-select2-avatar"><img width="20px" height="20px" style="display: inline-block; float: left; margin-right: 10px;" src="' + state.element.dataset.avatar + '" /> ' + state.text + '</span><span class="charitable-select2-meta"> ' + state.element.dataset.meta + '</span>' ); return $state; }, /** * If a cookie has saved where the user was last, attempt to bring them back to that screen. * * @since 1.8.0 * * @param {string} panel The name of the panel. * */ redirectBasedOnCookies( panel = false ) { var cookieContentSection = wpCookies.get( 'charitable_panel_content_section' ), cookieActiveFieldId = '' !== wpCookies.get( 'charitable_panel_active_field_id' ) ? parseInt( wpCookies.get( 'charitable_panel_active_field_id' ) ) : '', cookieActiveTabId = wpCookies.get( 'charitable_panel_tab_section_tab_id' ), cookieActiveLayoutOptionsGroup = wpCookies.get( 'charitable_panel_design_layout_options_group' ); if ( $('.charitable-preview').is(':visible') && $('ul.charitable-tabs li#layout-options').is(':visible') && '' !== cookieActiveLayoutOptionsGroup && '' === cookieActiveFieldId ) { if ( ! $('ul.charitable-tabs li#layout-options a').hasClass('active') ) { $('ul.charitable-tabs li#layout-options a').click(); } $('#charitable-field-options div.charitable-layout-options-tab-' + cookieActiveLayoutOptionsGroup + ' a.charitable-group-toggle').click(); } else if ( $('.charitable-preview').is(':visible') && '' !== cookieActiveTabId && $('nav.charitable-campaign-preview-nav li[data-tab-id="' + cookieActiveTabId + '"] a').is(':visible') ) { $('.charitable-preview nav.charitable-campaign-preview-nav li[data-tab-id="' + cookieActiveTabId + '"] a').click(); } else if ( $('.charitable-preview').is(':visible') && $('#charitable-field-' + cookieActiveFieldId + ' a').is(':visible') ) { app.clickFieldEdit( cookieActiveFieldId ); } else if ( $('.charitable-panel-sidebar').is(':visible') && $('a.charitable-panel-sidebar-section[data-section="' + cookieContentSection + '"').is(':visible') ) { // settings section $('a.charitable-panel-sidebar-section[data-section="' + cookieContentSection + '"').click(); } else if ( '' !== cookieActiveFieldId && $('#charitable-field-' + cookieActiveFieldId ).is(':visible') ) { $('#charitable-field-' + cookieActiveFieldId ).click(); } else if ( $('.charitable-panel-sidebar').is(':visible') && cookieContentSection && $('.charitable-tabs').is(':visible') && $('.charitable-tabs li#' + cookieContentSection + ' a').is(':visible') ) { // design tabs $('.charitable-tabs li#' + cookieContentSection + ' a').click(); } else if ( false === panel && false !== app.hasTemplate() ) { app.panelSwitch( 'design' ); } else { wpchar.debug('redirectBasedOnCookies nothing'); } }, /** * Simulates a click on an edit fields as if the user did it themselves. * * @since 1.8.0 * * @param {string} fieldId Upgrade modal type (with video or not). * */ clickFieldEdit( fieldId ) { $('#charitable-field-' + fieldId + ' a.charitable-field-edit').click(); }, /** * Reassigns the .tab-content to the variable, making sure it holds the latest. * * @since 1.8.0 * */ refreshTabFieldsSortDrag() { elements.$sortableTabContent = $( '.charitable-campaign-preview .tab-content' ); }, /** * Attempts to determine if the campaign has a template assigned to it or not. * * @since 1.8.0 * */ hasTemplate() { if ( typeof s.templateID !== 'undefined' && s.templateID.length > 0 ) { return true; } var templateID = parseInt( elements.$templateID.val() ); if ( templateID > 0 ) { return true; } return false; }, /** * Changes UI so user can select a template and can't select other UI. * * @since 1.8.0 * */ forceTemplateSelect() { $( '#charitable-panels-toggle' ).find( 'button' ).removeClass( 'active' ).addClass('disabled'); elements.$templateButton.removeClass('disabled').addClass( 'active' ); app.panelSwitch( 'template' ); }, /** * Removes the disabled UI that foreced a template selection. * * @since 1.8.0 * */ unforceTemplateSelect() { $( '#charitable-panels-toggle' ).find( 'button' ).removeClass( 'disabled' ); }, /** * Changes UI so user cannot visit the template tab to change a template. * * @since 1.8.0 * */ disableTemplateSelect() { elements.$templateButton.removeClass('active').addClass( 'disabled' ); }, /** * When a template is seleced, certain UI and CSS classes need to be updated. * * @since 1.8.0 * * @param {string} templateID The 'slug' of the template. * @param {string} templateLabel The text/label of the template. * */ updateTemplateID( templateID = '', templateLabel = '' ) { // update the invisible value. elements.$templateID.val( templateID ); elements.$templateLabel.val( templateLabel ); // update the admin preview CSS stylesheet. app.updateThemeCSS( null, templateID, s.primaryThemeColor, s.secondaryThemeColor, s.tertiaryThemeColor, s.buttonThemeColor, false ); // update some critical preview CSS. $('.charitable-preview').removeClass( function( index, className ) { return (className.match (/(^|\s)charitable-builder-template-\S+/g) || []).join(' '); }).addClass( 'charitable-builder-template-' + templateID ); // update template name in preview top bar if ( templateLabel !== '' ) { $('.charitable-preview-top-bar .charitable-campaign-theme-label').text( templateLabel ); } else if ( templateID !== '' ) { $('.charitable-preview-top-bar .charitable-campaign-theme-label').text( templateID ); } }, /** * Update Theme CSS file for preview * * @since 1.8.0 * * @param {string} whatChanged 'primary', etc. helpful for updating JUST the right CSS file. * @param {string} templateID The 'slug' of the template. * @param {string} primaryThemeColor Full alphanumeric hex value without hashtag. * @param {string} secondaryThemeColor * @param {string} tertiaryThemeColor * @param {string} buttonThemeColor * */ updateThemeCSS( whatChanged = null, templateID = '', primaryThemeColor = '', secondaryThemeColor = '', tertiaryThemeColor = '', buttonThemeColor = '', justColors = true ) { // There needs to be a templateID or we can't link to the CSS file. if ( '' === templateID && '' === s.templateID ) { return; } if ( typeof s.primaryThemeColor === 'undefined' || '' === primaryThemeColor ) { if ( typeof s.primaryThemeColor !== 'undefined' && '' !== s.primaryThemeColor ) { primaryThemeColor = s.primaryThemeColor; } else if ( typeof s.primaryThemeColorBase !== 'undefined' && '' !== s.primaryThemeColorBase ) { primaryThemeColor = s.primaryThemeColorBase; } else { primaryThemeColor = '000000'; // shouldn't get to this point. } } if ( typeof s.secondaryThemeColor === 'undefined' || '' === secondaryThemeColor ) { if ( typeof s.secondaryThemeColor !== 'undefined' && '' !== s.secondaryThemeColor ) { secondaryThemeColor = s.secondaryThemeColor; } else if ( typeof s.secondaryThemeColorBase !== 'undefined' && '' !== s.secondaryThemeColorBase ) { secondaryThemeColor = s.secondaryThemeColorBase; } else { secondaryThemeColor = '000000'; // shouldn't get to this point. } } if ( typeof s.tertiaryThemeColor === 'undefined' || '' === tertiaryThemeColor ) { if ( typeof s.tertiaryThemeColor !== 'undefined' && '' !== s.tertiaryThemeColor ) { tertiaryThemeColor = s.tertiaryThemeColor; } else if ( typeof s.tertiaryThemeColorBase !== 'undefined' && '' !== s.tertiaryThemeColorBase ) { tertiaryThemeColor = s.tertiaryThemeColorBase; } else { tertiaryThemeColor = '000000'; // shouldn't get to this point. } } if ( typeof s.buttonThemeColor === 'undefined' || '' === buttonThemeColor ) { if ( typeof s.buttonThemeColor !== 'undefined' && '' !== s.buttonThemeColor ) { buttonThemeColor = s.buttonThemeColor; } else if ( typeof s.buttonThemeColorBase !== 'undefined' && '' !== s.buttonThemeColorBase ) { buttonThemeColor = s.buttonThemeColorBase; } else { buttonThemeColor = '000000'; // shouldn't get to this point. } } // ensure colors are passed raw hex without the hashtag primaryThemeColor = primaryThemeColor.replace(/[^a-zA-Z 0-9]+/g, ''); secondaryThemeColor = secondaryThemeColor.replace(/[^a-zA-Z 0-9]+/g, ''); tertiaryThemeColor = tertiaryThemeColor.replace(/[^a-zA-Z 0-9]+/g, ''); buttonThemeColor = buttonThemeColor.replace(/[^a-zA-Z 0-9]+/g, ''); var colorQueryString = 'p=' + primaryThemeColor + '&s=' + secondaryThemeColor + '&t=' + tertiaryThemeColor + '&b=' + buttonThemeColor + '&ver=' + s.version; // add class to entire preview area // update the admin preview CSS stylesheet. // $("head link[rel='stylesheet']").last().after('<link rel="stylesheet" id="charitable-builder-template-preview-theme-css-temp" href="' + charitable_builder.charitable_assets_dir + 'css/campaign-builder/themes/admin/' + templateID + '.php?' + colorQueryString + '" type="text/css" media="screen">'); if ( justColors === false ) { $('link[id="charitable-builder-template-preview-theme-css"]').attr('href', charitable_builder.charitable_assets_dir + 'css/campaign-builder/themes/admin/' + templateID + '.php?' + colorQueryString ); } if ( whatChanged !== null ) { app.replaceCSSFile( whatChanged, templateID, colorQueryString ); } else { app.replaceCSSFile( 'primary', templateID, colorQueryString ); app.replaceCSSFile( 'secondary', templateID, colorQueryString ); app.replaceCSSFile( 'tertiary', templateID, colorQueryString ); app.replaceCSSFile( 'button', templateID, colorQueryString ); } }, /** * Replace Theme CSS file for preview * * @since 1.8.0 * * @param {string} whatChanged 'primary', etc. helpful for updating JUST the right CSS file. * @param {string} templateID The 'slug' of the template. * @param {string} colorQueryString * */ replaceCSSFile: function ( whatChanged, templateID, colorQueryString ) { $('head').find('link#charitable-builder-template-preview-theme-colors-' + whatChanged + '-css').remove(); $('head').append('<link rel="stylesheet" data-color-type="' + whatChanged + '" id="charitable-builder-template-preview-theme-colors-temp" href="' + charitable_builder.charitable_assets_dir + 'css/campaign-builder/themes/admin/' + templateID + '-colors.php?' + colorQueryString + '" type="text/css" media="screen">'); $('#charitable-design-wrap').addClass('loading'); setTimeout(function() { $('head').find('#charitable-builder-template-preview-theme-colors-temp').attr('id', 'charitable-builder-template-preview-theme-colors-' + whatChanged + '-css'); $('#charitable-design-wrap').removeClass('loading'); }, 250); }, /** * Search template callback. * * @since 1.8.0 * * @param {object} e Event object. */ searchTemplate: function( e ) { e.preventDefault(); let $active = $('.charitable-setup-templates-categories li.active'), category = $active.data( 'category' ), searchQuery = $( this ).val(); app.performSearch( searchQuery, category ); }, /** * Perform search value. * * @since 1.8.0 * * @param {string} query Value to search. * @param {string} category Another value to search. */ performSearch( query = '', category = '' ) { let $templateList = elements.$templatePreview.find('.charitable-template-list'); if ( query === '' && ( category === '' || category === 'all' ) ) { $templateList.find('.charitable-template-list-container-item').removeClass('charitable-hidden'); } else { $templateList.find('.charitable-template-list-container-item').addClass('charitable-hidden'); if ( query !== '' && category !== '' && category !== 'all' ) { $templateList.find('.charitable-template[data-template-tags*="' + query + '"][data-template-categories*="' + category + '"]').parent().removeClass('charitable-hidden'); } else if ( query !== '' && ( category === '' || category === 'all' ) ) { $templateList.find('.charitable-template[data-template-tags*="' + query + '"],.charitable-template[data-template-categories*="' + query + '"]').parent().removeClass('charitable-hidden'); } else { $templateList.find('.charitable-template[data-template-tags*="' + category + '"],.charitable-template[data-template-categories*="' + category + '"]').parent().removeClass('charitable-hidden'); } } var numItems = $('.charitable-template-list-container-item').not('.hidden').length; $( '.charitable-templates-no-results' ).toggle( ! numItems ); if ( ! elements.$templatePreview.find('#charitable-setup-template-search').val() ) { elements.$templatePreview.find('.charitable-setup-templates-search-wrap .fa-close').hide(); } else { elements.$templatePreview.find('.charitable-setup-templates-search-wrap .fa-close').show(); } app.showCheckTemplateList(); app.showUpgradeBanner(); }, /** * Actions after a user selects a category in the template screen. * * @since 1.8.0 * * @param {object} e Event object. */ selectCategory: function( e ) { e.preventDefault(); let $item = $( this ), $active = $item.closest( 'ul' ).find( '.active' ), category = $item.data( 'category' ), searchQuery = $( '#charitable-setup-template-search' ).val(); $active.removeClass( 'active' ); $item.addClass( 'active' ); app.performSearch( searchQuery, category ); }, /** * Show upgrade banner if licence type is less than Pro. * * @since 1.8.0 */ showUpgradeBanner: function() { if ( ! $( '#tmpl-charitable-templates-upgrade-banner' ).length ) { return; } if ( $('#charitable-template-list .charitable-template-upgrade-banner').length > 0 ) { $('#charitable-template-list .charitable-template-upgrade-banner').remove(); } if ( ! app.isFunction( wp.template ) ) { // eslint-disable-line wpchar.debug( 'wp.template not a function' ); return; } else { wpchar.debug( 'wp.template is a function' ); } let template = wp.template( 'charitable-templates-upgrade-banner' ); // eslint-disable-line if ( ! template ) { return; } const $templates = $( '#charitable-template-list .charitable-template-list-container-item:not(.charitable-hidden)'), $insertPoint = $( '#charitable-template-list .charitable-template-list-container-item'); if ( $templates.length > 5 ) { $ ('#charitable-template-list .charitable-template-list-container > div:last-child').after( template() ); return; } $insertPoint.last().after( template() ); }, /** * Called when the template list probably has changed - see if we hide/show the sections if there is/are no templates for those sections. * * @since 1.8.1.12 */ showCheckTemplateList: function() { // if there are no more template items (.charitable-template-list-container-item) with the class of blank then hide the blank section (otherwise show it). if ( $('#charitable-template-list .charitable-template-list-container-item.blank:not(.charitable-hidden)').length === 0 ) { $('#charitable-template-list .charitable-template-list-section-blank').addClass('charitable-hidden'); $('#charitable-template-list .charitable-template-list-section-prebuilt').addClass('charitable-hidden'); } else { $('#charitable-template-list .charitable-template-list-section-blank').removeClass('charitable-hidden'); $('#charitable-template-list .charitable-template-list-section-prebuilt').removeClass('charitable-hidden'); } // if there are no more template items (.charitable-template-list-container-item) without the class of blank then hide the prebuuilt section (otherwise show it). if ( $('#charitable-template-list .charitable-template-list-container-item.prebuilt:not(.charitable-hidden)').length === 0 ) { $('#charitable-template-list .charitable-template-list-section-prebuilt').addClass('charitable-hidden'); } else { $('#charitable-template-list .charitable-template-list-section-prebuilt').removeClass('charitable-hidden'); } if ( $('#charitable-template-list .charitable-template-list-container-item.prebuilt:not(.charitable-hidden)').length > 0 && $('#charitable-template-list .charitable-template-list-container-item.blank:not(.charitable-hidden)').length === 0 ) { $('#charitable-template-list .charitable-template-list-section-prebuilt').addClass('charitable-hidden'); } }, /** * Upon page load (or general resets) make sure the top button is showing the proper status and dropdown has the right available status choices. * * @since 1.8.0 */ initStatusButton: function( formStatus = '', formStatusLabel = '' ) { var $statusDropdown = $( 'ul#charitable-status-dropdown' ); if ( formStatus == '' && s.formStatus.length > 0 ) { formStatus = s.formStatus; } if ( formStatusLabel == '' && s.formStatusLabel.length > 0 ) { formStatusLabel = s.formStatusLabel; } // make sure dropdown isn't visible $statusDropdown.addClass('charitable-hidden'); $( "#charitable-status-button" ).removeClass('active'); // change status $( '#charitable-status-button span.text').html( formStatusLabel ); $( '#charitable-status-button').attr('data-status', formStatus ); $statusDropdown.find('a').removeClass('charitable-hidden'); $statusDropdown.find('a.switch-' + formStatus).addClass('charitable-hidden'); $statusDropdown.find('a.' + formStatus).addClass('charitable-hidden'); if ( formStatus === 'draft' ) { // $statusDropdown.find('a[class*="switch-"]').addClass('charitable-hidden'); } else if ( formStatus === 'publish' ) { // $statusDropdown.find('a.draft').addClass('charitable-hidden'); // $statusDropdown.find('a.pending').addClass('charitable-hidden'); // $statusDropdown.find('a.review').addClass('charitable-hidden'); } }, /** * Init the template panel and setup the actions, etc. * * @since 1.8.0 */ initTemplatePanel: function() { $( '#charitable-template-container' ) .on( 'keyup', '#charitable-setup-template-search', app.searchTemplate ) .on( 'click', '.charitable-setup-templates-categories li', app.selectCategory ); if ( ! s.didInitHTMLEditorFields ) { $( '.campaign-builder-htmleditor' ).each( function() { app.initHTMLEditorFields( $( this ) ); }); $( '.campaign-builder-htmleditor-min' ).each( function() { app.initHTMLEditorFields( $( this ), true ); }); s.didInitHTMLEditorFields = true; } // feedback form. elements.$templatePreview.on( 'click', '.charitable-template-lite-to-pro a.button, .charitable-setup-templates-feedback a.send-feedback', function( e ) { e.preventDefault(); // Scroll to the top of the charitable-panel-content-wrap div container. $('.charitable-panel-content-wrap').animate({ scrollTop: 0 }, 500); $('.charitable-template-list-container').addClass('disabled'); $('.charitable-feedback-form-container').after('<div id="charitable-builder-underlay" class="charitable-builder-underlay"></div>'); $('.charitable-feedback-form-container').css("opacity", "100" ).css("visibility", "visible" ); $('.charitable-feedback-form-container').find('.charitable-feedback-form-interior').removeClass('charitable-hidden'); $('.charitable-feedback-form-container').find('textarea').val(''); $('.charitable-feedback-form-interior-confirmation').addClass('charitable-hidden'); }); // Close button on feedback form. $builderForm.on( 'click', '#charitable-feedback-form .charitable-templates-close-icon, #charitable-feedback-form-confirmation .charitable-templates-close-icon', function( e ) { e.preventDefault(); $('.charitable-template-list-container').removeClass('disabled'); $('.charitable-builder-underlay').remove(); $('#charitable-panel-template .charitable-feedback-form-container').css("opacity", "0" ).css("visibility", "hidden" ); }); // Template Preview form. $builderForm.on( 'click', '.template-buttons a.preview-campaign', function( e ) { e.preventDefault(); $('.charitable-template-list-container').addClass('disabled'); $('.charitable-feedback-form-container').after('<div id="charitable-builder-underlay" class="charitable-builder-underlay"></div>'); // Dynamically update the popup with elemnets from the selected/clicked on <li> element. const previewBox = $( this ).closest('.charitable-template'), templateLabel = typeof previewBox.data('template-label') !== 'undefined' ? previewBox.data('template-label') : '', templateDescription = typeof previewBox.data('template-description') !== 'undefined' ? previewBox.data('template-description') : '', templatePreviewURL = typeof previewBox.data('template-preview-url') !== 'undefined' ? previewBox.data('template-preview-url') : '', templateCode = typeof previewBox.data('template-code') !== 'undefined' ? previewBox.data('template-code') : ''; $('#charitable-builder-modal-template-preview').find('h4').html( templateLabel ); $('#charitable-builder-modal-template-preview').find('.charitable-templates-preview-description').html( '<p>' + templateDescription + '</p>' ); $('#charitable-builder-modal-template-preview').find('img').attr('src', templatePreviewURL ); $('#charitable-builder-modal-template-preview').find('img').attr('alt', templateLabel ); $('#charitable-builder-modal-template-preview').find('a.button-link').attr('data-template-id', templateCode ); $('.charitable-builder-modal.charitable-builder-modal-template-preview').addClass('active'); }); $builderForm.on( 'click', '#charitable-templates-preview-form .charitable-templates-close-icon', function( e ) { e.preventDefault(); $('.charitable-template-list-container').removeClass('disabled'); $('#charitable-builder-underlay').remove(); $('.charitable-builder-modal.charitable-builder-modal-template-preview').removeClass('active'); }); // Tab and filtering. elements.$templatePreview.on( 'click', 'nav.charitable-template-tabs a', function( e ) { e.preventDefault(); var $this = $( this ), templateTabFilter = ( $this ).data('template-tab-filter') ? ( $this ).data('template-tab-filter') : false, $templateList = elements.$templatePreview.find('.charitable-template-list '); elements.$templatePreview.find('nav.charitable-template-tabs a').removeClass('active'); $this.addClass('active'); $templateList.find('.charitable-template').removeClass('hidden'); if ( templateTabFilter ) { $templateList.find('.charitable-template[data-template-type!="' + templateTabFilter + '"]').addClass('hidden'); } }); // Show default templates. elements.$templatePreview.on( 'click', 'a.charitable-trigger-blank', function( e ) { e.preventDefault(); $('#charitable-template-list .charitable-template-upgrade-banner').remove(); elements.$templatePreview.find('#charitable-setup-template-search').val('simple').trigger('keyup').addClass('highlighted').addClass('with-x'); elements.$templatePreview.find('.charitable-setup-templates-categories').find('li[data-category=all').click(); app.showCheckTemplateList(); app.showUpgradeBanner(); }); elements.$templatePreview.on( 'click', 'i.fa-close', function( e ) { // eslint-disable-line elements.$templatePreview.find('#charitable-setup-template-search').val('').trigger('keyup').removeClass('highlighted'); }); // Create campaign. elements.$templatePreview.on( 'click', '.button.create-campaign', function( e ) { e.preventDefault(); if ( app.hasTemplate() ) { // Display error in modal window. $.confirm( { title: charitable_builder.heads_up, content: '<p>' + charitable_builder.error_already_started_campaign + '</p>', icon: 'fa fa-exclamation-circle', type: 'orange', buttons: { confirm: { text: charitable_builder.ok, btnClass: 'btn-confirm', keys: [ 'enter' ], action: function() { s.templateID = $( this ).closest('.charitable-template').data('template-code'); s.templateLabel = $( this ).closest('.charitable-template').data('template-label'); s.primaryThemeColorBase = s.primaryThemeColor = $( this ).closest('.charitable-template').data('template-primary'); s.secondaryThemeColorBase = s.secondaryThemeColor = $( this ).closest('.charitable-template').data('template-secondary'); s.tertiaryThemeColorBase = s.tertiaryThemeColor = $( this ).closest('.charitable-template').data('template-tertiary'); s.buttonThemeColorBase = s.buttonThemeColor = $( this ).closest('.charitable-template').data('template-button'); elements.$primaryThemeColorBase.val( s.primaryThemeColorBase ); elements.$secondaryThemeColorBase.val( s.secondaryThemeColorBase ); elements.$tertiaryThemeColorBase.val( s.tertiaryThemeColorBase ); elements.$buttonThemeColorBase.val( s.buttonThemeColorBase ); $('input[name="layout__advanced__theme_color_primary"]').val( s.primaryThemeColor ); $('input[name="layout__advanced__theme_color_secondary"]').val( s.secondaryThemeColor ); $('input[name="layout__advanced__theme_color_tertiary"]').val( s.tertiaryThemeColor ); $('input[name="layout__advanced__theme_color_button"]').val( s.buttonThemeColor ); document.querySelector('input[name="layout__advanced__theme_color_primary"]').dispatchEvent(new Event('input', { bubbles: true })); document.querySelector('input[name="layout__advanced__theme_color_secondary"]').dispatchEvent(new Event('input', { bubbles: true })); document.querySelector('input[name="layout__advanced__theme_color_tertiary"]').dispatchEvent(new Event('input', { bubbles: true })); document.querySelector('input[name="layout__advanced__theme_color_button"]').dispatchEvent(new Event('input', { bubbles: true })); app.restartForm( s.templateID, null, s.templateLabel ); app.restartTemplateScreen( s.templateID ); } }, cancel: { text: charitable_builder.cancel, keys: [ 'esc' ] } } } ); } else { s.templateID = $( this ).closest('.charitable-template').data('template-code'); s.templateLabel = $( this ).closest('.charitable-template').data('template-label'); s.primaryThemeColorBase = s.primaryThemeColor = $( this ).closest('.charitable-template').data('template-primary'); s.secondaryThemeColorBase = s.secondaryThemeColor = $( this ).closest('.charitable-template').data('template-secondary'); s.tertiaryThemeColorBase = s.tertiaryThemeColor = $( this ).closest('.charitable-template').data('template-tertiary'); s.buttonThemeColorBase = s.buttonThemeColor = $( this ).closest('.charitable-template').data('template-button'); elements.$primaryThemeColorBase.val( s.primaryThemeColorBase ); elements.$secondaryThemeColorBase.val( s.secondaryThemeColorBase ); elements.$tertiaryThemeColorBase.val( s.tertiaryThemeColorBase ); elements.$buttonThemeColorBase.val( s.buttonThemeColorBase ); $('input[name="layout__advanced__theme_color_primary"]').val( s.primaryThemeColor ); $('input[name="layout__advanced__theme_color_secondary"]').val( s.secondaryThemeColor ); $('input[name="layout__advanced__theme_color_tertiary"]').val( s.tertiaryThemeColor ); $('input[name="layout__advanced__theme_color_button"]').val( s.buttonThemeColor ); document.querySelector('input[name="layout__advanced__theme_color_primary"]').dispatchEvent(new Event('input', { bubbles: true })); document.querySelector('input[name="layout__advanced__theme_color_secondary"]').dispatchEvent(new Event('input', { bubbles: true })); document.querySelector('input[name="layout__advanced__theme_color_tertiary"]').dispatchEvent(new Event('input', { bubbles: true })); document.querySelector('input[name="layout__advanced__theme_color_button"]').dispatchEvent(new Event('input', { bubbles: true })); app.updateTemplateID( s.templateID, s.templateLabel ); app.unforceTemplateSelect(); app.enableFormActions(); app.restartForm( s.templateID, 'design', s.templateLabel ); app.restartTemplateScreen( s.templateID ); if ( ! s.didInitHTMLEditorFields ) { $( '.campaign-builder-htmleditor' ).each( function() { app.initHTMLEditorFields( $( this ) ); }); $( '.campaign-builder-htmleditor-min' ).each( function() { app.initHTMLEditorFields( $( this ), true ); }); s.didInitHTMLEditorFields = true; } // app.disableTemplateSelect(); CharitableUtils.triggerEvent( $builder, 'charitableCampaignFormScreen', [ s.templateID ] ); // Shepherd.activeTour.next(); } } ); // Create campaign via preview window. Sneaky! $builder.on( 'click', '.button-preview-create-campaign', function( e ) { e.preventDefault(); // find the create button in the list and click that instead of trying to duplicate everything. var $theButton = $( this ), theTemplateID = $theButton.data('template-id'); if ( theTemplateID !== '' ) { $('.charitable-template-list-container').removeClass('disabled'); $('#charitable-builder-underlay').remove(); // $('.charitable-templates-preview-container').addClass('charitable-hidden'); $('.charitable-builder-modal.charitable-builder-modal-template-preview').removeClass('active'); // if the button.update-campaign exists, click that. if ( $('#charitable-template-list .charitable-template[data-template-code="' + theTemplateID + '"] .button.update-campaign').length > 0 ) { elements.$templatePreview.find('.charitable-template-list-container-item.charitable-template-' + theTemplateID + ' .button.update-campaign').click(); } else { // if the button.create-campaign exists, click that. elements.$templatePreview.find('.charitable-template-list-container-item.charitable-template-' + theTemplateID + ' .button.create-campaign').click(); } } } ); $builder.on( 'click', '.button-preview-update-campaign', function( e ) { e.preventDefault(); // find the create button in the list and click that instead of trying to duplicate everything. var $theButton = $( this ), theTemplateID = $theButton.data('template-id'); if ( theTemplateID !== '' ) { $('.charitable-template-list-container').removeClass('disabled'); $('#charitable-builder-underlay').remove(); // $('.charitable-templates-preview-container').addClass('charitable-hidden'); $('.charitable-builder-modal.charitable-builder-modal-template-preview').removeClass('active'); // if the button.update-campaign exists, click that. if ( $('#charitable-template-list .charitable-template[data-template-code="' + theTemplateID + '"] .button.update-campaign').length > 0 ) { elements.$templatePreview.find('.charitable-template-list-container-item.charitable-template-' + theTemplateID + ' .button.update-campaign').click(); } else { // if the button.create-campaign exists, click that. elements.$templatePreview.find('.charitable-template-list-container-item.charitable-template-' + theTemplateID + ' .button.create-campaign').click(); } } } ); // Update campaign. elements.$templatePreview.on( 'click', '.button.update-campaign', function( e ) { e.preventDefault(); var theButton = $( this ); if ( app.hasTemplate() ) { // Display error in modal window. $.confirm( { title: charitable_builder.heads_up, content: '<p>' + charitable_builder.error_already_started_campaign + '</p>', icon: 'fa fa-exclamation-circle', type: 'orange', buttons: { confirm: { text: charitable_builder.ok, btnClass: 'btn-confirm', keys: [ 'enter' ], action: function() { s.templateID = theButton.closest('.charitable-template').data('template-code'); s.templateLabel = theButton.closest('.charitable-template').data('template-label'); app.updateTemplateID( s.templateID, s.templateLabel ); s.primaryThemeColorBase = s.primaryThemeColor = theButton.closest('.charitable-template').data('template-primary'); s.secondaryThemeColorBase = s.secondaryThemeColor = theButton.closest('.charitable-template').data('template-secondary'); s.tertiaryThemeColorBase = s.tertiaryThemeColor = theButton.closest('.charitable-template').data('template-tertiary'); s.buttonThemeColorBase = s.buttonThemeColor = theButton.closest('.charitable-template').data('template-button'); elements.$primaryThemeColorBase.val( s.primaryThemeColorBase ); elements.$secondaryThemeColorBase.val( s.secondaryThemeColorBase ); elements.$tertiaryThemeColorBase.val( s.tertiaryThemeColorBase ); elements.$buttonThemeColorBase.val( s.buttonThemeColorBase ); $('input[name="layout__advanced__theme_color_primary"]').val( s.primaryThemeColor ); $('input[name="layout__advanced__theme_color_secondary"]').val( s.secondaryThemeColor ); $('input[name="layout__advanced__theme_color_tertiary"]').val( s.tertiaryThemeColor ); $('input[name="layout__advanced__theme_color_button"]').val( s.buttonThemeColor ); document.querySelector('input[name="layout__advanced__theme_color_primary"]').dispatchEvent(new Event('input', { bubbles: true })); document.querySelector('input[name="layout__advanced__theme_color_secondary"]').dispatchEvent(new Event('input', { bubbles: true })); document.querySelector('input[name="layout__advanced__theme_color_tertiary"]').dispatchEvent(new Event('input', { bubbles: true })); document.querySelector('input[name="layout__advanced__theme_color_button"]').dispatchEvent(new Event('input', { bubbles: true })); // update the template screen UI, first clearing any "current" labels, etc. $('#charitable-template-list .charitable-template').removeClass('active'); $('#charitable-template-list .charitable-banner-container').each( function() { $( this ).addClass('charitable-hidden'); $( this ).parent().find('.template-buttons').removeClass('charitable-hidden'); }); theButton.closest('.charitable-template').addClass('active'); theButton.closest('.charitable-template').find('.template-buttons').addClass('charitable-hidden'); theButton.closest('.charitable-template').find('.charitable-banner-container').removeClass('charitable-hidden'); // Update the text. $('.charitable-setup-desc.secondary-text strong.template-name').html( s.templateLabel ); wpchar.debug('chose this path'); app.restartForm( s.templateID, 'design', s.templateLabel ); app.restartTemplateScreen( s.templateID ); } }, cancel: { text: charitable_builder.cancel, keys: [ 'esc' ] } } } ); } } ); app.showUpgradeBanner(); }, /** * Restart the template page to reflect any current template changes. * * @since 1.8.0 * * @param {boolean} templateID Template slug. * */ restartTemplateScreen: function( templateID = 0 ) { if ( templateID === '' || templateID === 0 ) { templateID = s.templateID; } if ( templateID === '' || templateID === 0) { return; } const templateList = $('.charitable-template-list-container'); // first remove any 'preview' buttons in the thumbnails. templateList.find('.template-buttons').remove('.preview-campaign'); // replace the "create campaign" buttons with the "update campaign" buttons. templateList.find('.button.create-campaign').removeClass('create-campaign').addClass('update-campaign').html( charitable_builder.update_campaign ); // remove any active charitable-templates so we can reset things. templateList.find('.charitable-template').removeClass('active'); templateList.find('.charitable-template .charitable-banner-container').addClass('charitable-hidden'); // now find the charitable-template with a data attr "template code" that matches the templateID. templateList.find('.charitable-template[data-template-code="' + templateID + '"]').addClass('active'); templateList.find('.charitable-template[data-template-code="' + templateID + '"] .charitable-banner-container').removeClass('charitable-hidden'); }, /** * Restart the forms, restart key values. * * @since 1.8.0 * * @param {boolean} templateID Template slug. * @param {boolean} panel Panel slug. * @param {boolean} templateLabel Text/label of template. * */ restartForm: function( templateID = 0, panel = 'design', templateLabel = false ) { app.updateTemplateID( templateID, templateLabel ); app.showLoadingOverlay(); var data = { action : 'charitable_get_campaign_builder_template_data', id : templateID, title : s.campaignTitle, nonce : charitable_builder.nonce }; $.post( charitable_builder.ajax_url, data, function( response ) { if ( response.success ) { // Clear all hidden fields that represent placed field son preview form, if we are starting over ore resetting. $('#charitable-field-options .charitable-layout-options-group-inner').find('.charitable-panel-field').remove(); $('#charitable-field-options .charitable-select-field-notice').show(); s.quilled = []; elements.$nextFieldId.val( 0 ); app.hideLoadingOverlay(); var previewLayout = typeof response.data.preview !== 'undefined' ? response.data.preview : false, previewFieldOptions = typeof response.data.field_options !== 'undefined' ? response.data.field_options : false, previewTabOptions = typeof response.data.tab_options !== 'undefined' ? response.data.tab_options : false, previewAdvancedOptions = typeof response.data.advanced !== 'undefined' ? response.data.advanced : false; if ( previewLayout ) { app.addLayoutToPreview( previewLayout ); } else { wpchar.debug( 'previewLayout is false or not defined' ); } if ( previewFieldOptions ) { app.addFieldOptions( previewFieldOptions ); } else { wpchar.debug( 'previewFieldOptions is false or not defined' ); } if ( previewTabOptions ) { app.addTabOptions( previewTabOptions ); } else { wpchar.debug( 'previewTabOptions is false or not defined' ); } if ( previewAdvancedOptions ) { app.addAdvancedOptions( previewAdvancedOptions ); } else { wpchar.debug( 'previewAdvancedOptions is false or not defined' ); } if ( Charitable.Admin.Builder.DragFields && typeof Charitable.Admin.Builder.DragFields.ready === 'function' ) { Charitable.Admin.Builder.DragFields.ready(); } app.updateFormHiddenFields(); app.updateFormHiddenFieldID(); // if ( ! s.didInitHTMLEditorFields ) { $( '.campaign-builder-htmleditor' ).each( function() { app.initHTMLEditorFields( $( this ) ); }); $( '.campaign-builder-htmleditor-min' ).each( function() { app.initHTMLEditorFields( $( this ), true ); }); s.didInitHTMLEditorFields = true; // } // check sections to see if there are fields. elements.$preview.find('.charitable-field-section').each( function() { app.checkFieldTargetState( $( this ) ); }); // check recommended fields and check/uncheck depending on what was loaded. app.checkAllRecommendedFields(); // Goal and End Date checks app.updateGoalRelatedItems(); app.updateEndDateRelatedItems(); // swiitching over to the design panel view. if ( panel ) { app.panelSwitch( 'design' ); } // Handle fields that will likely appear AFTER a template select or dynamic fields added after a form reset. // This handles the unique suggested donation area that creates dynamic rows. $( '.charitable-campaign-suggested-donations-mini' ).each( function() { app.initSuggestedDonationsMini( $( this ) ); app.updateSuggestdDonationsMiniRowsFromSettings( $( this ) ); }); // Check the field max values and set buttons in "add layout" accordingly. app.checkFieldAllow(); app.checkFieldMax(); // Was there a description in the template data? if ( typeof response.data.settings.general.description !== 'undefined' && response.data.settings.general.description != '' ) { s.campaignDescription = response.data.settings.general.description; elements.$settingsPanel.find( 'input[name="settings[general][description]"').val( s.campaignDescription ); } // Finally, make sure to note that the campaign isn't saved. app.setCampaignNotSaved(); $builder.trigger( 'charitableEditorScreenStart' ); } else { app.formSaveError( response.data ); } } ).fail( function( xhr, textStatus, e ) { // eslint-disable-line app.formSaveError(); } ).always( function() { } ); }, /** * Check and see if it's ok to add/remove the "no fields preview" UI. * * @since 1.8.0 * * @param {array} previewAdvancedOptions Advanced Options * */ checkNoFieldsPreview( forceModeOff = false ) { // note: we ignore fields in special tab sections. if ( forceModeOff === false && elements.$preview.find('.charitable-field-section[data-section-type="fields"] .charitable-field').length === 0 && typeof( charitable_builder.no_field_preview ) !== 'undefined' ) { // Is there any fields in preview? If not add the no-fields-preview as it goes into the void. // $('.charitable-campaign-preview-loader').after( charitable_builder.no_field_preview ); $('#charitable-design-wrap').addClass('no-fields-mode'); if ( $builder.find( '.charitable-no-fields-area' ).hasClass('charitable-hidden') ) { $builder.find( '.charitable-no-fields-area' ).removeClass('charitable-hidden'); } } else if ( forceModeOff !== false ) { if ( ! $builder.find( '.charitable-no-fields-area' ).hasClass('charitable-hidden') ) { $builder.find( '.charitable-no-fields-area' ).addClass('charitable-hidden'); } $('#charitable-design-wrap').removeClass('no-fields-mode'); } else { if ( ! $builder.find( '.charitable-no-fields-area' ).hasClass('charitable-hidden') ) { $builder.find( '.charitable-no-fields-area' ).addClass('charitable-hidden'); } $('#charitable-design-wrap').removeClass('no-fields-mode'); } }, /** * * * @since 1.8.0 * * @param {array} previewAdvancedOptions Advanced Options * */ checkFieldTargetState( $section = false ) { if ( false === $section ) { return; } if ( $section.data('section-type') !== 'fields' && $section.data('section-type') !== 'tabs' ) { return; } if ( $section.data('section-type') === 'fields' ) { if ( $section.find('.charitable-field').length === 0 ) { $section.removeClass('charitable-field-target-inactive').addClass('charitable-field-target'); } else { $section.removeClass('charitable-field-target').addClass('charitable-field-target-inactive'); } } else if ( $section.data('section-type') === 'tabs' ) { if ( $section.find('.tab_content_item.active .charitable-field').length === 0 ) { $section.find('.tab_content_item.active').removeClass('empty-tab').addClass('empty-tab'); } else { $section.find('.tab_content_item.active').removeClass('empty-tab'); } } }, /** * Setup values in the advanced tab area based on passed in parameters, likely coming from an ajax call when restarting the form. * * @since 1.8.0 * * @param {array} previewAdvancedOptions Advanced Options * */ addAdvancedOptions( previewAdvancedOptions ) { // update advanced options if they came with the theme var advancedFieldsInTab = $('.charitable-layout-options-tab-advanced').find('input, select'); advancedFieldsInTab.each(function() { var $thisInput = $( this ), advancedFieldId = $thisInput.data('advanced-field-id'); if ( typeof previewAdvancedOptions[advancedFieldId] !== 'undefined' && advancedFieldId != '' ) { if ( $thisInput.is('select') ) { $thisInput.val( previewAdvancedOptions[advancedFieldId] ).change(); } else { $thisInput.val( previewAdvancedOptions[advancedFieldId] ); } } }); }, /** * Add HTML of field options to preview. * * @since 1.8.0 * * @param {string} previewFieldOptions Advanced Options * */ addFieldOptions( previewFieldOptions ) { elements.$fieldOptions.find('.charitable-layout-options-group-inner .charitable-select-field-notice').after( previewFieldOptions ); }, /** * Add HTML of tab options to preview. * * @since 1.8.0 * * @param {string} previewTabOptions Advanced Options * */ addTabOptions( previewTabOptions ) { elements.$fieldOptions.find('.charitable-layout-options-tab.charitable-layout-options-tab-tabs .charitable-layout-options-group-inner').html( previewTabOptions ); }, /** * Add HTML of the layout to preview area. * * @since 1.8.0 * * @param {string} previewLayout Advanced Options * */ addLayoutToPreview( previewLayout ) { elements.$preview.find('.charitable-design-wrap').replaceWith( previewLayout ); }, /** * Add align field listeners to field settings in the left column for design panel. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ alignFieldEvents: function( $builder ) { // Number Slider field: update hints. $builder.on( 'click', '.charitable-panel-field-align a', function( e ) { e.preventDefault(); var clickedLink = $( this ), panelField = clickedLink.closest( '.charitable-panel-field' ), alignValue = '' !== clickedLink.data('align-value') ? clickedLink.data('align-value') : 'center'; panelField.find('span').removeClass('active'); panelField.find('input[type="hidden"').val( alignValue ); clickedLink.parent().addClass('active'); app.setCampaignNotSaved(); } ); }, /** * Add number slider events listeners to field settings in the left column for design panel. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ numberSliderEvents: function( $builder ) { elements.$fieldOptions.on( 'input change', 'input[type="range"]', function( e ) { // eslint-disable-line var minimum_value = ( $( this ).attr('min-actual') ) ? parseInt( $( this ).attr('min-actual') ) : 0, scrolled_value = $( this ).val(); if ( minimum_value > 0 ) { if ( scrolled_value <= minimum_value ) { $( this ).val( minimum_value ); $( this ).next().addClass('min-reach'); } else { $( this ).next().removeClass('min-reach'); } } app.setCampaignNotSaved(); } ); // Number Slider field: update hints. $builder.on( 'change input', '.charitable-panel-field-number-slider input[type=range]', function( event ) { var hintEl = $( event.target ).siblings( '.charitable-number-slider-hint' ); hintEl.attr( 'data-hint', event.target.value ); hintEl.html( event.target.value + hintEl.data('symbol') + '<small>minimum</small>' ); } ); // Minimum update. $builder.on( 'input', '.charitable-field-option-row-min_max .charitable-input-row .charitable-number-slider-min', app.fieldNumberSliderUpdateMin ); // Maximum update. $builder.on( 'input', '.charitable-field-option-row-min_max .charitable-input-row .charitable-number-slider-max', app.fieldNumberSliderUpdateMax ); // Change default input value. $builder.on( 'input', '.charitable-number-slider-default-value', _.debounce( app.changeNumberSliderDefaultValue, 500 ) // eslint-disable-line ); // Change step value. $builder.on( 'input', '.charitable-number-slider-step', _.debounce( app.changeNumberSliderStep, 500 ) // eslint-disable-line ); // Check step value. $builder.on( 'focusout', '.charitable-number-slider-step', app.checkNumberSliderStep ); // Change value display. $builder.on( 'input', '.charitable-number-slider-value-display', _.debounce( app.changeNumberSliderValueDisplay, 500 ) // eslint-disable-line ); // Change min value. $builder.on( 'input', '.charitable-number-slider-min', _.debounce( app.changeNumberSliderMin, 500 ) // eslint-disable-line ); // Change max value. $builder.on( 'input', '.charitable-number-slider-max', _.debounce( app.changeNumberSliderMax, 500 ) // eslint-disable-line ); }, /** * Change number slider min option. * * @since 1.8.0 * * @param {object} event Input event. */ changeNumberSliderMin: function( event ) { var fieldID = $( event.target ).parents( '.charitable-field-option-row' ).data( 'fieldId' ); var value = parseFloat( event.target.value ); if ( isNaN( value ) ) { return; } app.updateNumberSliderDefaultValueAttr( fieldID, event.target.value, 'min' ); }, /** * Change number slider max option. * * @since 1.8.0 * * @param {object} event Input event. */ changeNumberSliderMax: function( event ) { var fieldID = $( event.target ).parents( '.charitable-field-option-row' ).data( 'fieldId' ); var value = parseFloat( event.target.value ); if ( isNaN( value ) ) { return; } app.updateNumberSliderDefaultValueAttr( fieldID, event.target.value, 'max' ) .updateNumberSliderStepValueMaxAttr( fieldID, event.target.value ); }, /** * Change number slider value display option. * * @since 1.8.0 * * @param {object} event Input event. */ changeNumberSliderValueDisplay: function( event ) { var str = event.target.value; var fieldID = $( event.target ).parents( '.charitable-field-option-row' ).data( 'fieldId' ); var defaultValue = document.getElementById( 'charitable-field-option-' + fieldID + '-default_value' ); if ( defaultValue ) { app.updateNumberSliderHintStr( fieldID, str ) .updateNumberSliderHint( fieldID, defaultValue.value ); } }, /** * Change number slider step option. * * @since 1.8.0 * * @param {object} event Input event. */ changeNumberSliderStep: function( event ) { var value = parseFloat( event.target.value ); if ( isNaN( value ) ) { return; } var max = parseFloat( event.target.max ), min = parseFloat( event.target.min ), fieldID = $( event.target ).parents( '.charitable-field-option-row' ).data( 'fieldId' ); if ( value <= 0 ) { return; } if ( value > max ) { event.target.value = max; return; } if ( value < min ) { event.target.value = min; return; } app.updateNumberSliderAttr( fieldID, value, 'step' ) .updateNumberSliderDefaultValueAttr( fieldID, value, 'step' ); }, /** * Check number slider step option. * * @since 1.8.0 * * @param {object} event Focusout event object. */ checkNumberSliderStep: function( event ) { var value = parseFloat( event.target.value ), $input = $( this ); if ( ! isNaN( value ) && value > 0 ) { return; } $.confirm( { title : charitable_builder.heads_up, content : charitable_builder.error_number_slider_increment, icon : 'fa fa-exclamation-circle', type : 'orange', buttons : { confirm: { text: charitable_builder.ok, btnClass: 'btn-confirm', keys: [ 'enter' ], action: function() { $input.val( '' ).trigger( 'focus' ); } } } } ); }, /** * Change number slider default value option. * * @since 1.8.0 * * @param {object} event Input event. */ changeNumberSliderDefaultValue: function( event ) { var value = parseFloat( event.target.value ); if ( ! isNaN( value ) ) { var max = parseFloat( event.target.max ), min = parseFloat( event.target.min ), fieldID = $( event.target ).parents( '.charitable-field-option-row-default_value' ).data( 'fieldId' ); if ( value > max ) { event.target.value = max; return; } if ( value < min ) { event.target.value = min; return; } app.updateNumberSlider( fieldID, value ) .updateNumberSliderHint( fieldID, value ); } }, /** * Update number slider default value attribute. * * @since 1.8.0 * * @param {number} fieldID Field ID. * @param {*} newValue Default value attribute. * @param {*} attr Attribute name. * * @returns {object} App instance. */ updateNumberSliderDefaultValueAttr: function( fieldID, newValue, attr ) { var input = document.getElementById( 'charitable-field-option-' + fieldID + '-default_value' ); if ( input ) { var value = parseFloat( input.value ); input.setAttribute( attr, newValue ); newValue = parseFloat( newValue ); if ( 'max' === attr && value > newValue ) { input.value = newValue; $( input ).trigger( 'input' ); } if ( 'min' === attr && value < newValue ) { input.value = newValue; $( input ).trigger( 'input' ); } } return this; }, /** * Update number slider value. * * @since 1.8.0 * * @param {number} fieldID Field ID. * @param {string} value Number slider value. * * @returns {object} App instance. */ updateNumberSlider: function( fieldID, value ) { var numberSlider = document.getElementById( 'charitable-number-slider-' + fieldID ); if ( numberSlider ) { numberSlider.value = value; } return this; }, /** * Update number slider attribute. * * @since 1.8.0 * * @param {number} fieldID Field ID. * @param {mixed} value Attribute value. * @param {*} attr Attribute name. * * @returns {object} App instance. */ updateNumberSliderAttr: function( fieldID, value, attr ) { var numberSlider = document.getElementById( 'charitable-number-slider-' + fieldID ); if ( numberSlider ) { numberSlider.setAttribute( attr, value ); } return this; }, /** * Update number slider hint string. * * @since 1.8.0 * * @param {number} fieldID Field ID. * @param {string} str Hint string. * * @returns {object} App instance. */ updateNumberSliderHintStr: function( fieldID, str ) { var hint = document.getElementById( 'charitable-number-slider-hint-' + fieldID ); if ( hint ) { hint.dataset.hint = str; } return this; }, /** * Update number slider Hint value. * * @since 1.8.0 * * @param {number} fieldID Field ID. * @param {string} value Hint value. * * @returns {object} App instance. */ updateNumberSliderHint: function( fieldID, value ) { var hint = document.getElementById( 'charitable-number-slider-hint-' + fieldID ); if ( hint ) { hint.innerHTML = wpchar.sanitizeHTML( hint.dataset.hint ).replace( '{value}', '<b>' + value + '</b>' ); } return this; }, /** * Update min attribute. * * @since 1.8.0 * * @param {object} event Input event. */ fieldNumberSliderUpdateMin: function( event ) { var $options = $( event.target ).parents( '.charitable-field-option-row-min_max' ), max = parseFloat( $options.find( '.charitable-number-slider-max' ).val() ), current = parseFloat( event.target.value ); if ( isNaN( current ) ) { return; } if ( max <= current ) { event.preventDefault(); this.value = max; return; } var fieldId = $options.data( 'field-id' ), numberSlider = $builder.find( '#charitable-field-' + fieldId + ' input[type="range"]' ); numberSlider.attr( 'min', current ); }, /** * Update max attribute. * * @since 1.8.0 * * @param {object} event Input event. */ fieldNumberSliderUpdateMax: function( event ) { var $options = $( event.target ).parents( '.charitable-field-option-row-min_max' ), min = parseFloat( $options.find( '.charitable-number-slider-min' ).val() ), current = parseFloat( event.target.value ); if ( isNaN( current ) ) { return; } if ( min >= current ) { event.preventDefault(); this.value = min; return; } var fieldId = $options.data( 'field-id' ); var numberSlider = $builder.find( '#charitable-field-' + fieldId + ' input[type="range"]' ); numberSlider.attr( 'max', current ); }, /** * Update max attribute for step value. * * @since 1.8.0 * * @param {number} fieldID Field ID. * @param {*} newValue Default value attribute. * * @returns {object} App instance. */ updateNumberSliderStepValueMaxAttr: function( fieldID, newValue ) { var input = document.getElementById( 'charitable-field-option-' + fieldID + '-step' ); if ( input ) { var value = parseFloat( input.value ); input.setAttribute( 'max', newValue ); newValue = parseFloat( newValue ); if ( value > newValue ) { input.value = newValue; $( input ).trigger( 'input' ); } } return this; }, /** * Builder was visited via back button in browser. * * @since 1.8.0 * * @returns {boolean} True if the builder was visited via back button in browser. */ isVisitedViaBackButton: function() { if ( ! performance ) { // todo: check this. return false; } var isVisitedViaBackButton = false; performance.getEntriesByType( 'navigation' ).forEach( function( nav ) { if ( nav.type === 'back_forward' ) { isVisitedViaBackButton = true; } } ); return isVisitedViaBackButton; }, /** * Remove loading overlay. * * @since 1.8.0 */ hideLoadingOverlay: function() { var $overlay = $( '#charitable-builder-overlay' ); $overlay.addClass( 'fade-out' ); setTimeout( function() { $overlay.hide(); }, 200 ); }, /** * Attempts to load a code editor when the page loads, or at other times called. * * @since 1.8.4.3. */ initCodeEditor: function() { // if a textarea for a coded field is present, init the code editor. if ( $( '.campaign-builder-codeeditor' ).length > 0 ) { var field_id = ''; // get the field id which should be the number after charitable-panel-field-settings-field_html_html_ in the id attr. // for each element that has the id 'charitable-panel-field-settings-field_html_html_' + field_id, init the editor. $( '.campaign-builder-codeeditor' ).each( function() { // does this element have 'charitable-panel-field-settings-field_html_html_' in the id? if ( $( this ).attr( 'id' ).indexOf( 'charitable-panel-field-settings-field_html_html_' ) !== -1 ) { field_id = $( this ).attr( 'id' ).replace( 'charitable-panel-field-settings-field_html_html_', '' ); wpchar.debug( 'field_id: ' + field_id ); $builder.trigger( 'charitableFieldAddHTML', [ field_id, 'html' ] ); } }); } }, /** * Show loading overlay. * * @since 1.8.0 */ showLoadingOverlay: function() { var $overlay = $( '#charitable-builder-overlay' ); $overlay.removeClass( 'fade-out' ); $overlay.show(); }, /** * Update some element of form UI. * Element and value might be to update something speicfic, if not passed assume it's everything. * * @since 1.8.0 * * @param {string} element Template slug. * @param {string} value Text/label of template. * */ updateFormUI: function( element = false, value = false ) { var title = false; // Title. if ( element === 'title' ) { title = value; } else { title = $( 'input.charitable-form-name' ).val(); } // Clean the string. title = title.replace(/[^a-z0-9 _.,!"'/$]/gi, ''); // Should we allow a blank title even temp? // if ( '' === $.trim(title) ) { // title = s.campaignTitle; // } // Campaign Title. elements.$campaignNameTopBanner = $( 'input.charitable-form-name' ); // the campaign title in the top banner elements.$campaignNamePreview = $( '.charitable-preview .charitable-form-name' ); // in the "preview" window // elements.$campaignNameGeneralSettings = $( '#charitable-panel-settings #charitable-panel-field-settings-campaign_title' ); // this is the name field in settings -> general elements.$campaignNameFieldTitleSettings = $('input.charitable-campaign-builder-title'); // this is all the campaign title block input text boxes (left panel) elements.$campaignNameTopBanner.val( title ); elements.$campaignNamePreview.html( title ); // elements.$campaignNameGeneralSettings.val( title ); elements.$campaignNameFieldTitleSettings.val( title ); elements.$preview.find('.charitable-field-campaign-title .charitable-campaign-builder-placeholder-preview-text').html( '<h1 class="charitable-campaign-title">' + ( title ) + '</h1>' ); // elements.$preview.find('.charitable-field-campaign-title .charitable-campaign-builder-placeholder-preview-text').html( '<h5>' + ( title ) + '</h5>' ); if ( element === 'title' ) { s.campaignTitle = title; app.resizeTopCampaignTitleInputBox(); } }, /** * Element bindings. * * @since 1.8.0 */ bindUIActions: function() { // Campaign Title. app.bindAutoResizeCampaignTitle(); app.bindUIEditCampaignTitle(); app.bindCampaignTitleBlockTextField(); // General Panels. app.bindUIActionsPanels(); // Fields Panel. app.bindUIActionsFields(); // Preview. app.bindUIActionsPreview(); // Save and Exit. app.bindUIActionsSaveExit(); // General/ global. app.bindUIActionsGeneral(); // Tab related. app.bindUITabs(); // Listen to form and tag form not as saved if there is a change. $builder.on( 'change', 'input, textarea, select, checkbox, radio', function( e ) { // eslint-disable-line app.setCampaignNotSaved(); } ); // Advanced Layout Options app.bindUILayoutOptionsAdvanced(); // Setting "Reveals" (like Recurring Donations). app.bindUISettingsRevealGroups(); // Auto-santitize numeric/money fields. app.bindUIMoneyTextFields(); // Check Field Conditionals app.checkFieldConditionals(); $builder.on( 'change', 'select#charitable-panel-field-settings-campaign_campaign_creator_id', function( e ) { // eslint-disable-line app.updateCampaignCreatorInfo(); } ); $builder.on( 'click', 'div#charitable-marketing-form a.button-link, div#charitable-payment-form a.button-link, div#charitable-feedback-form a.button-link', function( e ) { // eslint-disable-line e.preventDefault(); app.initFeedbackForms( $(this) ); } ); // Suggested Donation Amounts $builder.on( 'keyup', 'table.charitable-campaign-suggested-donations-mini input', function( e ) { // eslint-disable-line var field_id = parseInt( $(this).closest('.charitable-panel-field').data('field-id') ); if ( field_id > 0 ) { var theIndex = $(this).index( '.charitable-panel-field[data-field-id="' + field_id + '"] table.charitable-campaign-suggested-donations-mini input[type="text"].campaign_suggested_donations' ); app.updateSuggestDonationsSettings( $(this), theIndex ); } } ); $builder.on( 'change keyup blur input', 'table.charitable-campaign-suggested-donations input[type="text"].campaign_suggested_donations', function( e ) { // eslint-disable-line var theIndex = $(this).index( '.charitable-campaign-suggested-donations input[type="text"].campaign_suggested_donations' ), field_name = $(this).attr('name'); if ( field_name.indexOf('recurring') < 1 ) { app.updateSuggestDonationsSettings( $(this), theIndex ); } } ); $builder.on( 'change', '.charitable-campaign-builder-allow-custom-donations input[type="checkbox"]', function( e ) { // eslint-disable-line // make sure all checkboxes with the same "charitable-campaign-builder-allow-custom-donations" class are matching the same value. $('.charitable-campaign-builder-allow-custom-donations input[type="checkbox"]').prop('checked', $(this).is(':checked') ); app.updateAllowCustomDonationSettings( $( this ).is(':checked') ); } ); $builder.on( 'change', 'input[type="radio"].campaign_suggested_donations', function( e ) { // eslint-disable-line var field_id = parseInt( $(this).closest('.charitable-panel-field').data('field-id') ), // eslint-disable-line field_name = $(this).attr('name'); // eslint-disable-line // do not proceed with updating other suggest amount boxes if the field_name contains the string 'recurring' (only do this for the default non-recurring). if ( field_name.indexOf('recurring') < 1 ) { app.updateSuggestedDonationAmountDefault( $( this ).val() ); } } ); // General/ global. app.bindUIInputRange(); $builder.on( 'click', '.education-buttons button.update-to-pro-link', function( e ) { // eslint-disable-line // if there is a link right above this button element, have the window open to the url that is assigned to the href in that link. if ( $( this ).prev('a').length > 0 ) { window.open( $( this ).prev('a').attr('href'), '_blank' ); } else { window.open("https://wpcharitable.com/lite-vs-pro/", "_blank"); } } ); }, /** * Element bindings for general panel tasks. * * @since 1.8.0 */ bindUILayoutOptionsAdvanced: function() { // This is the area at the top of the builder where you can change the campaign title. $builder.on( 'change', 'select#charitable-design-layout-options-advanced-tab-style', function( e ) { e.preventDefault(); var $this = $( this ), $preview_nav = $( 'nav.charitable-campaign-preview-nav' ); // get all possible values so we can review any possible css that might exist? $( $this ).find('option').each(function() { $preview_nav.removeClass('tab-style-' + this.value ); }); $preview_nav.addClass( 'tab-style-' + $this.find(":selected").val() ); } ); $builder.on( 'change', 'select#charitable-design-layout-options-advanced-tab-size', function( e ) { e.preventDefault(); var $this = $( this ), $preview_nav = $( 'nav.charitable-campaign-preview-nav' ); // get all possible values so we can review any possible css that might exist? $( $this ).find('option').each(function() { $preview_nav.removeClass('tab-size-' + this.value ); }); $preview_nav.addClass( 'tab-size-' + $this.find(":selected").val() ); } ); }, /** * Add new group tab. * * @since 1.8.0 * * @param {object} el jQuery element. * @param {object} e Event. * */ tabGroupsAdd: function( el, e ) { e.preventDefault(); // count the number of tabs currently created. var count = elements.$sortableTabContent.find('.tab_content_item').length; if ( count >= s.maxNumberOfTabs ) { // 4 for now is the tab limit app.formGenericNotice('You cannot have more than ' + s.maxNumberOfTabs + ' tabs in your campaign template.'); return; } var $this = $( el ), $groupLast = $this.parent().find( '.charitable-group.charitable-layout-options-tab-group.hidden' ).last(), $newGroup = $groupLast.clone(), tab_content = elements.$preview.find('.tab-content'), default_tab_content_type = 'html'; // Get the cloned group_id and add +1. var dataList = $(".charitable-group.charitable-layout-options-tab-group").map(function() { return parseInt($(this).attr("data-group_id")); }).get(); var groupID = Math.max.apply(null, dataList) + 1; if ( typeof groupID === 'undefined' ) { app.formGenericError('Error ecountered attempting to add another tab.'); return; } $newGroup.attr( 'data-group_id', groupID ); // update the data-tab-id. $newGroup.attr( 'data-tab-id', groupID ); $newGroup.find('.charitable-group-row').attr( 'data-tab-id', groupID ); // Replace the __xx__ in the names of the fields in the clone with the groupID, thereby making them unique. $newGroup.find('input, select, textarea, label').each( function(index) { // eslint-disable-line var $this = $( this ), forAttr = $this.attr('for'), nameAttr = $this.attr('name'), idAttr = $this.attr('id'); if ( typeof idAttr !== 'undefined' && idAttr !== false ) { $this.attr( 'id', $this.attr('id').replace('_xxx_', '_' + groupID + '_') ); } if ( typeof nameAttr !== 'undefined' && nameAttr !== false ) { $this.attr( 'name', $this.attr('name').replace('_xxx_', '_' + groupID + '_') ); } // check if there is a "for" (label) and update that too. if ( typeof forAttr !== 'undefined' && forAttr !== false ) { $this.attr( 'for', $this.attr('for').replace('_xxx_', '_' + groupID + '_') ); } }); // Assign default values to items that have been cloned in the group. $newGroup.find( 'input[name="tabs__' + groupID + '__title"]' ).val('New Tab'); $newGroup.find( 'textarea[name="tabs__' + groupID + '__desc"]' ).html('Content'); // Whip the active class to reset the tab area on the left. $('.charitable-layout-options-tab-group').removeClass('active'); $newGroup.addClass('active'); // Make sure the clone is open (not closed) and not hidden. $newGroup.removeClass('charitable-closed').addClass('charitable-open').removeClass('hidden').find('.charitable-angle-right').removeClass('charitable-angle-right').addClass('charitable-angle-down'); $this.before( $newGroup ); app.bindUIActionPanelsTabs(); app.checkHideTabNavigation(); // Update now the preview area, making the latest new tab the active one (first clearing the actives). $('nav.charitable-campaign-preview-nav ul li').removeClass('active'); tab_content.find('ul li').removeClass('active'); $('nav.charitable-campaign-preview-nav ul').append('<li data-tab-type="html" data-tab-id="' + groupID + '" class="tab_title active" id="tab_' + groupID + '_title"><a href="#">' + charitable_builder.new_tab + '</a></li>'); tab_content.find('ul').append('<li id="tab_' + groupID + '_content" class="tab_content_item empty-tab active tab_type_' + default_tab_content_type + '" data-tab-type="' + default_tab_content_type + '" data-tab-id="' + groupID + '"><div class="charitable-tab-wrap ui-sortable"><p class="empty-tab-notice">' + charitable_builder.empty_tab + '</p></div></li>'); tab_content.removeClass('empty-tabs'); tab_content.find('.no-tab-notice').remove(); $builder.trigger( 'charitableAddNewTab', groupID ); }, //--------------------------------------------------------------------// // General Panels //--------------------------------------------------------------------// /** * Element bindings for tabs. * * @since 1.8.0 */ bindUITabs: function() { // Conditional add new group tab. $builder.on( 'click', 'button.charitable-tab-groups-add', function( e ) { app.tabGroupsAdd( this, e ); } ); // Moving the tabs around. $builder.find('.charitable-layout-options-tab-tabs .charitable-layout-options-group-inner').sortable({ handle: '.charitable-draggable', update: function( event, ui ) { // eslint-disable-line // get the list of tabs in the fields var dataList = $(".charitable-group.charitable-layout-options-tab-group").map(function() { if ( ! $(this).hasClass('hidden') ) { return parseInt($(this).attr("data-group_id")); } }).get(); var activeList = $(".charitable-group.charitable-layout-options-tab-group").map(function() { if ( $(this).hasClass('active') ) { return parseInt($(this).attr("data-group_id")); } }).get(); $('nav.charitable-campaign-preview-nav ul').empty(); dataList.forEach( function( groupID ) { // do something with `item` var $tab = $("#charitable-field-options").find('[data-group_id="' + groupID + '"]'), textFieldnName = groupID, isActive = activeList.indexOf( groupID ) >= 0 ? 'active' : '', tabType = ( groupID !== 0 && '' !== $tab.find('input[name="tabs__' + textFieldnName + '__type"').val() ) ? $tab.find('input[name="tabs__' + textFieldnName + '__type"').val() : 'html', tabTitle = $tab.find('input[name="tabs__' + textFieldnName + '__title"').val(); $('nav.charitable-campaign-preview-nav ul').append('<li data-tab-type="' + tabType + '" data-tab-id="' + groupID + '" class="tab_title ' + isActive + '" id="tab_' + groupID + '_title"><a href="#">' + tabTitle + '</a></li>'); }); } }); $builder.on( 'click', 'input, select, textarea, .ql-editor', '.charitable-layout-options-tab-tabs .charitable-layout-options-group-inner .charitable-layout-options-tab-group', function( e ) { // eslint-disable-line if ( ! $( this ).closest('.charitable-layout-options-tab-group').hasClass( 'active' ) ) { var group_id = $( this ).closest('.charitable-layout-options-tab-group').data('group_id'); $('.charitable-preview nav.charitable-campaign-preview-nav li[data-tab-id="' + group_id + '"] a').click(); } } ); // Tab Links that do things in the admin UI. $builder.on( 'click', 'a.charitable-configure-tab-settings', function( e ) { // eslint-disable-line // make sure to switch over to the "tabs" tab under layout options app.fieldTabToggle('layout-options'); $('.charitable-layout-options-tab').removeClass('active'); $('.charitable-layout-options-tab.charitable-layout-options-tab-tabs').addClass('active'); } ); // Clickable Tabs $builder.on( 'click', 'nav li.tab_title a', function( e ) { // eslint-disable-line e.preventDefault(); var $preview = $( '.charitable-campaign-preview' ), tab_id = $( this ).parent().data('tab-id'), tab_type = $preview.find( 'li#tab_' + tab_id + '_title').attr( 'data-tab-type' ); // eslint-disable-line // clear the active states of the tabs and content areas in the preview area $('.tab-content ul li').removeClass('active'); $('nav li.tab_title').removeClass('active'); // make the clicked on tab and it's content area active $( this ).parent().addClass('active'); $('.tab-content ul li#tab_' + tab_id + '_content').addClass('active'); // make sure to switch over to the "tabs" tab under layout options $('.charitable-layout-options-tab').removeClass('active'); $('.charitable-layout-options-tab.charitable-layout-options-tab-tabs').addClass('active'); // Using cookies make sure the tabs are open or closed $( '.charitable-layout-options-tab' ).find('.charitable-layout-options-tab-group').each(function() { $( this ).removeClass('charitable-open'); var cookieValue = wpCookies.get( 'charitable_panel_layout_options_tabs_tab_open_' + $( this ).data('group_id') ); if ( cookieValue === 'true' ) { $( this ).addClass('charitable-open'); $( this ).find('.charitable-general-layout-heading a.charitable-toggleable-group i').addClass('charitable-angle-down'); $( this ).find('.charitable-general-layout-heading a.charitable-toggleable-group i').removeClass('charitable-angle-right'); $( this ).removeClass('charitable-closed'); } else { $( this ).removeClass('charitable-open'); $( this ).find('.charitable-general-layout-heading a.charitable-toggleable-group i').removeClass('charitable-angle-down'); $( this ).find('.charitable-general-layout-heading a.charitable-toggleable-group i').addClass('charitable-angle-right'); $( this ).addClass('charitable-closed'); } }); // now clear any of the left option panel 'tabs' from being active... then add active to the proper one $('.charitable-layout-options-tab .charitable-group').removeClass('active'); $(".charitable-layout-options-tab").find('[data-group_id=' + tab_id + ']').addClass('active').removeClass('charitable-closed'); $(".charitable-layout-options-tab").find('[data-group_id=' + tab_id + ']').find('.charitable-group-rows').show(); $(".charitable-layout-options-tab").find('[data-group_id=' + tab_id + ']').find('.charitable-toggleable-group i').removeClass('.charitable-angle-right').addClass('charitable-angle-down'); $( '#layout-options a' ).click(); $("#charitable-preview-tab-container").addClass('active'); wpCookies.set( 'charitable_panel_tab_section_tab_id', tab_id, 2592000 ); // 1 month. wpCookies.set( 'charitable_panel_layout_options_tabs_tab_open_' + tab_id, true, 2592000 ); // 1 month. wpCookies.set( 'charitable_panel_content_section', '', 2592000 ); wpCookies.set( 'charitable_panel_active_field_id', '', 2592000 ); } ); // Change the tab type when the select dropdown is changed. $builder.on( 'change', '.charitable-group select.tab_type', function( e ) { e.preventDefault(); var $this = $( this ), group_id = $this.closest('.charitable-group').data('group_id'), $preview = $( '.charitable-campaign-preview' ), selected_value = $this.val(); // Update the tabs in the preview area with this new type. $preview.find('nav li.tab_title[data-tab-id=' + group_id + ']').attr( 'data-tab-type', selected_value ); $preview.find('div.tab-content ul li#tab_' + group_id + '_content').attr( 'data-tab-type', selected_value ); $preview.find('div.tab-content ul li#tab_' + group_id + '_content').removeClass (function (index, className) { return (className.match (/(^|\s)tab_type_\S+/g) || []).join(' '); }); $preview.find('div.tab-content ul li#tab_' + group_id + '_content').addClass( 'tab_type_' + selected_value ); var data = { action : 'charitable_tab_content_preview', type : selected_value, group_id : group_id, nonce : charitable_builder.nonce }; return $.post( charitable_builder.ajax_url, data, function( response ) { if ( response.success ) { $preview.find('div.tab-content ul li#tab_' + group_id + '_content').html( response.data.output ); } else { app.formSaveError( response.data ); } } ).fail( function( xhr, textStatus, e ) { // eslint-disable-line app.formSaveError(); } ).always( function() { } ); } ); $builder.on( 'input', 'input#charitable-panel-field-settings-charitable-campaign-enable-tabs', function( e ) { // eslint-disable-line const isChecked = $( this ).is(':checked'); if ( isChecked ) { // fade an disable the tab area on the preview. $("#charitable-preview-tab-container").addClass('disabled'); // also fade and disable the style/size tab attributes in the advanced tab. $("#charitable-design-layout-options-advanced-tab-style").prop('disabled', true).addClass('disabled'); $("#charitable-design-layout-options-advanced-tab-size").prop('disabled', true).addClass('disabled'); } else { // remove the fade on preview tabs. $("#charitable-preview-tab-container").removeClass('disabled'); // unfade and enable the style/size tab attributes in the advanced tab. $("#charitable-design-layout-options-advanced-tab-style").prop('disabled', false).removeClass('disabled'); $("#charitable-design-layout-options-advanced-tab-size").prop('disabled', false).removeClass('disabled'); } } ); $builder.on( 'input', 'input.charitable-settings-tab-visible-nav', function( e ) { // eslint-disable-line const isChecked = $( this ).is(':checked'), tabID = $( this ).closest('.charitable-tab-title-row').data('tab-id'); if ( isChecked ) { elements.$preview.find('nav li#tab_' + tabID + '_title').addClass('charitable-tab-hide'); } else { elements.$preview.find('nav li#tab_' + tabID + '_title').removeClass('charitable-tab-hide'); } } ); $builder.on( 'keydown', '.charitable-tab-title-row input[type="text"]', function( e ) { // eslint-disable-line var k = e.keyCode || e.which, ok = k >= 65 && k <= 90 || // A-Z ( k >= 96 ) && ( k <= 105 ) || // a-z ( k >= 35 ) && ( k <= 40 ) || // arrows ( k == 32 ) || // space ( e.ctrlKey && k == 65 ) || // Ctrl + A ( e.ctrlKey && k == 67 ) || // Ctrl + C ( e.ctrlKey && k == 88 ) || // Ctrl + X ( e.ctrlKey && k == 86 ) || // Ctrl + V ( e.metaKey && k == 65 ) || // command + a ( e.metaKey && k == 67 ) || // command + c ( e.metaKey && k == 88 ) || // command + x ( e.metaKey && k == 86 ) || // command + v ( k >= 96 && k <= 105 ) || // allow numbers entered from a number pad ( k == 110 || k == 190 ) || // period or decimal point ( k >= 37 && k <= 40 ) || // allow arrow keys ( k == 46 ) || // allow delete key ( k == 173 ) || // dash ( k == 8 ) || // backspaces ( k >= 48 && k <= 57 ); // only 0-9 (ok SHIFT options) if ( !ok || ( e.ctrlKey && e.altKey ) ) { e.preventDefault(); } } ); $builder.on( 'change', '.charitable-tab-title-row input[type="text"]', function( e ) { // eslint-disable-line // If the text input box is empty, then add a default value. if ( $( this ).val().trim() === '' ) { $( this ).val( 'New Tab' ); } } ); }, /** * Element bindings for input type range UI elements in settings, usually in left panel for 'design'. * * @since 1.8.0 */ bindUIInputRange: function() { /* charitable indicator */ $builder.on( 'mouseenter', 'input[type="range"].charitable-indicator-on-hover, .charitable-panel-field-align a', function( e ) { // eslint-disable-line var field_id = parseInt( $(this).closest('.charitable-panel-field').data('field-id') ); if ( field_id > 0 ) { elements.$preview.find('#charitable-field-' + field_id + ' .charitable-preview-field-indicator').removeClass('charitable-hidden'); } } ); $builder.on( 'mouseleave', 'input[type="range"].charitable-indicator-on-hover, .charitable-panel-field-align a', function( e ) { // eslint-disable-line var field_id = parseInt( $(this).closest('.charitable-panel-field').data('field-id') ); if ( field_id > 0 ) { elements.$preview.find('#charitable-field-' + field_id + ' .charitable-preview-field-indicator').addClass('charitable-hidden'); } } ); }, /** * Element bindings for campign title fields. * * @since 1.8.0 */ bindAutoResizeCampaignTitle: function() { // Resize the width of the HTML input text field based on the number of characters that are being typed. $builder.on( 'input', 'input#charitable_settings_title', function( e ) { // eslint-disable-line var $this = $( this ), the_text = $this.val(), the_text_characters = the_text.length, the_padding = 10, the_input_box_width = ( the_text_characters * 12.8 ) + the_padding; wpchar.debug( the_text ); wpchar.debug( the_text_characters ); wpchar.debug( $('#charitable_settings_title').val() ); // $this.css( 'width', the_input_box_width + 'px' ); app.setCampaignNotSaved(); // if the title is changed, that's a trigger. app.updateFormUI( 'title', the_text ); app.resizeTopCampaignTitleInputBox(); }); // If the field loses focus, then update the title status. $builder.on( 'focusout', 'input#charitable_settings_title', function( e ) { // eslint-disable-line // app.setCampaignTitleSet(); }); }, /** * Element bindings for campign title fields. * * @since 1.8.0 */ resizeTopCampaignTitleInputBox: function() { // var $this = $( 'input#charitable_settings_title' ), // the_text = $this.val(), // the_text_characters = the_text.length, // the_padding = 10, // the_input_box_width = ( the_text_characters * 12.8 ) + the_padding; // $this.css( 'width', the_input_box_width + 'px' ); }, /** * Update the title when it gets changed in the campaign title input text field. * * @since 1.8.0 */ bindCampaignTitleBlockTextField: function () { $builder.on( 'keyup', 'input.charitable-campaign-builder-title', function( e ) { // eslint-disable-line app.updateFormUI( 'title', $( this ).val() ); } ); }, /** * Element bindings for campign title fields. * * @since 1.8.0 */ bindUIEditCampaignTitle: function() { // This is the area at the top of the builder where you can change the campaign title. // $builder.on( 'click', '.charitable-edit-campaign-title-area', function( e ) { // e.preventDefault(); // app.allowTitleUpdate( $( this ) ); // } ); // $builder.on( 'focusout', 'input#charitable_settings_title', function( e ) { // eslint-disable-line // $('.charitable-edit-campaign-title-area').removeClass( 'edit' ); // if ( $('#charitable_settings_title' ).val().trim() === '' ) { // $( '#charitable_settings_title' ).val( charitable_builder.default_campaign_title ); // leave a default title, this should not be blank. // } // $('#charitable_settings_title').attr('disabled', true); // app.updateFormUI( 'title', $('#charitable_settings_title').val() ); // var $this = $( 'input#charitable_settings_title' ), // the_text = $this.val(), // the_text_characters = the_text.length, // the_padding = 10, // the_input_box_width = ( the_text_characters * 11 ) + the_padding; // $this.css( 'width', the_input_box_width + 'px' ); // } ); // $(document).on( 'mouseup', $builder, function( e ) { // if ($(e.target).closest(".charitable-edit-campaign-title-area").length === 0) { // $('.charitable-edit-campaign-title-area').removeClass( 'edit' ); // if ( $('#charitable_settings_title' ).val().trim() === '' ) { // $( '#charitable_settings_title' ).val( charitable_builder.default_campaign_title ); // leave a default title, this should not be blank. // } // $('#charitable_settings_title').attr('disabled', true); // } // app.updateFormUI( 'title', $('#charitable_settings_title').val() ); // } ); }, allowTitleUpdate: function( $container ) { if ( $container.hasClass( 'edit' ) ) { $('#charitable_settings_title').attr('disabled', true); $container.removeClass( 'edit' ); } else { $('#charitable_settings_title').removeAttr('disabled'); $container.addClass( 'edit' ); $('#charitable_settings_title').focus().select(); } }, /** * Element bindings for general panel tasks. * * @since 1.8.0 */ bindUIActionsPanels: function() { // Panel switching. $builder.on( 'click', '#charitable-panels-toggle button:not(.charitable-panel-help-button), .charitable-panel-switch', function( e ) { e.preventDefault(); // if the button has a disabled class, then we can't switch the panel because it's disabled. if ( ! $( this ).hasClass('disabled') ) { app.panelSwitch( $( this ).data( 'panel' ) ); } } ); // Panel sections switching. $builder.on( 'click', '.charitable-panel .charitable-panel-sidebar-section:not(.charitable-need-upgrade):not(.charitable-not-available):not(.charitable-not-installed):not(.charitable-not-activated):not(.charitable-installed-refresh):not(.charitable-not-available):not(.charitable-addon-file-missing)', function( e ) { app.panelSectionSwitch( this, e ); } ); // Panel sidebar toggle. $builder.on( 'click', '.charitable-panels .charitable-panel-sidebar-content .charitable-panel-sidebar-toggle', function() { $( this ).parent().toggleClass( 'charitable-panel-sidebar-closed' ); } ); $builder.on( 'focusout', 'input[name="tabs__campaign__title"]', function( e ) { e.preventDefault(); app.updateFormUI( 'tabs__campaign__title', $( this ).val() ); } ); app.bindUIActionPanelsTabs(); }, /** * Element bindings for general panel tasks. * * @since 1.8.0 */ bindUIActionPanelsTabs: function() { $builder.on( 'input', '.charitable-tab-title-row input[type="text"]', function( e ) { e.preventDefault(); var $textBox = $( this ), $the_element = $textBox.closest('.charitable-group'), theGroupID = $the_element.attr("data-group_id"), updatedText = ( 0 === $textBox.val().length ) ? 'New Tab' : $textBox.val(), updatedTextClean = app.removeTags( updatedText ) // Change the title of the current tab that the text field is in. $the_element.find('.charitable-general-layout-heading').find('span').html( updatedTextClean ); // Update in preview area. $('nav.charitable-campaign-preview-nav ul').find('#tab_' + theGroupID + '_title a').html( updatedTextClean ); } ); }, /** * This specifically checks to see if we have to force on and disable thie "hide tab navigation" functionality... if there is more than on tab, the user can't hide nav for any tab. * * @since 1.8.0 * * @param {string} theString The string. * */ checkHideTabNavigation: function () { const tab_count = $('#charitable-field-options .charitable-layout-options-tab-group').length - 1; if ( tab_count > 1 ) { // disable and force on. $('#charitable-field-options').find('input.charitable-settings-tab-visible-nav').each(function () { $( this ).prop( 'checked', false ).attr( 'disabled', true ); $( this ).parent().find('label').addClass( 'charitable-disabled' ); elements.$preview.find('nav.charitable-campaign-preview-nav li').removeClass( 'charitable-tab-hide' ); }); } else { $('#charitable-field-options').find('input.charitable-settings-tab-visible-nav').each(function () { $( this ).removeAttr( 'disabled' ); $( this ).parent().find('label').removeClass( 'charitable-disabled' ); }); } }, /** * Remove tags from a string. * * @since 1.8.0 * * @param {string} theString The string. * */ removeTags: function ( theString ) { return theString; // var rex = /(<([^>]+)>)/ig; // return( theString.replace( rex , "" ) ); }, /** * Switch Panels. * * @since 1.8.0 * * @param {string} panel Panel slug. * * @returns {mixed} Void or false. */ panelSwitch: function( panel ) { var $panel = $( '#charitable-panel-' + panel ), $panelBtn = $( '.charitable-panel-' + panel + '-button' ), cookieName = 'charitable_panel'; /* check and see if a template has been selected */ if ( ! app.hasTemplate() && panel !== 'template' ) { return; } if ( ! $panel.hasClass( 'active' ) ) { const event = CharitableUtils.triggerEvent( $builder, 'charitablePanelSwitch', [ panel ] ); // Allow callbacks on `charitablePanelSwitch` to cancel panel switching by triggering `event.preventDefault()`. if ( event.isDefaultPrevented() || ! charitable_panel_switch ) { return false; } $( '#charitable-panels-toggle' ).find( 'button' ).removeClass( 'active' ); $( '.charitable-panel' ).removeClass( 'active' ); $panelBtn.addClass( 'active' ); $panel.addClass( 'active' ); history.replaceState( {}, null, wpchar.updateQueryString( 'view', panel ) ); $builder.trigger( 'charitablePanelSwitched', [ panel ] ); wpCookies.set( cookieName, panel, 2592000 ); // 1 month. wpCookies.set( 'charitable_panel_content_section', '', 2592000 ); wpCookies.set( 'charitable_panel_active_field_id', '', 2592000 ); } }, /** * Switch Panel section. * * @since 1.8.0 * * @param {object} el DOM element object. * @param {object} e Event object. * */ panelSectionSwitch: function( el, e ) { if ( e ) { e.preventDefault(); } var $this = $( el ), $panel = $this.parent().parent(), section = $this.data( 'section' ), $sectionButtons = $panel.find( '.charitable-panel-sidebar-section' ), $sectionButton = $panel.find( '.charitable-panel-sidebar-section-' + section ); if ( $this.hasClass( 'upgrade-modal' ) || $this.hasClass( 'education-modal' ) ) { return; } if ( ! $sectionButton.hasClass( 'active' ) ) { app.panelSectionSwitchTo( section, $panel, $sectionButtons, $sectionButton ); } }, /** * Switch Panel section to something specific. * * @since 1.8.0 * * @param {string} section The section slug. * @param {object} $panel Panel object. * @param {object} $sectionButtons Buttons object. * @param {object} $sectionButton Button object. * */ panelSectionSwitchTo: function ( section, $panel, $sectionButtons, $sectionButton ) { const event = CharitableUtils.triggerEvent( $builder, 'charitablePanelSectionSwitch', section ); // Allow callbacks on `charitablePanelSectionSwitch` to cancel panel section switching by triggering `event.preventDefault()`. if ( event.isDefaultPrevented() || ! charitable_panel_switch ) { return false; } $sectionButtons.removeClass( 'active' ); $sectionButton.addClass( 'active' ); $panel.find( '.charitable-panel-content-section' ).hide(); $panel.find( '.charitable-panel-content-section-' + section ).show(); var cookieName = 'charitable_panel_content_section'; wpCookies.set( cookieName, section, 2592000 ); // 1 month }, //--------------------------------------------------------------------// // Fields Panel //--------------------------------------------------------------------// /** * Element bindings for Fields panel. * * @since 1.8.0 */ bindUIActionsFields: function() { // Field sidebar tab toggle. $builder.on( 'click', '.charitable-tab a', function( e ) { e.preventDefault(); app.fieldTabToggle( $( this ).parent().attr( 'id' ) ); if ( 'add-layout' === $( this ).parent().attr( 'id' ) ) { app.resetPreviewArea(); } } ); $builder.on( 'click', '.charitable-layout-options-tab-tabs .charitable-toggleable-group', function( e ) { e.preventDefault(); app.fieldGroupTogglev2( $( this ), 'click' ); } ); $builder.on( 'click', '.charitable-add-fields .charitable-toggleable-group', function( e ) { e.preventDefault(); app.fieldGroupTogglev3( $( this ), 'click' ); } ); // Tab delete. $builder.on( 'click', '.charitable-tab-group-delete', function( e ) { e.preventDefault(); e.stopPropagation(); if ( app.isFormPreviewActionsDisabled( this ) ) { return; } var $the_element = $( this ).closest('.charitable-group'), theGroupID = $the_element.attr("data-group_id"); app.tabDelete( theGroupID ); } ); // Form field preview clicking. $builder.on( 'click', '.charitable-field', function( e ) { // Allow clicking on the dismiss button inside the field. if ( e.target.classList.contains( 'charitable-dismiss-button' ) ) { return; } e.stopPropagation(); $( this ).find('.charitable-field-edit').click(); } ); // Field delete. $builder.on( 'click', '.charitable-field-delete', function( e ) { e.preventDefault(); e.stopPropagation(); var confirmation = $( this ).parent().hasClass('charitable-missing-addon-content' ) ? false : true, field_id = parseInt( $( this ).closest('.charitable-field').data( 'field-id' ) ); app.fieldDelete( field_id, confirmation ); } ); // Field duplicate. $builder.on( 'click', '.charitable-field-duplicate', function( e ) { e.preventDefault(); e.stopPropagation(); app.fieldDuplicate( $( this ).parent().data( 'field-id' ) ); } ); // Field edit $builder.on( 'click', '.charitable-field-edit', function( e ) { e.preventDefault(); e.stopPropagation(); app.resetPreviewArea(); $( this ).parent().addClass('active'); $('ul.charitable-tabs li#add-layout a').removeClass('active'); $('ul.charitable-tabs li#layout-options a').addClass('active'); var field_id = parseInt( $( this ).parent().data( 'field-id' ) ); wpCookies.set( 'charitable_panel_active_field_id', field_id, 2592000 ); // 1 month. app.fieldEdit( $( this ).data( 'type' ), $( this ).data( 'section' ), $( this ).parent().data( 'field-id' ), field_id, $( this ).parent().data( 'field-type' ) ); } ); // Field add. $builder.on( 'click', '.charitable-add-fields-button', function( e ) { e.preventDefault(); const $field = $( this ); if ( $field.hasClass( 'ui-draggable-disabled' ) ) { return; } let type = $field.data( 'field-type' ), event = CharitableUtils.triggerEvent( $builder, 'charitableBeforeFieldAddOnClick', [ type, $field ] ); // Allow callbacks on `charitableBeforeFieldAddOnClick` to cancel adding field // by triggering `event.preventDefault()`. if ( event.isDefaultPrevented() ) { return; } app.fieldAdd( type, { $sortable: 'default' } ); } ); // New field choices should be sortable $builder.on( 'charitableFieldAdd', function( event, id, type ) { const fieldTypes = [ 'campaign-title', 'campaign-description', 'campaign-overview', 'progress-bar', 'donation-options', 'social-sharing', 'social-links', 'photo', 'organizer', 'html', 'donate-button', 'donate-amount', 'campaign-summary', 'donate-form', 'donor-wall', 'shortcode', 'text', 'video' ]; if ( $.inArray( type, fieldTypes ) !== -1 ) { app.fieldChoiceSortable( type, `#charitable-field-option-row-${id}-choices ul` ); } else { // not found in the fieldTypes. } } ); // Field Options group tabs. $builder.on( 'click', '.charitable-group-toggle', function( e ) { // was charitable-field-option-group-toggle const event = CharitableUtils.triggerEvent( $builder, 'charitableFieldOptionGroupToggle' ); // Allow callbacks on `charitableFieldOptionGroupToggle` to cancel tab toggle by triggering `event.preventDefault()`. if ( event.isDefaultPrevented() ) { return false; } e.preventDefault(); app.resetPreviewArea(); var $group = $( this ).closest( '.charitable-layout-options-tab' ); $group.siblings( '.charitable-layout-options-tab' ).removeClass( 'active' ); $group.addClass( 'active' ); if ( $( this ).parent().hasClass('charitable-layout-options-tab-tabs') ) { $("#charitable-preview-tab-container").toggleClass('active'); } else { $("#charitable-preview-tab-container").removeClass('active'); } if ( $( this ).parent().hasClass('charitable-layout-options-tab-general') ) { wpCookies.set( 'charitable_panel_design_layout_options_group', 'general', 2592000 ); // 1 month. } else if ( $( this ).parent().hasClass('charitable-layout-options-tab-tabs') ) { wpCookies.set( 'charitable_panel_design_layout_options_group', 'tabs', 2592000 ); // 1 month. } else if ( $( this ).parent().hasClass('charitable-layout-options-tab-advanced') ) { wpCookies.set( 'charitable_panel_design_layout_options_group', 'advanced', 2592000 ); // 1 month. } // reset cookies for anything else wpCookies.set( 'charitable_panel_active_field_id', '', 2592000 ); // 1 month. $('.charitable-layout-options-tab-general .charitable-layout-options-group-inner').html(); $('.charitable-campaign-preview .charitable-select-field').removeClass('active'); } ); // Preview $builder.on( 'click', '.charitable-field-edit', function( e ) { e.preventDefault(); $( '#layout-options a' ).addClass( 'active' ); $( '.charitable-add-fields' ).hide(); $( '.charitable-field-options' ).show(); var $group = $( '.charitable-layout-options-tab-general' ); $group.siblings( '.charitable-layout-options-tab' ).removeClass( 'active' ); $group.addClass( 'active' ); } ); // On any click check if we had focusout event. $builder.on( 'click', function() { app.focusOutEvent(); } ); // Generalized field/block types. /* photo */ app.photoFieldEvents( $builder ); /* campaign summary */ app.campaignSummaryEvents( $builder ); /* social sharing */ app.socialSharingEvents( $builder ); /* social linking */ app.socialLinkingEvents( $builder ); /* donate button */ app.donateButtonEvents( $builder ); /* donate wall */ app.donateWallEvents( $builder ); /* progress bar */ app.progressBarEvents( $builder ); /* shortcodes */ app.shortcodeEvents( $builder ); /* organizer */ app.organizerEvents( $builder ); // Generalized form fields (in settings/left pane) types. /* text fields */ app.cssTextFieldEvents( $builder ); app.textFieldEvents( $builder ); /* headlines */ app.headlineEvents( $builder ); /* number sliders */ app.numberSliderEvents( $builder ); /* align */ app.alignFieldEvents( $builder ); / *highlights */ app.highlightEvents( $builder ); // Layout advanced. app.advancedLayoutOptionsEvents( $builder ); // Preview related. app.previewHover( $builder ); // Goal related app.goalEvents( $builder ); // End date related app.endDateEvents( $builder ); }, /** * Logic: checks if there is a campaign goal and depending if there is or isn't, hides and disables items in the preview field. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ endDateEvents: function( $builder ) { $builder.on( 'change', '#charitable-panel-field-settings-campaign_end_date', function( e ) { // eslint-disable-line app.updateEndDateRelatedItems( $( this ).val() ); } ); }, /** * Logic: checks what the end date for the campaign is (if any) and adjusts the preview area accordingly. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ updateEndDateRelatedItems: function( endDate = '', theField = $('#charitable-panel-field-settings-campaign_end_date') ) { if ( endDate === '' ) { // if no end Date has been passed in, get the value from theField if theField exists. if ( theField.length ) { endDate = theField.val(); } } if ( endDate.trim() === '' ) { wpchar.debug('updateEndDateRelatedItems - no end date'); // if there is no value, then there is no end date... for each campaign summary field, check and see if it has a charitable-hidden class... and if it doesn't, add it. elements.$preview.find('.charitable-field-campaign-summary').each(function () { var field_id = $( this ).attr('data-field-id'); $(this).find('.campaign-time-left.campaign-summary-item').addClass('charitable-hidden'); // ... and also disable the checkbox field to hide the amount raised. wpchar.debug( $('input[name="_fields[' + field_id + '][show_hide][campaign_hide_time_remaining]' ) ); // uncheck checkbox elements.$fieldOptions.find( 'input[name="_fields[' + field_id + '][show_hide][campaign_hide_time_remaining]' ).attr( 'disabled', true ).addClass('charitable-disabled').prop( 'checked', false ).next().addClass('charitable-disabled'); }); } else { wpchar.debug('updateEndDateRelatedItems - there is an end date'); elements.$preview.find('.charitable-field-campaign-summary').each(function () { var field_id = $( this ).attr('data-field-id'); // $(this).find('.campaign-time-left.campaign-summary-item').removeClass('charitable-hidden'); //$(this).find('.campaign-time-left.campaign-summary-item').removeClass('charitable-hidden'); // ... and also enable the checkbox field to hide the amount raised. elements.$fieldOptions.find( 'input[name="_fields[' + field_id + '][show_hide][campaign_hide_time_remaining]' ).attr( 'disabled', false ).removeClass('charitable-disabled').next().removeClass('charitable-disabled'); }); } }, /** * Logic: checks if there is a campaign goal and depending if there is or isn't, hides and disables items in the preview field. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ goalEvents: function( $builder ) { $builder.on( 'change', '#charitable-panel-field-settings-campaign_goal', function( e ) { // eslint-disable-line app.updateGoalRelatedItems( $( this ).val() ); } ); }, /** * Logic: checks if there is a campaign goal and depending if there is or isn't, hides and disables items in the preview field. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ updateGoalRelatedItems: function( goalAmount = '', theField = $('#charitable-panel-field-settings-campaign_goal') ) { // If the user adds or removes a goal in settings, then we should adjust the progress bar field in preview live. wpchar.debug ( goalAmount, 'goalAmount'); if ( goalAmount === '' ) { // if no Goal Amount has been passed in, get the value from theField if theField exists. if ( theField.length ) { goalAmount = theField.val(); } } if ( goalAmount === '' || goalAmount === '0' || goalAmount === '0.00' ) { wpchar.debug('updateGoalRelatedItems - checkpoint 0'); // if there is no value, then there is no goal and therefore no progress bar. elements.$preview.find('.charitable-field-progress-bar .progress').addClass('charitable-campaign-preview-not-available').addClass('charitable-hidden'); // for each campaign summary field, check and see if it has a charitable-hidden class... and if it doesn't, add it. elements.$preview.find('.charitable-field-campaign-summary').each(function () { var field_id = $( this ).attr('data-field-id'); $(this).find('.campaign-raised.campaign-summary-item').addClass('charitable-hidden'); // ... and also disable the checkbox field to hide the amount raised. wpchar.debug( elements.$fieldOptions.find( 'input[name="_fields[' + field_id + '][show_hide][campaign_hide_percent_raised]' ) ); elements.$fieldOptions.find( 'input[name="_fields[' + field_id + '][show_hide][campaign_hide_percent_raised]' ).prop( 'checked', false ).attr( 'disabled', true ).addClass('charitable-disabled').next().addClass('charitable-disabled'); }); // update the goal field. elements.$preview.find('.charitable-field-progress-bar .campaign-goal').each(function () { var goalLabel = $( this ).find('span').html(); $( this ).html( '<span>' + goalLabel + '</span>' + '∞' ); }); } else { // does the goalAmount have a decimal point? var regex_decemial = /^\d+\.\d+$/, regex_comma = /^\d+\,\d+$/; // eslint-disable-line if ( regex_comma.test( goalAmount ) ) { wpchar.debug('updateGoalRelatedItems - checkpoint 1'); app.updateGoalisPresentRelatedUI(); elements.$preview.find('.charitable-field-progress-bar .campaign-goal').each(function () { var goalLabel = $( this ).find('span').html(), santitizedValue = parseFloat( goalAmount ).toFixed(2); // eslint-disable-line wpchar.debug( charitable_builder.currency_symbol + goalAmount ); $( this ).html( '<span>' + goalLabel + '</span>' + ' ' + charitable_builder.currency_symbol + goalAmount ); }); } else if ( regex_decemial.test( goalAmount ) ) { wpchar.debug('updateGoalRelatedItems - checkpoint 2'); app.updateGoalisPresentRelatedUI(); elements.$preview.find('.charitable-field-progress-bar .campaign-goal').each(function () { var goalLabel = $( this ).find('span').html(), santitizedValue = parseFloat( goalAmount ).toFixed(2); // Add commas to the interger part of the number. santitizedValue = goalAmount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); $( this ).html( '<span>' + goalLabel + '</span>' + ' ' + charitable_builder.currency_symbol + santitizedValue ); }); } else { wpchar.debug('updateGoalRelatedItems - checkpoint 3'); app.updateGoalisPresentRelatedUI(); // Remove all characters except commas, decimeals, and numbers. goalAmount = goalAmount.replace(/[^0-9\.\,]/g, ''); // eslint-disable-line elements.$preview.find('.charitable-field-progress-bar .campaign-goal').each(function () { var goalLabel = $( this ).find('span').html(); $( this ).html( '<span>' + goalLabel + '</span>' + ' ' + charitable_builder.currency_symbol + goalAmount ); }); } } }, /** * Updates UI related to the campaign goal in settings being present. * * @since 1.8.0 */ updateGoalisPresentRelatedUI: function () { elements.$preview.find('.charitable-field-campaign-summary').each(function () { var field_id = $( this ).attr('data-field-id'), $preview_summary = $( this ); // if the checkbox to show this unchecked don't show it even though a goal has been added. if ( $( 'input[name="_fields[' + field_id + '][show_hide][campaign_hide_percent_raised]' ).is(':checked') ) { if ( ! $( this ).hasClass('charitable-hidden') ) { $preview_summary.find('.campaign-raised.campaign-summary-item').removeClass('charitable-hidden'); } } // ... and also enable the checkbox field to hide the amount raised. elements.$fieldOptions.find( 'input[name="_fields[' + field_id + '][show_hide][campaign_hide_percent_raised]' ).attr( 'disabled', false ).removeClass('charitable-disabled').next().removeClass('charitable-disabled'); }); elements.$preview.find('.charitable-field-progress-bar .progress').removeClass('charitable-campaign-preview-not-available').removeClass('charitable-hidden'); }, /** * Add handlers for "highlighting" certain areas of settings (like the recurring donations area). * * @since 1.8.0 * * @param {object} $builder JQuery object. */ highlightEvents: function( $builder ) { // Custom settings button redirects (recurring). $builder.on( 'click', 'a.charitable-addon-installed-charitable-lite, a.charitable-addon-installed-charitable-pro', function( e ) { // eslint-disable-line e.preventDefault(); if ( $( this ).hasClass('charitable-addon-recurring-donations') ) { elements.$settingsPanel.find('.charitable-panel-fields-group-recurring-donations').removeClass('charitable-highlight'); $('a.charitable-panel-sidebar-section-donation-options').click(); // highlight the area when the user goes to the section. elements.$settingsPanel.find('.charitable-panel-fields-group-recurring-donations').addClass('charitable-highlight'); } } ); $builder.on( 'webkitAnimationEnd oanimationend msAnimationEnd animationend', '.charitable-panel-fields-group-recurring-donations', function( e ) { // eslint-disable-line elements.$settingsPanel.find('.charitable-panel-fields-group-recurring-donations').removeClass('charitable-highlight'); } ); }, /** * Add handlers for changing advanced options settings. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ advancedLayoutOptionsEvents: function( $builder ) { $builder.on( 'change', 'select#charitable-design-layout-options-show-field-names', function( e ) { // eslint-disable-line const theField = $( this ); if ( theField.val() === 'hide' ) { elements.$formPreview.addClass('charitable-preview-hide-field-names'); } else if ( theField.val() === 'show' ) { elements.$formPreview.removeClass('charitable-preview-hide-field-names'); } } ); $builder.on( 'change', 'select#charitable-design-layout-options-preview-mode', function( e ) { // eslint-disable-line const theField = $( this ); if ( theField.val() === 'normal' ) { elements.$formPreview.removeClass('charitable-preview-minimum-preview'); } else if ( theField.val() === 'minimum' ) { elements.$formPreview.addClass('charitable-preview-minimum-preview'); } } ); }, /** * Add handlers for hovering over preview (live effect). * * @since 1.8.0 * * @param {object} $builder JQuery object. */ previewHover: function( $builder ) { $builder.on( 'mouseover', '.charitable-view-campaign-external-link', function( e ) { // eslint-disable-line elements.$formPreview.addClass('charitable-preview-live'); } ); $builder.on( 'mouseleave', '.charitable-view-campaign-external-link', function( e ) { // eslint-disable-line elements.$formPreview.removeClass('charitable-preview-live'); } ); }, /** * Add handlers for preview: updating the donate button text. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ donateButtonEvents: function( $builder ) { $builder.on( 'input', '.charitable-panel-field-text input[type="text"].charitable-campaign-builder-donate-button-button-label', function( e ) { // eslint-disable-line const theTextBox = $( this ), field_id = theTextBox.closest('.charitable-panel-field').data('field-id'); app.updateDonateButtonPreview( field_id, theTextBox.attr('name'), theTextBox.val() ); } ); }, /** * Updating the donate button text. * * @since 1.8.0 * * @param {integer} field_id Field ID. * @param {string} textFieldName Not currently used. * @param {string} $label_value Value of text to update. */ updateDonateButtonPreview: function( field_id = 0, textFieldName = '', label_value = 'Donate' ) { // eslint-disable-line const preview_field = $('#charitable-field-' + field_id ); label_value = label_value.length > 0 ? CharitableUtils.santitizeTextInput( label_value ) : 'Donate'; preview_field.find('.placeholder').html( label_value ); }, /** * Add handlers for preview: updating the donate wall text. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ donateWallEvents: function( $builder ) { $builder.on( 'input', '.charitable-panel-field.charitable-campaign-builder-donor-wall input, .charitable-panel-field.charitable-campaign-builder-donor-wall select', function( e ) { // eslint-disable-line const theFormField = $( this ), field_id = theFormField.closest('.charitable-panel-field').data('field-id'); app.updateDonateWallPreview( field_id, theFormField ); } ); }, /** * Updating the donate wall text. * * @since 1.8.0 * * @param {integer} field_id Field ID. * @param {string} theFormField Not currently used. */ updateDonateWallPreview: function( field_id = 0, theFormField ) { // eslint-disable-line var data = {}; $('.charitable-panel-field.charitable-campaign-builder-donor-wall[data-field-id="' + field_id + '"]').each(function () { var theArea = $( this ); theArea.find('input.charitable-checkbox-for-toggle[type="checkbox"]:checked').each(function () { var theName = $(this).closest('.charitable-toggle-control[data-field-id="' + field_id + '"]').data('ajax-label'); if ( $( this ).is(':checked') ) { data[theName] = $( this ).val(); } else { data[theName] = 0; } }); theArea.find('input[type="radio"]:checked,input[type="text"],input[type="number"],select').each(function () { var theName = $(this).closest('.charitable-panel-field[data-field-id="' + field_id + '"]').data('ajax-label'); data[theName] = $( this ).val(); }); data.campaign_id = s.formID; data.field_type = 'donation-wall'; data.field_id = field_id; data.action = 'charitable_builder_field_content_preview', data.nonce = charitable_builder.nonce } ); // Disable stuff - move this into it's own function. app.disableFormActions(); $('.charitable-layout-options-tab-general .charitable-panel-field[data-field-id="' + field_id + '"]').addClass('charitable-loading'); $('#charitable-field-' + field_id + ' .charitable-preview-field-container span.placeholder').addClass('charitable-loading').parent().prepend('<div class="charitable-loading-spinner preview-ajax"></div>'); return $.post( charitable_builder.ajax_url, data, function( res ) { // eslint-disable-line complexity if ( ! res.success ) { wpchar.debug( 'Add field AJAX call is unsuccessful:', res ); return; } $('#charitable-field-' + field_id + ' .charitable-preview-field-container').replaceWith( res.data.output ); var theTextBox = $( '.charitable-panel-field-text[data-field-id="' + field_id + '"] input[type="text"].charitable-campaign-builder-headline' ); app.updateHeadlinePreview( field_id, theTextBox.attr('name'), theTextBox.val(), theTextBox ); app.enableFormActions(); $('.charitable-layout-options-tab-general .charitable-panel-field[data-field-id="' + field_id + '"]').removeClass('charitable-loading'); $('#charitable-field-' + field_id + ' .charitable-preview-field-container span.placeholder').removeClass('charitable-loading').parent().remove('.charitable-loading'); } ).fail( function( xhr, textStatus, e ) { // eslint-disable-line wpchar.debug( 'Add field AJAX call failed:', xhr.responseText ); $('.charitable-layout-options-tab-general .charitable-panel-field[data-field-id="' + field_id + '"]').removeClass('charitable-loading'); $('#charitable-field-' + field_id + ' .charitable-preview-field-container span.placeholder').removeClass('charitable-loading').parent().remove('.charitable-loading'); } ).always( function() { } ); }, /** * Add handlers for preview: progress bars. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ progressBarEvents: function( $builder ) { $builder.on( 'change', '.charitable-panel-field.charitable-campaign-builder-progress-bar input, .charitable-panel-field.charitable-campaign-builder-progress-bar select', function( e ) { // eslint-disable-line var theFormField = $( this ), field_id = theFormField.attr('data-field-id'); app.progressBarEventsPreview( field_id, theFormField ); } ); $builder.on( 'keyup', '.charitable-panel-field.charitable-panel-field-text input.donate_label, .charitable-panel-field.charitable-panel-field-text input.donate_goal', function( e ) { // eslint-disable-line var theFormField = $( this ), field_id = theFormField.attr('data-field-id'); app.progressBarEventsPreviewLabels( field_id, theFormField ); } ); }, /** * Updating the labels for the progress bar field. * * @since 1.8.0 * * @param {integer} field_id Field ID. * @param {string} theFormField Not currently used. */ progressBarEventsPreviewLabels: function( field_id = 0, theFormField = '' ) { const preview_field = $('#charitable-field-' + field_id ); if ( theFormField.hasClass('donate_label') ) { preview_field.find('.campaign-percent-raised span' ).html( theFormField.val() ); } if ( theFormField.hasClass('donate_goal') ) { preview_field.find('.campaign-goal span' ).html( theFormField.val() ); } }, /** * Updating the fields for the progress bar field. * * @since 1.8.0 * * @param {integer} field_id Field ID. * @param {string} theFormField Not currently used. */ progressBarEventsPreview: function( field_id = 0, theFormField = '' ) { const preview_field = $('#charitable-field-' + field_id ); if ( theFormField.val() === 'show_donated' ) { preview_field.find('.campaign-percent-raised' ).toggleClass('charitable-hidden'); } if ( theFormField.val() === 'show_goal' ) { preview_field.find('.campaign-goal' ).toggleClass('charitable-hidden'); } }, /** * Add handlers for preview: CSS text boxes. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ cssTextFieldEvents: function( $builder ) { $builder.on( 'input', '.charitable-panel-field-text input[data-ajax-label="css_class"]', function( e ) { // eslint-disable-line const theTextBox = $( this ), textboxString = CharitableUtils.santitizeCSSInput( theTextBox.val() ); // Clean the string. $( this ).val( textboxString ); app.setCampaignNotSaved(); } ); }, /** * Add handlers for preview: generic text boxes. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ textFieldEvents: function( $builder ) { $builder.on( 'input', '.charitable-panel-field-text input[type="text"][data-ajax-label!="css_class"]:not(.charitable-campaign-builder-headline, .charitable-campaign-builder-donate-button-button-label)', function( e ) { // eslint-disable-line const theTextBox = $( this ), textboxString = CharitableUtils.santitizeTextInput( theTextBox.val() ); // Clean the string. $( this ).val( textboxString ); app.setCampaignNotSaved(); } ); }, /** * Add handlers for preview: headlines. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ headlineEvents: function( $builder ) { $builder.on( 'input', '.charitable-panel-field-text input[type="text"].charitable-campaign-builder-headline', function( e ) { // eslint-disable-line const theTextBox = $( this ), field_id = theTextBox.closest('.charitable-panel-field').data('field-id'); app.updateHeadlinePreview( field_id, theTextBox.attr('name'), theTextBox.val(), theTextBox ); app.setCampaignNotSaved(); } ); }, /** * Updating the fields for headlines. * * @since 1.8.0 * * @param {integer} field_id Field ID. * @param {string} textFieldName Not currently used. * @param {string} $label_value Value of text to update. */ updateHeadlinePreview: function( field_id = 0, textFieldName = '', label_value = '', theTextBox ) { // eslint-disable-line const preview_field = $('#charitable-field-' + field_id ), headline = CharitableUtils.santitizeTitle( label_value ), // Clean the string. headline_html = label_value.length > 0 ? '<h5 class="charitable-field-preview-headline">' + headline + '</h5>': '', tempPlaceholderContainer = preview_field.find('.charitable-placeholder').length > 0 ? '.charitable-placeholder' : '.placeholder', placeholderContainer = preview_field.find('.charitable-field-preview-social-sharing-headline-container').length > 0 ? '.charitable-field-preview-social-sharing-headline-container' : tempPlaceholderContainer; theTextBox.val( headline ); preview_field.find( placeholderContainer ).find( 'h5.charitable-field-preview-headline' ).remove(); preview_field.find( placeholderContainer ).first().prepend( headline_html ); }, /** * Add handlers for preview: shortcodes. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ shortcodeEvents: function( $builder ) { $builder.on( 'input', '.charitable-panel-field-text input[type="text"].charitable-campaign-builder-shortcode', function( e ) { // eslint-disable-line const theTextBox = $( this ), field_id = theTextBox.closest('.charitable-panel-field').data('field-id'); app.updateShortcodePreview( field_id, theTextBox.attr('name'), theTextBox.val() ); } ); }, /** * Updating the fields for shortcodes. * * @since 1.8.0 * * @param {integer} field_id Field ID. * @param {string} textFieldName Not currently used. * @param {string} $label_value Value of text to update. */ updateShortcodePreview: function( field_id = 0, textFieldName = '', label_value = '' ) { // eslint-disable-line const preview_field = $('#charitable-field-' + field_id ), headline_html = label_value.length > 0 ? '<h5 class="charitable-field-preview-shortcode">' + label_value + '</h5>': ''; preview_field.find('.placeholder.shortcode-preview').find( 'h5.charitable-field-preview-shortcode' ).remove(); preview_field.find('.placeholder.shortcode-preview').first().prepend( headline_html ); }, /** * Add handlers for preview: organizer. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ organizerEvents: function( $builder ) { $builder.on( 'change', '.charitable-panel-field.campaign-builder-campaign-creator-id-mini select', function( e ) { // eslint-disable-line var theFormField = $( this ), theAvatarURL = $( this ).find('option:selected').data('avatar'), field_id = theFormField.closest('.charitable-panel-field').attr('data-field-id'); app.organizerEventsPreview( field_id, theFormField, theAvatarURL ); } ); }, /** * Updating the fields for social sharing. * * @since 1.8.0 * * @param {integer} field_id Field ID. * @param {object} $theFormField Value of text to update. */ organizerEventsPreview: function( field_id = 0, theFormField = '', theAvatarURL = '' ) { // update the creator dropdown in settings $('select#charitable-panel-field-settings-campaign_campaign_creator_id').select2( "val", theFormField.val() ); // update the name in the preview area. const preview_field = $('#charitable-field-' + field_id ); preview_field.find('.charitable-organizer-name').html( theFormField.find("option:selected").text() ); preview_field.find('.charitable-organizer-image').attr( 'style', 'background-image: url(' + theAvatarURL + ');' ); }, /** * Add handlers for preview: campaign summary * * @since 1.8.0 * * @param {object} $builder JQuery object. */ campaignSummaryEvents: function( $builder ) { $builder.on( 'click', '.charitable-campaign-summary-checkboxes input[type="checkbox"]', function( e ) { // eslint-disable-line const theCheckbox = $( this ), field_id = theCheckbox.closest('.charitable-panel-field').data('field-id'); app.updateCampaignSummaryPreview( field_id, theCheckbox.attr('name') ); } ); }, /** * Updating the fields for social sharing. * * @since 1.8.0 * * @param {integer} field_id Field ID. * @param {string} $checkboxName */ updateCampaignSummaryPreview: function( field_id = 0, checkboxName = '' ) { const preview_field = $('#charitable-field-' + field_id ); if ( checkboxName.indexOf( 'campaign_hide_percent_raised' ) >= 0 ) { preview_field.find('.campaign_hide_percent_raised' ).toggleClass('charitable-hidden'); } if ( checkboxName.indexOf( 'campaign_hide_amount_donated' ) >= 0 ) { preview_field.find('.campaign_hide_amount_donated' ).toggleClass('charitable-hidden'); } if ( checkboxName.indexOf( 'campaign_hide_number_of_donors' ) >= 0 ) { preview_field.find('.campaign_hide_number_of_donors' ).toggleClass('charitable-hidden'); } if ( checkboxName.indexOf( 'campaign_hide_time_remaining' ) >= 0 ) { preview_field.find('.campaign_hide_time_remaining' ).toggleClass('charitable-hidden'); } }, /** * Add handlers for preview: social sharing icons. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ socialSharingEvents: function( $builder ) { $builder.on( 'click', '.charitable-social-network-checkboxes input[type="checkbox"]', function( e ) { // eslint-disable-line const theCheckbox = $( this ), field_id = theCheckbox.closest('.charitable-panel-field').data('field-id'); app.updateSocialSharingPreview( field_id, theCheckbox.attr('name') ); } ); }, /** * Updating the fields for social sharing. * * @since 1.8.0 * * @param {integer} field_id Field ID. * @param {string} textFieldName Not currently used. * @param {string} $label_value Value of text to update. */ updateSocialSharingPreview: function( field_id = 0, checkboxName = '' ) { const preview_field = $('#charitable-field-' + field_id ); if ( checkboxName.indexOf( 'twitter' ) >= 0 ) { preview_field.find('.charitable-social-sharing-preview-twitter' ).toggleClass('charitable-hidden'); } if ( checkboxName.indexOf( 'facebook' ) >= 0 ) { preview_field.find('.charitable-social-sharing-preview-facebook' ).toggleClass('charitable-hidden'); } if ( checkboxName.indexOf( 'linkedin' ) >= 0 ) { preview_field.find('.charitable-social-sharing-preview-linkedin' ).toggleClass('charitable-hidden'); } if ( checkboxName.indexOf( 'instagram' ) >= 0 ) { preview_field.find('.charitable-social-sharing-preview-instagram' ).toggleClass('charitable-hidden'); } if ( checkboxName.indexOf( 'tiktok' ) >= 0 ) { preview_field.find('.charitable-social-sharing-preview-tiktok' ).toggleClass('charitable-hidden'); } if ( checkboxName.indexOf( 'pinterest' ) >= 0 ) { preview_field.find('.charitable-social-sharing-preview-pinterest' ).toggleClass('charitable-hidden'); } if ( checkboxName.indexOf( 'mastodon' ) >= 0 ) { preview_field.find('.charitable-social-sharing-preview-mastodon' ).toggleClass('charitable-hidden'); } if ( checkboxName.indexOf( 'threads' ) >= 0 ) { preview_field.find('.charitable-social-sharing-preview-threads' ).toggleClass('charitable-hidden'); } if ( checkboxName.indexOf( 'bluesky' ) >= 0 ) { preview_field.find('.charitable-social-sharing-preview-bluesky' ).toggleClass('charitable-hidden'); } }, /** * Add handlers for preview: social linking. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ socialLinkingEvents: function( $builder ) { $builder.on( 'input', '.charitable-panel-field-text input[type="url"].charitable-campaign-builder-social-links-text-field', function( e ) { // eslint-disable-line var theTextField = $( this ), field_id = theTextField.attr('data-field-id'); app.updateSocialLinksPreview( field_id, theTextField.attr('name'), theTextField.val() ); } ); }, /** * Updating the fields for social links. * * @since 1.8.0 * * @param {integer} field_id Field ID. * @param {string} textFieldName Not currently used. * @param {string} $label_value Value of text to update. */ updateSocialLinksPreview: function( field_id = 0, textFieldName = '', linkURL = '' ) { const preview_field = $('#charitable-field-' + field_id ), social_networks = [ 'twitter', 'facebook', 'linkedin', 'instagram', 'tiktok', 'pinterest', 'mastodon', 'youtube', 'threads', 'bluesky' ]; var visibleNetworks = 0; $.each( social_networks , function( _index, network ) { if ( textFieldName.indexOf( network ) >= 0 && app.isValidURL( linkURL ) ) { preview_field.find('.charitable-social-linking-preview-' + network ).removeClass('charitable-hidden'); } else if ( textFieldName.indexOf( network ) >= 0 ) { preview_field.find('.charitable-social-linking-preview-' + network ).addClass('charitable-hidden'); } if ( preview_field.find('.charitable-social-linking-preview-' + network ).hasClass('charitable-hidden') ) { // Do Nothing. } else { visibleNetworks++; } } ); if ( visibleNetworks > 0 ) { preview_field.find('.charitable-social-linking-no-links').addClass('charitable-hidden'); } else { preview_field.find('.charitable-social-linking-no-links').removeClass('charitable-hidden'); } }, /** * Add handlers for preview: photo field. * * @since 1.8.0 * * @param {object} $builder JQuery object. */ photoFieldEvents: function( $builder ) { // WP 3.5+ uploader var file_frame; window.formfield = ''; $builder.on( 'click', '.charitable-campaign-builder-upload-button', function( e ) { e.preventDefault(); var button = $( this ), field_id = $( this ).closest('.charitable-panel-field').data('field-id'); window.formfield = $( this ).parent().prev(); window.field_id = field_id; // 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( { // eslint-disable-line 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 ) { // eslint-disable-line attachment = attachment.toJSON(); window.formfield.val( attachment.url ); app.updateImagePhotoPreview( window.field_id, attachment.url ); window.field_id = false; } ); } ); // Finally, open the modal file_frame.open(); } ); $builder.on( 'click', '.charitable-campaign-builder-clear-button', function( e ) { e.preventDefault(); const button = $( this ), field_id = $( this ).closest('.charitable-panel-field').data('field-id'); button.closest('.charitable-internal').find('input[type="url"]').val(''); app.updateImagePhotoPreview( field_id, false ); } ); }, /** * Updating the photo of the photo field in the preview area. * * @since 1.8.0 * * @param {integer} field_id Field ID. * @param {string} imageUrl The URL of the image file. */ updateImagePhotoPreview: function( field_id = 0, imageUrl = '' ) { const preview_field = $('#charitable-field-' + field_id ), preview_field_image = preview_field.find('img.charitable-campaign-builder-preview-photo'); if ( false === imageUrl || '' === imageUrl || ! app.isValidURL( imageUrl ) ) { preview_field.find('.primary-image-container .primary-image img').remove(); preview_field.find('.primary-image-container .primary-image').append('<img src="../../images/campaign-builder/fields/photo/temp-icon.svg" class="temp-icon" alt="" />'); preview_field.find('.primary-image-container').removeClass('has-image'); } else { preview_field.find('i.temp-icon').remove(); if ( preview_field_image.length > 0 ) { preview_field_image.attr('src', imageUrl ); } else { preview_field.find('.primary-image-container .primary-image').append('<img src="' + imageUrl + '" class="charitable-campaign-builder-preview-photo" />'); preview_field.find('.primary-image-container').addClass('has-image'); } } }, /** * A utiliay funciton that checks to see if an input is a valid URL. * * @since 1.8.0 * * @param {string} str The URL of the image file. */ isValidURL: function( str ) { var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string '(\\#[-a-z\\d_]*)?$','i'); // fragment locator return !!pattern.test(str); }, /** * General reset of the preview area (maybe when tabs and/or fields are added and/or removed and/or moved) * * @since 1.8.0 * * @param {string} str The URL of the image file. */ resetPreviewArea: function() { elements.$formPreview.find('.charitable-field').each(function() { $( this ).removeClass( 'active' ); }); $('.charitable-select-field-notice').show(); $('.charitable-layout-options-tab-general .charitable-panel-field').removeClass('active'); $("#charitable-preview-tab-container").removeClass('active'); }, /** * Delete a field. * * @param {int} id Field ID. * @param {boolean} confirmation Show a confirmation popup - true or false. * * @since 1.8.0 */ fieldDelete: function( id, confirmation = true ) { var $field = $( '#charitable-field-' + id ), type = $field.data( 'field-type' ); if ( $field.hasClass( 'no-delete' ) ) { app.youCantRemoveFieldPopup(); return; } if ( confirmation ) { app.confirmFieldDeletion( id, type ); } else { app.fieldDeleteById( id, type ); } }, /** * Show the confirmation popup before the field deletion. * * @param {int} id Field ID. * @param {string} type Field type. * * @since 1.8.0 */ confirmFieldDeletion: function( id, type ) { var fieldData = { 'id' : id, 'message' : charitable_builder.delete_confirm }; var event = CharitableUtils.triggerEvent( $builder, 'charitableBeforeFieldDeleteAlert', [ fieldData, type ] ); // Allow callbacks on `charitableBeforeFieldDeleteAlert` to prevent field deletion by triggering `event.preventDefault()`. if ( event.isDefaultPrevented() ) { return; } $.confirm( { title : false, content : fieldData.message, icon : 'fa fa-exclamation-circle', type : 'orange', buttons: { confirm: { text : charitable_builder.ok, btnClass : 'btn-confirm', keys : [ 'enter' ], action: function() { app.fieldDeleteById( id, type ); } }, cancel: { text: charitable_builder.cancel, keys: [ 'esc' ] } } } ); }, /** * Add handlers to create confirmation popup before the campaign deletion. * * @since 1.8.0 */ confirmCampaignDeletion: function() { // Embed form. $builder.on( 'click', '.charitable-button.alert.delete-campaign', function( e ) { e.preventDefault(); $.alert( { title: false, content : charitable_builder.campaign_delete_confirm, icon: 'fa fa-info-circle', type: 'red', buttons: { confirm: { text : charitable_builder.ok, btnClass : 'btn-confirm', keys : [ 'enter' ], action: function() { // delete the campaign. } }, cancel: { text: charitable_builder.cancel, keys: [ 'esc' ] } } } ); } ); }, /** * Remove the field by ID. * * @since 1.8.0 * * @param {int} id Field ID. * @param {string} type Field type/slug * @param {int} duration Duration of animation. */ fieldDeleteById: function( id = false, type = '', duration = 200 ) { // eslint-disable-line if ( id === false ) { return; } $( `#charitable-field-${id}` ).fadeOut( duration, function() { const $field = $( this ), section = $field.closest('.charitable-field-section'), type = $field.data( 'field-type' ), max = typeof $field.data('field-max') !== 'undefined' ? parseInt( $field.data('field-max') ) : 99; $builder.trigger( 'charitableBeforeFieldDelete', [ id, type ] ); $field.remove(); $( '#charitable-field-option-' + id ).remove(); $( '.charitable-field, .charitable-preview-top-bar' ).removeClass( 'active' ); // Remove the settings boxes, assuming they existed. $('.charitable-layout-options-tab-general .charitable-panel-field[data-field-id="' + id + '"]').remove(); $('.charitable-select-field-notice').show(); app.checkNoFieldsPreview(); app.checkFieldTargetState( section ); // Possible enable the field button on the left if the field had a max and deleteing it just freed up something. if ( max === 0 || elements.$preview.find('.charitable-field.charitable-field-donate-amount').length < max ) { $('#charitable-panel-design button#charitable-add-fields-donate-amount').removeClass('charitable-disabled'); } // if this was removed in a tab, check to see if the tab is now empty app.checkIfTabsAreEmpty(); if ( $('.charitable-layout-options-tab.charitable-layout-options-tab-general').hasClass('active') ) { app.fieldTabToggle( 'add-layout' ); } const $fieldsOptions = $( '.charitable-field-option' ), $submitButton = $builder.find( '.charitable-field-submit' ); // No fields remains. if ( $fieldsOptions.length < 1 ) { elements.$sortableFieldsWrap.append( elements.$noFieldsPreview.clone() ); elements.$fieldOptions.append( elements.$noFieldsOptions.clone() ); $submitButton.hide(); } // Only Layout fields remains. if ( ! $fieldsOptions.filter( ':not(.charitable-field-option-layout)' ).length ) { $submitButton.hide(); } // Check and see if deleting this changed any enabling of add field buttons on the left. app.checkFieldAllow(); app.checkFieldMax( type, max ); // Check and see if this enables/disables a checkmark for recommended buttons on the left. app.checkRecommendedFields( type ); if ( wpCookies.get( 'charitable_panel_active_field_id' ) === id ) { wpCookies.set( 'charitable_panel_active_field_id', '', 2592000 ); // 1 month. } // Finally, make sure to note that the campaign isn't saved. app.setCampaignNotSaved(); $builder.trigger( 'charitableFieldDelete', [ id, type ] ); } ); }, /** * Edit the field by ID. * * @since 1.8.0 * * @param {int} id Field ID. * @param {string} type Field type (deprecated) * @param {int} duration Duration of animation. */ fieldEdit: function ( type, section, edit_field_id, field_id, field_type ) { if ( section === 'general' || section === 'standard' || section === 'pro' || section === 'recommended' ) { app.panelSwitch( 'design' ); $('.charitable-select-field-notice').hide(); $('.charitable-layout-options-tab-general .charitable-panel-field').removeClass('active'); $('.charitable-layout-options-tab-general .charitable-panel-field[data-field-id="' + field_id + '"]').addClass('active'); // If the first setting is a form field go ahead and make that the focus. $('.charitable-layout-options-tab-general .charitable-panel-field[data-field-id="' + field_id + '"]').find('input[type=text],input[type=button],input[type=range],input[type=url],textarea,select').filter(':visible:first').focus(); if ( 'html' === field_type ) { // CharitableCampaignBuilderFieldHTML.codemirrorInit( field_id ); // eslint-disable-line // trigger an event that another JS file can listen for. $builder.trigger( 'charitableFieldAddHTML', [ field_id, field_type ] ); } else { $builder.trigger( 'charitableFieldEdit', [ type, section, edit_field_id, field_id, field_type ] ); } } }, /** * Duplicate field. * * @since 1.8.0 * * @param {string} id Field id. */ fieldDuplicate: function( id ) { const $field = $( `#charitable-field-${id}` ); if ( $field.hasClass( 'no-duplicate' ) ) { $.alert( { title: charitable_builder.field_locked, content: charitable_builder.field_locked_no_duplicate_msg, icon: 'fa fa-info-circle', type: 'blue', buttons: { confirm: { text: charitable_builder.close, btnClass: 'btn-confirm', keys: [ 'enter' ] } } } ); return; } $.confirm( { title : false, content : charitable_builder.duplicate_confirm, icon : 'fa fa-exclamation-circle', type : 'orange', buttons : { confirm: { text: charitable_builder.ok, btnClass: 'btn-confirm', keys: [ 'enter' ], action: function() { // Disable the current button to avoid firing multiple click events. // By default, "jconfirm" tends to destroy any modal DOM element upon button click. this.$$confirm.prop( 'disabled', true ); const beforeEvent = CharitableUtils.triggerEvent( $builder, 'charitableBeforeFieldDuplicate', [ id, $field ] ); // Allow callbacks on `charitableFieldBeforeDuplicate` to cancel field duplication. if ( beforeEvent.isDefaultPrevented() ) { return; } const newFieldId = app.fieldDuplicateRoutine( id ), $newField = $( `#charitable-field-${newFieldId}` ); CharitableUtils.triggerEvent( $builder, 'charitableFieldDuplicated', [ id, $field, newFieldId, $newField ] ); } }, cancel: { text: charitable_builder.cancel, keys: [ 'esc' ] } } } ); }, /** * Duplicate field routine. * * @since 1.8.0 * * @param {integer|number|string} id Field Id. * * @returns {number} New field Id. */ fieldDuplicateRoutine: function( id ) { // eslint-disable-line max-lines-per-function, complexity const $field = $( `#charitable-field-${id}` ), $fieldActiveFields = elements.$sortableFieldsWrap.find( '> .active' ), $fieldActiveTabs = elements.$sortableFieldsWrap.find( '> .active' ), $newField = $field.clone(), newFieldID = parseInt( elements.$nextFieldId.val(), 10 ) + 1, $settingsArea = $( '#charitable-field-options .charitable-layout-options-group-inner .charitable-panel-field[data-field-id="' + id + '"]' ); if ( $newField ) { // Update next field id hidden input value. app.updateFormHiddenFieldID( newFieldID ); } // Toggle visibility states. $field.after( $newField ); $fieldActiveFields.removeClass( 'active' ); $fieldActiveTabs.removeClass( 'active' ); $newField.addClass( 'active' ).attr( { 'id' : `charitable-field-${newFieldID}`, 'data-field-id': newFieldID } ); $settingsArea.each(function(){ var $newSettingsField = $(this).clone(), isContains = $newSettingsField.text().indexOf('ID:') > -1; $newSettingsField.attr('data-field-id', newFieldID ); $(this).removeClass('active'); $newSettingsField.addClass('active'); if ( isContains ) { $newSettingsField.text(function(index,text){ return text.replace( 'ID: ' + id, 'ID: ' + newFieldID ); }); } if ( typeof $newSettingsField.attr('name') !== 'undefined' && $newSettingsField.attr('name').length > 0 ) { $newSettingsField.attr('name', $newSettingsField.attr('name').replace( id, newFieldID ) ); } if ( typeof $newSettingsField.attr('id') !== 'undefined' && $newSettingsField.attr('id').length > 0 ) { $newSettingsField.attr('id', $newSettingsField.attr('id').replace( id, newFieldID ) ); } $newSettingsField.find('*').each(function () { var $subField = $( this ); if ( typeof $subField.attr('for') !== 'undefined' && $subField.attr('for').length > 0 ) { $subField.attr('for', $subField.attr('for').replace( id, newFieldID ) ); } if ( typeof $subField.attr('name') !== 'undefined' && $subField.attr('name').length > 0 ) { $subField.attr('name', $subField.attr('name').replace( id, newFieldID ) ); } if ( typeof $subField.attr('id') !== 'undefined' && $subField.attr('id').length > 0 ) { $subField.attr('id', $subField.attr('id').replace( id, newFieldID ) ); } if ( typeof $subField.data('field-id') !== 'undefined' && $subField.data('field-id').length > 0 ) { $newSettingsField.attr('data-field-id', newFieldID ); } }); $newSettingsField.find('.charitable-toggle-control').attr('data-field-id', newFieldID ); $newSettingsField.find('.charitable-checkbox-for-toggle').attr('data-field-id', newFieldID ); $('#charitable-field-options .charitable-layout-options-tab-general .charitable-layout-options-group-inner').append( $newSettingsField ); // Is this setting a WYSIWYG field for a campaign description? if ( typeof $newSettingsField.data('special-type') !== 'undefined' && $newSettingsField.data('special-type') === 'campaign_description' ) { // replace the current field in the "each" with a field then init it for the quill. let contentToCopy = $newSettingsField.find('.campaign-builder-htmleditor .ql-editor').html(); $newSettingsField.find( '.ql-toolbar' ).remove(); $newSettingsField.find('.campaign-builder-htmleditor').html( '<div data-textarea-name="_fields[' + newFieldID + '][content]" id="charitable-panel-field-settings-field_campaign-description_html_' + newFieldID + '" class="campaign-builder-htmleditor">' + contentToCopy + '</div>' ); app.initHTMLEditorFields( $newSettingsField.find('.campaign-builder-htmleditor'), false ); } // Check and see if duplicated this changed any enabling of add field buttons on the left. app.checkFieldAllow(); app.checkFieldMax(); }); return newFieldID; }, /** * Check if we had focusout event from certain fields. * * @since 1.8.0 */ focusOutEvent: function() { if ( elements.$focusOutTarget === null ) { return; } elements.$focusOutTarget = null; }, /** * Determine if form wrapper has sorting locked. * * @since 1.8.0 * * @param {mixed} el DOM element or jQuery object of some container on the field preview. * * @returns {bool} True if form preview wrapper sorting is disabled. */ isFormPreviewActionsDisabled: function( el ) { return $( el ).closest( '.charitable-field-wrap' ).hasClass( 'ui-sortable-disabled' ); }, /** * Toggle field group visibility in the field sidebar. * * @since 1.8.0 * * @param {mixed} el DOM element or jQuery object. * @param {string} action Action. */ fieldGroupTogglev2: function( el, action ) { var $this = $( el ), groupName = $this.closest('.charitable-group').data( 'group_id' ), $nearestGroup = $this.closest('.charitable-group'), $rows = $nearestGroup.find( '.charitable-group-rows' ), $group = $rows.parent(), // eslint-disable-line $icon = $this.find( 'i' ), cookieName = 'charitable_panel_layout_options_tabs_tab_open_' + groupName; if ( action === 'click' ) { $icon.toggleClass( 'charitable-angle-right' ); $rows.stop().slideToggle( '', function() { $nearestGroup.toggleClass( 'charitable-closed' ); if ( $nearestGroup.hasClass( 'charitable-closed' ) ) { $nearestGroup.removeClass( 'charitable-open' ); wpCookies.remove( cookieName ); } else { wpCookies.set( cookieName, 'true', 2592000 ); // 1 month } } ); return; } }, /** * Toggle field group visibility in the field sidebar. * * @since 1.8.0 * * @param {mixed} el DOM element or jQuery object. * @param {string} action Action. */ fieldGroupTogglev3: function( el, action = 'click' ) { var $this = $( el ), $nearestGroup = $this.closest('.charitable-add-fields-group'), $rows = $nearestGroup.find( '.charitable-group-rows' ), $icon = $this, groupName = 'test', cookieName = 'charitable_panel_add_layout_blocks_open_' + groupName; if ( action === 'click' ) { $icon.toggleClass( 'charitable-angle-right' ); $rows.stop().slideToggle( '', function() { $nearestGroup.toggleClass( 'charitable-closed' ); if ( $nearestGroup.hasClass( 'charitable-closed' ) ) { $nearestGroup.removeClass( 'charitable-open' ); wpCookies.remove( cookieName ); } else { wpCookies.set( cookieName, 'true', 2592000 ); // 1 month } } ); return; } }, /** * Toggle field group visibility in the field sidebar. * * @since 1.8.0 * * @param {mixed} el DOM element or jQuery object. * @param {string} action Action. */ fieldGroupToggle: function( el, action ) { var $this = $( el ), $buttons = $this.next( '.charitable-add-fields-buttons' ), $group = $buttons.parent(), $icon = $this.find( 'i' ), groupName = $this.data( 'group' ), cookieName = 'charitable_field_group_' + groupName; if ( groupName == 'general-layout-campaign' || groupName == 'general-layout-faq' ) { //$buttons = $this.next('.charitable-field-option-row'); $group = $this.parent().find('.charitable-' + groupName + '-group-inner'); $buttons = $group; } if ( action === 'click' ) { if ( $group.hasClass( 'charitable-closed' ) ) { wpCookies.remove( cookieName ); } else { wpCookies.set( cookieName, 'true', 2592000 ); // 1 month } $icon.toggleClass( 'charitable-angle-right' ); $buttons.stop().slideToggle( '', function() { $group.toggleClass( 'charitable-closed' ); } ); return; } else if ( action === 'load' ) { $buttons = $this.find( '.charitable-add-fields-buttons' ); $icon = $this.find( '.charitable-add-fields-heading i' ); groupName = $this.find( '.charitable-add-fields-heading' ).data( 'group' ); cookieName = 'charitable_field_group_' + groupName; if ( wpCookies.get( cookieName ) === 'true' ) { $icon.toggleClass( 'charitable-angle-right' ); $buttons.hide(); $this.toggleClass( 'charitable-closed' ); } } }, /** * Add new field. * * @since 1.8.0 * * @param {string} type Field type. * @param {object} options Additional options. * */ fieldMove: function( type, options ) { // eslint-disable-line max-lines-per-function var $field = options.field; $field.find('.charitable-field-edit').click(); // remove disabled from add fields. $builder.find( '.charitable-add-fields .charitable-add-fields-button' ).prop( 'disabled', false ); // if a field moved, check the section it landed on and adjust the field target state. var section = $field.closest('.charitable-field-section'); app.checkFieldTargetState( section ); // if a field moved, also check where it came FROM to see if it's now empty. if ( options.section ) { app.checkFieldTargetState( options.section ); } // add a trigger for anything else that wants to hook. $builder.trigger( 'charitableFieldMove', [ options.fieldId, type ] ); }, /** * Add new field. * * @since 1.8.0 * * @param {string} type Field type. * @param {object} options Additional options. * * @returns {promise|void} jQuery.post() promise interface. */ fieldAdd: function( type, options ) { // eslint-disable-line max-lines-per-function const $btn = $( `#charitable-add-fields-${type}` ); // eslint-disable-line adding = true; if ( Charitable.Admin.Builder.DragFields && typeof Charitable.Admin.Builder.DragFields.disableDragAndDrop === 'function' ) { Charitable.Admin.Builder.DragFields.disableDragAndDrop(); } app.disableFormActions(); let defaults = { campaign_title: s.campaignTitle, position: 'bottom', $sortable: 'base', placeholder: false, scroll: true, defaults: false, column_id : options.column_id, tab_id : options.tab_id, section_id : options.section_id, area: 'fields' // vs tabs }; options = $.extend( {}, defaults, options ); let data = { action : 'charitable_new_field_' + type, id : s.formID, column_id : options.column_id, tab_id : options.tab_id, section_id : options.section_id, field_id : parseInt( elements.$nextFieldId.val() ) + 1, type : type, campaign_title : options.campaign_title, defaults : options.defaults, nonce : charitable_builder.nonce }; return $.post( charitable_builder.ajax_url, data, function( res ) { // eslint-disable-line complexity if ( ! res.success ) { wpchar.debug( 'Add field AJAX call is unsuccessful:', res ); return; } wpchar.debug ('fieldAdd return'); app.refreshTabFieldsSortDrag(); // define the base container. let $baseFieldsContainer = ( options.area === 'tabs' ) ? elements.$sortableTabContent.find( 'li[data-tab-id="' + data.tab_id + '"] .charitable-tab-wrap' ) : elements.$formPreview.find( '.charitable-field-wrap[data-section-id="' + data.section_id + '"]' ); wpchar.debug( $baseFieldsContainer ); const $newField = $( res.data.preview ), maxAllowed = typeof res.data.max !== 'undefined' ? parseInt( res.data.max ): 99, $newOptions = $( res.data.options ); let $fieldContainer = options.$sortable; adding = false; $newField.css( 'display', 'none' ); if ( options.placeholder ) { options.placeholder.remove(); } if ( options.$sortable === 'default' || ! options.$sortable.length ) { $fieldContainer = $baseFieldsContainer.find( '.charitable-fields-sortable-default' ); } if ( options.$sortable === 'base' || ! $fieldContainer.length ) { $fieldContainer = $baseFieldsContainer; } let event = CharitableUtils.triggerEvent( $builder, 'charitableBeforeFieldAddToDOM', [ options, $newField, $newOptions, $fieldContainer ] ); // Allow callbacks on `charitableBeforeFieldAddToDOM` to cancel adding field // by triggering `event.preventDefault()`. if ( event.isDefaultPrevented() ) { return; } // Add field to the base level of fields. // Allow callbacks on `charitableBeforeFieldAddToDOM` to skip adding field to the base level // by setting `event.skipAddFieldToBaseLevel = true`. if ( ! event.skipAddFieldToBaseLevel ) { // wpchar.debug('adding to base level'); app.fieldAddToBaseLevel( options, $newField, $newOptions ); } // Do we now disable the field add button because of "max"? if ( elements.$preview.find('.charitable-field.charitable-field-donate-amount').length >= maxAllowed ) { $('#charitable-panel-design button#charitable-add-fields-donate-amount').addClass('charitable-disabled'); } // IT IT SHOWTIME... FADE IN THE FIELD. $newField.fadeIn(); app.checkFieldTargetState( $('.charitable-field-section[data-section-id="' + data.section_id + '"]') ); $newField.find('.charitable-field-edit').click(); if ( $( '.charitable-field-option:not(.charitable-field-option-layout)' ).length ) { $builder.find( '.charitable-field-submit' ).show(); } // Update next field id hidden input value. app.updateFormHiddenFieldID( res.data.field_id ); // add the invisible field under 'settings' tab so the user can instantly edit the settings for the field if ( res.data.edit_field_html !== '' ) { $('.charitable-layout-options-tab-general .charitable-layout-options-group-inner').append( res.data.edit_field_html ).find('.charitable-panel-field[data-field-id="' + res.data.field_id + '"]').addClass('active'); // Does this new field have any WYSIWYG fields in the settings? if ( res.data.html_field != '' ) { // this requires a quill assignment, an HTML field. $('.charitable-panel-field[data-field-id="' + res.data.field_id + '"]').find( '.campaign-builder-htmleditor' ).each( function() { app.initHTMLEditorFields( $( this ), false ); }); } // check and see if the field default text requires an update, say maybe for campaign description. if ( type === 'campaign-description' && typeof s.campaignDescription !== 'undefined' ) { $newField.find('.charitable-campaign-builder-no-description-preview').html( '<div>' + s.campaignDescription + '</div>' ); if ( $( '#charitable-panel-field-settings-field_campaign-description_html_' + data.field_id ).find('.ql-editor').length === 0 ) { app.initHTMLEditorFields( $( '#charitable-panel-field-settings-field_campaign-description_html_' + data.field_id ) ); } $( '#charitable-panel-field-settings-field_campaign-description_html_' + data.field_id).find('.ql-editor').html( s.campaignDescription ); } } // if this is a new organizer field, we need to init the dropdown. if ( res.data.field.type === 'organizer' ) { $('.campaign-builder-campaign-creator-id-mini[data-field-id="' + res.data.field_id + '"] select').select2({ templateResult: app.campaignCreatorFormatOptions }); } //wpchar.initTooltips(); // Check and see if duplicated this changed any enabling of add field buttons on the left. app.checkFieldAllow(); app.checkFieldMax(); app.updateEndDateRelatedItems(); app.updateGoalRelatedItems(); // Check and see if this enables/disables a checkmark for recommended buttons on the left. app.checkRecommendedFields( type ); // determine if we add/remove the no fields preview area var fieldContainerSectionType = $fieldContainer.data( 'section-type' ), forceDeleteNoPreview = false; if (typeof fieldContainerSectionType !== 'undefined' && fieldContainerSectionType === 'fields' ) { // could also be 'tabs' but we want to just check 'fields'. forceDeleteNoPreview = true; // eslint-disable-line } app.checkNoFieldsPreview(); // if this is a photo, auto open the media library. if ( 'photo' === type ) { $( '.charitable-panel-field-uploader[data-field-id="' + res.data.field_id + '"] input.charitable-campaign-builder-upload-button' ).click(); } else if ( 'donate-amount' === type ) { $( '.charitable-campaign-suggested-donations-mini' ).each( function() { app.initSuggestedDonationsMini( $( this ) ); app.updateSuggestdDonationsMiniRowsFromSettings( $( this ) ); }); } // finally... just trigger and we're done. $builder.trigger( 'charitableFieldAdd', [ res.data.field.id, type ] ); } ).fail( function( xhr, textStatus, e ) { // eslint-disable-line adding = false; } ).always( function() { $builder.find( '.charitable-add-fields .charitable-add-fields-button' ).prop( 'disabled', false ); if ( ! adding ) { if ( Charitable.Admin.Builder.DragFields && typeof Charitable.Admin.Builder.DragFields.enableDragAndDrop === 'function' ) { Charitable.Admin.Builder.DragFields.enableDragAndDrop(); } app.enableFormActions(); } } ); }, /** * Add new field to the base level of fields. * * @since 1.8.0 * * @param {object} options Field add additional options. * @param {jQuery} $newField New field preview object. * @param {jQuery} $newOptions New field options object. */ fieldAddToBaseLevel: function( options, $newField, $newOptions ) { // eslint-disable-line wpchar.debug ('options'); wpchar.debug ( options ); let $baseFieldsContainer = ''; if ( options.area === 'tabs' ) { $baseFieldsContainer = elements.$sortableTabContent.find( 'li[data-tab-id="' + options.tab_id + '"] .charitable-tab-wrap' ); $baseFieldsContainer.parent().removeClass('empty-tab'); } else { $baseFieldsContainer = elements.$formPreview.find( '.charitable-field-wrap[data-section-id="' + options.section_id + '"]' ); } wpchar.debug ('baseFieldsContainer'); wpchar.debug ( $baseFieldsContainer ); // $baseFieldsContainer = elements.$sortableFieldsWrap, const $baseFields = $baseFieldsContainer.find( '> :not(.charitable-field-drag-pending)' ), $lastBaseField = $baseFields.last(), totalBaseFields = $baseFields.length; let $fieldInPosition = elements.$fieldOptions; if ( options.position === 'top' ) { // Add field to top of base level fields. $baseFieldsContainer.prepend( $newField ); return; } if ( options.position === 'bottom' && ( ! $lastBaseField.length || ! $lastBaseField.hasClass( 'charitable-field-stick' ) ) ) { wpchar.debug ('adding field to the bottom!!!!'); // Add field to the bottom of base level fields. $baseFieldsContainer.append( $newField ); return; } if ( options.position === 'bottom' ) { options.position = totalBaseFields; } if ( options.position === totalBaseFields && $lastBaseField.length && $lastBaseField.hasClass( 'charitable-field-stick' ) ) { // Check to see if the last field we have is configured to // be stuck to the bottom, if so add the field above it. $lastBaseField.before( $newField ); // $fieldOptions.find( `#charitable-field-option-${lastBaseFieldId}` ).before( $newOptions ); return; } $fieldInPosition = $baseFieldsContainer.children( ':not(.charitable-field-drag-pending)' ).eq( options.position ); if ( $fieldInPosition.length ) { // Add field to a specific location. $fieldInPosition.before( $newField ); // $fieldOptions.find( `#charitable-field-option-${fieldInPositionId}` ).before( $newOptions ); return; } // Something is wrong. Just add the field. This should never occur. $baseFieldsContainer.append( $newField ); }, /** * Check if the tabs in the preview area have no fields. * * @since 1.8.0 */ checkIfTabsAreEmpty: function () { elements.$preview.find('.tab-content ul li.tab_content_item').each(function(){ var numfields = $(this).find('.charitable-field').length; if ( numfields === 0 ) { $(this).addClass('empty-tab'); } }); }, /** * Disable Preview, Embed, Save form actions and Form Builder exit button. * * @since 1.8.0 * * @param {boolean} disableExit Exit button. * @param {boolean} disableCampaignTitleEdit Campaign title edit. * @param {boolean} disablePreviewButton Preview button. * */ disableFormActions: function( disableExit = false, disableCampaignTitleEdit = true, disablePreviewButton = false ) { $.each( [ elements.$embedButton, elements.$statusButton, elements.$saveButton ], function( _index, button ) { button.prop( 'disabled', true ).addClass( 'charitable-disabled' ); } ); if ( disableExit ) { $.each( [ elements.$exitButton ], function( _index, button ) { button.prop( 'disabled', true ).addClass( 'charitable-disabled' ); } ); } if ( disableCampaignTitleEdit ) { $('.charitable-edit-campaign-title-area').addClass('charitable-disabled'); $('.charitable-edit-campaign-title-area input').prop( 'disabled', true ); $('.charitable-edit-campaign-title-area a').addClass('charitable-disabled'); } if ( disablePreviewButton ) { elements.$previewButton.prop( 'disabled', true ).addClass( 'charitable-disabled' ); } }, /** * Enable Preview, Embed, Save form actions and Form Builder exit button. * * @since 1.8.0 */ enableFormActions: function() { $.each( [ // elements.$previewButton, // elements.$embedButton, elements.$statusButton, elements.$saveButton, elements.$exitButton ], function( _index, button ) { button.prop( 'disabled', false ).removeClass( 'charitable-disabled' ); } ); $('.charitable-edit-campaign-title-area').removeClass('charitable-disabled'); $('.charitable-edit-campaign-title-area input').prop( 'disabled', false ); $('.charitable-edit-campaign-title-area a').removeClass('charitable-disabled'); if ( s.formStatus === 'publish' ) { elements.$embedButton.prop( 'disabled', false ).removeClass( 'charitable-disabled' ); } }, /** * Field choice delete error alert. * * @since 1.8.0 */ fieldChoiceDeleteAlert: function() { $.alert( { title : false, content : charitable_builder.error_choice, icon : 'fa fa-info-circle', type : 'blue', buttons : { confirm: { text: charitable_builder.ok, btnClass: 'btn-confirm', keys: [ 'enter' ] } } } ); }, /** * Make field choices sortable. * Currently used for select, radio, and checkboxes field types. * * @since 1.8.0 * * @param {string} type Field type. * @param {string} selector Element. */ fieldChoiceSortable: function( type, selector ) { selector = typeof selector !== 'undefined' ? selector : '.charitable-field-option-' + type + ' .charitable-field-option-row-choices ul'; $( selector ).sortable( { items : 'li', axis : 'y', delay : 100, opacity: 0.6, handle : '.move', stop:function( e, ui ) { var id = ui.item.parent().data( 'field-id' ); app.fieldChoiceUpdate( type, id ); $builder.trigger( 'charitableFieldChoiceMove', ui ); }, update: function( e, ui ) { // eslint-disable-line } } ); }, /** * Delete a tab. * * @param {int} id Field ID. * * @since 1.8.0 */ tabDelete: function( groupID ) { app.confirmTabDeletion( groupID ); }, /** * Show the confirmation popup before the tab deletion. * * @param {int} groupID Group ID. * * @since 1.8.0 */ confirmTabDeletion: function( groupID ) { var tabData = { 'id' : groupID, 'message' : charitable_builder.delete_tab_confirm }; var event = CharitableUtils.triggerEvent( $builder, 'charitableBeforeTabDeleteAlert', [ tabData ] ); // Allow callbacks on `charitableBeforeFieldDeleteAlert` to prevent field deletion by triggering `event.preventDefault()`. if ( event.isDefaultPrevented() ) { return; } $.confirm( { title : false, content : charitable_builder.delete_tab_confirm, icon : 'fa fa-exclamation-circle', type : 'orange', buttons : { confirm: { text : charitable_builder.ok, btnClass : 'btn-confirm', keys : [ 'enter' ], action : function() { app.tabDeleteById( groupID ); } }, cancel: { text: charitable_builder.cancel, keys: [ 'esc' ] } } } ); }, /** * Actual deletion of a tab. * * @param {int} groupID Group ID. * * @since 1.8.0 */ tabDeleteById: function ( groupID ) { const tab_settings = elements.$fieldOptions.find('[data-group_id="' + groupID + '"]'), tab_preview_nav = $('nav ul li#tab_' + groupID + '_title'), tab_preview_content = elements.$preview.find('.tab-content ul li.tab_content_item[data-tab-id="' + groupID + '"]'), tab_count = elements.$preview.find('.tab-content .tab_content_item').length - 1, previous_group_ID = Math.abs( groupID - 1 ), tab_content = elements.$preview.find('.tab-content'); tab_settings.remove(); tab_preview_nav.remove(); tab_preview_content.remove(); if ( elements.$preview.find('nav.charitable-campaign-preview-nav ul li[data-tab-id="' + previous_group_ID + '"] a').length > 0 ) { elements.$preview.find('nav.charitable-campaign-preview-nav ul li[data-tab-id="' + previous_group_ID + '"] a' ).click(); } else if ( tab_count === 1 ) { // there's at least one tab left, we need to make some tab active elements.$preview.find('nav.charitable-campaign-preview-nav ul li a' ).first().click(); } // adjust the CSS of the tab-content div to reflect no more tabs, if that's the case. if ( tab_count === 0 ) { tab_content.addClass('empty-tabs'); // add the HTML message. tab_content.append('<p class="no-tab-notice">' + charitable_builder.no_tabs + '</p>'); } else { tab_content.removeClass('empty-tabs'); tab_content.find('.no-tab-notice').remove(); } app.checkHideTabNavigation(); }, //--------------------------------------------------------------------// // Preview //--------------------------------------------------------------------// /** * Element bindings for Embed and Save/Exit items. * * @since 1.8.0 */ bindUIActionsPreview: function() { // Embed form. $('body').on( 'click', 'a#charitable-preview-btn', function( e ) { e.preventDefault(); e.stopPropagation(); if ( parseInt( elements.$campaignID.val() ) === 0 ) { $.alert( { title : charitable_builder.no_preview_must_save, content : charitable_builder.no_preview_must_save_msg, icon : 'fa fa-info-circle', type : 'blue', buttons : { confirm: { text: charitable_builder.close, btnClass: 'btn-confirm', keys: [ 'enter' ] } } } ); return; } else { var openNewTabURL = ''; if ( typeof this.href !== 'undefined' ) { openNewTabURL = this.href.replace( 'charitable_campaign_preview=0', 'charitable_campaign_preview=' + s.campaignID ); } // We are assuming that if they are able to click preview then the campaign is either in draft/not posiblished OR published but they made a change. // Determine if this is an already published campaign... if so, then save the campaign data TEMPORARILY so we can preview it... if ( typeof s.formStatus !== 'undefined' && s.formStatus === 'publish' ) { // Passing in "true" as the second parameter to formSave() will tell it to save the campaign data temporarily. app.formSave( false, true, openNewTabURL ); // false - no redirect, true - yes this is a preview. } else if ( typeof s.formStatus !== 'undefined' && s.formStatus === 'draft' ) { app.formSave( false, true, openNewTabURL ); // still previewing, so pass true. } } } ); }, //--------------------------------------------------------------------// // Save and Exit //--------------------------------------------------------------------// /** * Element bindings for Embed and Save/Exit items. * * @since 1.8.0 */ bindUIActionsSaveExit: function() { // Embed form. $builder.on( 'click', '#charitable-embed', function( e ) { e.preventDefault(); e.stopPropagation(); if ( $( this ).hasClass( 'charitable-disabled' ) ) { return; } CharitableCampaignEmbedWizard.openPopup( s.formID ); } ); // Change Status. $builder.on( 'click', '#charitable-status-button', function( e ) { e.preventDefault(); e.stopPropagation(); if ( $( this ).hasClass( 'charitable-disabled' ) ) { return; } if ( $( this ).hasClass( 'active' ) ) { $( this ).parent().find('ul#charitable-status-dropdown').addClass('charitable-hidden'); $( this ).removeClass( 'active' ); } else { $( this ).parent().find('ul#charitable-status-dropdown').removeClass('charitable-hidden'); $( this ).addClass( 'active' ); } } ); $builder.on( 'click', 'ul#charitable-status-dropdown a', function( e ) { e.preventDefault(); e.stopPropagation(); if ( $( '#charitable-status-button' ).hasClass( 'charitable-disabled' ) ) { return; } var newStatus = $( this ).data('status'), newStatusLabel = $( this ).data('status-label'), $statusDropdown = $( "ul#charitable-status-dropdown" ); $statusDropdown.addClass('charitable-hidden'); $( "#charitable-status-button" ).removeClass('active'); // change status // s.formStatus = newStatus; $( '#charitable-status-button span.text').html( newStatusLabel ); $( '#charitable-status-button').attr('data-status', newStatus ); $statusDropdown.find('a').removeClass('charitable-hidden'); $statusDropdown.find('a.switch-' + newStatus).addClass('charitable-hidden'); $statusDropdown.find('a.' + newStatus).addClass('charitable-hidden'); if ( newStatus === 'draft' ) { // $statusDropdown.find('a[class*="switch-"]').addClass('charitable-hidden'); } else if ( newStatus === 'publish' ) { // $statusDropdown.find('a.draft').addClass('charitable-hidden'); // $statusDropdown.find('a.pending').addClass('charitable-hidden'); // $statusDropdown.find('a.review').addClass('charitable-hidden'); } s.formStatus = newStatus; s.formStatusLabel = newStatusLabel; } ); $builder.on("click", function(e) { if ( $(e.target).is("#charitable-status-dropdown") === false) { $( "ul#charitable-status-dropdown" ).addClass('charitable-hidden'); $( "#charitable-status-button" ).removeClass('active'); } }); // Save form. $builder.on( 'click', '#charitable-save', function( e ) { e.preventDefault(); app.formSave( false ); } ); // Exit builder. $builder.on( 'click', '#charitable-exit', function( e ) { e.preventDefault(); app.formExit(); } ); // After form save. $builder.on( 'charitableSaved', function( e, data ) { // eslint-disable-line $('#charitable_settings_title').attr('disabled', true); /** * Remove `newform` parameter, if it's in URL, otherwise we can to get a "race condition". * E.g. form settings will be updated before some provider connection is loaded. */ wpchar.removeQueryParam( 'newform' ); } ); }, /** * Update the campaign <form> ID that gets stored in a few key places (like hidden fields) - usually happens when a new form is saved/gets it's ID. * * @since 1.8.0 */ updateFormID: function () { var data = { action: 'charitable_get_campaign_form_id', id : s.formID, nonce : charitable_builder.nonce }; return $.post( charitable_builder.ajax_url, data, function( response ) { if ( response.success ) { var campaignID = response.data.campaign_id, redirect = false; // update the campaign ID $('form#charitable-builder-form').attr('data-id', campaignID ); $('form#charitable-builder-form input[name="id"]').val( campaignID ); // update the field ID if ( response.data.field_id ) { elements.$nextFieldId.val( parseInt( response.data.field_id ) ); } wpchar.savedState = wpchar.getFormState( '#charitable-builder-form' ); wpchar.initialSave = false; $builder.trigger( 'charitableSaved', response.data ); // send the updated form of the campaign builder form to the debug window, along with the returned campaign id. app.updateDebugWindow( response.data, response.data.campaign_id ); if ( true === redirect ) { window.location.href = charitable_builder.exit_url; } } else { app.formSaveError( response.data ); } } ).fail( function( xhr, textStatus, e ) { // eslint-disable-line app.formSaveError(); } ).always( function() { } ); }, /** * Make sure critical hidden fields with critical data have the latest. * * @since 1.8.0 */ updateFormHiddenFields: function () { // fields area. $('#charitable-panel-design .charitable-panel-content-wrap input[type="hidden"]').remove(); $('.charitable-field-wrap .charitable-field, .charitable-tab-wrap .charitable-field').each(function(){ var row_type = $( this ).closest('.row').data('row-type'), row_id = $( this ).closest('.row').data('row-id'), row_css = $( this ).closest('.row').data('row-css').length > 0 ? $( this ).closest('.row').data('row-css') : 'no-css', column_id = $( this ).closest('.column.charitable-field-column').data('column-id'), section_type = $( this ).closest('.section.charitable-field-section').data('section-type'), section_id = $( this ).closest('.section.charitable-field-section').data('section-id'), field_id = $( this ).data('field-id'), tab_id = ( 'tabs' === section_type ) ? $( this ).closest('li.tab_content_item').data('tab-id') : false; if ( typeof row_id !== 'undefined' ) { if ( 'tabs' === section_type ) { elements.$formPreview.append('<input type="hidden" name="layout[row][row-type-' + row_type + '][' + row_id + '][' + row_css + '][column][' + column_id + '][section][section-type-' + section_type +'][' + section_id + '][tabs][' + tab_id + '][fields][' + field_id + ']" value="' + $(this).data('field-type') + '" />'); } else { elements.$formPreview.append('<input type="hidden" name="layout[row][row-type-' + row_type + '][' + row_id + '][' + row_css + '][column][' + column_id + '][section][section-type-' + section_type +'][' + section_id + '][fields][' + field_id + ']" value="' + $(this).data('field-type') + '" />'); } } }); }, /** * This updates the field id hidden field that tells the form what the current/next field ID is * which is useful if you are loading a template from the start and immedately want to add a field with a new incredmental ID (like ID: 3). * * @param {int} newValue New value. * * @since 1.8.0 */ updateFormHiddenFieldID: function ( newValue = 0 ) { if ( 0 === newValue ) { // Let's do a count ourselves. var field_id = 0; elements.$formPreview.find('.charitable-field').each(function() { var value = parseFloat($(this).attr('data-field-id')); field_id = (value > field_id) ? value : field_id; }); newValue = field_id; } elements.$nextFieldId.val( parseInt( newValue ) ); }, /** * This updates the link on the preview button in the top header, especially if this is a campaign saved for the first time. * * @param {int} newValue New value. * * @since 1.8.0 */ updatePreviewLink: function( previewLink = '') { elements.$previewButton.attr( 'href', previewLink ); }, /** * This updates the donation amount settings in the settings area when a user updates a value in the donation amount field settings in the preview/design area to keep insync. * * @param {object} $element The element on focus. * @param {int} theIndex Position of text box relative to the other text boxes. * * @since 1.8.0 */ updateSuggestDonationsSettings: function( $element, theIndex ) { if ( ! $element.is("input") || app.getInputType( $element ) !== 'text' ) { return; } // Update settings. $('table#campaign_donation_amounts tbody').find('input[type="text"].campaign_suggested_donations').eq( theIndex ).val( $element.val() ); // Update any donation amount setting fields on the left. $('.charitable-campaign-suggested-donations-mini tbody').find('input[type="text"].campaign_suggested_donations').eq( theIndex ).val( $element.val() ); // Update preview area on the right. elements.$preview.find('.charitable-field-donate-amount li.charitable-preview-donation-amount').eq( ( theIndex / 2 ) - 1 ).find('span').first().html( $element.val() ); }, /** * This updates the allow custom donation settings in the donation amount field in the preview area depending on the checkbox in the settings area. * * @param {object} $element The element on focus. * @param {int} theIndex Position of text box relative to the other text boxes. * * @since 1.8.0 */ updateAllowCustomDonationSettings: function ( isChecked ) { // // Update settings // $('#charitable-panel-field-settings-campaign_allow_custom_donations').prop( "checked", isChecked ); // // Update ANY toggle in field settings. // $('.charitable-panel-field.charitable-campaign-builder-allow-custom-donations input[type="checkbox"]').prop( "checked", isChecked ); // Hide or show field in preview depending on setting const $custom_preview_fields = elements.$preview.find('.charitable-preview-donation-options .custom-donation-amount'); if ( isChecked ) { $custom_preview_fields.removeClass('charitable-hidden'); } else { $custom_preview_fields.addClass('charitable-hidden'); } }, /** * This updates the suggested donation amount settings in the settings area when a user updates a value in the donation amount field settings in the preview/design area to keep insync. * * @since 1.8.0 * * @param {int} selectedValue The value of the selected radio button. */ updateSuggestedDonationAmountDefault: function( selectedValue = 0 ) { if ( selectedValue > 0 ) { $('input[type="radio"].campaign_suggested_donations').prop('checked', false ); $('input[type="radio"][value=' + selectedValue + '].campaign_suggested_donations').prop('checked', true ); elements.$preview.find('.charitable-field.charitable-field-donate-amount li').removeClass( 'selected' ); elements.$preview.find('.charitable-preview-donation-amounts li:nth-child(' + ( selectedValue ) + ')').addClass('selected'); if ( elements.$preview.find('.charitable-field.charitable-field-donate-amount input[type="radio"]').length > 0 ) { elements.$preview.find('.charitable-field.charitable-field-donate-amount input[type="radio"]:eq(' + ( selectedValue - 1 ) + ')').prop( 'checked', true ); } } else { $('input:radio].campaign_suggested_donations').prop('checked', false ); } }, /** * Gets input type of a field, see updateSuggestDonationsSettings(). * * @since 1.8.0 * * @param {object} $element The element on focus. */ getInputType: function( $element ) { var thistest = $element; return thistest[0].tagName.toString().toLowerCase() === "input" ? $(thistest[0]).prop("type").toLowerCase() : thistest[0].tagName.toLowerCase(); }, /** * This does an ajax call to update the "campaign creator" info, usually when the user selects a different valud in the user dropdown. * * @since 1.8.0 */ updateCampaignCreatorInfo: function () { // Update the campaign creator info if the select dropdown is changed upon usually a form save. var data = { action : 'charitable_update_campaign_creator', creator_id : parseInt( $( 'select#charitable-panel-field-settings-campaign_campaign_creator_id' ).val() ), campaign_id : s.formID, nonce : charitable_builder.nonce }; return $.post( charitable_builder.ajax_url, data, function( response ) { if ( response.success ) { $('#campaign-creator .charitable-campaign-creator-avatar img').attr('src', response.data.avatar_url ); $('#campaign-creator h3.creator-name').html( response.data.creator_name ); $('#campaign-creator p.joined-on span').html( response.data.joined_on ); $('#campaign-creator a.public-profile-link').attr('href', response.data.public_profile_link ); $('#campaign-creator a.edit-profile-link').attr('href', response.data.edit_profile_link ); } else { app.formSaveError( response.data ); } } ).fail( function( xhr, textStatus, e ) { // eslint-disable-line app.formSaveError(); } ).always( function() { } ); }, /** * General check for form save errors. * * @since 1.8.1.12 * */ formSaveCheck: function() { if ( $('#charitable_settings_title').val().length === 0 ) { $.alert( { title : charitable_builder.error_title, content : charitable_builder.error_no_title, icon : 'fa fa-info-circle', type : 'red', buttons : { confirm: { text: charitable_builder.ok, btnClass: 'btn-confirm', keys: [ 'enter' ] } } } ); return false; } }, /** * Save form. * * @since 1.8.0 * * @param {boolean} redirect Whether to redirect after save. */ formSave: function( redirect, preview = false, openNewTabURL = '', refreshAfterSave = false ) { var $saveBtn = elements.$saveButton, $icon = $saveBtn.find( 'img.topbar_icon' ), $spinner = $saveBtn.find( 'i.charitable-loading-spinner' ), $label = $saveBtn.find( 'span' ), currentPostStatus = s.formSavedStatus; // Saving a revision directly is not allowed. We need to notify the user that it will overwrite the current version. if ( $builder.hasClass( 'charitable-is-revision' ) && ! $builder.hasClass( 'charitable-revision-is-saving' ) ) { app.confirmSaveRevision(); return; } // Check and see if there is a name for this campaign. if ( app.formSaveCheck() === false ) { return; } if ( typeof tinyMCE !== 'undefined' ) { tinyMCE.triggerSave(); } var event = CharitableUtils.triggerEvent( $builder, 'charitableBeforeSave' ); // Allow callbacks on `charitableBeforeSave` to cancel form submission by triggering `event.preventDefault()`. if ( event.isDefaultPrevented() ) { return; } // Un-disable certain fields so they can be included in the data submit. $( '#charitable_settings_title' ).removeAttr('disabled'); // disable the save button. $saveBtn.prop( 'disabled', true ); // don't show the spinner if this is a preview save. if ( preview === false ) { $label.text( charitable_builder.saving ); $icon.addClass( 'charitable-hidden' ); $spinner.removeClass( 'charitable-hidden' ); } app.updateFormHiddenFields(); var data = { action : 'charitable_save_campaign', data : JSON.stringify( $( '#charitable-builder-form' ).serializeArray() ), id : s.formID, status : s.formStatus, statusLabel : s.formStatusLabel, preview : preview, nonce : charitable_builder.nonce }; return $.post( charitable_builder.ajax_url, data, function( response ) { if ( response.success ) { var campaignID = parseInt( response.data.campaign_id ); if ( refreshAfterSave ) { // is the current url the same as the new url? if so, reload the page. if ( window.location.href === app.addCampaignIDToURL( campaignID ) ) { window.location.href = app.addCampaignIDToURL( campaignID ); return; } else { // otherwise, redirect to the new url. window.location.href = app.addCampaignIDToURL( campaignID ); return; } } // update the campaign ID. $('form#charitable-builder-form').attr('data-id', campaignID ); $('form#charitable-builder-form input[name="id"]').val( campaignID ); s.formID = campaignID; // need to update this var so adding fields for new forms can work. // update the field ID if ( response.data.field_id ) { elements.$nextFieldId.val( parseInt( response.data.field_id ) ); } wpchar.savedState = wpchar.getFormState( '#charitable-builder-form' ); wpchar.initialSave = false; $builder.trigger( 'charitableSaved', response.data ); // send the updated form of the campaign builder form to the debug window, along with the returned campaign id. // app.updateDebugWindow( JSON.stringify( $( '#charitable-builder-form' ).serializeArray() ), response.data.campaign_id ); app.updateDebugWindow( response.data, response.data.campaign_id ); // If we got back a preview url, update the preview button. if ( typeof response.data.preview_url !== 'undefined' && response.data.preview_url.length > 0 ) { app.updatePreviewLink( response.data.preview_url ); } // Don't set the campaign to "saved" if this is just a save for a preview. if ( preview === false ) { app.setCampaignSaved(); } if ( true === redirect ) { window.location.href = charitable_builder.exit_url; } if ( history.pushState ) { var newUrl = app.addCampaignIDToURL( campaignID ); window.history.pushState( {path:newUrl} ,'', newUrl ); } else { window.location.href = app.addCampaignIDToURL( campaignID ); } s.campaignID = campaignID; // If this campaign was draft and now published, open the congrats popup. if ( ( 'draft' === currentPostStatus || '' === currentPostStatus ) && 'publish' === response.data.post_status && response.data.permalink ) { CharitableCampaignCongratsWizard.openPopup( s.formID, response.data.permalink ); } // If this campaign is published, make sure the 'view' button is clickable and has the correct URL, otherwise disable it. if ( 'publish' === response.data.post_status ) { elements.$viewCampaignButton.removeClass('charitable-disabled'); elements.$viewCampaignButton.attr('href', response.data.permalink ); $('a.charitable-admin-campaign-link').attr('href', response.data.permalink ); $('a.charitable-admin-campaign-link.show-url').html( response.data.permalink ); } else { elements.$viewCampaignButton.addClass('charitable-disabled'); } // Depending if the campaign is published, make the embed button disabled or not. if ( 'publish' === response.data.post_status ) { elements.$embedButton.prop( 'disabled', false ).removeClass( 'charitable-disabled' ); } else { elements.$embedButton.prop( 'disabled', true ).addClass( 'charitable-disabled' ); } s.formSavedStatus = response.data.post_status; s.formSavedStatusLabel = response.data.post_status_label; if ( openNewTabURL !== '' ) { window.open( openNewTabURL ); } // Make sure the shortcode in the embed wizard is updated. var campaignEmedCode = '[campaign id="' + campaignID + '"]'; $( '#charitable-admin-campaign-embed-wizard-shortcode-wrap #charitable-admin-campaign-embed-wizard-shortcode' ).remove(); $( '#charitable-admin-campaign-embed-wizard-shortcode-wrap').prepend("<input type=\"text\" id=\"charitable-admin-campaign-embed-wizard-shortcode\" class=\"charitable-admin-popup-shortcode\" value=\"" + campaignEmedCode + "\" />"); $( '#charitable-admin-campaign-embed-wizard-shortcode' ).prop( 'disabled', true ); // If this is a first time save, make sure to update the label re: campaign title. app.setCampaignTitleSet(); return app.addCampaignIDToURL( campaignID ); } else { app.formSaveError( response.data ); } } ).fail( function( xhr, textStatus, e ) { // eslint-disable-line app.formSaveError(); } ).always( function() { $label.text( charitable_builder.saved ); setTimeout( function() { $label.text( charitable_builder.save ); }, 2500 ); $saveBtn.prop( 'disabled', false ); $spinner.addClass( 'charitable-hidden' ); $icon.removeClass( 'charitable-hidden' ); } ); }, /** * Form save error. * * @since 1.8.0 * * @param {string} error Error message. */ formSaveError: function( error ) { // Default error message. if ( wpchar.empty( error ) ) { error = charitable_builder.error_save_form; } // Display error in modal window. $.confirm( { title : charitable_builder.heads_up, content : '<p>' + error + '</p><p>' + charitable_builder.error_contact_support + '</p>', icon : 'fa fa-exclamation-circle', type : 'orange', buttons : { confirm: { text: charitable_builder.ok, btnClass: 'btn-confirm', keys: [ 'enter' ] } } } ); }, /** * Form save error. * * @since 1.8.0 * * @param {string} error Error message. */ formGenericError: function( error ) { // Default error message. if ( wpchar.empty( error ) ) { error = charitable_builder.something_went_wrong; } // Display error in modal window. $.confirm( { title : charitable_builder.heads_up, content : '<p>' + error + '</p><p>' + charitable_builder.error_contact_support + '</p>', icon : 'fa fa-exclamation-circle', type : 'orange', buttons : { confirm: { text: charitable_builder.ok, btnClass: 'btn-confirm', keys: [ 'enter' ] } } } ); }, /** * Form save error. * * @since 1.8.0 * * @param {string} error Error message. */ formGenericNotice: function( error ) { // Default error message. if ( wpchar.empty( error ) ) { error = charitable_builder.something_went_wrong; } // Display error in modal window. $.confirm( { title : charitable_builder.heads_up, content : '<p>' + error + '</p>', icon : 'fa fa-exclamation-circle', type : 'orange', buttons : { confirm: { text: charitable_builder.ok, btnClass: 'btn-confirm', keys: [ 'enter' ] } } } ); }, /** * Appends campaign ID to the URL in the campign builder. * * @since 1.8.0 * * @param {int} campaignID ID of campaign. */ addCampaignIDToURL: function( campaignID ) { const currentURL = window.location.href, urlHasQueryString = currentURL.includes("?"); let updatedURL = false; if ( urlHasQueryString ) { // URL already has a query string. const queryString = window.location.search, campaignIDExists = queryString.includes("campaign_id"); if ( campaignIDExists ) { // URL already has a campaign ID parameter. // Remove any # and text after the # from the url. updatedURL = currentURL.split('#')[0]; return updatedURL; } else { // Remove any # and text after the # from the url. updatedURL = currentURL.split('#')[0]; // URL does not have a campaign ID parameter, so add it. return updatedURL + "&campaign_id=" + campaignID; } } else { // URL does not have a query string, so add one with the campaign ID parameter. return currentURL + "?campaign_id=" + campaignID; } }, //--------------------------------------------------------------------// // Fields (Design) Panel //--------------------------------------------------------------------// /** * Toggle fields tabs (Add Fields, Field Options. * * @since 1.8.0 * * @param {string|integer} id Field Id or `add-fields` or `field-options`. */ fieldTabToggle: function( id ) { const event = CharitableUtils.triggerEvent( $builder, 'charitableFieldTabToggle', [ id ] ); // Allow callbacks on `charitableFieldTabToggle` to cancel tab toggle by triggering `event.preventDefault()`. if ( event.isDefaultPrevented() ) { return false; } $( '.charitable-tab a' ).removeClass( 'active' ); $( '.charitable-field, .charitable-preview-top-bar' ).removeClass( 'active' ); if ( id === 'add-layout' ) { $( '#add-layout a' ).addClass( 'active' ); $( '.charitable-field-options' ).hide(); $( '.charitable-add-fields' ).show(); } else if ( id === 'layout-options' ) { $( '#layout-options a' ).addClass( 'active' ); $( '.charitable-add-fields' ).hide(); $( '.charitable-field-options' ).show(); } else { $( '#charitable-field-' + id ).addClass( 'active' ); $( '.charitable-field-option' ).hide(); $( '#charitable-field-option-' + id ).show(); $( '.charitable-add-fields' ).hide(); $( '.charitable-field-options' ).show(); $builder.trigger( 'charitableFieldOptionTabToggle', [ id ] ); } wpCookies.set( 'charitable_panel_content_section', id, 2592000 ); wpCookies.set( 'charitable_panel_active_field_id', '', 2592000 ); // 1 month wpCookies.set( 'charitable_panel_design_layout_options_group', '', 2592000 ); // 1 month wpCookies.set( 'charitable_panel_tab_section_tab_id', '', 2592000 ); // 1 month }, /** * Exit form builder. * * @since 1.8.0 */ formExit: function() { if ( app.formIsSaved() ) { window.location.href = charitable_builder.exit_url; } else { $.confirm( { title : false, content : '<p>' + charitable_builder.exit_confirm + '</p>', icon : 'fa fa-exclamation-circle', type : 'orange', closeIcon : true, buttons : { confirm: { text: charitable_builder.save_exit, btnClass: 'btn-confirm', keys: [ 'enter' ], action: function() { app.formSave( true ); } }, cancel: { text: charitable_builder.exit, keys: [ 'esc' ], action: function() { closeConfirmation = false; window.location.href = charitable_builder.exit_url; } } } } ); } }, /** * Check the field max values and set buttons in "add layout" accordingly. * This function can check things generally... or specifically if a type is passed. * * @since 1.8.0 * * @param {string} type Field type. * @param {int} max Max number of fields. */ checkFieldMax: function( type = '', max = 99 ) { if ( type.length === 0 ) { // count how many types of fields there are and if they are under the max, removeClass 'charitable-disabled' from the button. var fieldCount = elements.$preview.find('.charitable-field-' + type).length; if ( fieldCount < max ) { elements.$panelDesign.find('button#charitable-add-fields-' + type).removeClass('charitable-disabled'); } } else { elements.$preview.find( ".charitable-field[data-field-max!='']" ).each( function() { var max = parseInt( $( this ).data('field-max') ), fieldType = $( this ).data('field-type'), fieldCount = ( typeof fieldType === 'undefined' || fieldType.length === 0 ) ? 0 : elements.$preview.find('.charitable-field-' + fieldType).length; // count how many of the fields there are in the preview area and see if we need to deactivate the button. if ( ! isNaN( max ) && max > 0 && fieldCount >= max ) { // disable button. elements.$panelDesign.find('button#charitable-add-fields-' + fieldType).addClass('charitable-disabled'); } }); } }, /** * Check the field deny list to see if any fields should be disabled. * * @since 1.8.0 */ checkFieldAllow: function () { wpchar.debug( 'checkFieldAllow' ); // Assume all fields are enabled until we go through the deny list and find one instance where they would be disabled. $.each( s.denyList, function ( fieldPresent, fieldsNotAllowed ) { $.each( fieldsNotAllowed, function ( fieldsNotAllowedName, fieldsNotAllowedAmount ) { // eslint-disable-line app.enableAddFieldButton( fieldsNotAllowedName ); }); }); $.each( s.denyList, function ( fieldPresent, fieldsNotAllowed ) { wpchar.debug( 'fieldPresent: ' + fieldPresent ); // s.denyList = { // 'donation-form': { 'donate-button' : 0, 'donation-form' : 0, 'donate-amount' : 0 }, // 'donate-button': { 'donation-form' : 0 }, // 'donate-amount': { 'donation-form' : 0 }, // }; // check and see if the fieldPresent is... present. if ( app.checkFieldIsPresent( fieldPresent ) ) { $.each( fieldsNotAllowed, function ( fieldsNotAllowedName, fieldsNotAllowedAmount ) { if ( fieldsNotAllowedAmount === 0 || app.getFieldAmount( fieldsNotAllowedName ) > parseInt( fieldsNotAllowedAmount ) ) { wpchar.debug ( fieldsNotAllowedName + ' is not allowed'); // fieldsNotAllowedName shouldn't be allowed at all. app.disableAddFieldButton( fieldsNotAllowedName ); } }); } }); }, /** * Check all recommended files on the left to see if they need to be checked or unchecked base don the fields in the preview area. * * @since 1.8.0 */ checkAllRecommendedFields: function () { $.each( $('.charitable-add-fields-group-recommended button'), function ( ) { var type = $(this).data('field-type'); app.checkRecommendedFields( type ); }); }, /** * Check to see if a single recommended field (passed) needs to be checked or unchecked base don the fields in the preview area. * * @since 1.8.0 * * @param {string} type Field type. * */ checkRecommendedFields: function ( type = false ) { if ( ! type || type.length === 0 ) { return; } var numberOfFieldsByType = elements.$preview.find( ".charitable-field[data-field-type='" + type + "']" ).length, checkForRecommended = $builder.find( '#charitable-add-fields-' + type ).parent().find('.charitable-check'); if ( typeof checkForRecommended === 'undefined' || checkForRecommended.length === 0 ) { return; } if ( numberOfFieldsByType === 0 ) { checkForRecommended.removeClass('checked').addClass('unchecked'); } else { checkForRecommended.removeClass('unchecked').addClass('checked'); } }, /** * Disable add field button. * * @since 1.8.0 */ disableAddFieldButton: function( fieldType ) { elements.$panelDesign.find('button#charitable-add-fields-' + fieldType).addClass('charitable-disabled'); }, /** * Enable add field button. * * @since 1.8.0 */ enableAddFieldButton: function( fieldType = '' ) { elements.$panelDesign.find('button#charitable-add-fields-' + fieldType).removeClass('charitable-disabled'); }, /** * Get field amount. * * @since 1.8.0 */ getFieldAmount: function ( fieldType = '' ) { if ( fieldType.length === 0 ) { return; } return elements.$preview.find('.charitable-field-' + fieldType).length; }, /** * Check field is present. * * @since 1.8.0 */ checkFieldIsPresent: function ( fieldType = '' ) { if ( fieldType.length === 0 ) { return false; } if ( app.getFieldAmount( fieldType ) > 0 ) { return true; } return false; }, /** * Close confirmation setter. * * @since 1.8.0 * * @param {boolean} confirm Close confirmation flag value. */ setCloseConfirmation: function( confirm ) { closeConfirmation = ! ! confirm; }, /** * Check current form state. * * @since 1.8.0 */ formIsSaved: function() { if ( $( '#charitable-builder-form input#charitable-form-saved' ).val().length === 0 && ( typeof s.formSaved !== 'undefined' ) && s.formSaved.length === 0 ) { // the hidden field exists but contains no value, both of these fields SHOULD be in sync return true; } else { return false; } }, /** * Sets the campaign to a not saved mode. * * @since 1.8.1.12 */ setCampaignTitleNotSet: function () { $('.charitable-edit-campaign-title-label').text( 'Name Your Campaign:' ); }, /** * Sets the campaign to a not saved mode. * * @since 1.8.1.12 */ setCampaignTitleSet: function () { $('.charitable-edit-campaign-title-label').text( 'Now Editing:' ); }, /** * Sets the campaign to a not saved mode. * * @since 1.8.0 */ setCampaignNotSaved: function( enablePreviewButton = false ) { // eslint-disable-line var the_time = Date.now(); $( '#charitable-builder-form input#charitable-form-saved' ).val( the_time ); s.formSaved = the_time; // if the user has done something to the form, then we need to update the preview button to reflect that (enable the preview button). elements.$previewButton.removeClass('charitable-disabled'); }, /** * Sets the campaign to a saved mode. * * @since 1.8.0 */ setCampaignSaved: function() { $( '#charitable-builder-form input#charitable-form-saved' ).val( '' ); s.formSaved = ''; // For published campaigns disable preview button because there's nothing to currently preview untit the user makes another change... // ...otherwise if it's saved in draft, user should be able to click the preview buton because there's no other way to preview it. if ( typeof s.formStatus !== 'undefined' && s.formStatus === 'publish' ) { elements.$previewButton.addClass('charitable-disabled'); } else { elements.$previewButton.removeClass('charitable-disabled'); } }, /** * Bindings that prevent a user from entering anything but numbers, comma, and decimal point into a text field that represents a money value. * * @since 1.8.0 */ bindUIMoneyTextFields: function () { // we will be monitoring: // #charitable-panel-field-settings-campaign_minimum_donation_amount // #charitable-panel-field-settings-campaign_goal $builder.on( 'keydown', 'input#charitable-panel-field-settings-campaign_minimum_donation_amount, input#charitable-panel-field-settings-campaign_goal', function( e ) { // eslint-disable-line var k = e.keyCode || e.which, // show keycode for decimal point ok = k == 190 || // period k == 188 || // comma k == 32 || // space k == 9 || // tab // k == 173 || // dash k == 8 || // backspaces ( e.ctrlKey && k == 65 ) || // Ctrl + A ( e.ctrlKey && k == 67 ) || // Ctrl + C ( e.ctrlKey && k == 88 ) || // Ctrl + X ( e.ctrlKey && k == 86 ) || // Ctrl + V ( e.metaKey && k == 65 ) || // command + a ( e.metaKey && k == 67 ) || // command + c ( e.metaKey && k == 88 ) || // command + x ( e.metaKey && k == 86 ) || // command + v ( k >= 96 && k <= 105 ) || // allow numbers entered from a number pad ( k == 110 || k == 190 ) || // period or decimal point ( k >= 37 && k <= 40 ) || // allow arrow keys ( k == 46 ) || // allow delete key ( k >= 48 && k <= 57 ); // only 0-9 (ok SHIFT options) if ( !ok ) { e.preventDefault(); } } ); $builder.on( 'focusout', 'input#charitable-panel-field-settings-campaign_minimum_donation_amount, input#charitable-panel-field-settings-campaign_maximum_donation_amount, input#charitable-panel-field-settings-campaign_goal', function( e ) { // eslint-disable-line // add a decimal point followed by two zeros (.00) if the user clicks out of the input box and the money value is a whole number. var $this = $( this ), val = $this.val(), decimal_separator = charitable_builder.currency_decimal_separator, thousands_separator = charitable_builder.currency_thousands_separator; // if undefined or empty, return. if ( typeof decimal_separator === 'undefined' || decimal_separator.length === 0 ) { return; } if ( typeof thousands_separator === 'undefined' || thousands_separator.length === 0 ) { return; } if ( val.length > 0 && val.indexOf( decimal_separator ) === -1 ) { $this.val( val + decimal_separator + '00' ); } } ); }, /** * Element bindings for general panel tasks. * * @since 1.8.0 */ bindUISettingsRevealGroups: function() { $.each( elements.$settingsPanel.find( '.charitable-panel-fields-group.unfoldable' ), function() { // we found a reveal / foldable, see if we need to show it... find the id and see if the cookies exists. var $this = $( this ), dataGroup = $this.attr('data-group'), dataGroupCookie = wpCookies.get( 'charitable_fold_' + dataGroup ); if ( dataGroupCookie === 'true' && ! $this.hasClass('opened') ) { // open the section $this.addClass('opened'); $this.find('.charitable-panel-fields-group-inner').show(); } }); elements.$settingsPanel.on( 'click', '.charitable-track-cookie', function( e ) { // eslint-disable-line var $this = $( this ), dataGroup = $this.closest('.unfoldable').attr('data-group'); if ( ! $this.closest('.unfoldable').hasClass('opened') ) { wpCookies.set( 'charitable_fold_' + dataGroup, true, 2592000 ); // 1 month. } else { wpCookies.remove( 'charitable_fold_' + dataGroup ); } } ); }, /** * Checks fields to see if OTHER fields can be shown/hidden. Logical conditional showings. * * @since 1.8.0 */ checkFieldConditionals: function() { $.each( charitable_campaign_builder_field_conditionals, function( mainUIKey, mainUIValue) { var theUIElement = elements.$settingsPanel.find( mainUIKey ), changeArray = mainUIValue; if ( theUIElement.is('input[type="checkbox"]') ) { elements.$settingsPanel.on( 'click', mainUIKey, function( e ) { // eslint-disable-line var thisUIElement = $( this ), // eslint-disable-line isChecked = $(this).is(':checked'), checkedFields = changeArray['checked'], uncheckedFields = changeArray['unchecked']; if ( isChecked ) { $.each( checkedFields, function( checkedFieldKey, checkedFieldValue ) { // checkedFieldValue is the string selector for $ elements.$settingsPanel.find( checkedFieldValue + '' ).removeClass('charitable-hidden'); }); } else { $.each( uncheckedFields, function( checkedFieldKey, checkedFieldValue ) { // checkedFieldValue is the string selector for $ $.each( checkedFieldValue, function( hidingfieldKey, hidingfieldValue ) { elements.$settingsPanel.find( hidingfieldValue + '' ).addClass('charitable-hidden'); }); }); } } ); } if ( theUIElement.is('input[type="radio"]') ) { elements.$settingsPanel.on( 'click', theUIElement.closest('.charitable-panel-field-radio-options').find('input[type="radio"]'), function( e ) { // eslint-disable-line var thisUIElement = $( theUIElement ), isChecked = thisUIElement.is(':checked'), checkedFields = changeArray['checked'], uncheckedFields = changeArray['unchecked'], abort = false; if ( isChecked ) { $.each( checkedFields, function( checkedFieldKey, checkedFieldValue ) { // checkedFieldValue is the string selector for $ if ( checkedFieldKey === 'if' ) { $.each( checkedFieldValue, function( checkedIfFieldKey, checkedIfFieldValue ) { // checkedFieldValue is the string selector for $ if ( checkedIfFieldValue === 'checked' && false === elements.$settingsPanel.find( checkedIfFieldKey + '' ).is(':checked') ) { abort = true; } }); } if ( checkedFieldKey === 'show' && abort === false ) { elements.$settingsPanel.find( checkedFieldValue + '' ).removeClass('charitable-hidden'); } else if ( checkedFieldKey === 'show' && abort === true ) { elements.$settingsPanel.find( checkedFieldValue + '' ).addClass('charitable-hidden'); } }); } else { $.each( uncheckedFields, function( checkedFieldKey, checkedFieldValue ) { // checkedFieldValue is the string selector for $ elements.$settingsPanel.find( checkedFieldValue + '' ).addClass('charitable-hidden'); }); } } ); } }); }, /** * Check if the builder opened in the popup (iframe). * * @since 1.8.0 * * @returns {boolean} True if builder opened in the popup. */ isBuilderInPopup: function() { return window.self !== window.parent && window.self.frameElement.id === 'charitable-builder-iframe'; }, //--------------------------------------------------------------------// // General / global //--------------------------------------------------------------------// /** * Element bindings for general and global items * * @since 1.8.0 */ bindUIActionsGeneral: function() { // Toggle unfoldable group of fields. $builder.on( 'click', '.charitable-panel-fields-group.unfoldable .charitable-panel-fields-group-title', app.toggleUnfoldableGroup ); $builder.on( 'click', '.go-to-settings-button', function( e ) { e.preventDefault(); app.panelSwitch( 'settings' ); var $this = $( this ), section = ( $this ).data('settings-section'), $panel = $( '.charitable-panel-sidebar-content' ), $sectionButtons = $panel.find( '.charitable-panel-sidebar-section' ), $sectionButton = $panel.find( '.charitable-panel-sidebar-section-' + section ), cookieName = 'charitable_panel_sidebar_section'; if ( ! $sectionButton.hasClass( 'active' ) ) { app.panelSectionSwitchTo( section, $panel, $sectionButtons, $sectionButton ); wpCookies.set( cookieName, section, 2592000 ); // 1 month. } } ); // Mobile notice primary button / close icon click. $builder.on( 'click', '#charitable-builder-mobile-notice .charitable-fullscreen-notice-button-primary, #charitable-builder-mobile-notice .close', function() { window.location.href = charitable_builder.exit_url; } ); // Mobile notice secondary button click. $builder.on( 'click', '#charitable-builder-mobile-notice .charitable-fullscreen-notice-button-secondary', function() { window.location.href = wpchar.updateQueryString( 'force_desktop_view', 1, window.location.href ); } ); }, /** * Element bindings for general and global items * * @since 1.8.0 */ initFeedbackForms: function( $element ) { var theForm = $element.closest('.charitable-form'), theConfirmation = theForm.find('.charitable-feedback-form-interior-confirmation'), data = { name : theForm.find('.charitable-feedback-form-name').val(), email : theForm.find('.charitable-feedback-form-email').val(), feedback : theForm.find('.charitable-feedback-form-feedback').val(), type : theForm.find('.charitable-feedback-form-type').val() }; // required fields if ( '' === data.name || '' === data.email || '' === data.feedback ) { $.alert( { title: false, content : charitable_builder.feedback_form_fields_required, icon: 'fa fa-info-circle', type: 'red', buttons: { confirm: { text : charitable_builder.ok, btnClass : 'btn-confirm', keys : [ 'esc' ], action: function() { // delete the campaign. } } } } ); } else { $element.addClass('charitable-disabled'); theForm.addClass('charitable-processing'); theForm.find('.charitable-loading-spinner').removeClass('charitable-hidden'); var ajaxData = { action : 'charitable_campaign_builder_send_feedback_ajax', dataType : 'json', data : data, nonce : charitable_builder.nonce }; $.post( charitable_builder.ajax_url, ajaxData, function( response ) { if ( response.success ) { $element.removeClass('charitable-disabled'); theForm.removeClass('charitable-processing'); theForm.find('.charitable-feedback-form-interior').addClass('charitable-hidden'); theConfirmation.removeClass('charitable-hidden'); theConfirmation.find('.charitable-form-confirmation').removeClass('charitable-hidden'); } } ).fail( function( xhr, textStatus, e ) { // eslint-disable-line } ).always( function() { } ); } }, /** * Toggle unfoldable group of fields. * * @since 1.8.0 * * @param {object} e Event object. */ toggleUnfoldableGroup: function( e ) { e.preventDefault(); var $title = $( e.target ), $group = $title.closest( '.charitable-panel-fields-group' ), $inner = $group.find( '.charitable-panel-fields-group-inner' ), cookieName = 'charitable_fields_group_' + $group.data( 'group' ); if ( $group.hasClass( 'opened' ) ) { wpCookies.remove( cookieName ); $inner.stop().slideUp( 150, function() { $group.removeClass( 'opened' ); } ); } else { wpCookies.set( cookieName, 'true', 2592000 ); // 1 month. $group.addClass( 'opened' ); $inner.stop().slideDown( 150 ); } }, /** * Update via ajax the debug window. * * @since 1.8.0 * * @param {string} data Data. * @param {int} campaignID Camapign ID. */ updateDebugWindow: function( data, campaignID = 0 ) { var ajaxData = { action : 'charitable_update_debug_window_ajax', dataType : 'json', data : data, id : campaignID, nonce : charitable_builder.nonce }; $.post( charitable_builder.ajax_url, ajaxData, function( response ) { if ( response.success ) { $('.charitable-debug').html( response.data ); } } ).fail( function( xhr, textStatus, e ) { // eslint-disable-line } ).always( function() { // $label.text( text ); // $saveBtn.prop( 'disabled', false ); // $spinner.addClass( 'charitable-hidden' ); // $icon.removeClass( 'charitable-hidden' ); } ); }, //--------------------------------------------------------------------// // Alerts (notices). //--------------------------------------------------------------------// /** * Click on the Dismiss notice button. * * @since 1.8.0 */ dismissNotice: function() { $builder.on( 'click', '.charitable-alert-field-not-available .charitable-dismiss-button', function( e ) { e.preventDefault(); var $button = $( this ), $alert = $button.closest( '.charitable-alert' ), fieldId = $button.data( 'field-id' ); $alert.addClass( 'out' ); setTimeout( function() { $alert.remove(); }, 250 ); if ( fieldId ) { $( '#charitable-field-option-' + fieldId ).remove(); } } ); }, //--------------------------------------------------------------------// // Other functions. //--------------------------------------------------------------------// /** * Init all the HTML textarea fields so that Quill, etc. runs in them. * * @since 1.8.0 * * @param {object} $element Data. * @param {boolean} minmum Show or not show min interface for quill. */ initHTMLEditorFields: function( $element, minmum = false ) { if ( $.inArray( $element.attr('id'), s.quilled) == -1 ) { var $container_id = '#' + $element.attr('id'), div_height = 200, textarea_name = $element.data('textarea-name'); // ql-editor if ( minmum !== false ) { var toolbarOptions = ['bold', 'italic', 'underline', 'strike']; var quill = new Quill( $container_id, { // eslint-disable-line debug: 'info', theme: 'snow', modules: { toolbar: toolbarOptions } }); $( $container_id ).css('height', div_height+'px'); $( $container_id ).css('min-height', div_height+'px'); quill.focus; s.quilled.push ( $element.attr('id') ); } else { var quill = new Quill( $container_id, { // eslint-disable-line // debug: 'info', theme: 'snow' }); quill.focus; s.quilled.push ( $element.attr('id') ); } $( $container_id ).on( 'focus', '.ql-editor', function() { // eslint-disable-line var contents = $element.find('.ql-editor').html(); if ( $element.closest('.charitable-panel-field-textarea').attr('data-special-type') === 'campaign_description' ) { $('#charitable-panel-field-settings-campaign_description .ql-editor').html( contents ); elements.$preview.find('.charitable-field-campaign-description .charitable-campaign-builder-placeholder-preview-text').html( '<div>' + contents + '</div>' ); s.campaignDescription = contents; } }); quill.on( 'text-change', function( delta, oldDelta, source ) { // eslint-disable-line var contents = $element.find('.ql-editor').html(), tab_id = $element.closest('.charitable-group-row').data('tab-id'), field_id = $element.closest('.charitable-panel-field').data('field-id'); app.setCampaignNotSaved(); // this is a trigger. // fill the form field as the user types $('input[name="' + textarea_name + '"]').val( contents ); // if this is the CAMPAIGN DESCRIPTION in a DESCRIPTION FIELD we need to update any campaign description field in the settings and other design/preview areas too. if ( $element.closest('.charitable-panel-field-textarea').attr('data-special-type') === 'campaign_description' ) { if ( $.trim( app.removeTags( contents ) ) === '' ) { elements.$preview.find('.charitable-campaign-builder-no-description-preview').removeClass('charitable-hidden'); elements.$preview.find('.charitable-field-campaign-description .charitable-campaign-builder-placeholder-preview-text').html( '<div></div>' ); // elements.$fieldOptions.find('.campaign-builder-htmleditor .ql-editor').html( '<div></div>' ); s.campaignDescription = ''; } else { // elements.$preview.find('.charitable-campaign-builder-no-description-preview').addClass('charitable-hidden'); // elements.$preview.find('.charitable-field-campaign-description .charitable-campaign-builder-placeholder-preview-text').html( app.removeTags( contents ) ); elements.$preview.find('.charitable-field-campaign-description .charitable-campaign-builder-placeholder-preview-text').html( '<div>' + contents + '</div>' ); // elements.$fieldOptions.find('.charitable-panel-field').not('[data-field-id="' + field_id + '"]').find('.campaign-builder-htmleditor').pasteHTML([{ insert: contents }]); s.campaignDescription = contents; } $('#charitable-panel-field-settings-campaign_description .ql-editor').html( contents ); } if ( $element.closest('.charitable-panel-field-textarea').attr('data-special-type') === 'campaign_overview' ) { if ( $.trim( app.removeTags( contents ) ) === '' ) { elements.$preview.find('.charitable-campaign-builder-no-overview-preview').removeClass('charitable-hidden') elements.$preview.find('.charitable-field-campaign-overview .charitable-campaign-builder-placeholder-preview-text').html( '<div></div>' ); s.campaignDescription = ''; } else { elements.$preview.find('.charitable-field-campaign-overview .charitable-campaign-builder-placeholder-preview-text').html( '<div>' + contents + '</div>' ); s.campaignDescription = contents; } $('#charitable-panel-field-settings-campaign_overview .ql-editor').html( contents ); } if ( $element.closest('.charitable-panel-field-textarea').attr('data-special-type') === 'organizer_content' ) { field_id = parseInt( $element.closest('.charitable-panel-field-textarea').data('field-id') ); if ( $.trim( app.removeTags( contents ) ) === '' ) { elements.$preview.find('#charitable-field-' + field_id + ' .charitable-organizer-description').html( '<div></div>' ); } else { elements.$preview.find('#charitable-field-' + field_id + ' .charitable-organizer-description').html( '<div>' + contents + '</div>' ); } } if ( $element.closest('.charitable-panel-field-textarea').attr('data-special-type') === 'text' ) { field_id = parseInt( $element.closest('.charitable-panel-field-textarea').data('field-id') ); if ( $.trim( app.removeTags( contents ) ) === '' ) { elements.$preview.find('#charitable-field-' + field_id + ' .charitable-campaign-builder-placeholder-preview-text').html( '<div></div>' ); } else { elements.$preview.find('#charitable-field-' + field_id + ' .charitable-campaign-builder-placeholder-preview-text').html( '<div>' + contents + '</div>' ); } // $('#charitable-panel-field-settings-campaign_overview .ql-editor').html( contents ); } if ( minmum !== false ) { var div_height = parseInt( $element.find('.ql-editor').height() / 2 ); $('#tab_' + tab_id + '_content .placeholder.big').css('min-height', div_height+'px'); } }); } else { /* already on the list */ } }, /** * Init the suggested donations area in campaign settings. * * @since 1.8.0 * * @param {object} $element Data. */ initSuggestedDonations: function ( $element ) { wpchar.debug( $element, 'initSuggestedDonations' ); var $table = $element.closest( '.charitable-campaign-suggested-donations' ), $add_row_button = $element.find('[data-charitable-add-row]'), donation_type = $add_row_button.data( 'charitable-add-row' ), // eslint-disable-line $delete_row_button = $element.find('.charitable-delete-row'); $add_row_button.on( 'click', function( event ) { event.preventDefault(); event.stopImmediatePropagation(); var type = $( this ).data( 'charitable-add-row' ); if ( 'suggested-amount' === type ) { app.add_suggested_amount_row( $( this ) ); } else if ( 'suggested-recurring-amount' === type ) { app.add_suggested_amount_row( $( this ), 'recurring' ); } app.initSuggestedDonations( $element ); return false; }); $delete_row_button.on( 'click', function( event ) { event.preventDefault(); event.stopImmediatePropagation(); var donation_type = $( this ).closest( '.charitable-campaign-suggested-donations' ).find('[data-charitable-add-row]').data( 'charitable-add-row' ); if ( 'suggested-amount' === donation_type ) { app.delete_suggested_amount_row( $( this ) ); } else if ( 'suggested-recurring-amount' === donation_type ) { app.delete_suggested_amount_row( $( this ), 'recurring' ); } app.initSuggestedDonations( $element ); return false; }); $('.charitable-campaign-suggested-donations tbody').sortable({ items: "tr:not(.to-copy)", handle: ".handle", stop: function( event, ui ) { // eslint-disable-line app.reindex_rows(); // app.redrawDonationAmountsPreview( $table ); $( '.charitable-campaign-suggested-donations-mini' ).each( function() { // app.initSuggestedDonationsMini( $( this ) ); app.updateSuggestdDonationsMiniRowsFromSettings( $( this ) ); app.redrawDonationAmountsPreview( $( this ) ); }); } }); $table.on( 'click', 'th.default_amount-col a, a.charitable-clear-defaults', function() { $table.find('.default_amount-col input').prop('checked', false); $( this ).blur(); return false; }); // if there is any change in the radio button update with redrawDonationAmountsPreview. $table.on( 'change', 'input[type="radio"]', function() { app.redrawDonationAmountsPreview( $table ); }); }, /** * Just update the mini rows of a suggested donations table. * * @since 1.8.0 * * @param {object} $element Data. * @param {int} field_id Field ID. */ updateSuggestdDonationsMiniRowsFromSettings: function( $element, field_id = 0 ) { if ( 0 === field_id ) { field_id = $element.closest('.charitable-panel-field').data('field-id'); } // Remove all rows in this table except the table with the class 'to-copy'. $element.find('tbody').children('tr').not('.to-copy').remove(); // Get the values from the donation suggestions table in settings and update them for this table. $('#campaign_donation_amounts tbody').children('tr').not('.no-suggested-amounts').not('.to-copy').each( function( index ) { // eslint-disable-line var row_to_add = '', updatedIndex = index + 1, updatedDonationValue = $( this ).find('.amount-col input').val(), isChecked = $( this ).find('.default_amount-col input').is(':checked') ? 'checked' : ''; row_to_add = row_to_add + '<tr class="" data-index="' + updatedIndex + '">'; row_to_add = row_to_add + '<td class="reorder-col"><span class="charitable-icon charitable-icon-donations-grab handle ui-sortable-handle"></span></td>'; row_to_add = row_to_add + '<td class="default_amount-col"><input ' + isChecked + ' type="radio" class="campaign_suggested_donations" name="_fields][' + field_id + '][donation_amounts][campaign_suggested_donations_default][]" value="' + updatedIndex + '"></td>'; row_to_add = row_to_add + '<td class="amount-col"><input autocomplete="false" type="text" class="campaign_suggested_donations" name="_fields][' + field_id + '][donation_amounts][' + updatedIndex + '][amount]" value="' + updatedDonationValue + '" placeholder="Amount"></td>'; row_to_add = row_to_add + '<td class="description-col"><input type="text" class="campaign_suggested_donations" name="_fields][' + field_id + '][donation_amounts][' + updatedIndex + '][description]" value="This is a small donation." placeholder="Optional Description">'; row_to_add = row_to_add + '</td>'; row_to_add = row_to_add + '<td class="remove-col"><span class="dashicons-before dashicons-dismiss charitable-delete-row"></span></td>'; row_to_add = row_to_add + '</tr>'; $element.find('tbody').append( row_to_add ); }); return $element; }, /** * Just update the mini rows of a suggested donations table. * * @since 1.8.0 * * @param {object} $element Data. * @param {int} field_id Field ID. */ updateSuggestdDonationsRowsFromSettings: function( $miniTableTBody, $element ) { // Provide a default value. if ( typeof $element === 'undefined' || $element.length === 0 ) { $element = $('#campaign_donation_amounts'); } // Remove all rows in this table except the table with the class 'to-copy'. $element.find('tbody').children('tr').not('.to-copy').remove(); // Get the values from the donation suggestions table in settings and update them for this table. $miniTableTBody.children('tr').not('.no-suggested-amounts').not('.to-copy').each( function( index ) { // eslint-disable-line var row_to_add = '', updatedIndex = index + 1, updatedDonationValue = $( this ).find('.amount-col input').val(), isChecked = $( this ).find('.default_amount-col input').is(':checked') ? 'checked' : ''; row_to_add = row_to_add + '<tr class="" data-index="' + updatedIndex + '">'; row_to_add = row_to_add + '<td class="reorder-col"><span class="charitable-icon charitable-icon-donations-grab handle ui-sortable-handle"></span></td>'; row_to_add = row_to_add + '<td class="default_amount-col"><input ' + isChecked + ' type="radio" class="campaign_suggested_donations" name="settings][donation-options][donation_amounts][campaign_suggested_donations_default][]" value="' + updatedIndex + '">'; row_to_add = row_to_add + '<td class="amount-col"><input autocomplete="off" type="text" class="campaign_suggested_donations" name="settings][donation-options][donation_amounts][' + updatedIndex + '][amount]" value="' + updatedDonationValue + '" placeholder="Amount">'; row_to_add = row_to_add + '<td class="description-col"><input type="text" class="campaign_suggested_donations" name="settings][donation-options][donation_amounts][' + updatedIndex + '][description]" value="This is a small donation." placeholder="Optional Description">'; row_to_add = row_to_add + '</td>'; row_to_add = row_to_add + '<td class="remove-col"><span class="dashicons-before dashicons-dismiss charitable-delete-row"></span></td>'; row_to_add = row_to_add + '</tr>'; $element.find('tbody').append( row_to_add ); }); return $element; }, /** * Init the suggested donations area in campaign settings. * * @since 1.8.0 * * @param {object} $element Data. */ initSuggestedDonationsMini: function ( $element ) { wpchar.debug( $element, 'initSuggestedDonationsMini' ); wpchar.debug( 'initSuggestedDonationsMini' ); var field_id = $element.closest('.charitable-panel-field').data('field-id'); wpchar.debug( $element, 'initSuggestedDonationsMini' ); app.updateSuggestdDonationsMiniRowsFromSettings( $element, field_id ); wpchar.debug( $element, 'initSuggestedDonationsMini2' ); app.redrawDonationAmountsPreview( $element ); wpchar.debug( $element, 'initSuggestedDonationsMini3' ); var $table = $element.closest( '.charitable-campaign-suggested-donations-mini' ), $add_row_button = $element.find('[data-charitable-add-row]'); $add_row_button.on( 'click', function() { var type = $( this ).data( 'charitable-add-row' ); if ( 'suggested-amount' === type ) { wpchar.debug ('type is suggesetd amount'); wpchar.debug( $ ( this ) ); app.add_suggested_amount_row( $( this ), 'mini' ); } return false; }); $('.charitable-campaign-suggested-donations-mini tbody').sortable({ items: "tr:not(.to-copy)", handle: ".handle", stop: function( event, ui ) { // eslint-disable-line wpchar.debug( 'sortable test mini '); app.reindex_rows( 'mini' ); app.updateSuggestdDonationsRowsFromSettings( $( this ) ); app.redrawDonationAmountsPreview( $( this ).parent() ); } }); $table.on( 'click', '.charitable-delete-row', function() { app.delete_suggested_amount_row( $( this ), 'mini' ); return false; }); $table.on( 'click', 'th.default_amount-col a', function() { $table.find('.default_amount-col input').prop('checked', false); $( this ).blur(); return false; }); // if there is any change in the radio button update with redrawDonationAmountsPreview. $table.on( 'change', 'input[type="radio"]', function() { app.redrawDonationAmountsPreview( $table ); // If there is a change to the radio buttons, make sure to sync this change so that everyone ahs the same default donation. // Get the value of this radio button. var radioButtonValue = $(this).val(); $builder.find( '.charitable-campaign-suggested-donations-table' ).find('input[type="radio"]').prop('checked', false ); $builder.find( '.charitable-campaign-suggested-donations-table' ).each( function() { $(this).find('input[type="radio"][value="' + radioButtonValue + '"]').prop('checked', true ); }); }); }, /** * Adds a row in the suggestion dations area. * * @since 1.8.0 * * @param {object} $button Button, clicked. * @param {string} type The type of table to reindex. */ add_suggested_amount_row: function( $button, type = '' ) { // eslint-disable-line wpchar.debug('add_suggested_amount_row'); wpchar.debug('.charitable-campaign-suggested-donations' + type ); const $donations_table = type === 'recurring' ? $builder.find( '.charitable-campaign-suggested-recurring-donations-table' ) : $builder.find( '.charitable-campaign-suggested-donations-table' ); // Go through the donations table instances, in settings or not. $donations_table.each( function() { wpchar.debug( $( this ) ); var $table = $(this).closest('table').find('tbody'), $clone = $table.find('tr.to-copy').clone().removeClass('to-copy hidden'); // find the data-index in the tr in the clone and update it to the number of rows that already exist in the table. var newIndex = $table.find('tr:not(.to-copy)').length + 1; $clone.attr('data-index', newIndex ); // Replace the [0] in the input name with the data-index number. var inputFieldName = $clone.find('.amount-col input[type="text"].campaign_suggested_donations').attr('name'), newInputFieldName = inputFieldName.replace('[0]', '[' + newIndex + ']'), inputFieldNameDescription = $clone.find('.description-col input[type="text"].campaign_suggested_donations').attr('name'), newInputFieldNameDescription = inputFieldNameDescription.replace('[0]', '[' + newIndex + ']'); wpchar.debug( $clone.find('.amount-col input[type="text"].campaign_suggested_donations') ); wpchar.debug( $clone.find('.amount-col input[type="text"].campaign_suggested_donations').attr('name') ); $clone.find('.amount-col input[type="text"].campaign_suggested_donations').attr('name', newInputFieldName ); $clone.find('.description-col input[type="text"].campaign_suggested_donations').attr('name', newInputFieldNameDescription ); $clone.find('.default_amount-col input[type="radio"]').val( newIndex ); wpchar.debug( $table, 'table' ); wpchar.debug( $clone, 'clone' ); $table.find( '.no-suggested-amounts' ).hide(); $table.append( $clone ); $clone.on( 'click', '.charitable-delete-row', function() { app.delete_suggested_amount_row( $(this), type ); return false; }); }); app.redrawDonationAmountsPreview( $builder.find( '.charitable-campaign-suggested-donations-table' ).first() ); app.reindex_rows( type ); if ( type === '' ) { app.toggle_custom_donations_checkbox(); } }, /** * Removes a row in the suggestion dontions area. * * @since 1.8.0 * * @param {object} $button Button, clicked. * @param {string} type The type of table to reindex. */ delete_suggested_amount_row: function( $button, type = '' ) { wpchar.debug('delete_suggested_amount_row'); wpchar.debug( $button ); wpchar.debug( type ); var $row_to_delete = $button.closest( 'tr '), row_to_delete_index = parseInt( $row_to_delete.attr('data-index') ); wpchar.debug( $row_to_delete ); wpchar.debug( row_to_delete_index, 'row_to_delete_index' ); const $donations_table = type === 'recurring' ? $builder.find( '.charitable-campaign-suggested-recurring-donations-table' ) : $builder.find( '.charitable-campaign-suggested-donations-table' ), donations_table_class = type === 'recurring' ? '.charitable-campaign-suggested-recurring-donations-table' : '.charitable-campaign-suggested-donations-table'; if ( row_to_delete_index > 0 ) { wpchar.debug( $donations_table.find(' tbody tr[data-index="' + row_to_delete_index + '"]') ); wpchar.debug( donations_table_class + ' tbody tr[data-index="' + row_to_delete_index + '"]' ); // remove the row in all instances of the donations table $donations_table.find(' tbody tr[data-index="' + row_to_delete_index + '"]').remove(); } app.redrawDonationAmountsPreview( $builder.find( '.charitable-campaign-suggested-donations-table' ).first() ); var $table = $button.closest('table').find('tbody'); if ( $table.find( 'tr:not(.to-copy)' ).length == 1 ){ $table.find( '.no-suggested-amounts' ).removeClass('hidden').show(); } // Reindex the rows. app.reindex_rows( type ); if ( type === '' ) { app.reindex_rows( 'mini' ); } else if ( type === 'mini' ) { app.reindex_rows(); } if ( type === '' ) { app.toggle_custom_donations_checkbox(); } }, /** * Reindexes the rows in the suggestion dontions area. * * @since 1.8.0 * * @param {string} type The type of table to reindex. * */ reindex_rows: function( type = '' ) { wpchar.debug('reindex rows with type: ' + type ); if ( type !== '' ) { type = '-' + type; } $('.charitable-campaign-suggested-donations' + type + ' tbody').each(function(){ $(this).children('tr').not('.no-suggested-amounts .to-copy').each( function( index ) { $(this).find('input[type="radio"]').val( index ); $(this).attr('data-index', index ); $(this).find('input').each(function(i) { // eslint-disable-line this.name = this.name.replace(/(\[\d\])/, '[' + index + ']'); }); }); }); }, /** * Redraws the donation amounts preview based on the values in the suggested donations table. * * @since 1.8.0 * * @param {object} targetTable The table to redraw the preview for. * */ redrawDonationAmountsPreview: function( targetTable ) { // for each ul element called 'charitable-preview-donation-amounts'... elements.$preview.find('ul.charitable-preview-donation-amounts').each( function( index ) { // eslint-disable-line var $theDontionAmountsList = $( this ); // remove all the li. $theDontionAmountsList.find('li').remove(); // look at targetTable - a suggested donations table - and read each row and repopulate the amounts unordered list. $( targetTable ).find('tbody').children('tr').not('.no-suggested-amounts').not('.to-copy').not('hidden').each( function( index ) { // eslint-disable-line var theInputTextValue = $( this ).find('input[type="text"].campaign_suggested_donations').first().val(); // If the radio button is checked, add the class 'selected' to the li. var selected = ''; wpchar.debug($( this ).find('input[type="radio"]')); if ( $( this ).find('input[type="radio"]').is(':checked') ) { selected = ' selected'; } $theDontionAmountsList.append( '<li class="charitable-preview-donation-amount suggested-donation-amount' + selected + '"><label><input type="radio" name="donation_amount" value="' + index + '"><span class="amount">' + theInputTextValue + '</span></label></li>' ); }); // Add the custom donation HTML if the checkbox is checked. if ( $( '#charitable-panel-field-settings-campaign_allow_custom_donations').is(':checked') ) { $theDontionAmountsList.append( '<li class="charitable-preview-donation-amount custom-donation-amount "><span class="custom-donation-amount-wrapper"><label><input type="radio" name="donation_amount" value="custom"><span class="description">Custom amount</span></label><input type="text" disabled=""true"" class="custom-donation-input" name="custom_donation_amount" placeholder="Custom Donation Amount" value=""></span></li>' ); } }); }, /** * Add handler for the toggle that allows/disallows custom donations. * * @since 1.8.0 * */ toggle_custom_donations_checkbox: function() { var $custom = $('#campaign_allow_custom_donations'), $suggestions = $('.charitable-campaign-suggested-donations tbody tr:not(.to-copy)'), has_suggestions = $suggestions.length > 1 || false === $suggestions.first().hasClass('no-suggested-amounts'); $custom.prop( 'disabled', ! has_suggestions ); if ( ! has_suggestions ) { $custom.prop( 'checked', true ); } }, /** * Init the tag field in campaign settings. * * @since 1.8.0 * * @param {object} $element Data. */ initTagField: function( $element ) { $element.select2(); }, /** * Init color picker fields in campaign settings. * * @since 1.8.0 * * @param {object} $element Data. */ initColorPicker: function() { Coloris({ // eslint-disable-line el: '.coloris' }); Coloris.setInstance('.instance2.primary', { // eslint-disable-line defaultColor: s.primaryThemeColor, onChange : function ( color ) { if ( '' === color ) { $('input[name="layout__advanced__theme_color_primary"]').val( s.primaryThemeColorBase ); s.primaryThemeColor = s.primaryThemeColorBase; document.querySelector('input[name="layout__advanced__theme_color_primary"]').dispatchEvent(new Event('input', { bubbles: true })); } else { s.primaryThemeColor = color; } app.updateThemeCSS( 'primary', s.templateID, s.primaryThemeColor, s.secondaryThemeColor, s.tertiaryThemeColor, s.buttonThemeColor, true ); }, theme: 'polaroid', themeMode: 'light', alpha: false, formatToggle: true, closeButton: true, clearButton: true, clearLabel: 'Reset', swatches: [ '#067bc2', '#84bcda', '#80e377', '#ecc30b', '#f37748', '#d56062' ] }); Coloris.setInstance('.instance2.secondary', { // eslint-disable-line defaultColor: s.secondaryThemeColor, onChange : function ( color ) { if ( '' === color ) { $('input[name="layout__advanced__theme_color_secondary"]').val( s.secondaryThemeColorBase ); s.secondaryThemeColor = s.secondaryThemeColorBase; app.updateThemeCSS( 'secondary', s.templateID, s.primaryThemeColor, s.secondaryThemeColor, s.tertiaryThemeColor, s.buttonThemeColor, true ); document.querySelector('input[name="layout__advanced__theme_color_secondary"]').dispatchEvent(new Event('input', { bubbles: true })); } else { s.secondaryThemeColor = color; app.updateThemeCSS( 'secondary', s.templateID, s.primaryThemeColor, s.secondaryThemeColor, s.tertiaryThemeColor, s.buttonThemeColor, true ); } }, theme: 'polaroid', themeMode: 'light', alpha: false, formatToggle: true, closeButton: true, clearButton: true, clearLabel: 'Reset', swatches: [ '#067bc2', '#84bcda', '#80e377', '#ecc30b', '#f37748', '#d56062' ] }); Coloris.setInstance('.instance2.tertiary', { // eslint-disable-line defaultColor: s.tertiaryThemeColor, onChange : function ( color ) { if ( '' === color ) { $('input[name="layout__advanced__theme_color_tertiary"]').val( s.tertiaryThemeColorBase ); s.tertiaryThemeColor = s.tertiaryThemeColorBase; app.updateThemeCSS( 'teritary', s.templateID, s.primaryThemeColor, s.secondaryThemeColor, s.tertiaryThemeColor, s.buttonThemeColor, true ); document.querySelector('input[name="layout__advanced__theme_color_tertiary"]').dispatchEvent(new Event('input', { bubbles: true })); } else { s.tertiaryThemeColor = color; app.updateThemeCSS( 'teritary', s.templateID, s.primaryThemeColor, s.secondaryThemeColor, s.tertiaryThemeColor, s.buttonThemeColor, true ); } }, theme: 'polaroid', themeMode: 'light', alpha: false, formatToggle: true, closeButton: true, clearButton: true, clearLabel: 'Reset', swatches: [ '#067bc2', '#84bcda', '#80e377', '#ecc30b', '#f37748', '#d56062' ] }); Coloris.setInstance('.instance2.button-color', { // eslint-disable-line defaultColor: s.buttonThemeColor, onChange : function ( color ) { if ( '' === color ) { $('input[name="layout__advanced__theme_color_button"]').val( s.buttonThemeColorBase ); s.buttonThemeColor = s.buttonThemeColorBase; app.updateThemeCSS( 'button', s.templateID, s.primaryThemeColor, s.secondaryThemeColor, s.tertiaryThemeColor, s.buttonThemeColor, true ); document.querySelector('input[name="layout__advanced__theme_color_button"]').dispatchEvent(new Event('input', { bubbles: true })); } else { s.buttonThemeColor = color; app.updateThemeCSS( 'button', s.templateID, s.primaryThemeColor, s.secondaryThemeColor, s.tertiaryThemeColor, s.buttonThemeColor, true ); } }, theme: 'polaroid', themeMode: 'light', alpha: false, formatToggle: true, closeButton: true, clearButton: true, clearLabel: 'Reset', swatches: [ '#067bc2', '#84bcda', '#80e377', '#ecc30b', '#f37748', '#d56062' ] }); /* make it so clicking the badge triggers the popup */ elements.$fieldOptions.on( 'click', '.clr-field button', function( e ) { e.preventDefault(); $( this ).parent().find('input[type="text"]').trigger('click'); }); }, /** * Init the date pickers in campaign settings. * * @since 1.8.0 * * @param {object} $element Data. */ initDatePicker: function( $element ) { var $the_element = $element, options = { dateFormat : $the_element.data('format') || 'MM d, yy', minDate : $the_element.data('min-date') || '', beforeShow : function( input, inst ) { // eslint-disable-line setTimeout( function() { $('.ui-datepicker').css('z-index', 99999999999999); }, 0); } }; if ( $.isFunction( $the_element.datepicker ) ) { $the_element.datepicker( options ); if ( $the_element.data('date') ) { $the_element.datepicker( 'setDate', this.$el.data('date') ); } if ( $the_element.data('min-date') ) { $the_element.datepicker( 'option', 'minDate', this.$el.data('min-date') ); } } }, /** * Trim long form titles. * * @since 1.8.0 */ trimFormTitle: function() { var $title = $( '.charitable-center-form-name' ); if ( $title.text().length > 38 ) { var shortTitle = $title.text().trim().substring( 0, 38 ).split( ' ' ).slice( 0, -1 ).join( ' ' ) + '...'; $title.text( shortTitle ); } }, /** * Hotkeys: * Ctrl+t - Templates. * * @since 1.8.0 * @since 1.8.0.4 Added ctrl+x to exit builder. */ builderHotkeys: function() { hotkeys('esc,ctrl+1,ctrl+2,ctrl+3,ctrl+4,ctrl+5,ctrl+s,ctrl+p,ctrl+x,ctrl+v', function ( event, handler ){ // eslint-disable-line switch (handler.key) { case 'esc': // this is a non-standard modal popup, so we want to close it manually with the esc key. if ( $('.charitable-builder-modal.charitable-builder-modal-template-preview').hasClass('active') ) { $('.charitable-template-list-container').removeClass('disabled'); $('#charitable-builder-underlay').remove(); $('.charitable-builder-modal.charitable-builder-modal-template-preview').removeClass('active'); } break; case 'ctrl+1': $( elements.$templateButton, $builder ).trigger( 'click' ); break; case 'ctrl+2': $( elements.$designButton, $builder ).trigger( 'click' ); break; case 'ctrl+3': $( elements.$settingsButton, $builder ).trigger( 'click' ); break; case 'ctrl+4': $( elements.$marketingButton, $builder ).trigger( 'click' ); break; case 'ctrl+5': $( elements.$paymentButton, $builder ).trigger( 'click' ); break; case 'ctrl+s': // Save Campaign $( elements.$saveButton, $builder ).trigger( 'click' ); break; case 'ctrl+p': // Preview $( elements.$previewButton, $builder ).trigger( 'click' ); break; case 'ctrl+x': $( elements.$exitButton, $builder ).trigger( 'click' ); break; case 'ctrl+v': $( elements.$viewCampaignButton, $builder ).trigger( 'click' ); break; } }); }, /* LITE OR UPDATE/INSTALL SPECIFIC */ /** * Registers click events that should open upgrade modal. * * @since 1.8.0 */ openModalButtonClick: function() { $( document ) .on( 'click', '.charitable-not-available:not(.charitable-add-fields-button)', app.openModalButtonHandler ) .on( 'mousedown', '.charitable-not-available.charitable-add-fields-button', app.openModalButtonHandler ); $( document ) .on( 'click', '.charitable-disabled-modal:not(.charitable-add-fields-button)', app.openModalWarningModal ) .on( 'mousedown', '.charitable-add-fields-button.charitable-disabled-modal', app.openModalWarningModal ); $( document ) .on( 'click', '.charitable-disabled-same_page:not(.charitable-add-fields-button)', app.openModalWarningModal ) .on( 'mousedown', '.charitable-add-fields-button.charitable-disabled-same_page', app.openModalWarningModal ); $( document ) .on( 'click', '.charitable-not-installed:not(.charitable-add-fields-button)', app.openModalButtonHandlerInstall ) .on( 'mousedown', '.charitable-not-installed.charitable-add-fields-button', app.openModalButtonHandlerInstall ); $( document ) .on( 'click', '.charitable-not-activated:not(.charitable-add-fields-button)', app.openModalButtonHandlerActivate ) .on( 'mousedown', '.charitable-not-activated.charitable-add-fields-button', app.openModalButtonHandlerActivate ); $( document ) .on( 'click', '.charitable-addon-file-missing:not(.charitable-add-fields-button)', app.openModalButtonHandlerInstall ) .on( 'mousedown', '.charitable-addon-file-missing.charitable-add-fields-button', app.openModalButtonHandlerInstall ); $( document ) .on( 'click', '.charitable-not-available:not(.charitable-setting-panel-upgrade-to-pro)', app.openModalButtonHandler ) .on( 'mousedown', '.charitable-not-available.charitable-setting-panel-upgrade-to-pro', app.openModalButtonHandler ); $( document ) .on( 'click', '.charitable-need-upgrade:not(.charitable-setting-panel-upgrade-to-pro)', app.openModalButtonHandler ) .on( 'mousedown', '.charitable-need-upgrade.charitable-setting-panel-upgrade-to-pro', app.openModalButtonHandler ); $( document ) .on( 'click', '.charitable-installed-refresh:not(.charitable-add-fields-button)', app.openModalButtonHandlerActivatedRefresh ) .on( 'mousedown', '.charitable-installed-refresh.charitable-add-fields-button', app.openModalButtonHandlerActivatedRefresh ); /* the below represent buttons inside the preview area in the design tab */ $( document ) .on( 'click', 'a.button-link.charitable-not-activated', app.openModalButtonHandlerActivate ) .on( 'mousedown', 'a.button-link.charitable-not-activated', app.openModalButtonHandlerActivate ); $( document ) .on( 'click', 'a.button-link.charitable-not-installed', app.openModalButtonHandlerInstall ) .on( 'mousedown', 'a.button-link.charitable-not-installed', app.openModalButtonHandlerInstall ); /* the below represent buttons inside the marketing area */ $( document ) .on( 'click', 'a.button-link.charitable-not-activated-button', app.activateFromButton ) .on( 'mousedown', 'a.button-link.charitable-not-activated-button', app.activateFromButton ); $( document ) .on( 'click', 'a.button-link.charitable-not-installed-button', app.installFromButton ) .on( 'mousedown', 'a.button-link.charitable-not-installed-button', app.installFromButton ); }, /** * Open the upgrade modal to activate an extension/plugin from a sepcific button click. * * @since 1.8.1.12 * * @param {object} e Event. * * @return {void} * */ activateFromButton: function( e ) { e.preventDefault(); const $button = $( this ), plugin_url = $( this ).data( 'plugin-url' ), plugin_name = $( this ).data( 'name' ), settings_url = $( this ).data( 'settings-url' ), plugin_slug = $( this ).data( 'plugin-slug' ), enable_url = $( this ).data( 'enable-url' ).length > 0 ? $( this ).data( 'enable-url' ) : ''; // check to makes sure all the variables above are set. if ( ! plugin_url || ! plugin_name ) { return; } app.installFromButtonAjax( plugin_url, plugin_name, settings_url, plugin_slug, enable_url, 'activate', 'addon', $button ); }, /** * Open the upgrade modal to install an extension/plugin from a sepcific button click. * * @since 1.8.1.12 * * @param {object} e Event. * * @return {void} * */ installFromButton: function( e ) { e.preventDefault(); const $button = $( this ), plugin_url = $( this ).data( 'plugin-url' ), plugin_name = $( this ).data( 'name' ), settings_url = $( this ).data( 'settings-url' ), plugin_slug = $( this ).data( 'plugin-slug' ), enable_url = $( this ).data( 'enable-url' ).length > 0 ? $( this ).data( 'enable-url' ) : ''; // check to makes sure all the variables above are set. if ( ! plugin_url || ! plugin_name ) { return; } app.installFromButtonAjax( plugin_url, plugin_name, settings_url, plugin_slug, enable_url, 'install', 'addon', $button ); }, /** * Change plugin/addon state. * * @since 1.8.0 * * @param {string} plugin_url Plugin URL. * @param {string} plugin_name Plugin name. */ installFromButtonAjax: function( plugin_url, plugin_name, settings_url, plugin_slug, enable_url, state, pluginType, $button ) { wpchar.debug ( 'setAddonState' ); wpchar.debug ( plugin_url ); wpchar.debug ( plugin_name ); wpchar.debug ( state ); var actions = { 'activate': 'charitable_activate_addon', 'install': 'charitable_install_addon', 'deactivate': 'charitable_deactivate_addon' }, action = actions[ state ]; if ( ! action ) { return; } var plugin_ajax = plugin_url; // update the text of the button. if ( 'install' === state ) { if ( enable_url.length > 0 ) { // this is a payment extension $button.text( 'Installing and activating gateway...' ); } else { $button.text( 'Installing and activating...' ); } $button.removeClass( 'charitable-not-installed-button' ); $button.addClass( 'charitable-view-settings-button' ); } else if ( 'activate' === state ) { if ( enable_url.length > 0 ) { // this is a payment extension $button.text( 'Activating gateway...' ); } else { $button.text( 'Activating...' ); } $button.removeClass( 'charitable-not-activated-button' ); $button.addClass( 'charitable-view-settings-button' ); plugin_ajax = plugin_slug; } // Override the plugin var in the ajax if this is activation. var data = { action: action, nonce: charitable_admin.nonce, // eslint-disable-line plugin: plugin_ajax, type: pluginType }; wpchar.debug ( data ); $.post( charitable_admin.ajax_url, data, function( res ) { // eslint-disable-line // update the text of the button. if ( 'install' === state ) { // all buttons that have a data attribute of data-plugin-slug that matches "test". $( 'a.button-link[data-plugin-slug="' + plugin_slug + '"]' ).each( function() { $( this ).text( 'View Settings' ); $( this ).removeClass( 'charitable-not-installed-button' ); $( this ).addClass( 'charitable-view-settings-button' ); if ( enable_url.length > 0 ) { // this is a payment extension $( this ).attr( 'href', enable_url ); } else { $( this ).attr( 'href', settings_url ); } $( this ).attr( 'target', '_blank' ); }); $( 'section.header-content h2' ).addClass('charitable-hidden'); $( 'section.header-content h2.charitable-header-content-activated' ).removeClass('charitable-hidden'); } else if ( 'activate' === state ) { // all buttons that have a data attribute of data-plugin-slug that matches "test". $( 'a.button-link[data-plugin-slug="' + plugin_slug + '"]' ).each( function() { $( this ).text( 'View Settings' ); $( this ).removeClass( 'charitable-not-installed-button' ); $( this ).addClass( 'charitable-view-settings-button' ); if ( enable_url.length > 0 ) { // this is a payment extension $( this ).attr( 'href', enable_url ); } else { $( this ).attr( 'href', settings_url ); } $( this ).attr( 'target', '_blank' ); }); $( 'section.header-content h2' ).addClass('charitable-hidden'); $( 'section.header-content h2.charitable-header-content-activated' ).removeClass('charitable-hidden'); } } ).fail( function( xhr ) { wpchar.debug( xhr.responseText ); } ); }, /** * Open "you're using modal" modal handler. * * @since 1.8.0 * * @param {Event} event Event. */ openModalWarningModal: function( event ) { const $this = $( this ); event.preventDefault(); event.stopImmediatePropagation(); let name = $this.data( 'name' ), icon = '', reason = ''; if ( $this.hasClass( 'charitable-add-fields-button' ) ) { name = $this.text(); name += name.indexOf( charitable_builder.field ) < 0 ? ' ' + charitable_builder.field : ''; // if the button has an attribute of data-icon, we want to use that icon instead of the default one. if ( $this.data('field-icon') ) { icon = $this.data('field-icon'); } } if ( $this.hasClass( 'charitable-disabled-modal' ) ) { reason = 'modal'; } else if ( $this.hasClass( 'charitable-disabled-same_page' ) ) { reason = 'same_page'; } app.modalWarningModal( name, reason, icon ); }, /** * Open education modal handler. * * @since 1.8.0 * * @param {Event} event Event. */ openModalButtonHandlerInstall: function( event ) { const $this = $( this ); var icon = '', plugin_url = '', video = '', license = '', elementType = false; if ( $this.data( 'action' ) && [ 'activate', 'install' ].includes( $this.data( 'action' ) ) ) { return; } event.preventDefault(); event.stopImmediatePropagation(); let name = $this.data( 'name' ); if ( $this.hasClass( 'charitable-add-fields-button' ) ) { name = $this.text(); name += name.indexOf( charitable_builder.field ) < 0 ? ' ' + charitable_builder.field : ''; // if the button has an attribute of data-icon, we want to use that icon instead of the default one. if ( $this.data('field-icon') ) { icon = $this.data('field-icon'); } } if ( $this.data( 'install' ) ) { plugin_url = $this.data( 'install' ); } else if ( $this.data( 'plugin-url' ) ) { plugin_url = $this.data('plugin-url'); } if ( $this.data( 'video' ) ) { video = $this.data('video'); } if ( $this.data( 'license' ) ) { license = $this.data('license'); } app.installModal( name, plugin_url, license, video, $this, elementType, icon ); }, /** * Open education modal handler. * * @since 1.8.0 * * @param {Event} event Event. */ openModalButtonHandlerActivatedRefresh: function( event ) { const $this = $( this ); event.preventDefault(); event.stopImmediatePropagation(); let name = $this.data( 'name' ); app.activateRefreshModal( name, $this.data( 'video' ) ); }, /** * Open education modal handler. * * @since 1.8.0 * * @param {Event} event Event. */ openModalButtonHandlerActivate: function( event ) { const $this = $( this ); var icon = '', plugin_url = '', video = '', license = '', elementType = false; if ( $this.data( 'action' ) && [ 'activate', 'install' ].includes( $this.data( 'action' ) ) ) { return; } event.preventDefault(); event.stopImmediatePropagation(); let name = $this.data( 'name' ); if ( $this.data('plugin-url') ) { plugin_url = $this.data('plugin-url'); } if ( $this.data('video') ) { video = $this.data('video'); } if ( $this.data('license') ) { license = $this.data('license'); } app.activateModal( name, plugin_url, license, video, $this, elementType, icon ); }, /** * Open education modal handler. * * @since 1.8.0 * * @param {Event} event Event. */ openModalButtonHandler: function( event ) { const $this = $( this ); if ( $this.data( 'action' ) && [ 'activate', 'install' ].includes( $this.data( 'action' ) ) ) { return; } event.preventDefault(); event.stopImmediatePropagation(); let icon = '', name = $this.data( 'name' ), elementType = $this.data( 'type' ); if ( $this.hasClass( 'charitable-add-fields-button' ) ) { name = $this.text(); name += name.indexOf( charitable_builder.field ) < 0 ? ' ' + charitable_builder.field : ''; // if the button has an attribute of data-icon, we want to use that icon instead of the default one. if ( $this.data('field-icon') ) { icon = $this.data('field-icon'); } } const utmContent = 'utmValue'; // charitableEducation.core.getUTMContentValue( $this ); app.upgradeModal( name, utmContent, $this.data( 'license' ), $this.data( 'video' ), elementType, icon ); }, /** * Upgrade modal. * * @since 1.8.0 * * @param {string} feature Field name or feature. * @param {string} reason slug for the why reason. * @param {string} icon icon slug. */ modalWarningModal: function( feature, reason = '', icon = '' ) { var message = '', modalWidth = app.getUpgradeModalWidth( false ), title = ''; if ( reason === 'modal' ) { message = charitable_builder.field_disabled_due_to_modal.replace( /%name%/g, feature ) } else if ( reason === 'same_page' ) { message = charitable_builder.field_disabled_due_to_same_page.replace( /%name%/g, feature ) } var modal = $.alert( { // eslint-disable-line backgroundDismiss: true, title : title, icon : icon !== '' ? 'fa ' + icon : 'fa fa-thumbs-up', content : message, boxWidth : modalWidth, theme : 'modern,charitable-install-form', closeIcon : true, buttons : { confirm: { text : charitable_builder.ok, btnClass: 'btn-confirm', keys : [ 'enter' ], action: function() { } }, cancel: { text : charitable_builder.go_to_settings, btnClass: 'btn-confirm', action: function() { window.open( charitable_builder.settings_page_url ); } } } } ); }, /** * Change plugin/addon state. * * @since 1.8.0 * * @param {string} plugin Plugin slug or URL for download (example: charitable-geolocation/charitable-geolocation.php) * @param {string} state State status activate|deactivate|install. * @param {string} pluginType Plugin type addon or plugin. * @param {Function} callback Callback for get result from AJAX. */ setAddonState: function( plugin_url, plugin_name, state, pluginType, modal, clickedObject, callback ) { wpchar.debug ( 'setAddonState' ); wpchar.debug ( plugin_url ); wpchar.debug ( plugin_name ); wpchar.debug ( state ); var actions = { 'activate': 'charitable_activate_addon', 'install': 'charitable_install_addon', 'deactivate': 'charitable_deactivate_addon' }, action = actions[ state ]; if ( ! action ) { return; } var data = { action: action, nonce: charitable_admin.nonce, // eslint-disable-line plugin: plugin_url, type: pluginType }; wpchar.debug ( data ); $.post( charitable_admin.ajax_url, data, function( res ) { // eslint-disable-line callback( res, plugin_url, plugin_name, state, modal, clickedObject ); } ).fail( function( xhr ) { wpchar.debug( xhr.responseText ); } ); }, /** * Respond for the plugin/addon state. * * @since 1.8.0 * */ callBackAddonState: function( res, plugin_url = '', plugin_name = '', state = '', modal = false, clickedObject ) { wpchar.debug ( 'callBackAddonState' ); wpchar.debug ( res ); wpchar.debug ( state ); wpchar.debug ( modal ); var successText = ''; if ( res.success ) { if ( 'install' === state ) { wpchar.debug('installed'); // close the current modal window, if you can. if ( s.currentModal !== false && 'object' === typeof s.currentModal ) { s.currentModal.close(); } if ( res.data.is_activated ) { successText = res.data.msg; app.upgradeModalAddonInstalledAndActivated( plugin_url, plugin_name, successText ); } else { app.upgradeModalAddonInstalledAndActivatedFailed( plugin_url, plugin_name, successText ); } } else if ( 'activate' === state ) { wpchar.debug('activated'); successText = res.data; // close the current modal window, if you can. if ( s.currentModal !== false && 'object' === typeof s.currentModal ) { s.currentModal.close(); } app.upgradeModalAddonActivated( plugin_url, plugin_name, successText ); // Add class class to clickedObject, which should be the button they clicked. clickedObject.addClass( 'charitable-installed-refresh' ).removeClass( 'charitable-not-activated' ); app.openModalButtonClick(); } else { wpchar.debug('some other success'); successText = res.data; // close the current modal window, if you can. if ( s.currentModal !== false && 'object' === typeof s.currentModal ) { s.currentModal.close(); } app.upgradeModalAddonActivated( plugin_url, plugin_name, successText ); // Add class class to clickedObject, which should be the button they clicked. clickedObject.addClass( 'charitable-installed-refresh' ).removeClass( 'charitable-not-activated' ); app.openModalButtonClick(); } } else { // close the current modal window, if you can. if ( s.currentModal !== false && 'object' === typeof s.currentModal ) { s.currentModal.close(); } app.upgradeModalAddonActivatedFailed( plugin_url, plugin_name, successText ); } }, /** * Refresh notice modal. * * @since 1.8.0 * * @param {string} feature Feature name. * @param {string} type Feature license type: 'pro', 'basic', 'plus', 'agency', 'elite'. * @param {string} video Feature video URL. * @param {string} elementType Element type. */ activateRefreshModal: function( name, video, icon = '' ) { wpchar.debug('activateRefreshModal'); wpchar.debug( name ); wpchar.debug( video ); var message = charitable_builder.activated_refresh.replace( /%addon%/g, name ), isVideoModal = ! _.isEmpty( video ), // eslint-disable-line modalWidth = app.getUpgradeModalWidth( isVideoModal ), title = '<span class="charitable-upgrade-pro-title">' + name + ' ' + charitable_builder.activated_refresh_title + '</span>'; var modal = $.alert( { backgroundDismiss: true, title : title, icon : icon !== '' ? 'fa ' + icon : 'fa fa-thumbs-up', content : message, boxWidth : modalWidth, theme : 'modern,charitable-activate-refresh', closeIcon : true, buttons : { confirm: { text : charitable_builder.ok, btnClass: 'btn-confirm', keys : [ 'enter' ] } } } ); $( window ).on( 'resize', function() { modalWidth = app.getUpgradeModalWidth( isVideoModal ); if ( modal.isOpen() ) { modal.setBoxWidth( modalWidth ); } } ); }, /** * Activate addon modal. * * @since 1.8.0 * * @param {string} feature Feature name. * @param {string} plugin_url Likely the url that allows a download. * @param {string} type Feature license type: 'pro', 'basic', 'plus', 'agency', 'elite'. * @param {string} video Feature video URL. * @param {string} clickedObject What was clicked on. * @param {string} elementType Element type. * @param {string} icon Icon slug. */ activateModal: function( feature, plugin_url, type, video, clickedObject, elementType = false, icon = '' ) { wpchar.debug('activatelModal'); wpchar.debug( feature ); wpchar.debug( plugin_url ); wpchar.debug( type ); wpchar.debug( video ); wpchar.debug( elementType ); // Provide a default value. if ( typeof type === 'undefined' || type.length === 0 ) { type = 'pro'; } var message = charitable_builder.activate.message.replace( /%addon%/g, feature ), isVideoModal = ! _.isEmpty( video ), // eslint-disable-line modalWidth = app.getUpgradeModalWidth( isVideoModal ), title = '<span class="charitable-upgrade-pro-title">' + feature + ' ' + charitable_builder.activate.title + '</span>'; var modal = $.alert( { backgroundDismiss: true, title : title, icon : icon !== '' ? 'fa ' + icon : 'fa fa-thumbs-up', content : message, boxWidth : modalWidth, theme : 'modern,charitable-activate-addon', closeIcon : true, buttons : { cancel: { btnClass : 'btn-confirm', keys : [ 'esc' ], isHidden : false, // initially not hidden isDisabled : false, // initially not disabled action: function() { } }, install: { text : charitable_builder.activate.button, btnClass: 'btn-confirm', keys : [ 'enter' ], isHidden : false, // initially not hidden isDisabled : false, // initially not disabled action: function( activateButton ) { // change the name of the button to let the user know it's installing, or at least trying. activateButton.setText( charitable_builder.activating ); activateButton.disable(); this.$$cancel.prop('disabled', true); this.$$cancel.hide(); app.setAddonState( plugin_url, feature, 'activate', 'addon', $( this ), clickedObject, app.callBackAddonState ); return false; } } } } ); s.currentModal = modal; $( window ).on( 'resize', function() { modalWidth = app.getUpgradeModalWidth( isVideoModal ); if ( modal.isOpen() ) { modal.setBoxWidth( modalWidth ); } } ); }, /** * Install modal. * * @since 1.8.0 * * @param {string} feature Feature name. * @param {string} plugin_url Likely the url that allows a download. * @param {string} type Feature license type: 'pro', 'basic', 'plus', 'agency', 'elite'. * @param {string} video Feature video URL. * @param {object} clickedObject What was clicked on. * @param {string} elementType Element type. * @param {string} icon Icon slug. */ installModal: function( feature, plugin_url, type, video, clickedObject, elementType = false, icon = '' ) { wpchar.debug('installModal'); wpchar.debug( feature ); wpchar.debug( plugin_url ); wpchar.debug( type ); wpchar.debug( video ); wpchar.debug( clickedObject ); wpchar.debug( elementType ); // Provide a default value. if ( typeof type === 'undefined' || type.length === 0 ) { type = 'pro'; } // Make sure we received only supported types. if ( $.inArray( type, [ 'pro', 'basic', 'plus', 'agency', 'elite' ] ) < 0 ) { return; } var license_label = charitable_builder.charitable_license_label, message = charitable_builder.install[ type ].message.replace( /%name%/g, license_label ).replace( /%addon%/g, feature ), isVideoModal = ! _.isEmpty( video ), // eslint-disable-line modalWidth = app.getUpgradeModalWidth( isVideoModal ), title = ''; if ( elementType ) { title = '<span class="charitable-upgrade-pro-title">' + feature + ' ' + charitable_builder.install['pro-panel'].title + '</span>'; } else { title = '<span class="charitable-upgrade-pro-title">' + feature + ' ' + charitable_builder.install[type].title + '</span>'; } var modal = $.alert( { backgroundDismiss : false, title : title, icon : icon !== '' ? 'fa ' + icon : 'fa fa-thumbs-up', content : message, boxWidth : modalWidth, theme : 'modern,charitable-install-form', closeIcon : false, buttons : { cancel: { btnClass : 'btn-confirm', keys : [ 'esc' ], isHidden : false, // initially not hidden isDisabled : false, // initially not disabled action: function() { } }, confirmInstall: { text : charitable_builder.install[type].button, btnClass : 'btn-confirm', keys : [ 'enter' ], isHidden : false, // initially not hidden isDisabled : false, // initially not disabled action: function( confirmInstallButton ) { // change the name of the button to let the user know it's installing, or at least trying. confirmInstallButton.setText( charitable_builder.installing ); confirmInstallButton.disable(); this.$$cancel.prop('disabled', true); this.$$cancel.hide(); app.setAddonState( plugin_url, feature, 'install', 'addon', $( this ), clickedObject, app.callBackAddonState ); return false; } } } } ); s.currentModal = modal; $( window ).on( 'resize', function() { modalWidth = app.getUpgradeModalWidth( isVideoModal ); if ( modal.isOpen() ) { modal.setBoxWidth( modalWidth ); } } ); }, /** * Upgrade modal. * * @since 1.8.0 * * @param {string} feature Feature name. * @param {string} utmContent UTM content. * @param {string} type Feature license type: pro or elite. * @param {string} video Feature video URL. * @param {string} elementType Element type. * @param {string} icon Icon slug. */ upgradeModal: function( feature, utmContent, type, video, elementType = false, icon = '' ) { // Provide a default value. if ( typeof type === 'undefined' || type.length === 0 ) { type = 'pro'; } // Make sure we received only supported types. if ( $.inArray( type, [ 'pro', 'basic', 'plus', 'agency', 'elite' ] ) < 0 ) { return; } var isVideoModal = ! _.isEmpty( video ), // eslint-disable-line modalWidth = app.getUpgradeModalWidth( isVideoModal ), title = '', message = '', button = '', typeCapitlized = 'pro' !== type.toLowerCase() ? type.charAt(0).toUpperCase() + type.slice(1) : 'PRO'; if ( elementType ) { title = feature + ' ' + charitable_builder.upgrade['pro-panel'].title.replace( /%plan%/g, typeCapitlized ), message = charitable_builder.upgrade[ 'pro-panel' ].message.replace( /%name%/g, feature ), message = message.replace( /%plan%/g, typeCapitlized ), button = charitable_builder.upgrade[ 'pro-panel' ].button.replace( /%name%/g, feature ).replace( 'addon', '' ), button = button.replace( /%plan%/g, typeCapitlized ); } else { title = feature + ' ' + charitable_builder.upgrade[type].title.replace( /%plan%/g, typeCapitlized ), message = charitable_builder.upgrade[ type ].message.replace( /%name%/g, feature ), message = message.replace( /%plan%/g, typeCapitlized ), button = charitable_builder.upgrade[ type ].button.replace( /%name%/g, feature ).replace( 'addon', '' ), button = button.replace( /%plan%/g, typeCapitlized ); } var modal = $.alert( { backgroundDismiss: true, title : title, icon : icon !== '' ? 'fa ' + icon : 'fa fa-lock', content : message, boxWidth : modalWidth, theme : 'modern,charitable-upgrade-form-lite', closeIcon : true, onOpenBefore: function() { if ( isVideoModal ) { this.$el.addClass( 'has-video' ); } var videoHtml = isVideoModal ? '<iframe src="' + video + '" class="feature-video" frameborder="0" allowfullscreen="" width="475" height="267"></iframe>' : ''; // this.$btnc.after( '<div class="discount-note">' + charitable_builder.upgrade_bonus_modal + '</div>' ); this.$btnc.after( charitable_builder.upgrade[type].doc.replace( /%25name%25/g, feature ) ); this.$btnc.after( videoHtml ); this.$body.find( '.jconfirm-content' ).addClass( 'lite-upgrade' ); }, buttons : { confirm: { text : button, btnClass: 'btn-confirm', keys : [ 'enter' ], action: function() { window.open( app.getUpgradeURL( utmContent, type ), '_blank' ); app.upgradeModalThankYou( type ); } } } } ); $( window ).on( 'resize', function() { modalWidth = app.getUpgradeModalWidth( isVideoModal ); if ( modal.isOpen() ) { modal.setBoxWidth( modalWidth ); } } ); }, /** * Get install URL according to the UTM content and license type. * * @since 1.8.0 * * @param {string} utmContent UTM content. * @param {string} type Feature license type: pro or elite. * * @returns {string} Upgrade URL. */ getInstallURL: function( utmContent, type, searchKeyword = false ) { // eslint-disable-line var returnUrl = charitable_builder.charitable_addons_page; if ( searchKeyword ) { returnUrl = returnUrl + '&search=' + searchKeyword.replace(/[^0-9a-z+ ]/gi, '').replace('Field', '').trim(); } return returnUrl; }, /** * Get upgrade URL according to the UTM content and license type. * * @since 1.8.0 * * @param {string} utmContent UTM content. * @param {string} type Feature license type: pro or elite. * * @returns {string} Upgrade URL. */ getUpgradeURL: function( utmContent, type ) { var baseURL = charitable_builder.upgrade[ type ].url; if ( utmContent.toLowerCase().indexOf( 'template' ) > -1 ) { baseURL = charitable_builder.upgrade[ type ].url_template; } // Test if the base URL already contains `?`. var appendChar = /(\?)/.test( baseURL ) ? '&' : '?'; // If the upgrade link is changed by partners, appendChar has to be encoded. if ( baseURL.indexOf( 'https://wpcharitable.com' ) === -1 ) { appendChar = encodeURIComponent( appendChar ); } return baseURL + appendChar + 'utm_content=' + encodeURIComponent( utmContent.trim() ); }, /** * Upgrade modal thank you. * * @since 1.8.0 * * @param {string} type Feature license type: pro or elite. */ upgradeModalThankYou: function( type ) { $.alert( { title : charitable_builder.thanks_for_interest, content : charitable_builder.upgrade[type].modal, icon : 'fa fa-info-circle', type : 'blue', boxWidth : '565px', buttons : { confirm: { text : charitable_builder.ok, btnClass: 'btn-confirm', keys : [ 'enter' ] } } } ); }, /** * Activation failed message. * * @since 1.8.0.x * * @param {string} feature Addon. */ upgradeModalAddonInstalledAndActivated: function( plugin_url = '', plugin_name = '', successText = '' ) { // eslint-disable-line $.alert( { title : '<span class="charitable-upgrade-pro-title">' + plugin_name + ' ' + charitable_builder.installed_activated_title + '</span>', content : charitable_builder.installed_activated_reboot, icon : 'fa fa-info-circle', type : 'blue', boxWidth : '565px', buttons : { confirm: { text : charitable_builder.ok, btnClass: 'btn-confirm', keys : [ 'esc' ] }, saveRefresh: { text : charitable_builder.save_refresh, btnClass: 'btn-confirm', keys : [ 'enter' ], action: function( saveRefreshButton ) { // Check for campaign title first if ( $('#charitable_settings_title').val().length === 0 ) { // Close this modal this.close(); // Show the title error modal app.formSaveCheck(); return false; } saveRefreshButton.setText( charitable_builder.standby ); saveRefreshButton.disable(); this.$$confirm.prop('disabled', true); this.$$confirm.hide(); // Refresh the current page after saving the form. app.formSave( false, false, false, true ); return false; } } } } ); }, /** * Activation confirmation. * * @since 1.8.0 * * @param {string} plugin_url Plugin activation url. * @param {string} plugin_name Plugin name. * @param {string} successText Success text. * */ upgradeModalAddonActivated: function( plugin_url = '', plugin_name = '', successText = '' ) { // eslint-disable-line $.alert( { title : '<span class="charitable-upgrade-pro-title">' + plugin_name + ' ' + charitable_builder.activated_title + '</span>', content : charitable_builder.activated_reboot, icon : 'fa fa-info-circle', type : 'blue', boxWidth : '565px', buttons : { confirm: { text : charitable_builder.ok, btnClass: 'btn-confirm', keys : [ 'esc' ] }, saveRefresh: { text : charitable_builder.save_refresh, btnClass: 'btn-confirm', keys : [ 'enter' ], action: function( saveRefreshButton ) { // Check for campaign title first if ( $('#charitable_settings_title').val().length === 0 ) { // Close this modal this.close(); // Show the title error modal app.formSaveCheck(); return false; } saveRefreshButton.setText( charitable_builder.standby ); saveRefreshButton.disable(); this.$$confirm.prop('disabled', true); this.$$confirm.hide(); // Refresh the current page after saving the form. app.formSave( false, false, false, true ); return false; } } } } ); }, /** * Activation confirmation. * * @since 1.8.0 * * @param {string} plugin_url Plugin activation url. * @param {string} plugin_name Plugin name. * @param {string} successText Success text. */ upgradeModalAddonInstalledAndActivatedFailed: function( plugin_url = '', plugin_name = '', successText = '' ) { // eslint-disable-line $.alert( { title : '<span class="charitable-upgrade-pro-title">' + plugin_name + ' ' + charitable_builder.installed_activated_failed_title + '</span>', content : charitable_builder.installed_activated_failed_reboot, icon : 'fa fa-info-circle', type : 'blue', boxWidth : '565px', buttons : { confirm: { text : charitable_builder.ok, btnClass: 'btn-confirm', keys : [ 'enter' ] } } } ); }, /** * Activation failed message. * * @since 1.8.0 * * @param {string} plugin_url Plugin activation url. * @param {string} plugin_name Plugin name. * @param {string} successText Success text. */ upgradeModalAddonActivatedFailed: function( plugin_url = '', plugin_name = '', successText = '' ) { // eslint-disable-line $.alert( { title : '<span class="charitable-upgrade-pro-title">' + plugin_name + ' ' + charitable_builder.activated_failed_title + '</span>', content : charitable_builder.activated_failed_reboot, icon : 'fa fa-info-circle', type : 'blue', boxWidth : '565px', buttons : { confirm: { text : charitable_builder.ok, btnClass: 'btn-confirm', keys : [ 'enter' ] } } } ); }, /** * Get upgrade modal width. * * @since 1.8.0 * * @param {boolean} isVideoModal Upgrade modal type (with video or not). * * @returns {string} Modal width in pixels. */ getUpgradeModalWidth: function( isVideoModal ) { var windowWidth = $( window ).width(); if ( windowWidth <= 300 ) { return '250px'; } if ( windowWidth <= 750 ) { return '350px'; } if ( ! isVideoModal || windowWidth <= 1024 ) { return '560px'; } return windowWidth > 1070 ? '1040px' : '994px'; }, /** * Util for checking/confirming function is a function. * * @since 1.8.0 */ isFunction: function( functionToCheck ) { return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]'; } }; // Provide access to public functions/properties. return app; }( document, window, jQuery ) ); // eslint-disable-line CharitableCampaignBuilder.init();
/home/batcwwjx/www/wp-content/plugins/./charitable/assets/js/campaign-builder/admin-builder.js