![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/mautic.corals.io/app/bundles/CoreBundle/Assets/js/ |
/** * Parses the query string and returns a parameter value * @param name * @returns {string} */ Mautic.getUrlParameter = function (name) { name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); var regex = new RegExp('[\\?&]' + name + '=([^&#]*)'); var results = regex.exec(location.search); return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')); }; /** * Launch builder * * @param formName * @param actionName */ Mautic.launchBuilder = function (formName, actionName) { if (!mauticFroalaEnabled) { alert('The legacy builder needs Froala library to work. Please go to Global Configuration > System Settings and enable Froala.'); return; } var builder = mQuery('.builder'); Mautic.codeMode = builder.hasClass('code-mode'); Mautic.showChangeThemeWarning = true; mQuery('body').css('overflow-y', 'hidden'); // Activate the builder builder.addClass('builder-active').removeClass('hide'); if (typeof actionName == 'undefined') { actionName = formName; } var builderCss = { margin: "0", padding: "0", border: "none", width: "100%", height: "100%" }; // Load the theme from the custom HTML textarea var themeHtml = mQuery('textarea.builder-html').val(); if (Mautic.codeMode) { var rawTokens = mQuery.map(Mautic.builderTokens, function (element, index) { return index }).sort(); Mautic.builderCodeMirror = CodeMirror(document.getElementById('customHtmlContainer'), { value: themeHtml, lineNumbers: true, mode: 'htmlmixed', extraKeys: {"Ctrl-Space": "autocomplete"}, lineWrapping: true, hintOptions: { hint: function (editor) { var cursor = editor.getCursor(); var currentLine = editor.getLine(cursor.line); var start = cursor.ch; var end = start; while (end < currentLine.length && /[\w|}$]+/.test(currentLine.charAt(end))) ++end; while (start && /[\w|{$]+/.test(currentLine.charAt(start - 1))) --start; var curWord = start != end && currentLine.slice(start, end); var regex = new RegExp('^' + curWord, 'i'); var result = { list: (!curWord ? rawTokens : mQuery(rawTokens).filter(function(idx) { return (rawTokens[idx].indexOf(curWord) !== -1); })), from: CodeMirror.Pos(cursor.line, start), to: CodeMirror.Pos(cursor.line, end) }; return result; } } }); Mautic.keepPreviewAlive('builder-template-content'); } else { // hide preference center slots var isPrefCenterEnabled = eval(parent.mQuery('input[name="page[isPreferenceCenter]"]:checked').val()); var slots = [ 'segmentlist', 'categorylist', 'preferredchannel', 'channelfrequency', 'saveprefsbutton', 'successmessage' ]; mQuery.each(slots, function(i, s){ if (isPrefCenterEnabled) { mQuery('[data-slot-type=' + s + ']').show(); } else { mQuery('[data-slot-type=' + s + ']').hide(); } }); } var builderPanel = mQuery('.builder-panel'); var builderContent = mQuery('.builder-content'); var btnCloseBuilder = mQuery('.btn-close-builder'); var applyBtn = mQuery('.btn-apply-builder'); var panelHeight = (builderContent.css('right') == '0px') ? builderPanel.height() : 0; var panelWidth = (builderContent.css('right') == '0px') ? 0 : builderPanel.width(); var spinnerLeft = (mQuery(window).width() - panelWidth - 60) / 2; var spinnerTop = (mQuery(window).height() - panelHeight - 60) / 2; var form = mQuery('form[name='+formName+']'); applyBtn.off('click').on('click', function(e) { Mautic.activateButtonLoadingIndicator(applyBtn); try { Mautic.sendBuilderContentToTextarea(function () { // Trigger slot:destroy event if (typeof document.getElementById('builder-template-content').contentWindow.Mautic !== 'undefined') { document.getElementById('builder-template-content').contentWindow.Mautic.destroySlots(); } // Clear the customize forms mQuery('#slot-form-container, #section-form-container').html(''); Mautic.inBuilderSubmissionOn(form); var bgApplyBtn = mQuery('.btn-apply'); if (0 === bgApplyBtn.length && ("1" === Mautic.getUrlParameter('contentOnly') || Mautic.isInBuilder)) { var frm = mQuery('.btn-save').closest('form'); Mautic.inBuilderSubmissionOn(frm); frm.submit(); Mautic.inBuilderSubmissionOff(); } else { bgApplyBtn.trigger('click'); } Mautic.inBuilderSubmissionOff(); }, true); } catch (error) { Mautic.removeButtonLoadingIndicator(applyBtn); if (/SYNTAX ERROR/.test(error.message.toUpperCase())) { var errorMessage = 'Syntax error. Please check your HTML code.'; alert(errorMessage); console.error(errorMessage); } console.error(error.message); } }); // Blur and focus the focussed inputs to fix the browser autocomplete bug on scroll builderPanel.on('scroll', function(e) { // If Froala popup window open if(mQuery.find('.fr-popup:visible').length){ if(!Mautic.isInViewport(builderPanel.find('.fr-view:visible'))) { builderPanel.find('.fr-view:visible').blur(); builderPanel.find('input:focus').blur(); } }else{ builderPanel.find('input:focus').blur(); } }); var overlay = mQuery('<div id="builder-overlay" class="modal-backdrop fade in"><div style="position: absolute; top:' + spinnerTop + 'px; left:' + spinnerLeft + 'px" class="builder-spinner"><i class="fa fa-spinner fa-spin fa-5x"></i></div></div>').css(builderCss).appendTo('.builder-content'); // Disable the close button until everything is loaded btnCloseBuilder.prop('disabled', true); applyBtn.prop('disabled', true); // Insert the Mautic assets to the header var assets = Mautic.htmlspecialchars_decode(mQuery('[data-builder-assets]').html()); themeHtml = themeHtml.replace('</head>', assets+'</head>'); Mautic.initBuilderIframe(themeHtml, btnCloseBuilder, applyBtn); }; Mautic.isInViewport = function(el) { var elementTop = mQuery(el).offset().top; var elementBottom = elementTop + mQuery(el).outerHeight(); var viewportTop = mQuery(window).scrollTop(); var viewportBottom = viewportTop + mQuery(window).height(); return elementBottom > viewportTop && elementTop < viewportBottom; }; /** * Adds a hidded field which adds inBuilder=1 param to the request and will be returned in the response * * @param jQuery object of form */ Mautic.inBuilderSubmissionOn = function(form) { var inBuilder = mQuery('<input type="hidden" name="inBuilder" value="1" />'); form.append(inBuilder); } /** * Removes the hidded field which adds inBuilder=1 param to the request * * @param jQuery object of form */ Mautic.inBuilderSubmissionOff = function(form) { Mautic.isInBuilder = false; mQuery('input[name="inBuilder"]').remove(); } /** * Processes the Apply's button response * * @param object response */ Mautic.processBuilderErrors = function(response) { if (response.validationError) { mQuery('.btn-apply-builder').attr('disabled', true); mQuery('#builder-errors').show('fast').text(response.validationError); } }; /** * Frmats code style in the CodeMirror editor */ Mautic.formatCode = function() { Mautic.builderCodeMirror.autoFormatRange({line: 0, ch: 0}, {line: Mautic.builderCodeMirror.lineCount()}); } /** * Opens Filemanager window */ Mautic.openMediaManager = function() { Mautic.openServerBrowser( mauticBasePath + '/elfinder', screen.width * 0.7, screen.height * 0.7 ); } /** * Receives a file URL from Filemanager when selected */ Mautic.setFileUrl = function(url, width, height, alt) { Mautic.insertTextAtCMCursor(url); } /** * Inserts the text to the cursor position or replace selected range */ Mautic.insertTextAtCMCursor = function(text) { var doc = Mautic.builderCodeMirror.getDoc(); var cursor = doc.getCursor(); doc.replaceRange(text, cursor); } /** * Opens new window on the URL */ Mautic.openServerBrowser = function(url, width, height) { var iLeft = (screen.width - width) / 2 ; var iTop = (screen.height - height) / 2 ; var sOptions = "toolbar=no,status=no,resizable=yes,dependent=yes" ; sOptions += ",width=" + width ; sOptions += ",height=" + height ; sOptions += ",left=" + iLeft ; sOptions += ",top=" + iTop ; var oWindow = window.open( url, "BrowseWindow", sOptions ) ; } /** * Creates an iframe and keeps its content live from CodeMirror changes * * @param iframeId * @param slot */ Mautic.keepPreviewAlive = function(iframeId, slot) { var codeChanged = false; // Watch for code changes Mautic.builderCodeMirror.on('change', function(cm, change) { codeChanged = true; }); window.setInterval(function() { if (codeChanged) { var value = (Mautic.builderCodeMirror)?Mautic.builderCodeMirror.getValue():''; if (!Mautic.codeMode) { Mautic.setCodeModeSlotContent(slot, value); } Mautic.livePreviewInterval = Mautic.updateIframeContent(iframeId, value, slot); codeChanged = false; } }, 2000); }; Mautic.isValidHtml = function (html) { var doc = document.createElement('div'); doc.innerHTML = html; return (doc.innerHTML === html); } Mautic.setCodeModeSlotContent = function (slot, content) { if (Mautic.isValidHtml(content)) { slot.removeAttr('data-encode'); } else { slot.attr('data-encode', btoa(content)); } } Mautic.geCodeModetSlotContent = function (slot) { var html = slot.html(); if (slot.attr('data-encode')) { html = atob(slot.attr('data-encode')); } return html; } Mautic.prepareCodeModeBlocksBeforeSave = function(themeHtml) { var parser = new DOMParser(); var el = parser.parseFromString(themeHtml, "text/html"); var $b = mQuery(el); var codeBlocks = {}; $b.find('#codemodeHtmlContainer,.codemodeHtmlContainer').each(function (index) { var html = mQuery(this).html(); if (mQuery(this).attr('data-encode')) { html = atob(mQuery(this).attr('data-encode')); var token = '{CODEMODEBLOCK'+index+'}'; codeBlocks[token] = html; mQuery(this).html(token); } }) themeHtml = Mautic.domToString($b); for (codeBlock in codeBlocks) { themeHtml = themeHtml.replace(codeBlock, codeBlocks[codeBlock]); } return themeHtml; } Mautic.killLivePreview = function() { window.clearInterval(Mautic.livePreviewInterval); }; Mautic.destroyCodeMirror = function() { delete Mautic.builderCodeMirror; mQuery('#customHtmlContainer').empty(); }; /** * @param themeHtml * @param id * @param onLoadCallback */ Mautic.buildBuilderIframe = function(themeHtml, id, onLoadCallback) { if (mQuery('iframe#'+id).length) { var builder = mQuery('iframe#'+id); } else { var builder = mQuery("<iframe />", { css: { margin: "0", padding: "0", border: "none", width: "100%", height: "100%" }, id: id }).appendTo('.builder-content'); } builder.off('load').on('load', function() { if (typeof onLoadCallback === 'function') { onLoadCallback(); } }); Mautic.updateIframeContent(id, themeHtml); }; /** * @param encodedHtml * @returns {*} */ Mautic.htmlspecialchars_decode = function(encodedHtml) { encodedHtml = encodedHtml.replace(/"/g, '"'); encodedHtml = encodedHtml.replace(/'/g, "'"); encodedHtml = encodedHtml.replace(/&/g, '&'); encodedHtml = encodedHtml.replace(/</g, '<'); encodedHtml = encodedHtml.replace(/>/g, '>'); return encodedHtml; }; /** * Initialize theme selection * * @param themeField */ Mautic.initSelectTheme = function(themeField) { var customHtml = mQuery('textarea.builder-html'); var isNew = Mautic.isNewEntity('#page_sessionId, #emailform_sessionId'); Mautic.showChangeThemeWarning = true; Mautic.builderTheme = themeField.val(); if (isNew) { Mautic.showChangeThemeWarning = false; // Populate default content if (!customHtml.length || !customHtml.val().length) { Mautic.setThemeHtml(Mautic.builderTheme); } } if (customHtml.length) { mQuery('[data-theme]').click(function(e) { e.preventDefault(); var currentLink = mQuery(this); var theme = currentLink.attr('data-theme'); var isCodeMode = (theme === 'mautic_code_mode'); Mautic.builderTheme = theme; if (Mautic.showChangeThemeWarning && customHtml.val().length) { if (!isCodeMode) { if (confirm(Mautic.translate('mautic.core.builder.theme_change_warning'))) { customHtml.val(''); Mautic.showChangeThemeWarning = false; } else { return; } } else { if (confirm(Mautic.translate('mautic.core.builder.code_mode_warning'))) { } else { return; } } } // Set the theme field value themeField.val(theme); // Code Mode if (isCodeMode) { mQuery('.builder').addClass('code-mode'); mQuery('.builder .code-editor').removeClass('hide'); mQuery('.builder .code-mode-toolbar').removeClass('hide'); mQuery('.builder .builder-toolbar').addClass('hide'); } else { mQuery('.builder').removeClass('code-mode'); mQuery('.builder .code-editor').addClass('hide'); mQuery('.builder .code-mode-toolbar').addClass('hide'); mQuery('.builder .builder-toolbar').removeClass('hide'); // Load the theme HTML to the source textarea Mautic.setThemeHtml(theme); } // Manipulate classes to achieve the theme selection illusion mQuery('.theme-list .panel').removeClass('theme-selected'); currentLink.closest('.panel').addClass('theme-selected'); mQuery('.theme-list .select-theme-selected').addClass('hide'); mQuery('.theme-list .select-theme-link').removeClass('hide'); currentLink.closest('.panel').find('.select-theme-selected').removeClass('hide'); currentLink.addClass('hide'); }); } }; /** * Updates content of an iframe * * @param iframeId ID * @param content HTML content * @param slot */ Mautic.updateIframeContent = function(iframeId, content, slot) { // remove empty lines content = content.replace(/^\s*[\r\n]/gm, ''); if (iframeId) { var iframe = document.getElementById(iframeId); var doc = iframe.contentDocument || iframe.contentWindow.document; doc.open(); doc.write(content); doc.close(); // remove html classes because they are duplicated with each save if ('HTML' === doc.all[0].tagName) { mQuery(doc.all[0]).removeClass(); } } else if (slot) { slot.html(content); Mautic.setEmptySlotPlaceholder(slot.parent()); } }; /** * Set theme's HTML * * @param theme */ Mautic.setThemeHtml = function(theme) { mQuery.get(mQuery('#builder_url').val()+'?template=' + theme, function(themeHtml) { var textarea = mQuery('textarea.builder-html'); textarea.val(themeHtml); }); }; /** * Close the builder * * @param model */ Mautic.closeBuilder = function(model) { var panelHeight = (mQuery('.builder-content').css('right') == '0px') ? mQuery('.builder-panel').height() : 0, panelWidth = (mQuery('.builder-content').css('right') == '0px') ? 0 : mQuery('.builder-panel').width(), spinnerLeft = (mQuery(window).width() - panelWidth - 60) / 2, spinnerTop = (mQuery(window).height() - panelHeight - 60) / 2, closeBtn = mQuery('.btn-close-builder'), overlay = mQuery('#builder-overlay'), builder = mQuery('.builder'); mQuery('.builder-spinner').css({ left: spinnerLeft, top: spinnerTop }); overlay.removeClass('hide'); closeBtn.prop('disabled', true); mQuery('#builder-errors').hide('fast').text(''); try { Mautic.sendBuilderContentToTextarea(function() { if (Mautic.codeMode) { Mautic.killLivePreview(); Mautic.destroyCodeMirror(); delete Mautic.codeMode; } else { // Trigger slot:destroy event if(typeof document.getElementById('builder-template-content').contentWindow.Mautic !== 'undefined') { document.getElementById('builder-template-content').contentWindow.Mautic.destroySlots(); } // Clear the customize forms mQuery('#slot-form-container, #section-form-container').html(''); } // Kill the overlay overlay.remove(); // Hide builder builder.removeClass('builder-active').addClass('hide'); closeBtn.prop('disabled', false); mQuery('body').css('overflow-y', ''); builder.addClass('hide'); Mautic.stopIconSpinPostEvent(); mQuery('#builder-template-content').remove(); }, false); } catch (error) { overlay.addClass('hide'); closeBtn.prop('disabled', false); if (/SYNTAX ERROR/.test(error.message.toUpperCase())) { var errorMessage = 'Syntax error. Please check your HTML code.'; alert(errorMessage); console.error(errorMessage); } // prevent from being able to close builder console.error(error.message); } }; /** * Copies the HTML from the builder to the textarea and sanitizes it along the way. * * @param Function callback * @param bool keepBuilderContent */ Mautic.sendBuilderContentToTextarea = function(callback, keepBuilderContent) { var customHtml; if (Mautic.codeMode) { customHtml = Mautic.builderCodeMirror.getValue(); // Convert dynamic slot definitions into tokens customHtml = Mautic.convertDynamicContentSlotsToTokens(customHtml); // Store the HTML content to the HTML textarea mQuery('.builder-html').val(customHtml); callback(); } else { var builderHtml = mQuery('iframe#builder-template-content').contents(); if (keepBuilderContent) { // The content has to be cloned so the sanitization won't affect the HTML in the builder Mautic.cloneHtmlContent(builderHtml, function(themeHtml) { Mautic.sanitizeHtmlAndStoreToTextarea(themeHtml); callback(); }); } else { Mautic.sanitizeHtmlAndStoreToTextarea(builderHtml); callback(); } } }; Mautic.sanitizeHtmlAndStoreToTextarea = function(html) { var cleanHtml = Mautic.sanitizeHtmlBeforeSave(html); // Store the HTML content to the HTML textarea mQuery('.builder-html').val(Mautic.domToString(cleanHtml)); }; /** * Serializes DOM (full HTML document) to string * * @param object dom * @return string */ Mautic.domToString = function(dom) { if (typeof dom === 'string') { return dom; } var xs = new XMLSerializer(); return xs.serializeToString(dom.get(0)); }; /** * Removes stuff the Builder needs for it's magic but cannot be in the HTML result * * @param object htmlContent */ Mautic.sanitizeHtmlBeforeSave = function(htmlContent) { // Remove Mautic's assets htmlContent.find('[data-source="mautic"]').remove(); htmlContent.find('.atwho-container').remove(); htmlContent.find('.fr-image-overlay, .fr-quick-insert, .fr-tooltip, .fr-toolbar, .fr-popup, .fr-image-resizer').remove(); // Remove the slot focus highlight htmlContent.find('[data-slot-focus], [data-section-focus]').remove(); // Replace all url("${URL}") with url('${URL}') var customHtml = Mautic.domToString(htmlContent).replace(/url\("(.+)"\)/g, 'url(\'$1\')'); // Convert dynamic slot definitions into tokens customHtml = Mautic.convertDynamicContentSlotsToTokens(customHtml); return Mautic.prepareCodeModeBlocksBeforeSave(customHtml); }; /** * Clones full HTML document by creating a virtual iframe, putting the HTML into it and reading it back. This is async process. * * @param object content * @param Function callback(clonedContent) */ Mautic.cloneHtmlContent = function(content, callback) { var id = 'iframe-helper'; var iframeHelper = mQuery('<iframe id="'+id+'" />'); Mautic.buildBuilderIframe(Mautic.domToString(content), id, function() { callback(mQuery('iframe#'+id).contents()); iframeHelper.remove(); }); } Mautic.destroySlots = function() { // Trigger destroy slots event if (typeof Mautic.builderSlots !== 'undefined' && Mautic.builderSlots.length) { mQuery.each(Mautic.builderSlots, function(i, slotParams) { mQuery(slotParams.slot).trigger('slot:destroy', slotParams); }); delete Mautic.builderSlots; } // Destroy sortable Mautic.builderContents.find('[data-slot-container]').sortable().sortable('destroy'); // Remove empty class="" attr Mautic.builderContents.find('*[class=""]').removeAttr('class'); // Remove border highlighted by Froala Mautic.builderContents = Mautic.clearFroalaStyles(Mautic.builderContents); // Remove style="z-index: 2501;" which Froala forgets there Mautic.builderContents.find('*[style="z-index: 2501;"]').removeAttr('style'); // Make sure that the Froala editor is gone Mautic.builderContents.find('.fr-toolbar, .fr-line-breaker').remove(); // Remove the class attr vrom HTML tag used by Modernizer var htmlTags = document.getElementsByTagName('html'); htmlTags[0].removeAttribute('class'); }; Mautic.clearFroalaStyles = function(content) { mQuery.each(content.find('td, th, table, [fr-original-class], [fr-original-style]'), function() { var el = mQuery(this); if (el.attr('fr-original-class')) { el.attr('class', el.attr('fr-original-class')); el.removeAttr('fr-original-class'); } if (el.attr('fr-original-style')) { el.attr('style', el.attr('fr-original-style')); el.removeAttr('fr-original-style'); } if (el.css('border') === '1px solid rgb(221, 221, 221)') { el.css('border', ''); } }); content.find('link[href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css"]').remove(); // fix Mautc's tokens in the strong tag content.find('strong[contenteditable="false"]').removeAttr('style'); // data-atwho-at-query causes not working tokens content.find('[data-atwho-at-query]').removeAttr('data-atwho-at-query'); return content; } Mautic.toggleBuilderButton = function (hide) { if (mQuery('.toolbar-form-buttons .toolbar-standard .btn-builder')) { if (hide) { // Move the builder button out of the group and hide it mQuery('.toolbar-form-buttons .toolbar-standard .btn-builder') .addClass('hide btn-standard-toolbar') .appendTo('.toolbar-form-buttons') mQuery('.toolbar-form-buttons .toolbar-dropdown i.fa-cube').parent().addClass('hide'); } else { if (!mQuery('.btn-standard-toolbar.btn-builder').length) { mQuery('.toolbar-form-buttons .toolbar-standard .btn-builder').addClass('btn-standard-toolbar') } else { // Move the builder button out of the group and hide it mQuery('.toolbar-form-buttons .btn-standard-toolbar.btn-builder') .prependTo('.toolbar-form-buttons .toolbar-standard') .removeClass('hide'); mQuery('.toolbar-form-buttons .toolbar-dropdown i.fa-cube').parent().removeClass('hide'); } } } }; Mautic.initSectionListeners = function() { Mautic.activateGlobalFroalaOptions(); Mautic.selectedSlot = null; Mautic.builderContents.on('section:init', function(event, section, isNew) { section = mQuery(section); if (isNew) { Mautic.initSlots(section.find('[data-slot-container]')); } section.on('click', function(e) { var clickedSection = mQuery(this); var previouslyFocused = Mautic.builderContents.find('[data-section-focus]'); var sectionWrapper = mQuery(this); var section = sectionWrapper.find('[data-section]'); var focusParts = { 'top': {}, 'right': {}, 'bottom': {}, 'left': {}, 'clone': { classes: 'fa fa-copy', onClick: function() { var cloneBtn = mQuery(this); var clonedElem = cloneBtn.closest('[data-section-wrapper]'); clonedElem.clone().insertAfter(clonedElem); Mautic.initSlotListeners(); Mautic.initSections(); Mautic.initSlots(); } }, 'handle': { classes: 'fa fa-arrows-v' }, 'delete': { classes: 'ri-close-line', onClick: function() { if (confirm(parent.Mautic.translate('mautic.core.builder.section_delete_warning'))) { var deleteBtn = mQuery(this); var focusSeciton = deleteBtn.closest('[data-section-wrapper]').remove(); } } } }; var sectionForm = mQuery(parent.mQuery('script[data-section-form]').html()); var sectionFormContainer = parent.mQuery('#section-form-container'); if (previouslyFocused.length) { // Unfocus other section previouslyFocused.remove(); // Destroy minicolors sectionFormContainer.find('input[data-toggle="color"]').each(function() { mQuery(this).minicolors('destroy'); }); } Mautic.builderContents.find('[data-slot-focus]').each(function() { if (!mQuery(e.target).attr('data-slot-focus') && !mQuery(e.target).closest('data-slot').length && !mQuery(e.target).closest('[data-slot-container]').length) { mQuery(this).remove(); } }); // Highlight the section mQuery.each(focusParts, function (key, config) { var focusPart = mQuery('<div/>').attr('data-section-focus', key).addClass(config.classes); if (config.onClick) { focusPart.on('click', config.onClick); } sectionWrapper.append(focusPart); }); // Open the section customize form sectionFormContainer.html(sectionForm); // Prefill the sectionform with section color if (section.length && section.css('background-color') !== 'rgba(0, 0, 0, 0)') { sectionForm.find('#builder_section_content-background-color').val(Mautic.rgb2hex(section.css('backgroundColor'))); } // Prefill The Content Background Image if (bgImage = section.css('background-image')) { sectionForm.find('#builder_section_content-background-image').val(bgImage.replace(/url\((?:'|")(.+)(?:'|")\)/g, '$1')); } // Prefill The Content Background Size if (bgSize = section.css('background-size')) { sectionForm.find('#builder_section_content-background-size').val(bgSize || 'auto auto'); } // Prefill The Content Background Repeat if (bgRepeat = section.css('background-repeat')) { sectionForm.find('#builder_section_content-background-repeat').val(bgRepeat); } // Prefill The Content Background Position if (bgPosition = section.css('background-position')) { sectionForm.find('#builder_section_content-background-position').val(bgPosition); } // Prefill the sectionform with section wrapper color if (sectionWrapper.css('background-color') !== 'rgba(0, 0, 0, 0)') { sectionForm.find('#builder_section_wrapper-background-color').val(Mautic.rgb2hex(sectionWrapper.css('backgroundColor'))); } // Prefill The Wrapper Background Image if (bgImage = sectionWrapper.css('background-image')) { sectionForm.find('#builder_section_wrapper-background-image').val(bgImage.replace(/url\((?:'|")(.+)(?:'|")\)/g, '$1')); } // Prefill The Wrapper Background Size if (bgSize = sectionWrapper.css('background-size')) { sectionForm.find('#builder_section_wrapper-background-size').val(bgSize || 'auto auto'); } // Prefill The Wrapper Background Repeat if (bgRepeat = sectionWrapper.css('background-repeat')) { sectionForm.find('#builder_section_wrapper-background-repeat').val(bgRepeat); } // Prefill The Wrapper Background Position if (bgPosition = sectionWrapper.css('background-position')) { sectionForm.find('#builder_section_wrapper-background-position').val(bgPosition); } // Initialize the color picker sectionFormContainer.find('input[data-toggle="color"]').each(function() { parent.Mautic.activateColorPicker(this); }); // Handle color change events sectionForm.on('keyup paste change touchmove', function(e) { var field = mQuery(e.target); switch (field.attr('id')) { case 'builder_section_content-background-color': Mautic.sectionBackgroundChanged(section, field.val()); break; case 'builder_section_content-background-image': Mautic.sectionBackgroundImageChanged(section, field.val()); break; case 'builder_section_content-background-repeat': section.css('background-repeat', field.val()); break; case 'builder_section_content-background-size': Mautic.sectionBackgroundSize(section, field.val()); break; case 'builder_section_content-background-position': section.css('background-position', field.val()); break; case 'builder_section_wrapper-background-color': Mautic.sectionBackgroundChanged(sectionWrapper, field.val()); break; case 'builder_section_wrapper-background-image': Mautic.sectionBackgroundImageChanged(sectionWrapper, field.val()); break; case 'builder_section_wrapper-background-repeat': sectionWrapper.css('background-repeat', field.val()); break; case 'builder_section_wrapper-background-size': Mautic.sectionBackgroundSize(sectionWrapper, field.val()); break; case 'builder_section_wrapper-background-position': sectionWrapper.css('background-position', field.val()); break; } }); parent.mQuery('#section-form-container').on('change.minicolors', function(e, hex) { var field = mQuery(e.target); var focusedSectionWrapper = mQuery('[data-section-focus]').parent(); var focusedSection = focusedSectionWrapper.find('[data-section]'); if (focusedSection.length && field.attr('id') === 'builder_section_content-background-color') { Mautic.sectionBackgroundChanged(focusedSection, field.val()); } else if (field.attr('id') === 'builder_section_wrapper-background-color') { Mautic.sectionBackgroundChanged(focusedSectionWrapper, field.val()); } }); }); }); }; Mautic.initSections = function() { Mautic.initSectionListeners(); var sectionWrappers = Mautic.builderContents.find('[data-section-wrapper]'); // Make slots sortable var bodyOverflow = {}; Mautic.sortActive = false; mQuery('body').sortable({ helper: function(e, ui) { // Fix body overflow that messes sortable up bodyOverflow.overflowX = mQuery('body').css('overflow-x'); bodyOverflow.overflowY = mQuery('body').css('overflow-y'); mQuery('body').css({ overflowX: 'visible', overflowY: 'visible' }); return ui; }, axis: 'y', items: '[data-section-wrapper]', handle: '[data-section-focus="handle"]', placeholder: 'slot-placeholder', connectWith: 'body', start: function(event, ui) { Mautic.sortActive = true; ui.placeholder.height(ui.helper.outerHeight()); }, stop: function(event, ui) { if (ui.item.hasClass('section-type-handle')) { // Restore original overflow mQuery('body', parent.document).css(bodyOverflow); var newSection = mQuery('<div/>') .attr('data-section-wrapper', ui.item.attr('data-section-type')) .html(ui.item.find('script').html()); ui.item.replaceWith(newSection); Mautic.builderContents.trigger('section:init', [newSection, true]); } else { // Restore original overflow mQuery('body').css(bodyOverflow); } Mautic.sortActive = false; }, }); // Allow to drag&drop new sections from the section type menu var iframe = mQuery('#builder-template-content', parent.document).contents(); mQuery('#section-type-container .section-type-handle', parent.document).draggable({ iframeFix: true, connectToSortable: 'body', revert: 'invalid', iframeOffset: iframe.jQuery2Offset(), helper: function(e, ui) { // Fix body overflow that messes sortable up bodyOverflow.overflowX = mQuery('body', parent.document).css('overflow-x'); bodyOverflow.overflowY = mQuery('body', parent.document).css('overflow-y'); mQuery('body', parent.document).css({ overflowX: 'hidden', overflowY: 'hidden' }); var helper = mQuery(this).clone() .css('height', mQuery(this).height()) .css('width', mQuery(this).width()); return helper; }, zIndex: 8000, cursorAt: {top: 15, left: 15}, start: function(event, ui) { mQuery('#builder-template-content', parent.document).css('overflow', 'hidden'); mQuery('#builder-template-content', parent.document).attr('scrolling', 'no'); }, stop: function(event, ui) { // Restore original overflow mQuery('body', parent.document).css(bodyOverflow); mQuery('#builder-template-content', parent.document).css('overflow', 'visible'); mQuery('#builder-template-content', parent.document).attr('scrolling', 'yes'); } }).disableSelection(); // Initialize the slots sectionWrappers.each(function() { mQuery(this).trigger('section:init', this); }); }; Mautic.sectionBackgroundChanged = function(element, color) { if (color.length) { color = '#'+color; } else { color = 'transparent'; } element.css('background-color', color).attr('bgcolor', color); Mautic.updateOutlookTag(element); // Change the color of the editor for selected slots mQuery(element).find('[data-slot-focus]').each(function() { var focusedSlot = mQuery(this).closest('[data-slot]'); if (focusedSlot.attr('data-slot') == 'text') { Mautic.setTextSlotEditorStyle(parent.mQuery('#slot_text_content'), focusedSlot); } }); }; Mautic.sectionBackgroundImageChanged = function (element, imageUrl) { var regWrappedInUrl = /url\(.+\)/g; var match = regWrappedInUrl.exec(imageUrl); if (!imageUrl || imageUrl === 'none') { element.css('background-image', imageUrl); } else if (match) { element.css('background-image', imageUrl); } else { element.css('background-image', "url(" + imageUrl + ")"); } Mautic.updateOutlookTag(element); }; Mautic.sectionBackgroundSize = function (element, size) { if (!size) { size = 'auto auto'; } element.css('background-size', size); Mautic.updateOutlookTag(element); }; Mautic.rgb2hex = function(orig) { var rgb = orig.replace(/\s/g,'').match(/^rgba?\((\d+),(\d+),(\d+)/i); return (rgb && rgb.length === 4) ? "#" + ("0" + parseInt(rgb[1],10).toString(16)).slice(-2) + ("0" + parseInt(rgb[2],10).toString(16)).slice(-2) + ("0" + parseInt(rgb[3],10).toString(16)).slice(-2) : orig; }; Mautic.updateOutlookTag = function (element) { if (parent.mQuery('.builder').hasClass('email-builder')) { // section-wrapper is TABLE element, no outlook hack need if (element.get(0).tagName == 'TABLE') { return; } var sectionForm = parent.mQuery('#section-form-container'); if (element[0].hasAttribute('data-section-wrapper')) { var color = sectionForm.find('#builder_section_wrapper-background-color').val() ? '#'+sectionForm.find('#builder_section_wrapper-background-color').val() : ''; var image = sectionForm.find('#builder_section_wrapper-background-image').val(); var size = sectionForm.find('#builder_section_wrapper-background-size').val(); } else { var color = sectionForm.find('#builder_section_content-background-color').val() ? '#'+sectionForm.find('#builder_section_content-background-color').val() : ''; var image = sectionForm.find('#builder_section_content-background-image').val(); var size = sectionForm.find('#builder_section_content-background-size').val(); } var comments = element.contents().filter(function(){return this.nodeType == 8;}); if (comments.length === 0) { element.prepend( '<!--[if gte mso 9]>\n' + '<v:rect style="" xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false">\n' + '<v:fill type="tile" src="" color=""/>\n' + '<v:textbox style="" inset="0,0,0,0">\n' + '<![endif]-->' ); element.append( '<!--[if gte mso 9]>\n' + '</v:textbox>\n' + '</v:rect>\n' + '<![endif]-->' ); } comments.each(function(i, e) { if (i == 0) { mQuery(this)[0].data = e.data.replace(/src\s*=\s*".*?"/mg, 'src="' + image + '"'); mQuery(this)[0].data = e.data.replace(/color\s*=\s*".*?"/mg, 'color="' + color + '"'); if (!size) { mQuery(this)[0].data = e.data.replace(/rect\s*style=\s*".*?"/mg, 'rect style="mso-width-percent:1000;"'); mQuery(this)[0].data = e.data.replace(/textbox\s*style=\s*".*?"/mg, 'textbox style="mso-fit-shape-to-text:true"'); } else { var newSize = ""; var splitedSize = size.split(" "); if (splitedSize[0] && splitedSize[0].match(/[0-9]*?px/gm)) { newSize = "width:"+splitedSize[0]+";"; } else { newSize = "mso-width-percent:1000;"; } if (splitedSize[1] && splitedSize[1].match(/[0-9]*?px/gm)) { newSize += "height:"+splitedSize[1]+";"; mQuery(this)[0].data = e.data.replace(/textbox\s*style=\s*".*?"/mg, 'textbox style=""'); } else { mQuery(this)[0].data = e.data.replace(/textbox\s*style=\s*".*?"/mg, 'textbox style="mso-fit-shape-to-text:true"'); } mQuery(this)[0].data = e.data.replace(/rect\s*style=\s*".*?"/mg, 'rect style="'+newSize+'"'); } return false; } } ); } }; Mautic.initSlots = function(slotContainers) { if (!slotContainers) { slotContainers = Mautic.builderContents.find('[data-slot-container]'); } Mautic.builderContents.find('a').on('click', function(e) { e.preventDefault(); }); // Make slots sortable var bodyOverflow = {}; Mautic.sortActive = false; Mautic.parentDocument = parent.document; slotContainers.sortable({ helper: function(e, ui) { // Fix body overflow that messes sortable up bodyOverflow.overflowX = mQuery('body').css('overflow-x'); bodyOverflow.overflowY = mQuery('body').css('overflow-y'); mQuery('body').css({ overflowX: 'visible', overflowY: 'visible' }); return ui; }, items: '[data-slot]', handle: '[data-slot-toolbar]', placeholder: 'slot-placeholder', connectWith: '[data-slot-container]', start: function(event, ui) { Mautic.sortActive = true; ui.placeholder.height(ui.helper.outerHeight()); Mautic.builderContents.find('[data-slot-focus]').each( function() { var focusedSlot = mQuery(this).closest('[data-slot]'); if (focusedSlot.attr('data-slot') === 'image') { // Deactivate froala toolbar focusedSlot.find('img').each( function() { mQuery(this).froalaEditor('popups.hideAll'); }); Mautic.builderContents.find('.fr-image-resizer.fr-active').removeClass('fr-active'); } }); Mautic.builderContents.find('[data-slot-focus]').remove(); }, stop: function(event, ui) { if (ui.item.hasClass('slot-type-handle')) { // Restore original overflow mQuery('body', parent.document).css(bodyOverflow); var newSlot = mQuery('<div/>') .attr('data-slot', ui.item.attr('data-slot-type')) .html(ui.item.find('script').html()) ui.item.replaceWith(newSlot); Mautic.builderContents.trigger('slot:init', newSlot); } else { // Restore original overflow mQuery('body').css(bodyOverflow); } Mautic.sortActive = false; } }); // Allow to drag&drop new slots from the slot type menu var iframe = mQuery('#builder-template-content', parent.document).contents(); mQuery('#slot-type-container .slot-type-handle', parent.document).draggable({ iframeFix: true, connectToSortable: '[data-slot-container]', revert: 'invalid', iframeOffset: iframe.jQuery2Offset(), helper: function(e, ui) { // fix for Uncaught TypeError: Cannot read property 'document' of null // Fix body overflow that messes sortable up bodyOverflow.overflowX = mQuery('body', Mautic.parentDocument).css('overflow-x'); bodyOverflow.overflowY = mQuery('body', Mautic.parentDocument).css('overflow-y'); mQuery('body', Mautic.parentDocument).css({ overflowX: 'hidden', overflowY: 'hidden' }); return mQuery(this).clone() .css('height', mQuery(this).height()) .css('width', mQuery(this).width()); }, zIndex: 8000, cursorAt: {top: 15, left: 15}, start: function(event, ui) { mQuery('#builder-template-content', Mautic.parentDocument).css('overflow', 'hidden'); mQuery('#builder-template-content', Mautic.parentDocument).attr('scrolling', 'no'); // check if it is initialized first to prevent error if (slotContainers.data('sortable')) slotContainers.sortable('option', 'scroll', false); }, stop: function(event, ui) { // Restore original overflow mQuery('body', Mautic.parentDocument).css(bodyOverflow); mQuery('#builder-template-content', Mautic.parentDocument).css('overflow', 'visible'); mQuery('#builder-template-content', Mautic.parentDocument).attr('scrolling', 'yes'); // check if it is initialized first to prevent error if (slotContainers.data('sortable')) slotContainers.sortable('option', 'scroll', true); // this fixes an issue where after reopening the builder and trying to drag a slot, it leaves a clone behind parent.mQuery('.ui-draggable-dragging').remove(); } }).disableSelection(); iframe.on('scroll', function() { mQuery('#slot-type-container .slot-type-handle', Mautic.parentDocument).draggable("option", "cursorAt", { top: -1 * iframe.scrollTop() + 15 }); }); // Initialize the slots slotContainers.find('[data-slot]').each(function() { mQuery(this).trigger('slot:init', this); }); }; Mautic.getSlotToolbar = function(type) { Mautic.builderContents.find('[data-slot-toolbar]').remove(); var slotToolbar = mQuery('<div/>').attr('data-slot-toolbar', true); var deleteLink = Mautic.getSlotDeleteLink(); var cloneLink = Mautic.getSlotCloneLink(); if (typeof type !== 'undefined') { mQuery('<span style="color:#fff;margin-left:10px;font-family:sans-serif;font-size:smaller">' + type.toUpperCase() + '</span>').appendTo(slotToolbar); } deleteLink.appendTo(slotToolbar); cloneLink.appendTo(slotToolbar); return slotToolbar; }; Mautic.getSlotDeleteLink = function() { if (typeof Mautic.deleteLink == 'undefined') { Mautic.deleteLink = mQuery('<a><i class="fa fa-lg ri-close-line"></i></a>') .attr('data-slot-action', 'delete') .attr('alt', 'delete') .addClass('btn btn-delete btn-default'); } return Mautic.deleteLink; }; Mautic.getSlotCloneLink = function() { if (typeof Mautic.cloneLink == 'undefined') { Mautic.cloneLink = mQuery('<a><i class="fa fa-lg fa-copy"></i></a>') .attr('data-slot-action', 'clone') .attr('alt', 'clone') .addClass('btn btn-clone btn-clone'); } return Mautic.cloneLink; }; Mautic.getSlotFocus = function() { Mautic.builderContents.find('[data-slot-focus]').remove(); return mQuery('<div/>').attr('data-slot-focus', true); }; Mautic.cloneFocusForm = function(decId, removeFroala) { Mautic.reattachDEC(); var focusForm = parent.mQuery('#emailform_dynamicContent_' + decId); Mautic.activeDECParent = focusForm.parent(); // show if hidden focusForm.removeClass('fade'); // remove delete default button focusForm.find('.tab-pane:first').find('.remove-item').hide(); // hide add variant button focusForm.find('.addNewDynamicContentFilter').hide(); var element =focusForm.detach(); Mautic.activeDEC = element; return element; }; Mautic.initEmailDynamicContentSlotEdit = function (clickedSlot) { var decId = clickedSlot.attr('data-param-dec-id'); var focusForm; if (decId || decId === 0) { focusForm = Mautic.cloneFocusForm(decId); } var focusFormHeader = parent.mQuery('#customize-slot-panel').find('.panel-heading h4'); var newDynConButton = mQuery('<button/>') .css('float', 'right') .addClass('btn btn-success btn-xs'); newDynConButton.text('Add Variant'); newDynConButton.on('click', function(e) { e.stopPropagation(); Mautic.createNewDynamicContentFilter('#dynamicContentFilterTabs_'+decId, parent.mQuery); var focusForm = Mautic.cloneFocusForm(decId, false); focusForm.insertAfter(parent.mQuery('#slot_dynamiccontent > div.has-error')); }); focusFormHeader.append(newDynConButton); return focusForm; }; Mautic.removeAddVariantButton = function() { // Remove the Add Variant button for dynamicContent slots parent.mQuery('#customize-slot-panel').find('.panel-heading button').remove(); Mautic.reattachDEC(); }; Mautic.reattachDEC = function() { if (typeof Mautic.activeDEC !== 'undefined') { var element = Mautic.activeDEC.detach(); Mautic.activeDECParent.append(element); } }; Mautic.isSlotInitiated = function(slot) { if (typeof Mautic.builderSlots === 'undefined' || Mautic.builderSlots.length === 0) return false; return typeof Mautic.builderSlots.find(function(params) { return slot.is(params.slot); }) !== 'undefined'; }; Mautic.isCodeMode = function() { return mQuery('a[data-theme=mautic_code_mode]').first().hasClass('hide'); }; window.document.fileManagerInsertImageCallback = function(selector, url) { if (Mautic.isCodeMode()) { Mautic.insertTextAtCMCursor(url); } else { if (typeof FroalaEditorForFileManager !== 'underfined') { if (typeof FroalaEditorForFileManagerCurrentImage !== 'undefined') { FroalaEditorForFileManager.image.insert(url, false, {}, FroalaEditorForFileManagerCurrentImage); } else { FroalaEditorForFileManager.image.insert(url); } } else { if (typeof FroalaEditorForFileManagerCurrentImage !== 'undefined') { mQuery(selector).froalaEditor('image.insert', url, false, {}, FroalaEditorForFileManagerCurrentImage); } else { mQuery(selector).froalaEditor('image.insert', url); } } } }; Mautic.initSlotListeners = function() { Mautic.activateGlobalFroalaOptions(); Mautic.builderSlots = []; Mautic.selectedSlot = null; Mautic.builderContents.on('slot:selected', function(event, slot) { slot = mQuery(slot); Mautic.builderContents.find('[data-slot-focus]').remove(); mQuery(slot).append(Mautic.getSlotFocus()); }); Mautic.builderContents.on('slot:init', function(event, slot) { slot = mQuery(slot); var type = slot.attr('data-slot'); // Avoid initialising one slot several times if (Mautic.isSlotInitiated(slot)) return; // initialize the drag handle var slotToolbar = Mautic.getSlotToolbar(type); var deleteLink = Mautic.getSlotDeleteLink(); var cloneLink = Mautic.getSlotCloneLink(); var focus = Mautic.getSlotFocus(); slot.hover(function(e) { e.stopPropagation(); // Get new copies of the focus, toolbar slotToolbar = Mautic.getSlotToolbar(type); focus = Mautic.getSlotFocus(); if (Mautic.sortActive) { // don't activate while sorting return; } if(slot.html() == '') { slot.addClass('empty'); }else{ slot.removeClass('empty'); } slot.append(focus); deleteLink.click(function(e) { // if slot is DEC, delete it from the outside form if (type == 'dynamicContent') { var dynConId = slot.attr('data-param-dec-id'); dynConId = '#emailform_dynamicContent_' + dynConId; var dynConTarget = parent.mQuery(dynConId); // clear name, so the slot:destroy event deletes it dynConTarget.find(dynConId + '_tokenName').val(''); } slot.trigger('slot:destroy', {slot: slot, type: type}); mQuery.each(Mautic.builderSlots, function(i, slotParams) { if (slotParams.slot.is(slot)) { Mautic.builderSlots.splice(i, 1); return false; // break the loop } }); slot.remove(); focus.remove(); }); cloneLink.click(function(e) { if (type == 'dynamicContent') { var maxId = Mautic.getDynamicContentMaxId(); slot.clone().attr('data-param-dec-id', maxId + 1).insertAfter(slot); Mautic.createNewDynamicContentItem(parent.mQuery); } else { slot.clone().insertAfter(slot); } Mautic.initSlots(slot.closest('[data-slot-container="1"]')); }); if (slot.offset().top < 25) { // If at the top of the page, move the toolbar to be visible slotToolbar.css('top', '0'); } else { slotToolbar.css('top', '-24px'); } slot.append(slotToolbar); Mautic.setEmptySlotPlaceholder(slot); }, function() { if (Mautic.sortActive) { // don't activate while sorting return; } slotToolbar.remove(); focus.remove(); }); slot.on('click', function(e) { e.stopPropagation(); Mautic.deleteCodeModeSlot(); Mautic.removeAddVariantButton(); var clickedSlot = mQuery(this); // Trigger the slot:change event clickedSlot.trigger('slot:selected', clickedSlot); // Destroy previously initiated minicolors var minicolors = parent.mQuery('#slot-form-container .minicolors'); if (minicolors.length) { parent.mQuery('#slot-form-container input[data-toggle="color"]').each(function() { mQuery(this).minicolors('destroy'); }); parent.mQuery('#slot-form-container').off('change.minicolors'); } if (parent.mQuery('#slot-form-container').find('textarea.editor')) { // Deactivate all popups parent.mQuery('#slot-form-container').find('textarea.editor').each( function() { parent.mQuery(this).froalaEditor('popups.hideAll'); }); } // Update form in the Customize tab to the form of the focused slot type var focusType = clickedSlot.attr('data-slot'); var focusForm = mQuery(parent.mQuery('script[data-slot-type-form="'+focusType+'"]').html()); var slotFormContainer = parent.mQuery('#slot-form-container'); if (focusType == 'dynamicContent') { var nff = Mautic.initEmailDynamicContentSlotEdit(clickedSlot); // replace focusForm nff.insertAfter(focusForm.find('#slot_dynamiccontent > div.has-error')); } slotFormContainer.html(focusForm); // Prefill the form field values with the values from slot attributes if any parent.mQuery.each(clickedSlot.get(0).attributes, function(i, attr) { var regex = /data-param-(.*)/; var match = regex.exec(attr.name); if (match !== null) { focusForm.find('input[type="text"][data-slot-param="'+match[1]+'"]').val(attr.value); var selectField = focusForm.find('select[data-slot-param="'+match[1]+'"]'); if (selectField.length) { selectField.val(attr.value) } // URL fields var urlField = focusForm.find('input[type="url"][data-slot-param="'+match[1]+'"]'); if (urlField.length) { urlField.val(attr.value); } // Number fields var numberField = focusForm.find('input[type="number"][data-slot-param="'+match[1]+'"]'); if (numberField.length) { numberField.val(attr.value); } var radioField = focusForm.find('input[type="radio"][data-slot-param="'+match[1]+'"][value="'+attr.value+'"]'); if (radioField.length) { radioField.parent('.btn').addClass('active'); radioField.attr('checked', true); } } }); focusForm.on('keyup change', function(e) { var field = mQuery(e.target); // Store the slot settings as attributes if (field.attr('data-slot-param')) { clickedSlot.attr('data-param-'+field.attr('data-slot-param'), field.val()); } // Trigger the slot:change event clickedSlot.trigger('slot:change', {slot: clickedSlot, field: field, type: focusType}); }); focusForm.find('.btn').on('click', function(e) { var field = mQuery(this).find('input:radio'); if (field.length) { // Store the slot settings as attributes clickedSlot.attr('data-param-'+field.attr('data-slot-param'), field.val()); // Trigger the slot:change event clickedSlot.trigger('slot:change', {slot: clickedSlot, field: field, type: focusType}); } }); // Initialize the color picker focusForm.find('input[data-toggle="color"]').each(function() { parent.Mautic.activateColorPicker(this, { change: function() { var field = mQuery(this); // Store the slot settings as attributes clickedSlot.attr('data-param-'+field.attr('data-slot-param'), field.val()); clickedSlot.trigger('slot:change', {slot: clickedSlot, field: field, type: focusType}); } }); }); // initialize code mode slots $codeModeSlotTypes = ['codemode']; for (var i = 0; i < $codeModeSlotTypes.length; i++) { if ($codeModeSlotTypes[i] === type) { Mautic.codeMode = true; var element = focusForm.find('#slot_'+$codeModeSlotTypes[i]+'_content')[0]; if (element) { Mautic.builderCodeMirror = CodeMirror.fromTextArea(element, { lineNumbers: true, mode: 'htmlmixed', extraKeys: {"Ctrl-Space": "autocomplete"}, lineWrapping: true, }); var elem = slot.find('#codemodeHtmlContainer,.codemodeHtmlContainer'); html = Mautic.geCodeModetSlotContent(elem); Mautic.builderCodeMirror.getDoc().setValue(html); Mautic.keepPreviewAlive(null, elem); } break; } } focusForm.find('textarea.editor').each(function () { var theEditor = this; var slotHtml = parent.mQuery('<div/>').html(clickedSlot.html()); slotHtml.find('[data-slot-focus]').remove(); slotHtml.find('[data-slot-toolbar]').remove(); var buttons = ['undo', 'redo', '|', 'bold', 'italic', 'underline', 'paragraphFormat', 'fontFamily', 'fontSize', 'color', 'align', 'formatOL', 'formatUL', 'quote', 'clearFormatting', 'token', 'insertLink', 'insertImage', 'insertGatedVideo', 'insertTable', 'html', 'fullscreen']; var builderEl = parent.mQuery('.builder'); var froalaOptions = { toolbarButtons: buttons, toolbarButtonsMD: buttons, toolbarButtonsSM: buttons, toolbarButtonsXS: buttons, toolbarSticky: false, linkList: [], // TODO push here the list of tokens from Mautic.getPredefinedLinks imageEditButtons: ['imageReplace', 'imageAlign', 'imageRemove', 'imageAlt', 'imageSize', '|', 'imageLink', 'linkOpen', 'linkEdit', 'linkRemove'] }; if (builderEl.length && builderEl.hasClass('email-builder')) { buttons = parent.mQuery.grep(buttons, function (value) { return value != 'insertGatedVideo'; }); froalaOptions.imageOutputSize = true; } // prevent overriding variant content in editor if (focusType !== 'dynamicContent') { // init AtWho in a froala editor parent.mQuery(this).on('froalaEditor.initialized', function (e, editor) { parent.Mautic.initAtWho(editor.$el, parent.Mautic.getBuilderTokensMethod(), editor); Mautic.setTextSlotEditorStyle(editor.$el, clickedSlot); }); } parent.mQuery(this).on('froalaEditor.contentChanged', function (e, editor) { var slotHtml = mQuery('<div/>').append(editor.html.get()); // replace DEC with content from the first editor if (!(focusType == 'dynamicContent' && mQuery(this).attr('id').match(/filters/))) { clickedSlot.html(slotHtml.html()); Mautic.setEmptySlotPlaceholder(clickedSlot); } }); // replace only the first editor content for DEC if (!(focusType == 'dynamicContent' && mQuery(this).attr('id').match(/filters/))) { parent.mQuery(this).val(slotHtml.html()); } parent.mQuery(this).froalaEditor(parent.mQuery.extend({}, Mautic.basicFroalaOptions, froalaOptions)); }); }); // Initialize different slot types if (type === 'image' || type === 'imagecaption' || type === 'imagecard') { var image = slot.find('img'); // fix of badly destroyed image slot image.removeAttr('data-froala.editor'); image.on('froalaEditor.click', function (e, editor) { slot.closest('[data-slot]').trigger('click'); }); // Init Froala editor var froalaOptions = mQuery.extend({}, Mautic.basicFroalaOptions, { linkList: [], // TODO push here the list of tokens from Mautic.getPredefinedLinks imageEditButtons: ['imageReplace', 'imageAlign', 'imageAlt', 'imageSize', '|', 'imageLink', 'linkOpen', 'linkEdit', 'linkRemove'], useClasses: false, imageOutputSize: true } ); image.froalaEditor(froalaOptions); } else if (type === 'button') { slot.find('a').click(function(e) { e.preventDefault(); }); } else if (type === 'dynamicContent') { if (slot.html().match(/__dynamicContent__/)) { var maxId = Mautic.getDynamicContentMaxId(); slot.attr('data-param-dec-id', maxId + 1); slot.html('Dynamic Content'); Mautic.createNewDynamicContentItem(parent.mQuery); } } // Store the slot to a global var Mautic.builderSlots.push({slot: slot, type: type}); }); Mautic.getPredefinedLinks = function(callback) { var linkList = []; Mautic.getTokens(Mautic.getBuilderTokensMethod(), function(tokens) { if (tokens.length) { mQuery.each(tokens, function(token, label) { if (token.startsWith('{pagelink=') || token.startsWith('{assetlink=') || token.startsWith('{webview_url') || token.startsWith('{unsubscribe_url')) { linkList.push({ text: label, href: token }); } }); } return callback(linkList); }); }; Mautic.builderContents.on('slot:change', function(event, params) { // Change some slot styles when the values are changed in the slot edit form var fieldParam = params.field.attr('data-slot-param'); var type = params.type; if (type !== "dynamicContent") { Mautic.removeAddVariantButton(); } Mautic.clearSlotFormError(fieldParam); if (fieldParam === 'padding-top' || fieldParam === 'padding-bottom') { params.slot.css(fieldParam, params.field.val() + 'px'); } else if ('label-text' === fieldParam) { params.slot.find('label.control-label').text(params.field.val()); } else if ('label-text1' === fieldParam) { params.slot.find('label.label1').text(params.field.val()); } else if ('label-text2' === fieldParam) { params.slot.find('label.label2').text(params.field.val()); } else if ('label-text3' === fieldParam) { params.slot.find('label.label3').text(params.field.val()); } else if ('label-text4' === fieldParam) { params.slot.find('label.label4').text(params.field.val()); } else if ('flink' === fieldParam || 'tlink' === fieldParam) { params.slot.find('#'+fieldParam).attr('href', params.field.val()); } else if (fieldParam === 'href') { params.slot.find('a').eq(0).attr('href', params.field.val()); } else if (fieldParam === 'link-text') { params.slot.find('a').eq(0).text(params.field.val()); } else if (fieldParam === 'float') { var values = ['left', 'center', 'right']; params.slot.find('a').parent().attr('align', values[params.field.val()]); } else if (fieldParam === 'caption') { params.slot.find('figcaption').text(params.field.val()); } else if (fieldParam === 'cardcaption') { params.slot.find('td.imagecard-caption').text(params.field.val()); } else if (fieldParam === 'text-align') { var values = ['left', 'center', 'right']; if (type === 'imagecard') { params.slot.find('.imagecard-caption').css(fieldParam, values[params.field.val()]); } else if (type === 'imagecaption') { params.slot.find('figcaption').css(fieldParam, values[params.field.val()]); } } else if (fieldParam === 'align') { Mautic.builderContents.find('[data-slot-focus]').each( function() { var focusedSlot = mQuery(this).closest('[data-slot]'); if (focusedSlot.attr('data-slot') == 'image') { // Deactivate froala toolbar focusedSlot.find('img').each( function() { mQuery(this).froalaEditor('popups.hideAll'); }); Mautic.builderContents.find('.fr-image-resizer.fr-active').removeClass('fr-active'); } }); var values = ['left', 'center', 'right']; if ('socialfollow' === type) { params.slot.find('div.socialfollow').css('text-align', values[params.field.val()]); } else if ('imagecaption' === type) { params.slot.find('figure').css('text-align', values[params.field.val()]); } else if ('imagecard' === type) { params.slot.find('td.imagecard-image').css('text-align', values[params.field.val()]); } else { params.slot.find('img').closest('div').css('text-align', values[params.field.val()]); } } else if (fieldParam === 'border-radius') { params.slot.find('a.button').css(fieldParam, params.field.val() + 'px'); } else if (fieldParam === 'button-size') { var bg_clr = params.slot.attr('data-param-background-color'); var values = [ {borderWidth: '10px 20px', padding: '0', fontSize: '14px', borderColor : bg_clr, borderStyle: 'solid'}, {borderWidth: '20px 23px', padding: '0', fontSize: '20px', borderColor : bg_clr, borderStyle: 'solid'}, {borderWidth: '25px 40px', padding: '0', fontSize: '30px', borderColor : bg_clr, borderStyle: 'solid'} ]; params.slot.find('a.button').css(values[params.field.val()]); } else if (fieldParam === 'caption-color') { params.slot.find('.imagecard-caption').css('background-color', '#' + params.field.val()); } else if (fieldParam === 'background-color' || fieldParam === 'color') { var matches = params.field.val().match(/^#?([0-9a-f]{6}|[0-9a-f]{3})$/); if (matches !== null) { var color = matches[1]; if (fieldParam === 'background-color') { if ('imagecard' === type) { params.slot.find('.imagecard').css(fieldParam, '#' + color); } else { params.slot.find('a.button').css(fieldParam, '#' + color); params.slot.find('a.button').attr('background', '#' + color); params.slot.find('a.button').css('border-color', '#' + color); } } else if (fieldParam === 'color') { if ('imagecard' === type) { params.slot.find('.imagecard-caption').css(fieldParam, '#' + color); } else if ('imagecaption' === type) { params.slot.find('figcaption').css(fieldParam, '#' + color); } else { params.slot.find('a.button').css(fieldParam, '#' + color); } } } } else if (/gatedvideo/.test(fieldParam)) { // Handle gatedVideo replacements var toInsert = fieldParam.split('-')[1]; var insertVal = params.field.val(); if (toInsert === 'url') { var videoProvider = Mautic.getVideoProvider(insertVal); if (videoProvider == null) { Mautic.slotFormError(fieldParam, 'Please enter a valid YouTube, Vimeo, or MP4 url.'); } else { params.slot.find('source') .attr('src', insertVal) .attr('type', videoProvider); } } else if (toInsert === 'gatetime') { params.slot.find('video').attr('data-gate-time', insertVal); } else if (toInsert === 'formid') { params.slot.find('video').attr('data-form-id', insertVal); } else if (toInsert === 'height') { params.slot.find('video').attr('height', insertVal); } else if (toInsert === 'width') { params.slot.find('video').attr('width', insertVal); } } else if (fieldParam === 'separator-color') { params.slot.find('hr').css('border-color', '#' + params.field.val()); } else if (fieldParam === 'separator-thickness') { var sep_color = params.slot.attr('data-param-separator-color'); params.slot.find('hr').css('border', params.field.val() + 'px solid #'+ sep_color); } if (params.type == 'text') { Mautic.setTextSlotEditorStyle(parent.mQuery('#slot_text_content'), params.slot); } }); Mautic.builderContents.on('slot:destroy', function(event, params) { Mautic.reattachDEC(); if (params.type === 'text') { if (parent.mQuery('#slot_text_content').length) { parent.mQuery('#slot_text_content').froalaEditor('destroy'); parent.mQuery('#slot_text_content').find('.atwho-inserted').atwho('destroy'); } } else if (params.type === 'image') { Mautic.deleteCodeModeSlot(); var image = params.slot.find('img'); if (typeof image !== 'undefined' && image.hasClass('fr-view')) { image.froalaEditor('destroy'); image.removeAttr('data-froala.editor'); image.removeClass('fr-view'); } } else if (params.type === 'dynamicContent') { Mautic.removeAddVariantButton(); // remove new DEC if name is empty var dynConId = params.slot.attr('data-param-dec-id'); dynConId = '#emailform_dynamicContent_'+dynConId; if (Mautic.activeDEC && Mautic.activeDEC.attr('id') === dynConId.substr(1)) { delete Mautic.activeDEC; delete Mautic.activeDECParent; } var dynConTarget = parent.mQuery(dynConId); var dynConName = dynConTarget.find(dynConId+'_tokenName').val(); if (dynConName === '') { dynConTarget.find('a.remove-item:first').click(); // remove vertical tab in outside form parent.mQuery('.dynamicContentFilterContainer').find('a[href=' + dynConId + ']').parent().remove(); params.slot.remove(); } } // Remove Symfony toolbar Mautic.builderContents.find('.sf-toolbar').remove(); }); }; Mautic.deleteCodeModeSlot = function() { Mautic.killLivePreview(); Mautic.destroyCodeMirror(); delete Mautic.codeMode; }; Mautic.clearSlotFormError = function(field) { var customizeSlotField = parent.mQuery('#customize-form-container').find('[data-slot-param="'+field+'"]'); if (customizeSlotField.length) { customizeSlotField.attr('style', ''); customizeSlotField.next('[data-error]').remove(); } }; Mautic.slotFormError = function (field, message) { var customizeSlotField = parent.mQuery('#customize-form-container').find('[data-slot-param="'+field+'"]'); if (customizeSlotField.length) { customizeSlotField.css('border-color', 'red'); if (message.length) { var messageContainer = mQuery('<p/>') .text(message) .attr('data-error', 'true') .css({ color: 'red', padding: '5px 0' }); messageContainer.insertAfter(customizeSlotField); } } }; Mautic.getVideoProvider = function(url) { var providers = [ { test_regex: /^.*((youtu.be)|(youtube.com))\/((v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))?\??v?=?([^#\&\?]*).*/, provider: 'video/youtube' }, { test_regex: /^.*(vimeo\.com\/)((channels\/[A-z]+\/)|(groups\/[A-z]+\/videos\/))?([0-9]+)/, provider: 'video/vimeo' }, { test_regex: /mp4/, provider: 'video/mp4' } ]; for (var i = 0; i < providers.length; i++) { var vp = providers[i]; if (vp.test_regex.test(url)) { return vp.provider; } } return null; }; Mautic.setTextSlotEditorStyle = function(editorEl, slot) { // Set the editor CSS to that of the slot var wrapper = parent.mQuery(editorEl).closest('.form-group').find('.fr-wrapper .fr-element').first(); if (typeof wrapper == 'undefined') { return; } if (typeof slot.attr('style') !== 'undefined') { wrapper.attr('style', slot.attr('style')); } mQuery.each(['background-color', 'color', 'font-family', 'font-size', 'line-height', 'text-align'], function(key, style) { var overrideStyle = Mautic.getSlotStyle(slot, style, false); if (overrideStyle) { wrapper.css(style, overrideStyle); } }); }; Mautic.getSlotStyle = function(slot, styleName, fallback) { if ('background-color' == styleName) { // Get this browser's take on no fill // Must be appended else Chrome etc return 'initial' var temp = mQuery('<div style="background:none;display:none;"/>').appendTo('body'); var transparent = temp.css(styleName); temp.remove(); } var findStyle = function (slot) { function test(elem) { if ('background-color' == styleName) { if (typeof elem.attr('bgcolor') !== 'undefined') { // Email tables return elem.attr('bgcolor'); } if (elem.css(styleName) == transparent) { return !elem.is('body') ? test(elem.parent()) : fallback || transparent; } else { return elem.css(styleName); } } else if (typeof elem.css(styleName) !== 'undefined') { return elem.css(styleName); } else { return !elem.is('body') ? test(elem.parent()) : fallback; } } return test(slot); }; return findStyle(slot); }; /** * @returns {string} */ Mautic.getBuilderTokensMethod = function() { var method = 'page:getBuilderTokens'; if (parent.mQuery('.builder').hasClass('email-builder')) { method = 'email:getBuilderTokens'; } return method; }; Mautic.prepareBuilderIframe = function(themeHtml, btnCloseBuilder, applyBtn) { // find DEC tokens and inject them to builderTokens var decTokenRegex = /(?:{)dynamiccontent="(.*?)(?:")}/g; var match = decTokenRegex.exec(themeHtml); while (match !== null) { var dynConToken = match[0]; var dynConName = match[1]; // Add the dynamic content tokens if (!Mautic.builderTokens.hasOwnProperty(dynConToken)) { Mautic.builderTokens[dynConToken] = dynConName; } // fetch next token match = decTokenRegex.exec(themeHtml); } // Turn Dynamic Content Tokens into builder slots themeHtml = Mautic.prepareDynamicContentBlocksForBuilder(themeHtml); // hide preference center slots var isPrefCenterEnabled = eval(parent.mQuery('input[name="page[isPreferenceCenter]"]:checked').val()); if (!isPrefCenterEnabled) { var slots = [ 'segmentlist', 'categorylist', 'preferredchannel', 'channelfrequency', 'saveprefsbutton', 'successmessage' ]; mQuery.each(slots, function (i, s) { // delete existing tokens themeHtml = themeHtml.replace('{' + s + '}', ''); }); var parser = new DOMParser(); var el = parser.parseFromString(themeHtml, "text/html"); var $b = mQuery(el); mQuery.each(slots, function (i, s) { // delete existing slots $b.find('[data-slot=' + s + ']').remove(); }); themeHtml = Mautic.domToString($b); } Mautic.buildBuilderIframe(themeHtml, 'builder-template-content', function() { mQuery('#builder-overlay').addClass('hide'); btnCloseBuilder.prop('disabled', false); applyBtn.prop('disabled', false); }); }; Mautic.initBuilderIframe = function(themeHtml, btnCloseBuilder, applyBtn) { // Avoid to request the tokens if not necessary if (Mautic.builderTokensRequestInProgress) { // Wait till previous request finish var intervalID = setInterval(function(){ if (!Mautic.builderTokensRequestInProgress) { clearInterval(intervalID); Mautic.prepareBuilderIframe(themeHtml, btnCloseBuilder, applyBtn); } }, 500); } else { Mautic.prepareBuilderIframe(themeHtml, btnCloseBuilder, applyBtn); } }; Mautic.prepareDynamicContentBlocksForBuilder = function(builderHtml) { for (var token in Mautic.builderTokens) { // If this is a dynamic content token if (Mautic.builderTokens.hasOwnProperty(token) && /\{dynamic/.test(token)) { var defaultContent = Mautic.convertDynamicContentTokenToSlot(token); builderHtml = builderHtml.replace(token, defaultContent); } } return builderHtml; }; Mautic.convertDynamicContentTokenToSlot = function(token) { var dynConData = Mautic.getDynamicContentDataForToken(token); if (dynConData) { return '<div data-slot="dynamicContent" contenteditable="false" data-param-dec-id="'+dynConData.id+'">'+dynConData.content+'</div>'; } return token; }; Mautic.getDynamicContentDataForToken = function(token) { var dynConName = /\{dynamiccontent="(.*)"\}/.exec(token)[1]; var dynConTabs = parent.mQuery('#dynamicContentTabs'); var dynConTarget = dynConTabs.find('a:contains("'+dynConName+'")').attr('href'); var dynConContainer = parent.mQuery(dynConTarget); if (dynConContainer.html()) { var dynConContent = dynConContainer.find(dynConTarget+'_content'); if (Mautic.getActiveBuilderName() === 'legacy') { if (dynConContent.data('froala.editor')) { dynConContent = dynConContent.froalaEditor('html.get'); } else { dynConContent = dynConContent.text(); } } else { dynConContent = dynConContent.html(); } return { id: parseInt(dynConTarget.replace(/[^0-9]/g, '')), content: dynConContent }; } return null; }; Mautic.convertDynamicContentSlotsToTokens = function (builderHtml) { var dynConSlots = mQuery(builderHtml).find('[data-slot="dynamicContent"]'); if (dynConSlots.length) { dynConSlots.each(function(i) { var $this = mQuery(this); var dynConNum = $this.attr('data-param-dec-id'); var dynConId = '#emailform_dynamicContent_' + dynConNum; var dynConTarget = mQuery(dynConId); var dynConName = dynConTarget.find(dynConId + '_tokenName').val(); var dynConToken = '{dynamiccontent="' + dynConName+'"}'; // Add the dynamic content tokens if (!Mautic.builderTokens.hasOwnProperty(dynConToken)) { Mautic.builderTokens[dynConToken] = dynConName; } // hack to convert builder HTML to jQuery and replace slot with token var parser = new DOMParser(); var el = parser.parseFromString(builderHtml, "text/html"); var $b = mQuery(el); $b.find('div[data-param-dec-id=' + dynConNum + ']').replaceWith(dynConToken); builderHtml = Mautic.domToString($b); // If it's still wrapped in an atwho, remove that if ($this.parent().hasClass('atwho-inserted')) { var toReplace = $this.parent('.atwho-inserted').get(0).outerHTML; builderHtml = builderHtml.replace(toReplace, dynConToken); } }); } return builderHtml; }; Mautic.getPredefinedLinks = function(callback) { var linkList = []; Mautic.getTokens(Mautic.getBuilderTokensMethod(), function(tokens) { if (tokens.length) { mQuery.each(tokens, function(token, label) { if (token.startsWith('{pagelink=') || token.startsWith('{assetlink=') || token.startsWith('{webview_url') || token.startsWith('{unsubscribe_url')) { linkList.push({ text: label, href: token }); } }); } return callback(linkList); }); }; Mautic.getDynamicContentMaxId = function() { var decs = mQuery('[data-slot="dynamicContent"]'); var ids = mQuery.map(decs, function(e){return mQuery(e).attr('data-param-dec-id');}); var maxId = Math.max.apply(Math, ids); if (isNaN(maxId) || Number.NEGATIVE_INFINITY === maxId) maxId = 0; return maxId; }; Mautic.setEmptySlotPlaceholder = function (slot) { var clonedSlot = slot.clone(); clonedSlot.find('div[data-slot-focus="true"]').remove() clonedSlot.find('div[data-slot-toolbar="true"]').remove() if ((clonedSlot.text()).trim() == '' && !clonedSlot.find('img').length) { slot.addClass('empty'); } else { slot.removeClass('empty'); } }; // Init inside the builder's iframe mQuery(function() { if (parent && parent.mQuery && parent.mQuery('#builder-template-content').length) { Mautic.builderContents = mQuery('body'); if (!parent.Mautic.codeMode) { Mautic.initSlotListeners(); Mautic.initSections(); Mautic.initSlots(); } } });