8a2163bb34
Build / Build & Release draft (push) Failing after 0s
PHP tests / PHP Syntax check 5.6 => 8.1 (push) Failing after 10s
PHP tests / PHP-CS-Fixer (push) Failing after 1m6s
PHP tests / PHPStan (1.7.1.2) (push) Failing after 2m27s
PHP tests / PHPStan (1.7.2.5) (push) Failing after 1m32s
PHP tests / PHPStan (1.7.3.4) (push) Failing after 1m29s
PHP tests / PHPStan (1.7.4.4) (push) Failing after 1m45s
PHP tests / PHPStan (1.7.5.1) (push) Failing after 1m47s
PHP tests / PHPStan (1.7.6) (push) Failing after 1m45s
PHP tests / PHPStan (1.7.7) (push) Failing after 2m0s
PHP tests / PHPStan (1.7.8) (push) Failing after 1m56s
PHP tests / PHPStan (latest) (push) Failing after 2m13s
800 lines
29 KiB
JavaScript
800 lines
29 KiB
JavaScript
(function () {
|
|
function boot() {
|
|
var root = document.getElementById('adv-megamenu-admin');
|
|
if (!root) {
|
|
return;
|
|
}
|
|
|
|
var treeContainer = root.querySelector('.js-tree');
|
|
var treeInput = document.getElementById('advmegamenu_tree_json');
|
|
var ajaxUrl = root.getAttribute('data-ajax-url');
|
|
var token = root.getAttribute('data-token');
|
|
var languages = parseJson(root.querySelector('.js-adv-languages-data'), []);
|
|
var labels = parseJson(root.querySelector('.js-adv-i18n'), {});
|
|
var tree = parseJson(root.querySelector('.js-adv-tree-data'), []);
|
|
var tempId = Date.now();
|
|
var nodeModal = document.getElementById('advNodeModal');
|
|
var layoutModal = document.getElementById('advLayoutModal');
|
|
var confirmModal = document.getElementById('advConfirmModal');
|
|
var nodeModalState = null;
|
|
var layoutModalState = null;
|
|
var confirmAction = null;
|
|
var activeRootId = tree.length ? tree[0].id : null;
|
|
|
|
function nextId() {
|
|
tempId += 1;
|
|
return tempId;
|
|
}
|
|
|
|
function parseJson(element, fallback) {
|
|
if (!element || !element.textContent) {
|
|
return fallback;
|
|
}
|
|
|
|
try {
|
|
return JSON.parse(element.textContent);
|
|
} catch (error) {
|
|
return fallback;
|
|
}
|
|
}
|
|
|
|
function t(key, fallback) {
|
|
return labels[key] || fallback || key;
|
|
}
|
|
|
|
function showModal(element) {
|
|
if (window.jQuery && window.jQuery.fn && window.jQuery.fn.modal) {
|
|
window.jQuery(element).modal('show');
|
|
}
|
|
}
|
|
|
|
function hideModal(element) {
|
|
if (window.jQuery && window.jQuery.fn && window.jQuery.fn.modal) {
|
|
window.jQuery(element).modal('hide');
|
|
}
|
|
}
|
|
|
|
function createEmptyNode() {
|
|
var lang = {};
|
|
languages.forEach(function (language) {
|
|
lang[String(language.id_lang)] = {
|
|
title: '',
|
|
description: '',
|
|
custom_link: ''
|
|
};
|
|
});
|
|
|
|
return {
|
|
id: nextId(),
|
|
active: true,
|
|
type: 'link',
|
|
entity_id: 0,
|
|
icon_path: '',
|
|
icon_url: '',
|
|
new_window: false,
|
|
lang: lang,
|
|
layouts: [],
|
|
children: []
|
|
};
|
|
}
|
|
|
|
function createEmptyLayout() {
|
|
return {
|
|
id: nextId(),
|
|
column_width: 4,
|
|
show_title: true,
|
|
custom_image: '',
|
|
custom_image_url: '',
|
|
background_color: '',
|
|
block_type: 'promo',
|
|
products: []
|
|
};
|
|
}
|
|
|
|
function ensureNodeDefaults(node) {
|
|
if (!node.lang) {
|
|
node.lang = {};
|
|
}
|
|
if (!node.layouts) {
|
|
node.layouts = [];
|
|
}
|
|
if (!node.children) {
|
|
node.children = [];
|
|
}
|
|
languages.forEach(function (language) {
|
|
var langId = String(language.id_lang);
|
|
if (!node.lang[langId]) {
|
|
node.lang[langId] = {
|
|
title: '',
|
|
description: '',
|
|
custom_link: ''
|
|
};
|
|
}
|
|
});
|
|
}
|
|
|
|
function sanitizeTree(nodes, depth) {
|
|
nodes.forEach(function (node) {
|
|
ensureNodeDefaults(node);
|
|
|
|
if (depth === 0) {
|
|
node.icon_path = '';
|
|
node.icon_url = '';
|
|
Object.keys(node.lang).forEach(function (langId) {
|
|
node.lang[langId].description = '';
|
|
});
|
|
}
|
|
|
|
sanitizeTree(node.children || [], depth + 1);
|
|
});
|
|
}
|
|
|
|
function serializeTree() {
|
|
sanitizeTree(tree, 0);
|
|
treeInput.value = JSON.stringify(tree);
|
|
}
|
|
|
|
function render() {
|
|
serializeTree();
|
|
treeContainer.innerHTML = '';
|
|
|
|
if (!tree.length) {
|
|
var empty = document.createElement('div');
|
|
empty.className = 'adv-megamenu-admin__empty';
|
|
empty.textContent = t('emptyTree', 'No menu items yet.');
|
|
treeContainer.appendChild(empty);
|
|
return;
|
|
}
|
|
|
|
if (!findRootById(activeRootId)) {
|
|
activeRootId = tree[0].id;
|
|
}
|
|
|
|
var shell = document.createElement('div');
|
|
shell.className = 'adv-menu-admin-root-shell';
|
|
shell.innerHTML = '' +
|
|
'<div class="adv-menu-admin-root-tabs"></div>' +
|
|
'<div class="adv-menu-admin-root-panel"></div>';
|
|
|
|
var tabs = shell.querySelector('.adv-menu-admin-root-tabs');
|
|
var panel = shell.querySelector('.adv-menu-admin-root-panel');
|
|
|
|
tree.forEach(function (node, index) {
|
|
tabs.appendChild(renderRootTab(node, tree, index));
|
|
});
|
|
|
|
var activeRoot = findRootById(activeRootId) || tree[0];
|
|
if (activeRoot) {
|
|
panel.appendChild(renderNode(activeRoot, tree, getRootIndex(activeRoot.id), 0));
|
|
}
|
|
|
|
treeContainer.appendChild(shell);
|
|
}
|
|
|
|
function renderRootTab(node, collection, index) {
|
|
var button = document.createElement('button');
|
|
button.type = 'button';
|
|
button.className = 'adv-menu-admin-root-tab' + (node.id === activeRootId ? ' is-active' : '');
|
|
button.innerHTML = '' +
|
|
'<span class="adv-menu-admin-root-tab__main">' +
|
|
' <span class="adv-menu-admin-root-tab__title">' + escapeHtml(getNodeTitle(node) || t('rootItem', 'Root item')) + '</span>' +
|
|
' <span class="adv-menu-admin-root-tab__meta">' + escapeHtml(node.type || 'link') + '</span>' +
|
|
'</span>' +
|
|
'<span class="adv-menu-admin-root-tab__actions">' +
|
|
' <span class="btn btn-default btn-xs js-root-edit"><i class="icon-pencil"></i></span>' +
|
|
' <span class="btn btn-default btn-xs js-root-up"><i class="icon-arrow-left"></i></span>' +
|
|
' <span class="btn btn-default btn-xs js-root-down"><i class="icon-arrow-right"></i></span>' +
|
|
' <span class="btn btn-danger btn-xs js-root-delete"><i class="icon-trash"></i></span>' +
|
|
'</span>';
|
|
|
|
button.addEventListener('click', function () {
|
|
activeRootId = node.id;
|
|
render();
|
|
});
|
|
|
|
button.querySelector('.js-root-edit').addEventListener('click', function (event) {
|
|
event.stopPropagation();
|
|
openNodeModal(node, 0);
|
|
});
|
|
button.querySelector('.js-root-up').addEventListener('click', function (event) {
|
|
event.stopPropagation();
|
|
move(collection, index, 'up');
|
|
});
|
|
button.querySelector('.js-root-down').addEventListener('click', function (event) {
|
|
event.stopPropagation();
|
|
move(collection, index, 'down');
|
|
});
|
|
button.querySelector('.js-root-delete').addEventListener('click', function (event) {
|
|
event.stopPropagation();
|
|
askConfirm(t('deleteNodeTitle', 'Delete menu item'), t('deleteNodeText', 'This will remove the selected menu item together with its children and attached blocks.'), function () {
|
|
collection.splice(index, 1);
|
|
if (activeRootId === node.id) {
|
|
activeRootId = collection.length ? collection[Math.max(0, index - 1)].id : null;
|
|
}
|
|
render();
|
|
});
|
|
});
|
|
|
|
return button;
|
|
}
|
|
|
|
function renderNode(node, collection, index, depth) {
|
|
ensureNodeDefaults(node);
|
|
|
|
var wrapper = document.createElement('section');
|
|
wrapper.className = 'adv-menu-admin-node' + (depth === 0 ? ' adv-menu-admin-node--root' : '') + (depth >= 2 ? ' adv-menu-admin-node--compact' : '');
|
|
|
|
var title = getNodeTitle(node) || t(depth === 0 ? 'rootItem' : 'childItem', 'Menu item');
|
|
var customLink = getNodeLink(node);
|
|
var imageHtml = depth > 0 && node.icon_url ? '<img src="' + escapeHtml(node.icon_url) + '" alt="" class="adv-menu-admin-node__image">' : '';
|
|
var meta = [];
|
|
|
|
meta.push(metaItem(node.type || 'link', 'icon-tag'));
|
|
if (!node.active) {
|
|
meta.push(metaItem(t('inactive', 'Inactive'), 'icon-ban-circle'));
|
|
}
|
|
if (node.new_window) {
|
|
meta.push(metaItem(t('newWindow', 'New window'), 'icon-external-link'));
|
|
}
|
|
meta.push(metaItem(String((node.children || []).length) + ' ' + t('children', 'children'), 'icon-sitemap'));
|
|
meta.push(metaItem(String((node.layouts || []).length) + ' ' + t('blocks', 'blocks'), 'icon-th-large'));
|
|
|
|
wrapper.innerHTML = '' +
|
|
'<div class="adv-menu-admin-node__header">' +
|
|
' <div class="adv-menu-admin-node__header-main">' +
|
|
' <h4 class="adv-menu-admin-node__title">' +
|
|
' <i class="icon-' + (depth === 0 ? 'star' : 'chevron-right') + '"></i>' +
|
|
' <span class="adv-menu-admin-node__title-text">' + escapeHtml(title) + '</span>' +
|
|
' </h4>' +
|
|
' <div class="adv-menu-admin-node__meta">' + meta.join('') + '</div>' +
|
|
' </div>' +
|
|
' <div class="adv-menu-admin-node__actions">' +
|
|
actionButton('js-node-up', 'icon-arrow-up', '') +
|
|
actionButton('js-node-down', 'icon-arrow-down', '') +
|
|
actionButton('js-node-edit', 'icon-pencil', t('edit', 'Edit')) +
|
|
actionButton('js-node-add-child', 'icon-level-down', t('addChild', 'Add child')) +
|
|
actionButton('js-node-add-layout', 'icon-th-large', t('addBlock', 'Add block')) +
|
|
actionButton('js-node-delete btn-danger', 'icon-trash', t('delete', 'Delete')) +
|
|
' </div>' +
|
|
'</div>' +
|
|
'<div class="adv-menu-admin-node__body">' +
|
|
' <div class="adv-menu-admin-node__summary">' +
|
|
' <div>' +
|
|
(customLink ? ' <div class="adv-menu-admin-node__link"><i class="icon-link"></i><span>' + escapeHtml(customLink) + '</span></div>' : '') +
|
|
(depth === 0 ? ' <p class="help-block">' + escapeHtml(t('rootRule', 'First level only stores title and custom link.')) + '</p>' : '') +
|
|
' </div>' +
|
|
' <div>' + imageHtml + '</div>' +
|
|
' </div>' +
|
|
' <div class="adv-menu-admin-node__collections">' +
|
|
' <div class="adv-menu-admin-node__layouts-wrap"></div>' +
|
|
' <div class="adv-menu-admin-node__children-wrap"></div>' +
|
|
' </div>' +
|
|
'</div>';
|
|
|
|
bindNodeActions(wrapper, node, collection, index, depth);
|
|
|
|
var layoutsWrap = wrapper.querySelector('.adv-menu-admin-node__layouts-wrap');
|
|
if ((node.layouts || []).length) {
|
|
var layoutsTitle = document.createElement('h5');
|
|
layoutsTitle.className = 'adv-menu-admin-node__section-title';
|
|
layoutsTitle.innerHTML = '<i class="icon-th-large"></i><span>' + escapeHtml(t('blocks', 'blocks')) + '</span>';
|
|
layoutsWrap.appendChild(layoutsTitle);
|
|
|
|
var layoutList = document.createElement('div');
|
|
layoutList.className = 'adv-menu-admin-layout-list';
|
|
node.layouts.forEach(function (layout, layoutIndex) {
|
|
layoutList.appendChild(renderLayout(node.layouts, layout, layoutIndex));
|
|
});
|
|
layoutsWrap.appendChild(layoutList);
|
|
}
|
|
|
|
var childrenWrap = wrapper.querySelector('.adv-menu-admin-node__children-wrap');
|
|
if ((node.children || []).length) {
|
|
var childrenTitle = document.createElement('h5');
|
|
childrenTitle.className = 'adv-menu-admin-node__section-title';
|
|
childrenTitle.innerHTML = '<i class="icon-sitemap"></i><span>' + escapeHtml(t('children', 'children')) + '</span>';
|
|
childrenWrap.appendChild(childrenTitle);
|
|
|
|
var childList = document.createElement('div');
|
|
childList.className = 'adv-menu-admin-children-list adv-menu-admin-node__children' + (depth >= 1 ? ' adv-menu-admin-node__children--grid' : '');
|
|
node.children.forEach(function (child, childIndex) {
|
|
childList.appendChild(renderNode(child, node.children, childIndex, depth + 1));
|
|
});
|
|
childrenWrap.appendChild(childList);
|
|
}
|
|
|
|
return wrapper;
|
|
}
|
|
|
|
function renderLayout(layouts, layout, index) {
|
|
var wrapper = document.createElement('section');
|
|
wrapper.className = 'adv-menu-admin-layout';
|
|
|
|
var meta = [];
|
|
meta.push(metaItem('col-' + (layout.column_width || 4), 'icon-columns'));
|
|
meta.push(metaItem(layout.block_type || 'promo', 'icon-th'));
|
|
if (layout.show_title) {
|
|
meta.push(metaItem(t('showTitle', 'Show title'), 'icon-font'));
|
|
}
|
|
if ((layout.products || []).length) {
|
|
meta.push(metaItem(String(layout.products.length) + ' ' + t('products', 'Products'), 'icon-shopping-cart'));
|
|
}
|
|
|
|
wrapper.innerHTML = '' +
|
|
'<div class="adv-menu-admin-layout__header">' +
|
|
' <div class="adv-menu-admin-layout__header-main">' +
|
|
' <h5 class="adv-menu-admin-layout__title">' +
|
|
' <i class="icon-th-large"></i>' +
|
|
' <span class="adv-menu-admin-layout__title-text">' + escapeHtml(t('block', 'Block')) + ' #' + escapeHtml(String(index + 1)) + '</span>' +
|
|
' </h5>' +
|
|
' <div class="adv-menu-admin-layout__meta">' + meta.join('') + '</div>' +
|
|
' </div>' +
|
|
' <div class="adv-menu-admin-layout__actions">' +
|
|
actionButton('js-layout-up', 'icon-arrow-up', '') +
|
|
actionButton('js-layout-down', 'icon-arrow-down', '') +
|
|
actionButton('js-layout-edit', 'icon-pencil', t('edit', 'Edit')) +
|
|
actionButton('js-layout-delete btn-danger', 'icon-trash', t('delete', 'Delete')) +
|
|
' </div>' +
|
|
'</div>' +
|
|
'<div class="adv-menu-admin-layout__body">' +
|
|
(layout.custom_image_url ? '<img src="' + escapeHtml(layout.custom_image_url) + '" alt="" class="adv-menu-image-preview">' : '') +
|
|
'</div>';
|
|
|
|
wrapper.querySelector('.js-layout-up').addEventListener('click', function () {
|
|
move(layouts, index, 'up');
|
|
});
|
|
wrapper.querySelector('.js-layout-down').addEventListener('click', function () {
|
|
move(layouts, index, 'down');
|
|
});
|
|
wrapper.querySelector('.js-layout-edit').addEventListener('click', function () {
|
|
openLayoutModal(layout);
|
|
});
|
|
wrapper.querySelector('.js-layout-delete').addEventListener('click', function () {
|
|
askConfirm(t('deleteLayoutTitle', 'Delete rich block'), t('deleteLayoutText', 'This will remove the selected rich content block.'), function () {
|
|
layouts.splice(index, 1);
|
|
render();
|
|
});
|
|
});
|
|
|
|
return wrapper;
|
|
}
|
|
|
|
function bindNodeActions(wrapper, node, collection, index, depth) {
|
|
wrapper.querySelector('.js-node-up').addEventListener('click', function () {
|
|
move(collection, index, 'up');
|
|
});
|
|
wrapper.querySelector('.js-node-down').addEventListener('click', function () {
|
|
move(collection, index, 'down');
|
|
});
|
|
wrapper.querySelector('.js-node-edit').addEventListener('click', function () {
|
|
openNodeModal(node, depth);
|
|
});
|
|
wrapper.querySelector('.js-node-add-child').addEventListener('click', function () {
|
|
var child = createEmptyNode();
|
|
openNodeModal(child, depth + 1, {
|
|
onSave: function (savedChild) {
|
|
node.children.push(savedChild);
|
|
}
|
|
});
|
|
});
|
|
wrapper.querySelector('.js-node-add-layout').addEventListener('click', function () {
|
|
var layout = createEmptyLayout();
|
|
openLayoutModal(layout, {
|
|
onSave: function (savedLayout) {
|
|
node.layouts.push(savedLayout);
|
|
}
|
|
});
|
|
});
|
|
wrapper.querySelector('.js-node-delete').addEventListener('click', function () {
|
|
askConfirm(t('deleteNodeTitle', 'Delete menu item'), t('deleteNodeText', 'This will remove the selected menu item together with its children and attached blocks.'), function () {
|
|
collection.splice(index, 1);
|
|
render();
|
|
});
|
|
});
|
|
}
|
|
|
|
function actionButton(className, icon, label) {
|
|
return '' +
|
|
'<button type="button" class="btn btn-default btn-sm adv-menu-admin-action ' + className + '">' +
|
|
' <i class="' + icon + '"></i>' +
|
|
(label ? '<span>' + escapeHtml(label) + '</span>' : '') +
|
|
'</button>';
|
|
}
|
|
|
|
function metaItem(text, icon) {
|
|
return '<span class="adv-menu-admin-node__meta-item"><i class="' + icon + '"></i><span>' + escapeHtml(text) + '</span></span>';
|
|
}
|
|
|
|
function move(collection, index, direction) {
|
|
var target = direction === 'up' ? index - 1 : index + 1;
|
|
if (target < 0 || target >= collection.length) {
|
|
return;
|
|
}
|
|
|
|
var current = collection[index];
|
|
collection[index] = collection[target];
|
|
collection[target] = current;
|
|
if (collection === tree && current.id === activeRootId) {
|
|
activeRootId = current.id;
|
|
}
|
|
render();
|
|
}
|
|
|
|
function findRootById(id) {
|
|
for (var i = 0; i < tree.length; i += 1) {
|
|
if (tree[i].id === id) {
|
|
return tree[i];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function getRootIndex(id) {
|
|
for (var i = 0; i < tree.length; i += 1) {
|
|
if (tree[i].id === id) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
function openNodeModal(node, depth, options) {
|
|
nodeModalState = {
|
|
node: node,
|
|
depth: depth,
|
|
onSave: options && typeof options.onSave === 'function' ? options.onSave : null
|
|
};
|
|
ensureNodeDefaults(node);
|
|
|
|
nodeModal.querySelector('.js-node-modal-title').textContent = t('nodeModalTitle', 'Edit menu item');
|
|
nodeModal.querySelector('.js-node-type').value = node.type || 'link';
|
|
nodeModal.querySelector('.js-node-entity-id').value = node.entity_id || 0;
|
|
nodeModal.querySelector('.js-node-active').checked = !!node.active;
|
|
nodeModal.querySelector('.js-node-new-window').checked = !!node.new_window;
|
|
|
|
var rootHint = nodeModal.querySelector('.js-node-root-hint');
|
|
var imageGroup = nodeModal.querySelector('.js-node-image-group');
|
|
var previewWrap = nodeModal.querySelector('.js-node-icon-preview');
|
|
renderImagePreview(previewWrap, depth > 0 ? node.icon_url : '');
|
|
|
|
rootHint.style.display = depth === 0 ? 'block' : 'none';
|
|
rootHint.textContent = t('rootOnlyHint', 'For first-level items only title and custom link are edited here.');
|
|
imageGroup.style.display = depth === 0 ? 'none' : 'block';
|
|
|
|
renderNodeLanguagePanels(node, depth);
|
|
|
|
var uploadInput = nodeModal.querySelector('.js-node-icon-upload');
|
|
uploadInput.value = '';
|
|
uploadInput.onchange = function (event) {
|
|
uploadImage(event.target.files[0], 'menu_icon', function (response) {
|
|
node.icon_path = response.path;
|
|
node.icon_url = response.url;
|
|
renderImagePreview(previewWrap, response.url);
|
|
serializeTree();
|
|
});
|
|
};
|
|
|
|
showModal(nodeModal);
|
|
}
|
|
|
|
function renderNodeLanguagePanels(node, depth) {
|
|
var wrap = nodeModal.querySelector('.js-node-languages');
|
|
wrap.innerHTML = '';
|
|
|
|
languages.forEach(function (language) {
|
|
var langId = String(language.id_lang);
|
|
var lang = node.lang[langId] || { title: '', description: '', custom_link: '' };
|
|
var panel = document.createElement('div');
|
|
panel.className = 'adv-megamenu-admin__lang-panel';
|
|
panel.innerHTML = '' +
|
|
'<h5>' + escapeHtml(language.iso_code + ' / ' + language.name) + '</h5>' +
|
|
'<div class="adv-megamenu-admin__lang-grid">' +
|
|
' <label class="form-group">' +
|
|
' <span>' + escapeHtml(t('title', 'Title')) + '</span>' +
|
|
' <input type="text" class="form-control js-lang-title" value="' + escapeAttribute(lang.title || '') + '">' +
|
|
' </label>' +
|
|
(depth === 0 ? '' : (
|
|
' <label class="form-group">' +
|
|
' <span>' + escapeHtml(t('description', 'Description')) + '</span>' +
|
|
' <textarea class="form-control js-lang-description" rows="3">' + escapeHtml(lang.description || '') + '</textarea>' +
|
|
' </label>'
|
|
)) +
|
|
' <label class="form-group">' +
|
|
' <span>' + escapeHtml(t('customLinkLabel', 'Custom link')) + '</span>' +
|
|
' <input type="text" class="form-control js-lang-link" value="' + escapeAttribute(lang.custom_link || '') + '">' +
|
|
' </label>' +
|
|
'</div>';
|
|
|
|
panel.querySelector('.js-lang-title').addEventListener('input', function (event) {
|
|
node.lang[langId].title = event.target.value;
|
|
serializeTree();
|
|
});
|
|
if (depth > 0) {
|
|
panel.querySelector('.js-lang-description').addEventListener('input', function (event) {
|
|
node.lang[langId].description = event.target.value;
|
|
serializeTree();
|
|
});
|
|
}
|
|
panel.querySelector('.js-lang-link').addEventListener('input', function (event) {
|
|
node.lang[langId].custom_link = event.target.value;
|
|
serializeTree();
|
|
});
|
|
|
|
wrap.appendChild(panel);
|
|
});
|
|
}
|
|
|
|
function saveNodeModal() {
|
|
if (!nodeModalState) {
|
|
return;
|
|
}
|
|
|
|
var node = nodeModalState.node;
|
|
var depth = nodeModalState.depth;
|
|
var onSave = nodeModalState.onSave;
|
|
node.type = nodeModal.querySelector('.js-node-type').value;
|
|
node.entity_id = parseInt(nodeModal.querySelector('.js-node-entity-id').value || '0', 10);
|
|
node.active = nodeModal.querySelector('.js-node-active').checked;
|
|
node.new_window = nodeModal.querySelector('.js-node-new-window').checked;
|
|
|
|
if (depth === 0) {
|
|
node.icon_path = '';
|
|
node.icon_url = '';
|
|
Object.keys(node.lang).forEach(function (langId) {
|
|
node.lang[langId].description = '';
|
|
});
|
|
}
|
|
|
|
if (onSave) {
|
|
onSave(node);
|
|
}
|
|
|
|
hideModal(nodeModal);
|
|
nodeModalState = null;
|
|
render();
|
|
}
|
|
|
|
function openLayoutModal(layout, options) {
|
|
layoutModalState = {
|
|
layout: layout,
|
|
onSave: options && typeof options.onSave === 'function' ? options.onSave : null
|
|
};
|
|
layout.products = layout.products || [];
|
|
|
|
layoutModal.querySelector('.js-layout-width').value = layout.column_width || 4;
|
|
layoutModal.querySelector('.js-layout-type').value = layout.block_type || 'promo';
|
|
layoutModal.querySelector('.js-layout-title').checked = !!layout.show_title;
|
|
layoutModal.querySelector('.js-layout-bg').value = layout.background_color || '';
|
|
renderImagePreview(layoutModal.querySelector('.js-layout-preview'), layout.custom_image_url);
|
|
renderProducts(layout.products, layoutModal.querySelector('.js-layout-products'));
|
|
layoutModal.querySelector('.js-layout-product-results').innerHTML = '';
|
|
layoutModal.querySelector('.js-layout-product-search').value = '';
|
|
|
|
var uploadInput = layoutModal.querySelector('.js-layout-upload');
|
|
uploadInput.value = '';
|
|
uploadInput.onchange = function (event) {
|
|
uploadImage(event.target.files[0], 'layout_image', function (response) {
|
|
layout.custom_image = response.path;
|
|
layout.custom_image_url = response.url;
|
|
renderImagePreview(layoutModal.querySelector('.js-layout-preview'), response.url);
|
|
serializeTree();
|
|
});
|
|
};
|
|
|
|
bindLayoutProductSearch(layout);
|
|
showModal(layoutModal);
|
|
}
|
|
|
|
function bindLayoutProductSearch(layout) {
|
|
var resultsWrap = layoutModal.querySelector('.js-layout-product-results');
|
|
var searchInput = layoutModal.querySelector('.js-layout-product-search');
|
|
var searchTimer = null;
|
|
|
|
searchInput.oninput = function () {
|
|
clearTimeout(searchTimer);
|
|
var value = searchInput.value.trim();
|
|
if (value.length < 2) {
|
|
resultsWrap.innerHTML = '';
|
|
return;
|
|
}
|
|
|
|
searchTimer = window.setTimeout(function () {
|
|
fetch(ajaxUrl + '&ajax=1&action=searchProducts&q=' + encodeURIComponent(value))
|
|
.then(function (response) {
|
|
return response.json();
|
|
})
|
|
.then(function (payload) {
|
|
resultsWrap.innerHTML = '';
|
|
(payload.results || []).forEach(function (result) {
|
|
var button = document.createElement('button');
|
|
button.type = 'button';
|
|
button.textContent = result.label;
|
|
button.addEventListener('click', function () {
|
|
if (layout.products.indexOf(result.id) === -1) {
|
|
layout.products.push(result.id);
|
|
}
|
|
renderProducts(layout.products, layoutModal.querySelector('.js-layout-products'));
|
|
serializeTree();
|
|
});
|
|
resultsWrap.appendChild(button);
|
|
});
|
|
});
|
|
}, 200);
|
|
};
|
|
}
|
|
|
|
function renderProducts(products, wrap) {
|
|
wrap.innerHTML = '';
|
|
if (!products.length) {
|
|
wrap.innerHTML = '<span class="help-block">' + escapeHtml(t('noProducts', 'No products attached.')) + '</span>';
|
|
return;
|
|
}
|
|
|
|
products.forEach(function (productId, index) {
|
|
var chip = document.createElement('span');
|
|
chip.className = 'adv-menu-product-chip';
|
|
chip.innerHTML = '<span>#' + escapeHtml(String(productId)) + '</span><button type="button">×</button>';
|
|
chip.querySelector('button').addEventListener('click', function () {
|
|
products.splice(index, 1);
|
|
renderProducts(products, wrap);
|
|
serializeTree();
|
|
});
|
|
wrap.appendChild(chip);
|
|
});
|
|
}
|
|
|
|
function saveLayoutModal() {
|
|
if (!layoutModalState) {
|
|
return;
|
|
}
|
|
|
|
var layout = layoutModalState.layout;
|
|
var onSave = layoutModalState.onSave;
|
|
layout.column_width = parseInt(layoutModal.querySelector('.js-layout-width').value || '4', 10);
|
|
layout.block_type = layoutModal.querySelector('.js-layout-type').value;
|
|
layout.show_title = layoutModal.querySelector('.js-layout-title').checked;
|
|
layout.background_color = layoutModal.querySelector('.js-layout-bg').value;
|
|
|
|
if (onSave) {
|
|
onSave(layout);
|
|
}
|
|
|
|
hideModal(layoutModal);
|
|
layoutModalState = null;
|
|
render();
|
|
}
|
|
|
|
function askConfirm(title, text, callback) {
|
|
confirmAction = callback;
|
|
confirmModal.querySelector('.js-confirm-title').textContent = title;
|
|
confirmModal.querySelector('.js-confirm-text').textContent = text;
|
|
showModal(confirmModal);
|
|
}
|
|
|
|
function renderImagePreview(wrap, url) {
|
|
wrap.innerHTML = '';
|
|
if (!url) {
|
|
return;
|
|
}
|
|
|
|
var image = document.createElement('img');
|
|
image.src = url;
|
|
image.className = 'adv-menu-image-preview';
|
|
wrap.appendChild(image);
|
|
}
|
|
|
|
function getNodeTitle(node) {
|
|
var defaultLang = languages[0] ? String(languages[0].id_lang) : null;
|
|
if (defaultLang && node.lang[defaultLang] && node.lang[defaultLang].title) {
|
|
return node.lang[defaultLang].title;
|
|
}
|
|
|
|
var langIds = Object.keys(node.lang || {});
|
|
for (var i = 0; i < langIds.length; i += 1) {
|
|
if (node.lang[langIds[i]] && node.lang[langIds[i]].title) {
|
|
return node.lang[langIds[i]].title;
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
function getNodeLink(node) {
|
|
var defaultLang = languages[0] ? String(languages[0].id_lang) : null;
|
|
if (defaultLang && node.lang[defaultLang] && node.lang[defaultLang].custom_link) {
|
|
return node.lang[defaultLang].custom_link;
|
|
}
|
|
|
|
var langIds = Object.keys(node.lang || {});
|
|
for (var i = 0; i < langIds.length; i += 1) {
|
|
if (node.lang[langIds[i]] && node.lang[langIds[i]].custom_link) {
|
|
return node.lang[langIds[i]].custom_link;
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
function uploadImage(file, preset, callback) {
|
|
if (!file) {
|
|
return;
|
|
}
|
|
|
|
var formData = new FormData();
|
|
formData.append('ajax', '1');
|
|
formData.append('action', 'uploadImage');
|
|
formData.append('token', token);
|
|
formData.append('preset', preset || 'default');
|
|
formData.append('image', file);
|
|
|
|
fetch(ajaxUrl, {
|
|
method: 'POST',
|
|
body: formData
|
|
})
|
|
.then(function (response) {
|
|
return response.json();
|
|
})
|
|
.then(function (payload) {
|
|
if (payload && !payload.error) {
|
|
callback(payload);
|
|
}
|
|
});
|
|
}
|
|
|
|
function escapeHtml(value) {
|
|
return String(value)
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''');
|
|
}
|
|
|
|
function escapeAttribute(value) {
|
|
return escapeHtml(value).replace(/\n/g, ' ');
|
|
}
|
|
|
|
root.querySelector('.js-add-root-node').addEventListener('click', function () {
|
|
var node = createEmptyNode();
|
|
openNodeModal(node, 0, {
|
|
onSave: function (savedNode) {
|
|
tree.push(savedNode);
|
|
activeRootId = savedNode.id;
|
|
}
|
|
});
|
|
});
|
|
|
|
nodeModal.querySelector('.js-save-node').addEventListener('click', saveNodeModal);
|
|
layoutModal.querySelector('.js-save-layout').addEventListener('click', saveLayoutModal);
|
|
confirmModal.querySelector('.js-confirm-action').addEventListener('click', function () {
|
|
if (typeof confirmAction === 'function') {
|
|
confirmAction();
|
|
}
|
|
hideModal(confirmModal);
|
|
confirmAction = null;
|
|
});
|
|
|
|
if (window.jQuery) {
|
|
window.jQuery(nodeModal).on('hidden.bs.modal', function () {
|
|
nodeModalState = null;
|
|
});
|
|
window.jQuery(layoutModal).on('hidden.bs.modal', function () {
|
|
layoutModalState = null;
|
|
});
|
|
window.jQuery(confirmModal).on('hidden.bs.modal', function () {
|
|
confirmAction = null;
|
|
});
|
|
}
|
|
|
|
render();
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', boot);
|
|
} else {
|
|
boot();
|
|
}
|
|
})();
|