oont-contents/plugins/email-template-customizer-for-woo/assets/js/email-builder.js
2025-02-08 15:10:23 +01:00

783 lines
32 KiB
JavaScript

'use strict';
let styleSection = 'style',
contentSection = 'content',
viWecEditorArea = '#viwec-email-editor-content',
viWecChange = true,
viWecFontWeightOptions = [
{id: 300, text: 300},
{id: 400, text: 400},
{id: 500, text: 500},
{id: 600, text: 600},
{id: 700, text: 700},
{id: 800, text: 800},
{id: 900, text: 900}
],
viWecAlignmentOptions = [
{value: "left", title: "Left", icon: "dashicons dashicons-editor-alignleft", checked: true,},
{value: "center", title: "Center", icon: "dashicons dashicons-editor-aligncenter", checked: false,},
{value: "right", title: "Right", icon: "dashicons dashicons-editor-alignright", checked: false,}
],
viWecFontFamilyOptions = [
{id: "Roboto, RobotoDraft, Helvetica, Arial, sans-serif", text: 'Roboto'},
{id: "'andale mono', monospace", text: 'Andale Mono'},
{id: 'arial, helvetica, sans-serif', text: 'Arial'},
{id: "'arial black', sans-serif", text: 'Arial Black'},
{id: "'book antiqua', palatino, serif", text: 'Book Antiqua'},
{id: "'comic sans ms', sans-serif", text: 'Comic Sans MS'},
{id: "'courier new', courier, monospace", text: 'Courier New'},
{id: 'georgia, palatino, serif', text: 'Georgia'},
{id: 'helvetica, arial, sans-serif', text: 'Helvetica'},
{id: 'impact, sans-serif', text: 'Impact'},
{id: 'symbol', text: 'Symbol'},
{id: 'tahoma, arial, helvetica, sans-serif', text: 'Tahoma'},
{id: 'terminal, monaco, monospace', text: 'Terminal'},
{id: "'times new roman', times, serif", text: 'Times New Roman'},
{id: "'trebuchet ms', geneva, sans-serif", text: 'Trebuchet MS'},
{id: 'verdana, geneva, sans-serif', text: 'Verdana'},
{id: 'webdings', text: 'Webdings'},
{id: "wingdings, 'zapf dingbats'", text: 'Wingdings'},
],
viWecMapObj = viWecParams.shortcode_for_replace;
let viWecShortcodeList = viWecParams.shortcode.map((item) => {
return {text: item, value: item};
});
if (viWecParams.sc_3rd_party_for_text_editor) {
for (let sc in viWecParams.sc_3rd_party_for_text_editor) {
viWecShortcodeList.push(viWecParams.sc_3rd_party_for_text_editor[sc]);
}
}
let viWecShortcodeListValue = '';
if (viWecParams.shortcode) {
for (let sc of viWecParams.shortcode) {
viWecShortcodeListValue += '<li>' + sc + '</li>'
}
}
if (viWecParams.sc_3rd_party) {
for (let sc of viWecParams.sc_3rd_party) {
viWecShortcodeListValue += '<li>' + sc + '</li>'
}
}
if (ViWec === undefined) {
var ViWec = {};
}
(function () {
var cache = {};
window.viWecTmpl = function viWecTmpl(str, data) {
var fn = /^[-a-zA-Z0-9]+$/.test(str) ? cache[str] = cache[str] || viWecTmpl(document.getElementById(str).innerHTML) :
new Function("obj", "var p=[],print=function(){p.push.apply(p,arguments);};" + "with(obj){p.push('" +
str.replace(/[\r\t\n]/g, " ")
.split("{%").join("\t")
.replace(/((^|%})[^\t]*)'/g, "$1\r")
.replace(/\t=(.*?)%}/g, "',$1,'")
.split("\t").join("');")
.split("%}").join("p.push('")
.split("\r").join("\\'")
+ "');}return p.join('');");
// Provide some basic currying to the user
return data ? fn(data) : fn;
};
})();
jQuery(document).ready(function ($) {
window.viWecNoticeBox = (text, color, time = 3000) => {
color = color || 'white';
let box = $('#viwec-notice-box');
box.text(text).css({'color': color, 'bottom': 0});
setTimeout(function () {
box.css({'bottom': '-50px'});
}, time);
};
$.fn.handleRow = function () {
if (this.find('.viwec-layout-handle-outer').length === 0) {
this.append(viWecTmpl('viwec-input-handle-outer', {}));
}
this.on('click', '.viwec-delete-row-btn', () => {
this.remove();
ViWec.Builder.clearTab();
ViWec.Builder.activeTab('components');
});
this.on('click', '.viwec-duplicate-row-btn', () => {
let clone = this.clone();
clone.find('.viwec-column-sortable').columnSortAble();
clone.handleRow().handleColumn();
this.after(clone);
});
this.on('click', '.viwec-edit-outer-row-btn', () => {
ViWec.Builder.removeFocus();
this.addClass('viwec-block-focus');
ViWec.Builder.selectedEl = this.find('.viwec-layout-row');
ViWec.Builder.loadLayoutControl();
});
this.on('click', '.viwec-copy-row-btn', function () {
let row = $(this).closest('.viwec-block');
row = row.prop('outerHTML');
localStorage.setItem('viwecCopyRow', row);
viWecNoticeBox('Copied');
});
this.on('click', '.viwec-paste-row-btn', function () {
let row = localStorage.getItem('viwecCopyRow');
if (row) {
row = $(row);
row.find('.viwec-column-sortable').columnSortAble();
row.handleRow().handleColumn();
$(this).closest('.viwec-block').after(row);
}
});
return this;
};
$.fn.handleElement = function () {
this.append(`<div class="viwec-element-handle">
<span class="dashicons dashicons-welcome-add-page viwec-copy-element-btn" title="Copy"></span>
<span class="dashicons dashicons-admin-page viwec-duplicate-element-btn" title="Duplicate"></span>
<span class="dashicons dashicons-no-alt viwec-delete-element-btn" title="Delete"></span></div>`);
};
$.fn.columnSortAble = function () {
$(this).sortable({
cursor: 'move',
cursorAt: {left: 40, top: 18},
placeholder: 'viwec-placeholder',
connectWith: ".viwec-column-sortable",
thisColumn: '',
accept: '.viwec-content-draggable',
start: function (ev, ui) {
// ui.placeholder.height(30);
ui.helper.addClass('viwec-is-dragging');
this.thisColumn = ui.helper.closest('.viwec-column');
},
stop: function (ev, ui) {
let style = ui.item.get(0).style;
style.position = style.top = style.left = style.right = style.bottom = style.height = style.width = '';
ui.item.removeClass('viwec-is-dragging');
if (ui.item.offsetParent().find('.viwec-element').length) {
ui.item.offsetParent().removeClass('viwec-column-placeholder');
}
if (!(this.thisColumn.find('.viwec-element').length)) {
this.thisColumn.addClass('viwec-column-placeholder');
}
ui.item.click();
viWecChange = true;
}
});
};
$.fn.handleColumn = function () {
this.on('click', (e) => {
if (this.hasClass('viwec-column-placeholder') || this.find('.viwec-column-placeholder').length) {
ViWec.Builder.removeFocus();
ViWec.Builder.selectedEl = this.find('.viwec-column-sortable').addClass('viwec-block-focus');
ViWec.Builder.loadLayoutControl('editColumn');
}
});
this.on('click', '.viwec-column-edit', () => {
ViWec.Builder.removeFocus();
ViWec.Builder.selectedEl = this.find('.viwec-column-sortable').addClass('viwec-block-focus');
ViWec.Builder.loadLayoutControl('editColumn');
});
this.on('click', '.viwec-column-paste', function () {
let item = localStorage.getItem('viwecCopy');
if (item) {
item = $(item);
$(this).closest('.viwec-column').find('.viwec-column-sortable').append(item);
}
});
return this;
};
ViWec.viWecPreventXSS = (text) => {
if (!viWecParams?.DISALLOW_UNFILTERED_HTML){
return text;
}
let $reg, match;
//removing <script> tags
text.replace(/[<][^<]*script.*[>].*[<].*[\/].*script*[>]/i,"");
$reg = /[<][^<]*script.*[>].*[<].*[\/].*script*[>]/i;
match = $reg.exec(text);
if (match && match?.input && typeof match[0] !== "undefined"){
text = match.input.replaceAll(match[0],'');
}
//removing inline js events
text.replace(/([ ]on[a-zA-Z0-9_-]{1,}=\".*\")|([ ]on[a-zA-Z0-9_-]{1,}='.*')|([ ]on[a-zA-Z0-9_-]{1,}=.*[.].*)/,"");
$reg = /([ ]on[a-zA-Z0-9_-]{1,}=\".*\")|([ ]on[a-zA-Z0-9_-]{1,}='.*')|([ ]on[a-zA-Z0-9_-]{1,}=.*[.].*)/;
match = $reg.exec(text);
if (match && match?.input && typeof match[0] !== "undefined"){
text = match.input.replaceAll(match[0],'');
}
//removing inline js
text.replace(/[ ]src.*=[\"](.*javascript:.*|'.*javascript:.*'|.*javascript:.*)[\"]/i,"");
$reg = /[ ]src.*=[\"](.*javascript:.*|'.*javascript:.*'|.*javascript:.*)[\"]/i;
match = $reg.exec(text);
if (match && match?.input && typeof match[1] !== "undefined"){
text = match.input.replaceAll(match[1],'');
}
text.replace(/[ ]href.*=[\"](.*javascript:.*|'.*javascript:.*'|.*javascript:.*)[\"]/i,"");
$reg = /[ ]href.*=[\"](.*javascript:.*|'.*javascript:.*'|.*javascript:.*)[\"]/i;
match = $reg.exec(text);
if (match && match?.input && typeof match[1] !== "undefined"){
text = match.input.replaceAll(match[1],'');
}
return text;
}
ViWec.viWecReplaceShortcode = (text) => {
if (!text || typeof text !== 'string') return text;
var re = new RegExp(Object.keys(viWecMapObj).join("|"), "gm");
text = text.replace(re, function (matched) {
return viWecMapObj[matched];
});
return ViWec.viWecPreventXSS(text);
};
ViWec.Components = {
_categories: {},
_components: {
baseProp: {}
},
init() {
this.registerCategory('sample', 'Sample');
this.registerCategory('layout', 'Layout');
this.registerCategory('content', 'Basic content');
this.registerCategory('recover', 'Default template');
},
registerCategory(id, name) {
if (!this._categories[id]) this._categories[id] = {name: name, elements: []};
},
get: function (type) {
return this._components[type];
},
add(data) {
let categoryType = data.category || 'content';
if (this._categories[categoryType]) this._categories[categoryType].elements.push(data.type);
if (data.inheritProp) {
let inheritProperties = [];
for (let property of data.inheritProp) {
if (this._components.baseProp[property]) {
inheritProperties = [...inheritProperties, ...this._components.baseProp[property].properties];
}
}
if (!data.properties) data.properties = [];
data.properties = [...data.properties, ...inheritProperties];
}
this._components[data.type] = data;
},
addBaseProp(data) {
this._components.baseProp[data.type] = data;
},
render: function (type) {
let component = this._components[type], section, attributesArea = $('#viwec-attributes-list');
if (!component) return;
//set to viewer
var bindOnChangeToViewer = function (component, property, element) {
return property.input.on('propertyChange', function (event, value, input) {
viWecChange = true;
let viewValue = ViWec.viWecReplaceShortcode(value);
if (property.outputValue) value = property.outputValue;
if (property.htmlAttr) {
if (["style", 'childStyle'].indexOf(property.htmlAttr) > -1) {
let unit = property.unit ? property.unit : '';
element = ViWec.StyleManager.setStyle(element, property.key, value, unit);
} else if (property.htmlAttr === "innerHTML") {
if (property.renderShortcode) {
let clone = element.clone();
element = element.html(value).hide();
let virElement = element.parent().find('.viwec-text-view');
if (virElement.length === 0) {
clone = clone.removeClass().html(viewValue).addClass('viwec-text-view');
element.after(clone);
} else {
virElement.html(viewValue);
}
} else {
element.html(value);
}
} else {
element = element.attr(property.htmlAttr, value);
}
}
if (typeof component.onChange === 'function') {
element = component.onChange(element, property, value, input);
}
if (typeof property.onChange === 'function') {
element = property.onChange(element, value, viewValue, input, component, property);
}
return element;
});
};
let currentKey = '';
//render control
if (component.name) attributesArea.append(`<div id="viwec-component-name">Component: ${component.name}</div>`);
for (let i in component.properties) {
var property = component.properties[i];
var element = ViWec.Builder.selectedEl;
let value;
if (property.visible === false || property.target && !element.find(property.target).length) continue;
if (property.target && element.find(property.target).length) element = element.find(property.target);
if (property.data) {
property.data["key"] = property.key;
if (property.name) property.data["header"] = property.name;
} else {
property.data = {"key": property.key};
if (property.name) property.data["header"] = property.name;
}
if (!property.inputType) continue;
if (property.inputType.hasOwnProperty('init')) {
property.input = property.inputType.init(property.data);
}
if (property.init) {
property.inputType.setValue(property.init(element.get(0)));
} else if (property.htmlAttr) {
if (property.htmlAttr === "style") {
value = ViWec.StyleManager.getStyle(element, property);
} else if (property.htmlAttr === "childStyle") {
value = ViWec.StyleManager.getStyle(element, property);
} else if (property.htmlAttr === "innerHTML") {
value = element.html();
} else {
value = element.attr(property.htmlAttr);
}
if (!value && property.default) {
value = property.default;
}
if (value) {
property.inputType.setValue(value); //set to control
}
}
if (property.input) {
bindOnChangeToViewer(component, property, element);
}
section = property.section ? property.section : '';
if (section) {
if (attributesArea.find(`.viwec-${section}`).length === 0) {
attributesArea.append(`<div class="viwec-${section} vi-ui accordion styled fluid">
<div class="title active">
<i class="dropdown icon"></i>
${section.replace(/^./, section[0].toUpperCase())}
</div>
<div class="content active ${section}-properties">
</div></div>`);
}
if (property.inputType === SectionInput) {
attributesArea.find(`.viwec-${section} .${section}-properties`).append(viWecTmpl("viwec-input-sectioninput", property.data));
currentKey = property.key ? property.key : currentKey;
} else if (property.label) {
attributesArea.find(`.viwec-${section} .${currentKey}`).append(`<label class="viwec-group-name" for="input-model">${property.label}</label>`);
} else {
if (!property.hidden) {
let row = $(viWecTmpl('viwec-property', property));
row.find('.input').append(property.input);
if (typeof property.setup === 'function') row = property.setup(row, value); //Add custom events
attributesArea.find(`.viwec-${section} .${currentKey}`).append(row);
if (typeof property.inputType.subInit === 'function') {
property.inputType.subInit(element);
}
}
}
if (property.inputType.afterInit) {
property.inputType.afterInit(property.input);
}
}
}
$('.vi-ui.accordion').accordion();
if (component.init) component.init(ViWec.Builder.selectedEl.get(0));
}
};
ViWec.Blocks = {
_blocks: {},
get: function (type) {
return this._blocks[type];
},
add: function (type, data) {
data.type = type;
this._blocks[type] = data;
},
};
ViWec.Builder = {
component: {},
dragMoveMutation: false,
isPreview: false,
designerMode: false,
copyStorage: '',
init: function (callback) {
var self = this;
self.selectedEl = null;
self.initCallback = callback;
self.dragElement = null;
self.loadControlGroups();
self.initDragDrop();
self.initHandleBox();
self.loadContentControl();
self.loadBackgroundControl();
self.initQuickAddLayout();
self.globalEvent();
},
/* controls */
loadControlGroups: function () {
let componentsList = $("#viwec-components-list"), item = {}, component = {};
componentsList.empty();
for (let group in ViWec.Components._categories) {
componentsList.append(`<div class="vi-ui accordion styled fluid">
<div class="title active">
<i class="dropdown icon"></i>
${ViWec.Components._categories[group].name}
</div>
<div class="content active" data-section="${group}">
<ul></ul>
</div>
</div>`);
let componentsSubList = componentsList.find('div[data-section="' + group + '"] ul');
let components = ViWec.Components._categories[group].elements;
group = group === 'layout' ? 'layout' : 'content';
for (let i in components) {
let componentType = components[i], controlBtn;
component = ViWec.Components.get(componentType);
if (component) {
if (typeof component.setup === 'function') {
item = component.setup();
if (typeof component.onChange === 'function') component.onChange(item);
} else {
let classes = component.classes || '',
unLock = classes.includes('viwec-pro-version'),
dragAble = unLock ? '' : `viwec-${group}-draggable`,
unlockNotice = unLock ? "<div class='viwec-unlock-notice'><a target='_blank' href='https://1.envato.market/BZZv1'>Unlock this feature</a></div>" : '',
lockIcon = unLock ? "<div class='dashicons dashicons-lock'></div>" : '',
info = component.info || '';
controlBtn = `<div class="viwec-control-btn ${dragAble} ${classes}" data-type="${componentType}" data-drag-type="component">
${lockIcon} ${unlockNotice} ${info}
<div class="viwec-control-icon">
<i class="viwec-ctrl-icon-${component.icon}"></i>
</div>
<div class="viwec-ctrl-title">${component.name}</div>`;
item = $(`<li data-section="${group}">
${controlBtn}
</div></li>`);
}
componentsSubList.append(item);
if (group === 'layout') {
$('#viwec-quick-add-layout .viwec-layout-list').append(controlBtn);
}
}
}
}
$('.vi-ui.accordion').accordion();
},
activeTab: (tab) => {
$('#viwec-control-panel .item, #viwec-control-panel .tab').removeClass('active');
$(`#viwec-control-panel [data-tab=${tab}]`).addClass('active');
},
clearTab: () => {
$('#viwec-control-panel #viwec-attributes-list').empty();
},
loadLayoutControl: function (dataType) {
this.clearTab();
this.activeTab('editor');
let type = dataType || this.selectedEl.data('type');
ViWec.Components.render(type);
},
loadContentControl: function () {
let self = this, body = $('#viwec-email-editor-wrapper');
body.on('click', '.viwec-element', function (e) {
self.removeFocus();
$(this).addClass('viwec-element-focus');
self.clearTab();
self.activeTab('editor');
let type = $(this).data('type');
self.selectedEl = $(this);
ViWec.Components.render(type);
});
},
loadBackgroundControl: function () {
let self = this;
$('.viwec-edit-bgcolor-btn span').on('click', function (e) {
self.clearTab();
self.activeTab('editor');
self.selectedEl = $('#viwec-email-editor-wrapper');
ViWec.Components.render('background');
});
},
initHandleBox: function () {
let self = this, body = $('#viwec-email-editor-wrapper');
body.on('click', '.viwec-delete-element-btn', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
let $this = $(this);
let thisColumn = $this.closest('.viwec-column');
$this.closest('.viwec-element').remove();
self.clearTab();
self.activeTab('components');
if (thisColumn.find('.viwec-element').length === 0) {
thisColumn.addClass('viwec-column-placeholder');
}
});
body.on('click', '.viwec-duplicate-element-btn', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
let currentEl = $(this).closest('.viwec-element');
currentEl.after(currentEl.clone());
self.removeFocus();
});
body.on('click', '.viwec-copy-element-btn', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
let copiedEl = $(this).closest('.viwec-element');
copiedEl = copiedEl.prop('outerHTML');
localStorage.setItem('viwecCopy', copiedEl);
});
body.on('click', function (e) {
if ($(e.target).is('.viwec-layout-row')) {
self.removeFocus();
self.selectedEl = $(e.target);
self.selectedEl.closest('.viwec-block').addClass('viwec-block-focus');
self.loadLayoutControl();
}
})
},
removeFocus: function () {
$('body .viwec-element-focus').removeClass('viwec-element-focus');
$('body .viwec-block-focus').removeClass('viwec-block-focus');
this.clearTab();
this.activeTab('components');
},
/* drag and drop */
initDragDrop: function () {
let self = this;
$('.viwec-layout-draggable').draggable({
cursor: 'move',
cursorAt: {left: 40, top: 15},
helper: function () {
let type = $(this).data('type'), colsQty;
self.component = ViWec.Components.get(type);
colsQty = self.component.cols;
return viWecTmpl('viwec-block', {type: type, colsQty: colsQty});
},
start: function (e, ui) {
ui.helper.addClass('viwec-is-dragging');
},
stop: function (e, ui) {
ui.helper.handleRow();
ui.helper.find('.viwec-column').each(function (i, _this) {
$(_this).handleColumn();
});
ui.helper.removeClass('viwec-is-dragging');
viWecChange = true;
},
connectToSortable: viWecEditorArea
});
$('.viwec-sortable').sortable({
cursor: 'move',
placeholder: 'viwec-placeholder',
handle: '.dashicons-move',
cancel: '',
cursorAt: {left: 40, top: 18},
start: function (e, ui) {
// ui.placeholder.height(30);
ui.helper.addClass('viwec-is-dragging');
},
stop: function (ev, ui) {
ui.item.css({'width': 'auto', 'height': 'auto', 'z-index': 'unset'});
ui.item.find('.viwec-column-sortable').columnSortAble();
ui.item.removeClass('viwec-is-dragging');
viWecChange = true;
}
});
$('.viwec-content-draggable').draggable({
cursor: 'move',
cursorAt: {left: 40, top: 15},
helper: function () {
let $this = jQuery(this), html;
if ($this.data("drag-type") === "component") {
self.component = ViWec.Components.get($this.data("type"));
} else {
self.component = ViWec.Blocks.get($this.data("type"));
}
if (self.component.dragHtml) {
html = self.component.dragHtml;
} else {
html = self.component.html;
}
if ($(viWecEditorArea).children().length === 0) {
let row = $(viWecTmpl('viwec-block', {type: 'layout/grid1cols', colsQty: 1}));
row.handleRow().handleColumn();
row.find('.viwec-column-sortable').columnSortAble();
$('.viwec-sortable').append(row);
}
return `<div class='viwec-element' style="font-size:15px;border-radius: 0; overflow: hidden;line-height: 22px;" data-type="${$this.data('type')}">${html}</div>`;
},
start: function (ev, ui) {
ui.helper.addClass('viwec-is-dragging');
},
drag: function (ev, ui) {
},
stop: function (ev, ui) {
ui.helper.handleElement();
ui.helper.removeClass('viwec-is-dragging');
ui.helper.css('z-index', '');
ui.helper.click();
viWecChange = true;
$('#viwec-element-search input.viwec-search').val('').trigger('keyup');
$('#viwec-attributes-list input').trigger('keyup');
},
connectToSortable: '.viwec-column-sortable'
});
},
initQuickAddLayout: function () {
$('#viwec-quick-add-layout .viwec-control-btn').on('click', function () {
let type = $(this).data('type'), colsQty, row;
self.component = ViWec.Components.get(type);
colsQty = self.component.cols;
row = $(viWecTmpl('viwec-block', {type: type, colsQty: colsQty}));
row.handleRow().handleColumn();
row.find('.viwec-column-sortable').columnSortAble();
$('.viwec-sortable').append(row);
$(this).closest('.viwec-layout-list').toggle();
});
},
globalEvent: function () {
let $this = this, body = $('body');
body.on('click', function (e) {
if ($(e.target).is('#wpwrap') || $(e.target).is('#viwec-email-editor-wrapper')) {
$this.removeFocus();
$('.viwec-layout-list').hide();
}
});
}
};
ViWec.StyleManager = {
setStyle: function (element, styleProp, value, unit) {
return element.css(styleProp, value + unit);
},
_getCssStyle: function (element, property, key = null) {
let styleProp = key ? key : property.key;
if (styleProp === 'width' && property.unit && property.unit === '%') {
let child = parseInt(element.css('width'));
let parent = parseInt(element.parent().css('width'));
if (parent > 0) {
return Math.round((child / parent) * 100) + '%';
}
} else {
let el = element.get(0), css;
if (el) {
if (el.style && el.style.length > 0 && el.style[styleProp])//check inline
css = el.style[styleProp];
else if (el.currentStyle) //check defined css
css = el.currentStyle[styleProp];
else if (window.getComputedStyle) {
css = document.defaultView.getDefaultComputedStyle ?
document.defaultView.getDefaultComputedStyle(el, null).getPropertyValue(styleProp) :
window.getComputedStyle(el, null).getPropertyValue(styleProp);
}
if (css === 'transparent') css = '';
return css;
}
}
},
getStyle: function (element, property, key) {
return this._getCssStyle(element, property, key);
}
};
});