/** * 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('').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('', assets+''); 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(''); 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("