6181 lines
153 KiB
JavaScript
6181 lines
153 KiB
JavaScript
;(function() {
|
|
"use strict";
|
|
|
|
BX.namespace("BX.Landing");
|
|
|
|
// Utils
|
|
var deepFreeze = BX.Landing.Utils.deepFreeze;
|
|
var style = BX.Landing.Utils.style;
|
|
var insertAfter = BX.Landing.Utils.insertAfter;
|
|
var insertBefore = BX.Landing.Utils.insertBefore;
|
|
var append = BX.Landing.Utils.append;
|
|
var isPlainObject = BX.Landing.Utils.isPlainObject;
|
|
var isBoolean = BX.Landing.Utils.isBoolean;
|
|
var isNumber = BX.Landing.Utils.isNumber;
|
|
var isString = BX.Landing.Utils.isString;
|
|
var isArray = BX.Landing.Utils.isArray;
|
|
var isEmpty = BX.Landing.Utils.isEmpty;
|
|
var addClass = BX.Landing.Utils.addClass;
|
|
var removeClass = BX.Landing.Utils.removeClass;
|
|
var hasClass = BX.Landing.Utils.hasClass;
|
|
var toggleClass = BX.Landing.Utils.toggleClass;
|
|
var create = BX.Landing.Utils.create;
|
|
var debounce = BX.Landing.Utils.debounce;
|
|
var throttle = BX.Landing.Utils.throttle;
|
|
var fireCustomEvent = BX.Landing.Utils.fireCustomEvent;
|
|
var onCustomEvent = BX.Landing.Utils.onCustomEvent;
|
|
var bind = BX.Landing.Utils.bind;
|
|
var unbind = BX.Landing.Utils.unbind;
|
|
var getClass = BX.Landing.Utils.getClass;
|
|
var rect = BX.Landing.Utils.rect;
|
|
var setTextContent = BX.Landing.Utils.setTextContent;
|
|
var translateY = BX.Landing.Utils.translateY;
|
|
var nextSibling = BX.Landing.Utils.nextSibling;
|
|
var prevSibling = BX.Landing.Utils.prevSibling;
|
|
var join = BX.Landing.Utils.join;
|
|
var slice = BX.Landing.Utils.slice;
|
|
var decodeDataValue = BX.Landing.Utils.decodeDataValue;
|
|
var encodeDataValue = BX.Landing.Utils.encodeDataValue;
|
|
var data = BX.Landing.Utils.data;
|
|
var attr = BX.Landing.Utils.attr;
|
|
var removePanels = BX.Landing.Utils.removePanels;
|
|
var getCSSSelector = BX.Landing.Utils.getCSSSelector;
|
|
var remove = BX.Landing.Utils.remove;
|
|
var clone = BX.Landing.Utils.clone;
|
|
var trim = BX.Landing.Utils.trim;
|
|
var prepend = BX.Landing.Utils.prepend;
|
|
var random = BX.Landing.Utils.random;
|
|
var htmlToElement = BX.Landing.Utils.htmlToElement;
|
|
var proxy = BX.Landing.Utils.proxy;
|
|
var escapeText = BX.Landing.Utils.escapeText;
|
|
var isValidElementId = BX.Landing.Utils.isValidElementId;
|
|
|
|
// Collections
|
|
var BaseCollection = BX.Landing.Collection.BaseCollection;
|
|
var NodeCollection = BX.Landing.Collection.NodeCollection;
|
|
var FormCollection = BX.Landing.UI.Collection.FormCollection;
|
|
var CardCollection = BX.Landing.Collection.CardCollection;
|
|
var PanelCollection = BX.Landing.UI.Collection.PanelCollection;
|
|
|
|
// Panels
|
|
var BaseButtonPanel = BX.Landing.UI.Panel.BaseButtonPanel;
|
|
var CardActionPanel = BX.Landing.UI.Panel.CardAction;
|
|
var ContentEditPanel = BX.Landing.UI.Panel.ContentEdit;
|
|
|
|
// Buttons
|
|
var BaseButton = BX.Landing.UI.Button.BaseButton;
|
|
var ActionButton = BX.Landing.UI.Button.ActionButton;
|
|
var PlusButton = BX.Landing.UI.Button.Plus;
|
|
var CardActionButton = BX.Landing.UI.Button.CardAction;
|
|
|
|
// Factories
|
|
var StyleFactory = BX.Landing.UI.Factory.StyleFactory;
|
|
|
|
// Forms
|
|
var BaseForm = BX.Landing.UI.Form.BaseForm;
|
|
var StyleForm = BX.Landing.UI.Form.StyleForm;
|
|
var CardForm = BX.Landing.UI.Form.CardForm;
|
|
var CardsForm = BX.Landing.UI.Form.CardsForm;
|
|
|
|
// Other
|
|
var Group = BX.Landing.Group;
|
|
var BlockEvent = BX.Landing.Event.Block;
|
|
var TabCard = BX.Landing.UI.Card.TabCard;
|
|
var DynamicFieldsGroup = BX.Landing.UI.Card.DynamicFieldsGroup;
|
|
|
|
// noinspection JSUnusedLocalSymbols
|
|
/**
|
|
* Access denied
|
|
* @type {string}
|
|
*/
|
|
var ACCESS_D = "D";
|
|
|
|
/**
|
|
* Design only
|
|
* @type {string}
|
|
*/
|
|
var ACCESS_V = "V";
|
|
|
|
/**
|
|
* Edit without delete
|
|
* @type {string}
|
|
*/
|
|
var ACCESS_W = "W";
|
|
|
|
/**
|
|
* All access
|
|
* @type {string}
|
|
*/
|
|
var ACCESS_X = "X";
|
|
|
|
function getTypeSettings(prop)
|
|
{
|
|
let lp = BX.Landing.Main.getInstance();
|
|
let namespaces = Object.keys(lp.options.style);
|
|
|
|
for (let i = 0; i < namespaces.length; i++)
|
|
{
|
|
let namespace = namespaces[i];
|
|
let type = lp.options.style[namespace]["style"][prop];
|
|
|
|
if (!type)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
type.attrKey = prop;
|
|
|
|
if (prop === 'background')
|
|
{
|
|
const backgroundOverlayItems = lp.options.style[namespace]['style']['background-overlay']
|
|
.items.filter((obj) => obj.name !== 'g-bg--after');
|
|
type.items = [...type.items, ...backgroundOverlayItems];
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function getAttrsTypeSettings(prop)
|
|
{
|
|
let lp = BX.Landing.Main.getInstance();
|
|
let namespaces = Object.keys(lp.options.attrs);
|
|
|
|
for (let i = 0; i < namespaces.length; i++)
|
|
{
|
|
let namespace = namespaces[i];
|
|
let attr = lp.options.attrs[namespace]["attrs"][prop];
|
|
|
|
if (!attr)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
attr.attrKey = prop;
|
|
return attr;
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
function isGroup(prop)
|
|
{
|
|
let lp = BX.Landing.Main.getInstance();
|
|
let namespaces = Object.keys(lp.options.style);
|
|
|
|
for (let i = 0; i < namespaces.length; i++)
|
|
{
|
|
let namespace = namespaces[i];
|
|
|
|
if (!lp.options.style[namespace]["group"])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (prop in lp.options.style[namespace]["group"])
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function getGroupTypes(group)
|
|
{
|
|
let lp = BX.Landing.Main.getInstance();
|
|
let namespaces = Object.keys(lp.options.style);
|
|
|
|
for (let i = 0; i < namespaces.length; i++)
|
|
{
|
|
let namespace = namespaces[i];
|
|
|
|
if (!lp.options.style[namespace]["group"])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (lp.options.style[namespace]["group"][group])
|
|
{
|
|
return lp.options.style[namespace]["group"][group];
|
|
}
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
|
|
/**
|
|
* Shows loader for button
|
|
* @param {BX.Landing.UI.Button.BaseButton} button
|
|
*/
|
|
function showButtonLoader(button)
|
|
{
|
|
if (!!button)
|
|
{
|
|
if (!button.loader)
|
|
{
|
|
button.loader = new BX.Loader({
|
|
target: button.layout,
|
|
size: 16
|
|
});
|
|
|
|
void style(button.loader.layout.querySelector(".main-ui-loader-svg-circle"), {
|
|
"stroke-width": "4px"
|
|
});
|
|
}
|
|
|
|
button.loader.show();
|
|
addClass(button.text, "landing-ui-hide-icon");
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Hides button loader
|
|
* @param {BX.Landing.UI.Button.BaseButton} button
|
|
*/
|
|
function hideButtonLoader(button)
|
|
{
|
|
if (!!button)
|
|
{
|
|
if (button.loader)
|
|
{
|
|
button.loader.hide();
|
|
removeClass(button.text, "landing-ui-hide-icon");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @param {string} selector
|
|
* @return {boolean|*}
|
|
*/
|
|
function isNodeSelector(selector)
|
|
{
|
|
return !!selector && selector.includes("@");
|
|
}
|
|
|
|
var onBlockInitDebounced = BX.debounce(function() {
|
|
BX.Landing.PageObject.getBlocks().forEach(function(block) {
|
|
block.adjustSortButtonsState();
|
|
});
|
|
}, 400);
|
|
|
|
onCustomEvent("BX.Landing.Block:init", onBlockInitDebounced);
|
|
|
|
/**
|
|
* Implements interface for works with landing block
|
|
*
|
|
* @param {HTMLElement} element
|
|
* @param {blockOptions} options
|
|
*
|
|
* @property {BX.Landing.UI.Collection.PanelCollection.<BX.Landing.UI.Panel.BasePanel>} panels - Panels collection
|
|
* @property {BX.Landing.Collection.CardCollection.<BX.Landing.Block.Card>} cards - Cards collection
|
|
* @property {BX.Landing.Collection.NodeCollection.<BX.Landing.Node>} nodes - Nodes collection
|
|
* @property {blockManifest} manifest
|
|
*
|
|
* @constructor
|
|
*/
|
|
BX.Landing.Block = function(element, options)
|
|
{
|
|
this.node = element;
|
|
this.parent = element.parentElement;
|
|
this.content = element.firstElementChild;
|
|
this.siteId = data(element.parentElement, "data-site");
|
|
this.lid = data(element.parentElement, "data-landing");
|
|
this.id = isNumber(parseInt(options.id)) ? parseInt(options.id) : 0;
|
|
this.selector = join("#block", (isNumber(options.id) ? options.id : 0), " > :first-child");
|
|
this.repoId = isNumber(options.repoId) ? options.repoId : null;
|
|
this.active = isBoolean(options.active) ? options.active : true;
|
|
this.allowedByTariff = isBoolean(options.allowedByTariff) ? options.allowedByTariff : true;
|
|
this.manifest = isPlainObject(options.manifest) ? options.manifest : {};
|
|
this.manifest.nodes = isPlainObject(options.manifest.nodes) ? options.manifest.nodes : {};
|
|
this.manifest.cards = isPlainObject(options.manifest.cards) ? options.manifest.cards : {};
|
|
this.manifest.attrs = isPlainObject(options.manifest.attrs) ? options.manifest.attrs : {};
|
|
this.manifest.style = isPlainObject(options.manifest.style) ? options.manifest.style : {};
|
|
if (isPlainObject(options.manifest.style))
|
|
{
|
|
this.styleNodes = isPlainObject(options.manifest.style.nodes) ? options.manifest.style.nodes : {};
|
|
}
|
|
this.onStyleInputWithDebounce = debounce(this.onStyleInput, 300, this);
|
|
this.changeTimeout = null;
|
|
this.php = options.php;
|
|
this.designed = options.designed;
|
|
this.access = options.access;
|
|
this.anchor = options.anchor;
|
|
this.savedAnchor = options.anchor;
|
|
this.requiredUserActionOptions = options.requiredUserAction;
|
|
this.dynamicParams = options.dynamicParams || {};
|
|
this.sections = options.sections ? options.sections.split(',') : [];
|
|
|
|
// Make entities collections
|
|
this.nodes = new NodeCollection();
|
|
this.cards = new CardCollection();
|
|
this.panels = new PanelCollection();
|
|
this.groups = new BaseCollection();
|
|
this.changedNodes = new BaseCollection();
|
|
this.styles = new BaseCollection();
|
|
this.forms = new FormCollection();
|
|
this.menu = [];
|
|
|
|
if (isPlainObject(this.requiredUserActionOptions) && !isEmpty(this.requiredUserActionOptions))
|
|
{
|
|
this.showRequiredUserAction(this.requiredUserActionOptions);
|
|
this.requiredUserActionIsShown = true;
|
|
}
|
|
|
|
this.onEditorEnabled = this.onEditorEnabled.bind(this);
|
|
this.onEditorDisabled = this.onEditorDisabled.bind(this);
|
|
this.adjustPanelsPosition = this.adjustPanelsPosition.bind(this);
|
|
this.onMouseMove = this.onMouseMove.bind(this);
|
|
this.onStorage = this.onStorage.bind(this);
|
|
this.onBlockRemove = this.onBlockRemove.bind(this);
|
|
|
|
// Make manifest read only
|
|
deepFreeze(this.manifest);
|
|
|
|
// Apply block state
|
|
this.node.classList[this.active ? "remove" : "add"]("landing-block-disabled");
|
|
|
|
// Sets state
|
|
this.state = "ready";
|
|
|
|
// Init panels
|
|
this.initPanels();
|
|
this.initStyles();
|
|
this.initMenu();
|
|
this.adjustContextSensitivityStyles();
|
|
|
|
var envOptions = BX.Landing.Env.getInstance().getOptions();
|
|
if (this.isDefaultCrmFormBlock() || this.isCrmFormBlock())
|
|
{
|
|
const uri = new BX.Uri(window.top.location.toString());
|
|
if (BX.Text.toBoolean(uri.getQueryParam('replacedLanding')))
|
|
{
|
|
uri.removeQueryParam('replacedLanding');
|
|
top.window.history.replaceState({}, document.title, uri.toString());
|
|
|
|
this.onStyleShow();
|
|
setTimeout(() => {
|
|
const y = this.node.offsetTop;
|
|
BX.Landing.PageObject.getEditorWindow().scrollTo(0, y);
|
|
}, 300);
|
|
}
|
|
else
|
|
{
|
|
const showOptions = {
|
|
formId: envOptions.formEditorData.formOptions.id,
|
|
formOptions: this.getCrmFormOptions(),
|
|
block: this,
|
|
showWithOptions: true,
|
|
};
|
|
|
|
if (BX.Text.toBoolean(uri.getQueryParam('formCreated')))
|
|
{
|
|
showOptions.state = 'presets';
|
|
}
|
|
|
|
const formSettingsPanelInstance = BX.Landing.UI.Panel.FormSettingsPanel.getInstance();
|
|
if (
|
|
formSettingsPanelInstance
|
|
&& element.ownerDocument === BX.Landing.PageObject.getEditorWindow().document
|
|
)
|
|
{
|
|
formSettingsPanelInstance.show(showOptions);
|
|
}
|
|
}
|
|
}
|
|
|
|
BX.Landing.PageObject.getBlocks().push(this);
|
|
|
|
// Fire block init event
|
|
|
|
var eventData = {};
|
|
|
|
if (this.requiredUserActionIsShown)
|
|
{
|
|
eventData.requiredUserActionIsShown = true;
|
|
eventData.layout = this.node.firstElementChild;
|
|
eventData.button = this.node.firstElementChild.querySelector(".ui-btn");
|
|
}
|
|
|
|
fireCustomEvent(window, "BX.Landing.Block:init", [this.createEvent({data: eventData})]);
|
|
|
|
onCustomEvent("BX.Landing.Editor:enable", this.onEditorEnabled);
|
|
onCustomEvent("BX.Landing.Editor:disable", this.onEditorDisabled);
|
|
onCustomEvent("BX.Landing.Block:afterRemove", this.onBlockRemove);
|
|
|
|
bind(this.node, "mousemove", this.onMouseMove);
|
|
bind(this.node, "keydown", this.adjustPanelsPosition);
|
|
bind(top, "storage", this.onStorage);
|
|
};
|
|
|
|
BX.Landing.Block.storage = new BX.Landing.Collection.BlockCollection();
|
|
|
|
BX.Landing.Block.prototype = {
|
|
/**
|
|
* Handles mouse move event on block node
|
|
* Implements lazy initialization entities of block
|
|
* @private
|
|
*/
|
|
onMouseMove: function()
|
|
{
|
|
if (this.state === "ready")
|
|
{
|
|
unbind(this.node, "mousemove", this.onMouseMove);
|
|
this.initEntities();
|
|
this.lazyInitPanels();
|
|
this.state = "complete";
|
|
}
|
|
},
|
|
|
|
getBlockNode: function()
|
|
{
|
|
return this.node;
|
|
},
|
|
|
|
isAllowedByTariff: function()
|
|
{
|
|
return this.allowedByTariff;
|
|
},
|
|
|
|
showRequiredUserAction: function(data)
|
|
{
|
|
let container = this.node;
|
|
if (data.targetNodeSelector)
|
|
{
|
|
container = this.node.querySelector(data.targetNodeSelector);
|
|
}
|
|
container.innerHTML = (
|
|
"<div class=\"landing-block-user-action\">" +
|
|
"<div class=\"landing-block-user-action-inner\">" +
|
|
(data.header ? (
|
|
"<h3>"+"<i class=\"fa fa-exclamation-triangle g-mr-15\"></i>"+data.header+"</h3><hr>"
|
|
) : "") +
|
|
(data.description ? (
|
|
"<p>"+data.description+"</p>"
|
|
) : "") +
|
|
((data.href || data.onClick || data.className) && data.text ? (
|
|
"<div>" +
|
|
"<a href=\""+data.href+"\" class=\"landing-trusted-link ui-btn "+data.className+"\" target=\""+(data.target ? data.target : '')+"\">"+data.text+"</a>" +
|
|
"</div>"
|
|
) : "") +
|
|
"</div>" +
|
|
"</div>"
|
|
);
|
|
|
|
if (data.onClick)
|
|
{
|
|
var button = container.querySelector('.landing-block-user-action .ui-btn');
|
|
bind(button, 'click', function(event) {
|
|
event.preventDefault();
|
|
|
|
try
|
|
{
|
|
BX.evalGlobal(data.onClick);
|
|
}
|
|
catch (err)
|
|
{
|
|
console.error(err);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Disables content links and buttons
|
|
*/
|
|
disableLinks: function()
|
|
{
|
|
var selector = "a:not([class*='landing-ui']):not(.landing-trusted-link), .btn:not([class*='landing-ui']):not(.landing-trusted-link), button:not([class*='landing-ui']):not(.landing-trusted-link), input:not([class*='landing-ui'])";
|
|
var items = slice(this.content.querySelectorAll(selector));
|
|
|
|
items.forEach(function(item) {
|
|
var isChildOfNode = this.nodes.some(function(node) {
|
|
return node.node.contains(item);
|
|
});
|
|
|
|
var isMenuItem = this.menu.some(function(menu) {
|
|
return menu.root.contains(item);
|
|
});
|
|
|
|
if (!this.nodes.getByNode(item) && !isChildOfNode && !isMenuItem)
|
|
{
|
|
item.style.pointerEvents = "none";
|
|
}
|
|
}, this);
|
|
},
|
|
|
|
|
|
/**
|
|
* Adjusts context sensitivity styles
|
|
*/
|
|
adjustContextSensitivityStyles: function()
|
|
{
|
|
if (hasClass(this.parent, "landing-sidebar"))
|
|
{
|
|
if (!hasClass(this.content, "landing-adjusted"))
|
|
{
|
|
var selectors = Object.keys(this.manifest.style.nodes);
|
|
var needAdjust = selectors.filter(function(selector) {
|
|
return (
|
|
!!this.manifest.style.nodes[selector].type &&
|
|
this.manifest.style.nodes[selector].type.indexOf("columns") !== -1
|
|
);
|
|
}, this);
|
|
|
|
if (isEmpty(needAdjust))
|
|
{
|
|
return;
|
|
}
|
|
|
|
var columnsSettings = getTypeSettings("columns");
|
|
|
|
if (columnsSettings === null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
needAdjust.forEach(function(selector) {
|
|
var styleNode = this.styles.get(selector);
|
|
|
|
if (styleNode)
|
|
{
|
|
styleNode.setIsSelectGroup(true);
|
|
styleNode.setValue("col-lg-12", columnsSettings.items);
|
|
styleNode.unsetIsSelectGroupFlag();
|
|
}
|
|
}, this);
|
|
|
|
var blockStyleNode = this.styles.get(this.selector);
|
|
|
|
if (blockStyleNode)
|
|
{
|
|
blockStyleNode.setValue("landing-adjusted", ["landing-adjusted"]);
|
|
}
|
|
|
|
this.saveStyles();
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Forces block initialization
|
|
*/
|
|
forceInit: function()
|
|
{
|
|
this.onMouseMove();
|
|
},
|
|
|
|
|
|
/**
|
|
* Creates block event object
|
|
* @param {object} [options]
|
|
* @returns {BX.Landing.Event.Block}
|
|
*/
|
|
createEvent: function(options)
|
|
{
|
|
return new BlockEvent({
|
|
blockId: this.id,
|
|
block: this.node,
|
|
node: !!options && !!options.node ? options.node : null,
|
|
content: this.content,
|
|
card: !!options && !!options.card ? options.card : null,
|
|
data: (!!options && options.data) || {},
|
|
onForceInit: this.forceInit.bind(this),
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* Initializes block entities
|
|
* @private
|
|
*/
|
|
initEntities: function()
|
|
{
|
|
this.initCards();
|
|
this.initNodes();
|
|
this.initGroups();
|
|
this.disableLinks();
|
|
},
|
|
|
|
initMenu: function()
|
|
{
|
|
if (BX.type.isPlainObject(this.manifest.menu))
|
|
{
|
|
this.menu = Object.entries(this.manifest.menu).map(function(entry) {
|
|
var code = entry[0];
|
|
var value = entry[1];
|
|
|
|
return new BX.Landing.Menu.Menu({
|
|
code: code,
|
|
root: this.node.querySelector(code),
|
|
manifest: value,
|
|
block: this.id,
|
|
});
|
|
}, this);
|
|
}
|
|
},
|
|
|
|
initCardsLabels: function()
|
|
{
|
|
this.cards.forEach(function(card) {
|
|
card.label = this.createCardLabel(card.node, card.manifest);
|
|
}, this);
|
|
},
|
|
|
|
|
|
/**
|
|
* Initializes groups
|
|
*/
|
|
initGroups: function()
|
|
{
|
|
var groupsIds = [];
|
|
var groups = isPlainObject(this.manifest.groups) ? this.manifest.groups : {};
|
|
|
|
this.nodes.forEach(function(node) {
|
|
if (isString(node.manifest.group) && !groupsIds.includes(node.manifest.group))
|
|
{
|
|
groupsIds.push(node.manifest.group);
|
|
}
|
|
});
|
|
|
|
groupsIds.forEach(function(groupId) {
|
|
var nodes = this.nodes
|
|
.filter(function(node) {
|
|
return node.manifest.group === groupId;
|
|
})
|
|
.reduce(function(accumulator, node) {
|
|
var nodeIndex = parseInt(node.selector.split("@")[1]);
|
|
|
|
if (!accumulator[nodeIndex])
|
|
{
|
|
accumulator[nodeIndex] = new NodeCollection();
|
|
}
|
|
|
|
accumulator[nodeIndex].push(node);
|
|
|
|
return accumulator;
|
|
}, {});
|
|
|
|
Object.keys(nodes).forEach(function(key) {
|
|
this.groups.add(
|
|
new Group({
|
|
id: groupId,
|
|
name: groups[groupId],
|
|
nodes: nodes[key],
|
|
onClick: this.onGroupClick.bind(this)
|
|
})
|
|
);
|
|
}, this);
|
|
}, this);
|
|
},
|
|
|
|
|
|
/**
|
|
* Handles event on group click
|
|
* @param {BX.Landing.Group} group
|
|
*/
|
|
onGroupClick: function(group)
|
|
{
|
|
if (!BX.Landing.UI.Panel.StylePanel.getInstance().isShown())
|
|
{
|
|
this.showContentPanel({
|
|
name: group.name,
|
|
nodes: group.nodes,
|
|
compact: true,
|
|
nodesOnly: true,
|
|
showAll: true,
|
|
hideCheckbox: true
|
|
});
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Initializes block panels
|
|
*/
|
|
initPanels: function()
|
|
{
|
|
// Make "add block after this block" button
|
|
if (!this.panels.get("create_action"))
|
|
{
|
|
var createPanel = new BaseButtonPanel(
|
|
"create_action",
|
|
"landing-ui-panel-create-action"
|
|
);
|
|
|
|
createPanel.addButton(
|
|
new PlusButton('insert_after', {
|
|
text: BX.Landing.Loc.getMessage('ACTION_BUTTON_CREATE'),
|
|
onClick: throttle(this.addBlockAfterThis, 600, this),
|
|
}),
|
|
);
|
|
|
|
createPanel.show();
|
|
this.addPanel(createPanel);
|
|
|
|
if (this.isCrmFormPage())
|
|
{
|
|
var createBeforePanel = new BaseButtonPanel(
|
|
'create_before_action',
|
|
'landing-ui-panel-create-before-action'
|
|
);
|
|
|
|
createBeforePanel.addButton(
|
|
new PlusButton('insert_before', {
|
|
text: BX.Landing.Loc.getMessage('ACTION_BUTTON_CREATE'),
|
|
onClick: throttle(this.addBlockBeforeThis, 600, this),
|
|
}),
|
|
);
|
|
|
|
createBeforePanel.show();
|
|
this.addPanel(createBeforePanel);
|
|
}
|
|
|
|
createPanel.buttons[0].on("mouseover", this.onCreateButtonMouseover.bind(this));
|
|
createPanel.buttons[0].on("mouseout", this.onCreateButtonMouseout.bind(this));
|
|
}
|
|
},
|
|
|
|
isLastChildInArea: function()
|
|
{
|
|
return this.parent.querySelector("[class*='block-wrapper']:last-of-type") === this.node;
|
|
},
|
|
|
|
onCreateButtonMouseover: function()
|
|
{
|
|
if (this.isLastChildInArea() ||
|
|
hasClass(this.parent, "landing-header") ||
|
|
hasClass(this.parent, "landing-footer"))
|
|
{
|
|
var areas = BX.Landing.Main.getInstance().getLayoutAreas();
|
|
|
|
if (areas.length > 1)
|
|
{
|
|
var addBlockPanel = this.panels.get("create_action");
|
|
var addButton = addBlockPanel.buttons.get("insert_after");
|
|
|
|
switch (true)
|
|
{
|
|
case hasClass(this.parent, "landing-main"):
|
|
addButton.setText([
|
|
BX.Landing.Loc.getMessage("ACTION_BUTTON_CREATE"),
|
|
BX.Landing.Loc.getMessage("LANDING_ADD_BLOCK_TO_MAIN")
|
|
].join(" "));
|
|
break;
|
|
case hasClass(this.parent, "landing-header"):
|
|
addButton.setText([
|
|
BX.Landing.Loc.getMessage("ACTION_BUTTON_CREATE"),
|
|
BX.Landing.Loc.getMessage("LANDING_ADD_BLOCK_TO_HEADER")
|
|
].join(" "));
|
|
break;
|
|
case hasClass(this.parent, "landing-sidebar"):
|
|
addButton.setText([
|
|
BX.Landing.Loc.getMessage("ACTION_BUTTON_CREATE"),
|
|
BX.Landing.Loc.getMessage("LANDING_ADD_BLOCK_TO_SIDEBAR")
|
|
].join(" "));
|
|
break;
|
|
case hasClass(this.parent, "landing-footer"):
|
|
addButton.setText([
|
|
BX.Landing.Loc.getMessage("ACTION_BUTTON_CREATE"),
|
|
BX.Landing.Loc.getMessage("LANDING_ADD_BLOCK_TO_FOOTER")
|
|
].join(" "));
|
|
break;
|
|
}
|
|
|
|
clearTimeout(this.fadeTimeout);
|
|
|
|
this.fadeTimeout = setTimeout(function() {
|
|
addClass(this.parent, "landing-area-highlight");
|
|
areas.forEach(function(area) {
|
|
if (area !== this.parent)
|
|
{
|
|
addClass(area, "landing-area-fade");
|
|
}
|
|
}, this);
|
|
}.bind(this), 400);
|
|
}
|
|
}
|
|
},
|
|
|
|
onCreateButtonMouseout: function()
|
|
{
|
|
clearTimeout(this.fadeTimeout);
|
|
|
|
if (this.isLastChildInArea() ||
|
|
hasClass(this.parent, "landing-header") ||
|
|
hasClass(this.parent, "landing-footer"))
|
|
{
|
|
var areas = BX.Landing.Main.getInstance().getLayoutAreas();
|
|
|
|
if (areas.length > 1)
|
|
{
|
|
var addButton = this.panels.get("create_action").buttons[0];
|
|
addButton.setText(BX.Landing.Loc.getMessage("ACTION_BUTTON_CREATE"));
|
|
|
|
removeClass(this.parent, "landing-area-highlight");
|
|
|
|
areas.forEach(function(area) {
|
|
removeClass(area, "landing-area-fade");
|
|
}, this);
|
|
}
|
|
}
|
|
},
|
|
|
|
isInSidebar: function()
|
|
{
|
|
return !!this.node.closest(".landing-sidebar");
|
|
},
|
|
|
|
|
|
initSidebarActionPanel: function()
|
|
{
|
|
if (this.isInSidebar() && !this.panels.contains("sidebar_actions"))
|
|
{
|
|
var sidebarActionsPanel = new BaseButtonPanel(
|
|
"sidebar_actions",
|
|
"landing-ui-panel-sidebar-actions"
|
|
);
|
|
|
|
sidebarActionsPanel.addButton(
|
|
new ActionButton("showSidebarActions", {
|
|
onClick: this.onShowSidebarActionsClick.bind(this),
|
|
})
|
|
);
|
|
|
|
this.addPanel(sidebarActionsPanel);
|
|
sidebarActionsPanel.show();
|
|
}
|
|
},
|
|
|
|
showFeedbackForm: function() {
|
|
BX.Landing.Main.getInstance().showSliderFeedbackForm({
|
|
blockName: this.manifest.block.name,
|
|
blockCode: this.manifest.code,
|
|
blockSection: this.manifest.block.section,
|
|
landingId: BX.Landing.Main.getInstance().id,
|
|
target: "blockActions"
|
|
});
|
|
if (this.blockActionsMenu)
|
|
{
|
|
this.blockActionsMenu.close();
|
|
}
|
|
if (this.sidebarActionsMenu)
|
|
{
|
|
this.sidebarActionsMenu.close();
|
|
}
|
|
},
|
|
|
|
onShowSidebarActionsClick: function(event)
|
|
{
|
|
var bindElement = (
|
|
this.panels.get("sidebar_actions").buttons.get('showSidebarActions')
|
|
);
|
|
|
|
if (!this.sidebarActionsMenu)
|
|
{
|
|
this.sidebarActionsMenu = BX.Main.MenuManager.create({
|
|
id: this.id + '_sidebar_actions',
|
|
bindElement: bindElement.layout,
|
|
className: "landing-ui-block-actions-popup",
|
|
angle: {position: "top", offset: 95},
|
|
offsetTop: -6,
|
|
offsetLeft: -26,
|
|
events: {
|
|
onPopupClose: function() {
|
|
this.panels.get("sidebar_actions").buttons.get("showSidebarActions").deactivate();
|
|
removeClass(this.node, "landing-ui-hover");
|
|
}.bind(this)
|
|
},
|
|
items: [
|
|
(function() {
|
|
if (
|
|
(isPlainObject(this.manifest.nodes) || isPlainObject(this.manifest.attrs))
|
|
&& this.isAllowedByTariff()
|
|
)
|
|
{
|
|
return new BX.Main.MenuItem({
|
|
id: "content",
|
|
text: BX.Landing.Loc.getMessage("ACTION_BUTTON_CONTENT"),
|
|
disabled: !this.isEditBlockAllowed(),
|
|
disabledHint: this.getDisableEditBlockHint(),
|
|
onclick: function() {
|
|
this.onShowContentPanel();
|
|
this.sidebarActionsMenu.close();
|
|
}.bind(this)
|
|
});
|
|
}
|
|
}.bind(this))(),
|
|
(function() {
|
|
if (isPlainObject(this.manifest.style) && this.isAllowedByTariff())
|
|
{
|
|
return new BX.Main.MenuItem({
|
|
id: "style",
|
|
text: BX.Landing.Loc.getMessage("ACTION_BUTTON_STYLE"),
|
|
onclick: function() {
|
|
this.onStyleShow();
|
|
this.sidebarActionsMenu.close();
|
|
}.bind(this),
|
|
className: this.access < ACCESS_V ? "landing-ui-disabled" : ""
|
|
});
|
|
}
|
|
}.bind(this))(),
|
|
(function() {
|
|
if (
|
|
isPlainObject(this.manifest.style)
|
|
&& this.isAllowedByTariff()
|
|
&& !this.isMainpage()
|
|
)
|
|
{
|
|
return new BX.Main.MenuItem({
|
|
id: "designblock",
|
|
text: BX.Landing.Loc.getMessage("LANDING_BLOCKS_ACTIONS_DESIGN_BLOCK"),
|
|
className: !this.isDesignBlockAllowed() ? "landing-ui-disabled" : "",
|
|
onclick: function() {
|
|
this.onDesignerBlockClick();
|
|
this.sidebarActionsMenu.close();
|
|
}.bind(this)
|
|
});
|
|
}
|
|
}.bind(this))(),
|
|
(function() {
|
|
if (this.isAllowedByTariff())
|
|
{
|
|
return new BX.Main.MenuItem({
|
|
delimiter: true,
|
|
});
|
|
}
|
|
}.bind(this))(),
|
|
(function() {
|
|
var allPlacements = BX.Landing.Main.getInstance().options.placements.blocks;
|
|
|
|
if (isPlainObject(allPlacements) && (this.manifest.code in allPlacements || allPlacements["*"]))
|
|
{
|
|
var placementsList = [];
|
|
|
|
if (this.manifest.code in allPlacements)
|
|
{
|
|
Object.keys(allPlacements[this.manifest.code]).forEach(function(key) {
|
|
placementsList.push(allPlacements[this.manifest.code][key]);
|
|
}, this);
|
|
}
|
|
|
|
if (allPlacements["*"])
|
|
{
|
|
Object.keys(allPlacements["*"]).forEach(function(key) {
|
|
placementsList.push(allPlacements["*"][key]);
|
|
}, this);
|
|
}
|
|
|
|
if (placementsList.length)
|
|
{
|
|
if (typeof BX.Landing.PageObject.getRootWindow().BX.rest !== "undefined" &&
|
|
typeof BX.Landing.PageObject.getRootWindow().BX.rest.AppLayout !== "undefined")
|
|
{
|
|
var codes = ["*", this.manifest.code];
|
|
for (var i = 0, c = codes.length; i < c; i++)
|
|
{
|
|
var MessageInterface = BX.Landing.PageObject.getRootWindow().BX.rest.AppLayout.initializePlacement(
|
|
"LANDING_BLOCK_" + codes[i]
|
|
);
|
|
if (MessageInterface)
|
|
{
|
|
MessageInterface.prototype.refreshBlock = function(params, cb) {
|
|
var block = BX.Landing.PageObject.getBlocks().get(params.id);
|
|
|
|
if (block)
|
|
{
|
|
block
|
|
.reload()
|
|
.then(cb);
|
|
}
|
|
};
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return new BX.Main.MenuItem({
|
|
id: "actions",
|
|
text: BX.Landing.Loc.getMessage("ACTION_BUTTON_CONTENT_MORE"),
|
|
items: placementsList.map(function(placement) {
|
|
return new BX.Main.MenuItem({
|
|
id: "placement_" + placement.id + "_" + random(),
|
|
text: encodeDataValue(placement.title),
|
|
onclick: this.onPlacementClick.bind(this, placement)
|
|
})
|
|
}, this),
|
|
className: this.access < ACCESS_V ? "landing-ui-disabled" : ""
|
|
});
|
|
}
|
|
}
|
|
}.bind(this))(),
|
|
|
|
new BX.Main.MenuItem({
|
|
id: "up",
|
|
text: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_BLOCK_ACTION_SORT_UP"),
|
|
onclick: function() {
|
|
this.moveUp();
|
|
this.sidebarActionsMenu.close();
|
|
}.bind(this)
|
|
}),
|
|
new BX.Main.MenuItem({
|
|
id: "down",
|
|
text: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_BLOCK_ACTION_SORT_DOWN"),
|
|
onclick: function() {
|
|
this.moveDown();
|
|
this.sidebarActionsMenu.close();
|
|
}.bind(this)
|
|
}),
|
|
new BX.Main.MenuItem({
|
|
delimiter: true,
|
|
}),
|
|
new BX.Main.MenuItem({
|
|
id: "show_hide",
|
|
text: BX.Landing.Loc.getMessage(this.isEnabled() ? "ACTION_BUTTON_HIDE" : "ACTION_BUTTON_SHOW"),
|
|
className: !this.isChangeStateBlockAllowed() ? "landing-ui-disabled" : "",
|
|
onclick: function() {
|
|
this.onStateChange();
|
|
this.sidebarActionsMenu.close();
|
|
}.bind(this)
|
|
}),
|
|
new BX.Main.MenuItem({
|
|
delimiter: true,
|
|
}),
|
|
new BX.Main.MenuItem({
|
|
text: BX.Landing.Loc.getMessage("ACTION_BUTTON_ACTIONS_CUT"),
|
|
className: !this.isRemoveBlockAllowed() ? "landing-ui-disabled" : "",
|
|
onclick: function() {
|
|
BX.Landing.Main.getInstance().onCutBlock.bind(BX.Landing.Main.getInstance(), this)();
|
|
this.sidebarActionsMenu.close();
|
|
}.bind(this)
|
|
}),
|
|
new BX.Main.MenuItem({
|
|
text: BX.Landing.Loc.getMessage("ACTION_BUTTON_ACTIONS_COPY"),
|
|
onclick: function() {
|
|
BX.Landing.Main.getInstance().onCopyBlock.bind(BX.Landing.Main.getInstance(), this)();
|
|
this.sidebarActionsMenu.close();
|
|
}.bind(this)
|
|
}),
|
|
new BX.Main.MenuItem({
|
|
id: "block_paste",
|
|
text: BX.Landing.Loc.getMessage("ACTION_BUTTON_ACTIONS_PASTE"),
|
|
title: window.localStorage.landingBlockName,
|
|
className: this.isPasteBlockAllowed() ? "": "landing-ui-disabled",
|
|
onclick: function() {
|
|
BX.Landing.Main.getInstance().onPasteBlock.bind(BX.Landing.Main.getInstance(), this)();
|
|
this.sidebarActionsMenu.close();
|
|
}.bind(this)
|
|
}),
|
|
new BX.Main.MenuItem({
|
|
delimiter: true,
|
|
}),
|
|
(() => {
|
|
if (this.isShowFeedbackButton() === true)
|
|
{
|
|
return new BX.Main.MenuItem({
|
|
text: BX.Landing.Loc.getMessage('LANDING_BLOCKS_ACTIONS_FEEDBACK_BUTTON'),
|
|
onclick: this.showFeedbackForm.bind(this),
|
|
});
|
|
}
|
|
})(),
|
|
(() => {
|
|
if (!this.isMainpage())
|
|
{
|
|
return new BX.Main.MenuItem({
|
|
text: BX.Landing.Loc.getMessage("LANDING_BLOCKS_ACTIONS_SAVE_BLOCK_BUTTON_MSGVER_1"),
|
|
className: !this.isSaveBlockInLibraryAllowed() ? "landing-ui-disabled" : "",
|
|
onclick: function() {
|
|
this.saveBlock();
|
|
this.sidebarActionsMenu.close();
|
|
}.bind(this)
|
|
})
|
|
}
|
|
})(),
|
|
new BX.Main.MenuItem({
|
|
delimiter: true,
|
|
}),
|
|
new BX.Main.MenuItem({
|
|
id: "remove",
|
|
text: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_BLOCK_ACTION_REMOVE"),
|
|
onclick: function() {
|
|
this.deleteBlock();
|
|
this.sidebarActionsMenu.close();
|
|
}.bind(this),
|
|
className: !this.isRemoveBlockAllowed() ? "landing-ui-disabled" : ""
|
|
})
|
|
]
|
|
});
|
|
}
|
|
|
|
this.sidebarActionsMenu.show();
|
|
addClass(this.node, "landing-ui-hover");
|
|
},
|
|
|
|
|
|
/**
|
|
* Initializes action panels of block
|
|
* @private
|
|
*/
|
|
lazyInitPanels: function()
|
|
{
|
|
if (this.isInSidebar())
|
|
{
|
|
this.initSidebarActionPanel();
|
|
}
|
|
|
|
var allPlacements = BX.Landing.Main.getInstance().options.placements.blocks;
|
|
|
|
// Make content actions panel
|
|
if (
|
|
!this.panels.contains("content_actions")
|
|
&& (
|
|
(isPlainObject(this.manifest.nodes) && !isEmpty(this.manifest.nodes))
|
|
|| (isPlainObject(this.manifest.style) && !isEmpty(this.manifest.style))
|
|
|| (isPlainObject(allPlacements) && !isEmpty(allPlacements))
|
|
)
|
|
)
|
|
{
|
|
var contentPanel = new BaseButtonPanel(
|
|
"content_actions",
|
|
"landing-ui-panel-content-action"
|
|
);
|
|
|
|
contentPanel.addButton(
|
|
new ActionButton("collapse", {
|
|
html: "<span class='fas fa-caret-right'></span>",
|
|
onClick: this.onCollapseActionPanel.bind(this),
|
|
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_BLOCK_ACTION_COLLAPSE")},
|
|
separate: true,
|
|
})
|
|
);
|
|
|
|
if (this.isAllowedByTariff())
|
|
{
|
|
if (isPlainObject(this.manifest.style))
|
|
{
|
|
if (!this.isMainpage())
|
|
{
|
|
contentPanel.addButton(
|
|
new ActionButton("designblock", {
|
|
text: BX.Landing.Loc.getMessage("LANDING_BLOCKS_ACTIONS_DESIGN_BLOCK"),
|
|
onClick: this.onDesignerBlockClick.bind(this),
|
|
disabled: !this.isDesignBlockAllowed(),
|
|
attrs: {title: BX.Landing.Loc.getMessage("LANDING_BLOCKS_ACTIONS_DESIGN_BLOCK")},
|
|
separate: true,
|
|
}),
|
|
);
|
|
}
|
|
contentPanel.addButton(
|
|
new ActionButton("style", {
|
|
text: BX.Landing.Loc.getMessage("ACTION_BUTTON_STYLE"),
|
|
onClick: this.onStyleShow.bind(this),
|
|
disabled: !this.isStyleModifyAllowed(),
|
|
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_BLOCK_DESIGN")},
|
|
separate: true,
|
|
})
|
|
);
|
|
}
|
|
|
|
if (isPlainObject(this.manifest.nodes) || isPlainObject(this.manifest.attrs) )
|
|
{
|
|
contentPanel.addButton(
|
|
new ActionButton("content", {
|
|
text: BX.Landing.Loc.getMessage("ACTION_BUTTON_CONTENT"),
|
|
onClick: this.onShowContentPanel.bind(this),
|
|
disabled: !this.isEditBlockAllowed(),
|
|
disabledHint: this.getDisableEditBlockHint(),
|
|
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_BLOCK_EDIT")},
|
|
separate: true,
|
|
})
|
|
);
|
|
}
|
|
}
|
|
else {
|
|
contentPanel.addButton(
|
|
new ActionButton("expired", {
|
|
text: BX.Landing.Loc.getMessage("ACTION_BUTTON_EXPIRED"),
|
|
separate: true,
|
|
})
|
|
);
|
|
}
|
|
|
|
if (isPlainObject(allPlacements) && (this.manifest.code in allPlacements || allPlacements["*"]))
|
|
{
|
|
var placementsList = [];
|
|
|
|
if (this.manifest.code in allPlacements)
|
|
{
|
|
Object.keys(allPlacements[this.manifest.code]).forEach(function(key) {
|
|
placementsList.push(allPlacements[this.manifest.code][key]);
|
|
}, this);
|
|
}
|
|
|
|
if (allPlacements["*"])
|
|
{
|
|
Object.keys(allPlacements["*"]).forEach(function(key) {
|
|
placementsList.push(allPlacements["*"][key]);
|
|
}, this);
|
|
}
|
|
|
|
if (placementsList.length)
|
|
{
|
|
contentPanel.addButton(
|
|
new ActionButton("actions", {
|
|
html: BX.Landing.Loc.getMessage("ACTION_BUTTON_CONTENT_MORE"),
|
|
onClick: this.onPlacementButtonClick.bind(this, placementsList),
|
|
separate: true,
|
|
})
|
|
);
|
|
|
|
if (typeof BX.Landing.PageObject.getRootWindow().BX.rest !== "undefined" &&
|
|
typeof BX.Landing.PageObject.getRootWindow().BX.rest.AppLayout !== "undefined")
|
|
{
|
|
var codes = ["*", this.manifest.code];
|
|
for (var i = 0, c = codes.length; i < c; i++)
|
|
{
|
|
var MessageInterface = BX.Landing.PageObject.getRootWindow().BX.rest.AppLayout.initializePlacement(
|
|
"LANDING_BLOCK_" + codes[i]
|
|
);
|
|
if (MessageInterface)
|
|
{
|
|
MessageInterface.prototype.refreshBlock = function(params, cb) {
|
|
var block = BX.Landing.PageObject.getBlocks().get(params.id);
|
|
|
|
if (block)
|
|
{
|
|
block
|
|
.reload()
|
|
.then(cb);
|
|
}
|
|
};
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isPlainObject(this.manifest.style))
|
|
{
|
|
var blockDisplay = new ActionButton("block_display_info", {
|
|
html: " ",
|
|
separate: true,
|
|
onClick: this.onStyleShow.bind(this),
|
|
});
|
|
|
|
bind(blockDisplay.layout, "mouseenter", this.onBlockDisplayMouseenter.bind(this));
|
|
bind(blockDisplay.layout, "mouseleave", this.onBlockDisplayMouseleave.bind(this));
|
|
|
|
contentPanel.addButton(
|
|
blockDisplay
|
|
);
|
|
}
|
|
|
|
contentPanel.show();
|
|
this.addPanel(contentPanel);
|
|
}
|
|
|
|
|
|
// Make block actions panel
|
|
if (!this.panels.get("block_action"))
|
|
{
|
|
var blockPanel = new BaseButtonPanel(
|
|
"block_action",
|
|
"landing-ui-panel-block-action"
|
|
);
|
|
|
|
var block = this.getBlockFromRepository(this.manifest.code);
|
|
|
|
if (block && block.restricted)
|
|
{
|
|
var restrictedButton = new ActionButton("restricted", {
|
|
html: "!",
|
|
className: "landing-ui-block-restricted-button",
|
|
onClick: this.onRestrictedButtonClick.bind(this),
|
|
separate: true
|
|
});
|
|
|
|
bind(restrictedButton.layout, "mouseenter", this.onRestrictedButtonMouseenter.bind(this));
|
|
bind(restrictedButton.layout, "mouseleave", this.onRestrictedButtonMouseleave.bind(this));
|
|
blockPanel.addButton(restrictedButton);
|
|
}
|
|
|
|
|
|
blockPanel.addButton(
|
|
new ActionButton("down", {
|
|
html: BX.Landing.Loc.getMessage("ACTION_BUTTON_DOWN"),
|
|
onClick: this.moveDown.bind(this),
|
|
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_BLOCK_ACTION_SORT_DOWN")}
|
|
})
|
|
);
|
|
|
|
blockPanel.addButton(
|
|
new ActionButton("up", {
|
|
html: BX.Landing.Loc.getMessage("ACTION_BUTTON_UP"),
|
|
onClick: this.moveUp.bind(this),
|
|
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_BLOCK_ACTION_SORT_UP")}
|
|
})
|
|
);
|
|
|
|
blockPanel.addButton(
|
|
new ActionButton("actions", {
|
|
html: BX.Landing.Loc.getMessage("ACTION_BUTTON_ACTIONS"),
|
|
onClick: this.showBlockActionsMenu.bind(this),
|
|
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_BLOCK_ACTION_ADDITIONAL_ACTIONS")}
|
|
})
|
|
);
|
|
|
|
blockPanel.addButton(
|
|
new ActionButton("remove", {
|
|
html: BX.Landing.Loc.getMessage("ACTION_BUTTON_REMOVE"),
|
|
disabled: !this.isRemoveBlockAllowed(),
|
|
onClick: this.deleteBlock.bind(this),
|
|
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_BLOCK_ACTION_REMOVE")}
|
|
})
|
|
);
|
|
|
|
blockPanel.addButton(
|
|
new ActionButton("collapse", {
|
|
html: "<span class='fas fa-caret-right'></span>",
|
|
onClick: this.onCollapseActionPanel.bind(this),
|
|
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_BLOCK_ACTION_COLLAPSE")},
|
|
separate: true
|
|
})
|
|
);
|
|
|
|
blockPanel.show();
|
|
this.addPanel(blockPanel);
|
|
}
|
|
|
|
this.adjustPanelsPosition();
|
|
this.adjustSortButtonsState();
|
|
},
|
|
|
|
onCollapseActionPanel: function()
|
|
{
|
|
toggleClass(this.parent, "landing-ui-collapse");
|
|
},
|
|
|
|
getBlockFromRepository: function(code)
|
|
{
|
|
var blocks = BX.Landing.Main.getInstance().options.blocks;
|
|
var categories = Object.keys(blocks);
|
|
var category = categories.find(function(categoryId) {
|
|
return code in blocks[categoryId].items;
|
|
});
|
|
|
|
if (category)
|
|
{
|
|
return blocks[category].items[code];
|
|
}
|
|
},
|
|
|
|
|
|
onRestrictedButtonClick: function(event)
|
|
{
|
|
event.preventDefault();
|
|
},
|
|
|
|
onPlacementClick: function(placement)
|
|
{
|
|
BX.rest.AppLayout.openApplication(
|
|
placement.app_id,
|
|
{
|
|
ID: this.id,
|
|
CODE: this.manifest.code,
|
|
LID: BX.Landing.Main.getInstance().id
|
|
},
|
|
{
|
|
PLACEMENT: 'LANDING_BLOCK_' + placement.placement,
|
|
PLACEMENT_ID: placement.id
|
|
}
|
|
);
|
|
|
|
if (this.blockPlacementsActionsMenu)
|
|
{
|
|
this.blockPlacementsActionsMenu.close();
|
|
}
|
|
},
|
|
|
|
|
|
onPlacementButtonClick: function(placements)
|
|
{
|
|
this.panels.get("content_actions").buttons.get("actions").activate();
|
|
|
|
if (!this.blockPlacementsActionsMenu)
|
|
{
|
|
var blockActionButton = this.panels.get("content_actions").buttons.get("actions");
|
|
var blockActionMenuId = join("block_", this.id, "content_placement_actions_", random());
|
|
|
|
var menuItems = placements.map(function(placement) {
|
|
return new BX.Main.MenuItem({
|
|
id: "placement_" + (placement.id || random()) + "_" + random(),
|
|
text: encodeDataValue(placement.title),
|
|
disabled: placement.disabled === true,
|
|
onclick: (typeof placement.onClick === 'function')
|
|
? placement.onClick
|
|
: this.onPlacementClick.bind(this, placement)
|
|
})
|
|
}, this);
|
|
|
|
this.blockPlacementsActionsMenu = new BX.PopupMenuWindow({
|
|
id: blockActionMenuId,
|
|
bindElement: blockActionButton.layout,
|
|
items: menuItems,
|
|
angle: {position: "top", offset: 80},
|
|
offsetTop: -6,
|
|
events: {
|
|
onPopupClose: function() {
|
|
this.panels.get("content_actions").buttons.get("actions").deactivate();
|
|
removeClass(this.node, "landing-ui-hover");
|
|
}.bind(this)
|
|
}
|
|
});
|
|
}
|
|
|
|
addClass(this.node, "landing-ui-hover");
|
|
this.blockPlacementsActionsMenu.show();
|
|
},
|
|
|
|
onDesignerBlockClick: function()
|
|
{
|
|
BX.UI.Analytics.sendData({
|
|
tool: 'landing',
|
|
category: 'superblock',
|
|
event: 'open',
|
|
type: BX.Landing.Main.getAnalyticsCategoryByType(),
|
|
});
|
|
// get actual block content before designer edit
|
|
var oldContent = null;
|
|
BX.Landing.Backend.getInstance()
|
|
.action("Block::getContent", {
|
|
block: this.id,
|
|
lid: this.lid,
|
|
siteId: this.siteId,
|
|
editMode: 1
|
|
})
|
|
.then(function(response) {
|
|
oldContent = response.content;
|
|
});
|
|
|
|
// open slider with designer
|
|
var envOptions = BX.Landing.Env.getInstance().getOptions();
|
|
var sliderUrl = envOptions.params.sef_url["design_block"]
|
|
.replace("__block_id__", this.id)
|
|
.replace("__site_show__", this.siteId)
|
|
.replace("__landing_edit__", this.lid)
|
|
+ "&code=" + this.manifest.code
|
|
+ "&designed=" + (this.designed ? "Y" : "N")
|
|
+ "&deviceCode=" + BX.Landing.Main.getInstance().getDeviceCode();
|
|
BX.SidePanel.Instance.open(
|
|
sliderUrl,
|
|
{
|
|
cacheable: false,
|
|
allowChangeHistory: false,
|
|
requestMethod: "post",
|
|
customLeftBoundary: 40,
|
|
events: {
|
|
onClose: function(event)
|
|
{
|
|
// get actual block content after designer edit
|
|
BX.Landing.Backend.getInstance()
|
|
.action("Block::getContent", {
|
|
block: this.id,
|
|
lid: this.lid,
|
|
siteId: this.siteId,
|
|
editMode: 1
|
|
})
|
|
.then(function(response) {
|
|
var newContent = response.content;
|
|
if (oldContent !== newContent)
|
|
{
|
|
BX.UI.Analytics.sendData({
|
|
tool: 'landing',
|
|
category: 'superblock',
|
|
event: 'save',
|
|
type: BX.Landing.Main.getAnalyticsCategoryByType(),
|
|
});
|
|
|
|
BX.Landing.History.getInstance().push();
|
|
this.reload().then(function()
|
|
{
|
|
fireCustomEvent("BX.Landing.Block:onDesignerBlockSave", [this.id]);
|
|
}.bind(this));
|
|
}
|
|
else
|
|
{
|
|
BX.UI.Analytics.sendData({
|
|
tool: 'landing',
|
|
category: 'superblock',
|
|
event: 'close',
|
|
type: BX.Landing.Main.getAnalyticsCategoryByType(),
|
|
});
|
|
}
|
|
}.bind(this));
|
|
}.bind(this)
|
|
}
|
|
}
|
|
);
|
|
|
|
if (this.blockPlacementsActionsMenu)
|
|
{
|
|
this.blockPlacementsActionsMenu.close();
|
|
}
|
|
},
|
|
|
|
isDesignBlockAllowed: function()
|
|
{
|
|
return !(this.access < ACCESS_W || this.php || (this.isCrmFormPage() && this.isCrmFormBlock()));
|
|
},
|
|
|
|
isStyleModifyAllowed:function()
|
|
{
|
|
return !(this.access < ACCESS_V || isEmpty(this.manifest.style));
|
|
},
|
|
|
|
isEditBlockAllowed: function()
|
|
{
|
|
let allowedButton = this.access >= ACCESS_W;
|
|
this.disableEditBlockHintType = '';
|
|
|
|
const landing = BX.Landing.Main.getInstance();
|
|
const type = landing.options.params.type;
|
|
if (
|
|
type === 'MAINPAGE'
|
|
&& Object.keys(this.manifest.nodes).length === 0
|
|
&& Object.keys(this.manifest.attrs).length === 0
|
|
)
|
|
{
|
|
this.disableEditBlockHintType = 'empty';
|
|
|
|
return false;
|
|
}
|
|
|
|
if (this.manifest.block.disableEditButton === true)
|
|
{
|
|
this.disableEditBlockHintType = 'demo_data_option';
|
|
|
|
return false;
|
|
}
|
|
|
|
return allowedButton;
|
|
},
|
|
|
|
getDisableEditBlockHint: function()
|
|
{
|
|
let hint = null;
|
|
let type = 'BLOCK';
|
|
if (this.isMainpage())
|
|
{
|
|
type = 'WIDGET';
|
|
}
|
|
|
|
if (this.disableEditBlockHintType === 'empty')
|
|
{
|
|
const emptyPhraseCode = 'LANDING_TITLE_' + type + '_EDIT_BUTTON_DISABLE_HINT_EMPTY';
|
|
hint = BX.Landing.Loc.getMessage(emptyPhraseCode);
|
|
}
|
|
if (this.disableEditBlockHintType === 'demo_data_option')
|
|
{
|
|
const demoDataOptionPhraseCode = 'LANDING_TITLE_' + type + '_EDIT_BUTTON_DISABLE_HINT_DEMO_DATA';
|
|
hint = BX.Landing.Loc.getMessage(demoDataOptionPhraseCode);
|
|
}
|
|
|
|
return hint;
|
|
},
|
|
|
|
isRemoveBlockAllowed: function()
|
|
{
|
|
return !(this.access < ACCESS_X || (this.isCrmFormBlock() && this.isDefaultCrmFormBlock()));
|
|
},
|
|
|
|
isPasteBlockAllowed: function()
|
|
{
|
|
return window.localStorage.landingBlockId && !this.isDefaultCrmFormBlock();
|
|
},
|
|
|
|
isSaveBlockInLibraryAllowed: function()
|
|
{
|
|
return !this.isDefaultCrmFormBlock();
|
|
},
|
|
|
|
isChangeStateBlockAllowed: function()
|
|
{
|
|
return !((this.access < ACCESS_W) || this.isDefaultCrmFormBlock());
|
|
},
|
|
|
|
saveBlock: function()
|
|
{
|
|
BX.Landing.Main.getInstance().showSaveBlock(this);
|
|
},
|
|
|
|
onRestrictedButtonMouseenter: function(event)
|
|
{
|
|
clearTimeout(this.displayBlockTimer);
|
|
this.displayBlockTimer = setTimeout(function (target)
|
|
{
|
|
BX.Landing.UI.Tool.Suggest.getInstance().show(
|
|
target,
|
|
{
|
|
description: this.getRestrictedMessageText(),
|
|
}
|
|
);
|
|
}.bind(this), 200, event.currentTarget);
|
|
},
|
|
|
|
onRestrictedButtonMouseleave: function()
|
|
{
|
|
clearTimeout(this.displayBlockTimer);
|
|
BX.Landing.UI.Tool.Suggest.getInstance().hide();
|
|
},
|
|
|
|
onBlockDisplayMouseenter: function(event)
|
|
{
|
|
clearTimeout(this.displayBlockTimer);
|
|
this.displayBlockTimer = setTimeout(function(target) {
|
|
BX.Landing.UI.Tool.Suggest.getInstance().show(
|
|
target,
|
|
{
|
|
name: create("div", {
|
|
props: {className: "landing-ui-block-display-message-header"},
|
|
html: BX.Landing.Loc.getMessage("LANDING_BLOCK_DISABLED_ON_DESKTOP_NAME_2")
|
|
}).outerHTML,
|
|
description: this.getBlockDisplayItems()
|
|
}
|
|
);
|
|
}.bind(this), 300, event.currentTarget);
|
|
},
|
|
|
|
onBlockDisplayMouseleave: function()
|
|
{
|
|
clearTimeout(this.displayBlockTimer);
|
|
BX.Landing.UI.Tool.Suggest.getInstance().hide();
|
|
},
|
|
|
|
getBlockDisplayItems: function()
|
|
{
|
|
function createItem(mod)
|
|
{
|
|
return create("div", {
|
|
props: {className: "landing-ui-block-display-message"},
|
|
attrs: {"data-mod": mod},
|
|
children: [
|
|
create("div", {
|
|
props: {className: "landing-ui-block-display-message-left"},
|
|
html: " "
|
|
}),
|
|
create("div", {
|
|
props: {className: "landing-ui-block-display-message-right"},
|
|
children: [
|
|
create("p", {html: BX.Landing.Loc.getMessage("LANDING_BLOCK_HIDDEN_ON_"+(mod ? mod.toUpperCase() : ""))})
|
|
]
|
|
})
|
|
]
|
|
});
|
|
}
|
|
|
|
var result = create("div");
|
|
|
|
if (hasClass(this.content, "l-d-lg-none"))
|
|
{
|
|
result.appendChild(createItem("desktop"));
|
|
}
|
|
|
|
if (hasClass(this.content, "l-d-md-none"))
|
|
{
|
|
result.appendChild(createItem("tablet"));
|
|
}
|
|
|
|
if (hasClass(this.content, "l-d-xs-none"))
|
|
{
|
|
result.appendChild(createItem("mobile"));
|
|
}
|
|
|
|
return result.outerHTML;
|
|
},
|
|
|
|
|
|
/**
|
|
* Adjusts block panels position
|
|
*/
|
|
adjustPanelsPosition: function()
|
|
{
|
|
var blockRect = rect(this.node);
|
|
var contentActionsPanel = this.panels.get("content_actions");
|
|
var blockActionsPanel = this.panels.get("block_action");
|
|
var action = blockRect.height < 80 ? addClass : removeClass;
|
|
|
|
if (contentActionsPanel)
|
|
{
|
|
action(contentActionsPanel.layout, "landing-ui-panel-actions-compact");
|
|
}
|
|
|
|
if (blockActionsPanel)
|
|
{
|
|
action(blockActionsPanel.layout, "landing-ui-panel-actions-compact");
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Handles editor enable event
|
|
* Event fires when the editor was show
|
|
* @param {HTMLElement} element
|
|
*/
|
|
onEditorEnabled: function(element)
|
|
{
|
|
if (this.node.contains(element))
|
|
{
|
|
addClass(this.node, "landing-ui-hover");
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Handles editor disable event
|
|
* Event fires when the editor was hidden
|
|
*/
|
|
onEditorDisabled: function()
|
|
{
|
|
removeClass(this.node, "landing-ui-hover");
|
|
},
|
|
|
|
|
|
onStorage: function()
|
|
{
|
|
var menu = (this.blockActionsMenu || this.sidebarActionsMenu);
|
|
if (menu)
|
|
{
|
|
var item = menu.getMenuItem("block_paste");
|
|
|
|
if (item)
|
|
{
|
|
if (window.localStorage.landingBlockId)
|
|
{
|
|
item.layout.item.setAttribute("title", window.localStorage.landingBlockName);
|
|
removeClass(item.layout.item, "landing-ui-disabled");
|
|
addClass(item.layout.item, "menu-popup-no-icon");
|
|
}
|
|
else
|
|
{
|
|
item.layout.item.setAttribute("title", "");
|
|
addClass(item.layout.item, "landing-ui-disabled");
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Shows block popup menu with additional action menu
|
|
*/
|
|
showBlockActionsMenu: function()
|
|
{
|
|
this.panels.get("block_action").buttons.get("actions").activate();
|
|
|
|
if (!this.blockActionsMenu)
|
|
{
|
|
var useSmallOffset = hasClass(this.node.parentElement, "landing-sidebar");
|
|
var blockActionButton = this.panels.get("block_action").buttons.get("actions");
|
|
var blockActionMenuId = join("block_", this.id, "_actions_", random());
|
|
var landing = BX.Landing.Main.getInstance();
|
|
|
|
this.blockActionsMenu = new BX.PopupMenuWindow({
|
|
id: blockActionMenuId,
|
|
bindElement: blockActionButton.layout,
|
|
className: "landing-ui-block-actions-popup",
|
|
angle: {position: "top", offset: useSmallOffset ? 70 : 146},
|
|
offsetTop: -6,
|
|
offsetLeft: -26,
|
|
events: {
|
|
onPopupClose: function() {
|
|
this.panels.get("block_action").buttons.get("actions").deactivate();
|
|
removeClass(this.node, "landing-ui-hover");
|
|
}.bind(this),
|
|
onPopupShow: function() {
|
|
BX.Event.EventEmitter.emit('BX.Landing.PopupMenuWindow:onShow');
|
|
}.bind(this)
|
|
},
|
|
items: [
|
|
new BX.Main.MenuItem({
|
|
id: "show_hide",
|
|
text: BX.Landing.Loc.getMessage(this.isEnabled() ? "ACTION_BUTTON_HIDE" : "ACTION_BUTTON_SHOW"),
|
|
className: !this.isChangeStateBlockAllowed() ? "landing-ui-disabled" : "",
|
|
onclick: function() {
|
|
this.onStateChange();
|
|
this.blockActionsMenu.close();
|
|
}.bind(this)
|
|
}),
|
|
new BX.Main.MenuItem({
|
|
text: BX.Landing.Loc.getMessage("ACTION_BUTTON_ACTIONS_CUT"),
|
|
className: !this.isRemoveBlockAllowed() ? "landing-ui-disabled" : "",
|
|
onclick: function() {
|
|
landing.onCutBlock.bind(landing, this)();
|
|
this.blockActionsMenu.close();
|
|
}.bind(this)
|
|
}),
|
|
new BX.Main.MenuItem({
|
|
text: BX.Landing.Loc.getMessage("ACTION_BUTTON_ACTIONS_COPY"),
|
|
className: this.isDefaultCrmFormBlock() ? "landing-ui-disabled" : "",
|
|
onclick: function() {
|
|
landing.onCopyBlock.bind(landing, this)();
|
|
this.blockActionsMenu.close();
|
|
}.bind(this)
|
|
}),
|
|
new BX.Main.MenuItem({
|
|
id: "block_paste",
|
|
text: BX.Landing.Loc.getMessage("ACTION_BUTTON_ACTIONS_PASTE"),
|
|
title: window.localStorage.landingBlockName,
|
|
className: this.isPasteBlockAllowed() ? "": "landing-ui-disabled",
|
|
onclick: function() {
|
|
landing.onPasteBlock.bind(landing, this)();
|
|
this.blockActionsMenu.close();
|
|
}.bind(this)
|
|
}),
|
|
(() => {
|
|
if (this.isShowFeedbackButton() === true)
|
|
{
|
|
return new BX.Main.MenuItem({
|
|
text: BX.Landing.Loc.getMessage('LANDING_BLOCKS_ACTIONS_FEEDBACK_BUTTON'),
|
|
onclick: this.showFeedbackForm.bind(this),
|
|
});
|
|
}
|
|
})(),
|
|
(() => {
|
|
if (!this.isMainpage())
|
|
{
|
|
return new BX.Main.MenuItem({
|
|
delimiter: true,
|
|
});
|
|
}
|
|
})(),
|
|
(() => {
|
|
if (!this.isMainpage())
|
|
{
|
|
return new BX.Main.MenuItem({
|
|
text: BX.Landing.Loc.getMessage("LANDING_BLOCKS_ACTIONS_SAVE_BLOCK_BUTTON_MSGVER_1"),
|
|
className: !this.isSaveBlockInLibraryAllowed() ? "landing-ui-disabled" : "",
|
|
onclick: function() {
|
|
this.saveBlock();
|
|
this.blockActionsMenu.close();
|
|
}.bind(this)
|
|
});
|
|
}
|
|
})(),
|
|
]
|
|
});
|
|
}
|
|
|
|
addClass(this.node, "landing-ui-hover");
|
|
this.blockActionsMenu.show();
|
|
},
|
|
|
|
|
|
/**
|
|
* Moves the block up one position
|
|
* @param {boolean} [preventHistory = false] - Add this action to history or not. By default - add
|
|
*/
|
|
moveUp: function(preventHistory)
|
|
{
|
|
var prev = prevSibling(this.node, "block-wrapper");
|
|
var current = this.node;
|
|
|
|
if (prev)
|
|
{
|
|
var result = Promise.all([
|
|
translateY(current, -rect(prev).height),
|
|
translateY(prev, rect(current).height)
|
|
]);
|
|
|
|
result.then(function() {
|
|
void style(current, {"transform": null, "transition": null});
|
|
void style(prev, {"transform": null, "transition": null});
|
|
insertBefore(current, prev);
|
|
|
|
if (!preventHistory || typeof preventHistory === "object")
|
|
{
|
|
BX.Landing.Backend.getInstance()
|
|
.action(
|
|
"Landing::upBlock",
|
|
{block: this.id, lid: this.lid, siteId: this.siteId},
|
|
{code: this.manifest.code}
|
|
)
|
|
.then(() => {
|
|
BX.Landing.History.getInstance().push();
|
|
});
|
|
}
|
|
}.bind(this));
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Moves the block down one position
|
|
* @param {boolean} [preventHistory = false] - Add this action to history or not. By default - add
|
|
*/
|
|
moveDown: function(preventHistory)
|
|
{
|
|
var next = nextSibling(this.node, "block-wrapper");
|
|
var current = this.node;
|
|
|
|
if (!!next)
|
|
{
|
|
var result = Promise.all([
|
|
translateY(current, rect(next).height),
|
|
translateY(next, -rect(current).height)
|
|
]);
|
|
|
|
result.then(function() {
|
|
void style(current, {"transform": null, "transition": null});
|
|
void style(next, {"transform": null, "transition": null});
|
|
insertAfter(current, next);
|
|
|
|
if (!preventHistory || typeof preventHistory === "object")
|
|
{
|
|
BX.Landing.Backend.getInstance()
|
|
.action(
|
|
"Landing::downBlock",
|
|
{block: this.id, lid: this.lid, siteId: this.siteId},
|
|
{code: this.manifest.code}
|
|
)
|
|
.then(() => {
|
|
BX.Landing.History.getInstance().push();
|
|
});
|
|
}
|
|
}.bind(this));
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Adds panel into this block
|
|
* @param {BX.Landing.UI.Panel.BasePanel} panel
|
|
* @param {*} [target = this.node]
|
|
*/
|
|
addPanel: function(panel, target)
|
|
{
|
|
if (!this.panels.contains(panel))
|
|
{
|
|
this.panels.add(panel);
|
|
|
|
if (!target)
|
|
{
|
|
if (panel.id === 'content_edit' && window.parent)
|
|
{
|
|
let topWindow = BX.Landing.PageObject.getRootWindow();
|
|
append(panel.layout, topWindow.document.body);
|
|
}
|
|
else
|
|
{
|
|
append(panel.layout, this.node);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
insertBefore(panel.layout, target);
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
*
|
|
* @return {{code: string, id: string, type: string}|null}
|
|
*/
|
|
getBlockFormId: function()
|
|
{
|
|
var formScriptNode = this.node.querySelector('script[data-b24-form]');
|
|
if (BX.Type.isDomNode(formScriptNode))
|
|
{
|
|
var formId = BX.Dom.attr(formScriptNode, 'data-b24-form');
|
|
if (BX.Type.isStringFilled(formId))
|
|
{
|
|
var parsedFormId = formId.split('/');
|
|
if (BX.Type.isArray(parsedFormId) && parsedFormId.length === 3)
|
|
{
|
|
var instanceId = '';
|
|
var formUid = BX.Dom.attr(
|
|
formScriptNode.previousSibling.firstChild,
|
|
'id'
|
|
);
|
|
|
|
if (formUid)
|
|
{
|
|
instanceId = formUid.replace('b24-', '');
|
|
}
|
|
|
|
return {
|
|
id: parsedFormId[1],
|
|
type: parsedFormId[0],
|
|
code: parsedFormId[2],
|
|
instanceId: instanceId
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
formScriptNode = this.node.querySelector('[data-b24form]');
|
|
if (BX.Type.isDomNode(formScriptNode))
|
|
{
|
|
formId = BX.Dom.attr(formScriptNode, 'data-b24form');
|
|
if (BX.Type.isStringFilled(formId))
|
|
{
|
|
parsedFormId = formId.split('|');
|
|
if (BX.Type.isArray(parsedFormId) && parsedFormId.length === 3)
|
|
{
|
|
instanceId = '';
|
|
formUid = BX.Dom.attr(
|
|
formScriptNode.querySelector('.b24-form > div[id]'),
|
|
'id'
|
|
);
|
|
|
|
if (formUid)
|
|
{
|
|
instanceId = formUid.replace('b24-', '');
|
|
}
|
|
|
|
return {
|
|
id: parsedFormId[0],
|
|
type: parsedFormId[2] || 'inline',
|
|
code: parsedFormId[1],
|
|
instanceId: instanceId
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
getCrmFormOptions: function()
|
|
{
|
|
var formNode = this.node.querySelector('[data-b24form-use-style]');
|
|
var useAllowed = BX.Dom.attr(formNode, 'data-b24form-use-style');
|
|
var primaryMatcher = /--primary([\da-fA-F]{2})/;
|
|
|
|
if (BX.Type.isDomNode(formNode) && BX.Text.toBoolean(useAllowed))
|
|
{
|
|
var designOptions = BX.Dom.attr(formNode, 'data-b24form-design');
|
|
if (BX.Type.isPlainObject(designOptions))
|
|
{
|
|
var primaryColor = BX.Dom.style(document.documentElement, '--primary').trim();
|
|
Object.entries(designOptions.color).forEach(function(entry) {
|
|
if (
|
|
entry[1] === '--primary'
|
|
|| entry[1].match(primaryMatcher) !== null
|
|
)
|
|
{
|
|
designOptions.color[entry[0]] = entry[1].replace('--primary', primaryColor);
|
|
}
|
|
});
|
|
|
|
return {
|
|
data: {
|
|
design: designOptions,
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
return {};
|
|
},
|
|
|
|
/**
|
|
* Check is are crm form
|
|
* @return {boolean}
|
|
*/
|
|
isCrmFormPage: function()
|
|
{
|
|
return BX.Landing.Env.getInstance().getSpecialType() === 'crm_forms';
|
|
},
|
|
|
|
/**
|
|
* Check is page are mainpage
|
|
* @return {boolean}
|
|
*/
|
|
isMainpage: function()
|
|
{
|
|
return BX.Landing.Env.getInstance().getType() === 'MAINPAGE';
|
|
},
|
|
|
|
isCrmFormBlock: function()
|
|
{
|
|
return this.isCrmFormPage() && BX.Dom.attr(this.node, 'data-subtype') === 'form';
|
|
},
|
|
|
|
isDefaultCrmFormBlock: function()
|
|
{
|
|
return BX.Dom.hasClass(this.node, 'block-66-90-form-new-default');
|
|
},
|
|
|
|
/**
|
|
* Handles show panel event
|
|
* @private
|
|
*/
|
|
onShowContentPanel: function()
|
|
{
|
|
var formId = this.getBlockFormId();
|
|
var type = BX.Text.capitalize(
|
|
BX.Landing.Env.getInstance().getOptions().params.type
|
|
);
|
|
if (
|
|
BX.Type.isPlainObject(formId)
|
|
&& type !== 'SMN'
|
|
)
|
|
{
|
|
var rootWindow = BX.Landing.PageObject.getRootWindow();
|
|
void (function() {
|
|
if (BX.Landing.UI.Panel.FormSettingsPanel)
|
|
{
|
|
return Promise.resolve([
|
|
rootWindow.BX.Landing.UI.Panel,
|
|
BX.Landing.UI.Panel
|
|
]);
|
|
}
|
|
|
|
return Promise
|
|
.all([
|
|
rootWindow.BX.Runtime
|
|
.loadExtension('landing.ui.panel.formsettingspanel'),
|
|
BX.Runtime
|
|
.loadExtension('landing.ui.panel.formsettingspanel')
|
|
]);
|
|
})()
|
|
.then(function(result) {
|
|
var FormSettingsPanel = result[1].FormSettingsPanel;
|
|
if (FormSettingsPanel)
|
|
{
|
|
return FormSettingsPanel
|
|
.getInstance()
|
|
.show({
|
|
formId: formId.id,
|
|
instanceId: formId.instanceId,
|
|
formOptions: this.getCrmFormOptions(),
|
|
block: this,
|
|
});
|
|
}
|
|
}.bind(this));
|
|
}
|
|
else
|
|
{
|
|
this.showContentPanel();
|
|
}
|
|
|
|
BX.Landing.UI.Panel.EditorPanel.getInstance().hide();
|
|
},
|
|
|
|
|
|
/**
|
|
* Handles state change event
|
|
* @private
|
|
*/
|
|
onStateChange: function()
|
|
{
|
|
if (this.isEnabled())
|
|
{
|
|
this.disable();
|
|
}
|
|
else
|
|
{
|
|
this.enable();
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Checks that block is enabled
|
|
* @return {boolean}
|
|
*/
|
|
isEnabled: function()
|
|
{
|
|
return this.active;
|
|
},
|
|
|
|
|
|
/**
|
|
* Enables block
|
|
*/
|
|
enable: function()
|
|
{
|
|
this.active = true;
|
|
removeClass(this.node, "landing-block-disabled");
|
|
|
|
let menu = (this.blockActionsMenu || this.sidebarActionsMenu);
|
|
if (menu)
|
|
{
|
|
setTextContent(menu.getMenuItem("show_hide").getLayout().text, BX.Landing.Loc.getMessage("ACTION_BUTTON_HIDE"));
|
|
}
|
|
|
|
fireCustomEvent("BX.Landing.Block:changeState", [this.id, true]);
|
|
|
|
BX.Landing.Backend.getInstance().action(
|
|
"Landing::showBlock",
|
|
{block: this.id, lid: this.lid, siteId: this.siteId},
|
|
{code: this.manifest.code}
|
|
);
|
|
},
|
|
|
|
|
|
/**
|
|
* Disables block
|
|
*/
|
|
disable: function()
|
|
{
|
|
this.active = false;
|
|
addClass(this.node, "landing-block-disabled");
|
|
|
|
let menu = (this.blockActionsMenu || this.sidebarActionsMenu);
|
|
if (menu)
|
|
{
|
|
setTextContent(menu.getMenuItem("show_hide").getLayout().text, BX.Landing.Loc.getMessage("ACTION_BUTTON_SHOW"));
|
|
}
|
|
|
|
fireCustomEvent("BX.Landing.Block:changeState", [this.id, false]);
|
|
|
|
BX.Landing.Backend.getInstance().action(
|
|
"Landing::hideBlock",
|
|
{block: this.id, lid: this.lid, siteId: this.siteId},
|
|
{code: this.manifest.code}
|
|
);
|
|
},
|
|
|
|
|
|
/**
|
|
* Creates card label
|
|
* @param {HTMLElement} node
|
|
* @param {cardManifest} manifest
|
|
* @return {div}
|
|
*/
|
|
createCardLabel: function(node, manifest)
|
|
{
|
|
var labelSelectors = [];
|
|
|
|
if (isString(manifest.label))
|
|
{
|
|
labelSelectors.push(manifest.label);
|
|
}
|
|
else if (isArray(manifest.label))
|
|
{
|
|
labelSelectors = labelSelectors.concat(manifest.label);
|
|
}
|
|
|
|
var cardNodes = this.nodes.filter(function(currentNode) {
|
|
return node.contains(currentNode.node);
|
|
});
|
|
|
|
var children = [];
|
|
|
|
labelSelectors.forEach(function(selector) {
|
|
var labelNode = cardNodes.find(function(currentNode) {
|
|
return currentNode.manifest.code === selector;
|
|
});
|
|
|
|
if (labelNode)
|
|
{
|
|
var currentLabel;
|
|
|
|
if (labelNode instanceof BX.Landing.Node.Text)
|
|
{
|
|
currentLabel = create("span", {
|
|
props: {className: "landing-card-title-text"},
|
|
html: escapeText(create("div", {html: labelNode.getValue()}).innerText)
|
|
});
|
|
children.push(currentLabel);
|
|
|
|
onCustomEvent(labelNode.getField(), "change", function(value) {
|
|
currentLabel.innerHTML = escapeText(create("div", {html: value}).innerText);
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
if (labelNode instanceof BX.Landing.Node.Link)
|
|
{
|
|
currentLabel = create("span", {
|
|
props: {className: "landing-card-title-link"},
|
|
html: escapeText(labelNode.getValue().text)
|
|
});
|
|
children.push(currentLabel);
|
|
|
|
onCustomEvent(labelNode.getField(), "change", function(value) {
|
|
currentLabel.innerHTML = escapeText(value.text);
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
if (labelNode instanceof BX.Landing.Node.Icon)
|
|
{
|
|
currentLabel = create("span", {
|
|
props: {className: "landing-card-title-icon"},
|
|
children: [create("span", {props: {className: labelNode.getValue().classList.join(" ")}})]
|
|
});
|
|
children.push(currentLabel);
|
|
|
|
onCustomEvent(labelNode.getField(), "change", function(value) {
|
|
currentLabel.firstChild.className = "landing-card-title-icon " + value.classList.join(" ");
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
if (labelNode instanceof BX.Landing.Node.Img)
|
|
{
|
|
currentLabel = create("span", {
|
|
props: {className: "landing-card-title-img"},
|
|
attrs: {
|
|
style: "background-color: #fafafa"
|
|
},
|
|
children: [create('img', {props: {src: labelNode.getValue().src}})]
|
|
});
|
|
children.push(currentLabel);
|
|
|
|
onCustomEvent(labelNode.getField(), "change", function(value) {
|
|
currentLabel.innerHTML = "";
|
|
currentLabel.appendChild(create('img', {props: {src: value.src}}));
|
|
});
|
|
}
|
|
}
|
|
}, this);
|
|
|
|
return create("div", {
|
|
props: {className: "landing-card-title"},
|
|
children: !isEmpty(children) ? children : manifest.name
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* Init Cards of Block.
|
|
*/
|
|
initCards: function()
|
|
{
|
|
if (this.access < ACCESS_W)
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.cards.clear();
|
|
this.forEachCard(function(node, selector, index) {
|
|
var manifest = BX.clone(this.manifest.cards[selector]);
|
|
var cardSelector = join(selector, "@", index);
|
|
|
|
if (this.isDynamicCards(selector))
|
|
{
|
|
manifest.allowInlineEdit = false;
|
|
}
|
|
|
|
removePanels(node);
|
|
var instance = new BX.Landing.Block.Card(node, manifest, cardSelector);
|
|
this.cards.add(instance);
|
|
|
|
if (manifest.allowInlineEdit !== false)
|
|
{
|
|
var cardAction = new CardActionPanel(
|
|
"cardAction",
|
|
"landing-ui-panel-block-card-action"
|
|
);
|
|
cardAction.show();
|
|
instance.addPanel(cardAction);
|
|
|
|
cardAction.addButton(new CardActionButton("clone", {
|
|
html: " ",
|
|
onClick: function(event) {
|
|
event.stopPropagation();
|
|
|
|
if (instance.manifest.sync)
|
|
{
|
|
var syncedSelectors = instance.manifest.sync;
|
|
|
|
if (isString(instance.manifest.sync))
|
|
{
|
|
syncedSelectors = [instance.manifest.sync];
|
|
}
|
|
|
|
if (isArray(syncedSelectors))
|
|
{
|
|
syncedSelectors.forEach(function(currentSyncSelector) {
|
|
this.cloneCard(join(currentSyncSelector, "@", index));
|
|
}, this);
|
|
}
|
|
}
|
|
|
|
this.cloneCard(cardSelector);
|
|
}.bind(this),
|
|
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_CARD_ACTION_CLONE")}
|
|
}));
|
|
|
|
cardAction.addButton(new CardActionButton("remove", {
|
|
html: " ",
|
|
onClick: function(event) {
|
|
event.stopPropagation();
|
|
|
|
if (instance.manifest.sync)
|
|
{
|
|
var syncedSelectors = instance.manifest.sync;
|
|
|
|
if (isString(instance.manifest.sync))
|
|
{
|
|
syncedSelectors = [instance.manifest.sync];
|
|
}
|
|
|
|
if (isArray(syncedSelectors))
|
|
{
|
|
syncedSelectors.forEach(function(currentSyncSelector) {
|
|
this.removeCard(join(currentSyncSelector, "@", index));
|
|
}, this);
|
|
}
|
|
}
|
|
|
|
this.removeCard(cardSelector);
|
|
}.bind(this),
|
|
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_CARD_ACTION_REMOVE")}
|
|
}));
|
|
}
|
|
|
|
instance.selector = cardSelector;
|
|
instance.sortIndex = index;
|
|
|
|
this.adjustCardRemoveButton(cardSelector);
|
|
});
|
|
|
|
this.cards.sort(function(a, b) {
|
|
return a.getIndex() > b.getIndex();
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* Clones Card.
|
|
* @param {string} selector - Selector of Card, which want clone.
|
|
* @param {?boolean} [preventHistory = false]
|
|
* @return {Promise}
|
|
*/
|
|
cloneCard: function(selector, preventHistory)
|
|
{
|
|
var card = this.cards.getBySelector(selector);
|
|
var cloneButton = card.panels.get("cardAction").buttons.get("clone");
|
|
var requestData = {block: this.id, selector: selector, lid: this.lid, siteId: this.siteId};
|
|
var queryParams = {code: this.manifest.code};
|
|
var self = this;
|
|
|
|
showButtonLoader(cloneButton);
|
|
|
|
let clonePromise = Promise.resolve();
|
|
if ((isBoolean(preventHistory) && !preventHistory) || !isBoolean(preventHistory))
|
|
{
|
|
requestData.preventHistory = 0;
|
|
clonePromise = BX.Landing.Backend.getInstance()
|
|
.action("Landing\\Block::cloneCard", requestData, queryParams)
|
|
.then(result => {
|
|
BX.Landing.History.getInstance().push();
|
|
|
|
return result;
|
|
});
|
|
}
|
|
|
|
return clonePromise
|
|
.then(function() {
|
|
fireCustomEvent("BX.Landing.Block:Card:beforeAdd", [
|
|
self.createEvent({card: card.node})
|
|
]);
|
|
})
|
|
|
|
// Clone
|
|
.then(function() {
|
|
var clonedCard = BX.clone(card.node);
|
|
removePanels(clonedCard);
|
|
insertAfter(clonedCard, card.node);
|
|
return clonedCard;
|
|
})
|
|
|
|
// After clone
|
|
.then(function(clonedCard) {
|
|
hideButtonLoader(cloneButton);
|
|
|
|
fireCustomEvent("BX.Landing.Block:Card:add", [
|
|
self.createEvent({card: clonedCard})
|
|
]);
|
|
|
|
self.initEntities();
|
|
self.initStyles();
|
|
})
|
|
|
|
// Handle errors
|
|
.catch(function() {
|
|
hideButtonLoader(cloneButton);
|
|
return Promise.reject();
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* Removes Card.
|
|
* @param {String} selector - Selector of Card, which want remove.
|
|
* @param {?boolean} [preventHistory = false]
|
|
* @return {Promise}
|
|
*/
|
|
removeCard: function(selector, preventHistory)
|
|
{
|
|
var card = this.cards.getBySelector(selector);
|
|
var removeButton = card.panels.get("cardAction").buttons.get("remove");
|
|
var requestData = {block: this.id, selector: selector, lid: this.lid, siteId: this.siteId};
|
|
var queryParams = {code: this.manifest.code};
|
|
var self = this;
|
|
|
|
showButtonLoader(removeButton);
|
|
|
|
let removePromise = Promise.resolve();
|
|
if ((isBoolean(preventHistory) && !preventHistory) || !isBoolean(preventHistory))
|
|
{
|
|
requestData.preventHistory = 0;
|
|
removePromise = BX.Landing.Backend.getInstance()
|
|
.action("Landing\\Block::removeCard", requestData, queryParams)
|
|
.then(result => {
|
|
BX.Landing.History.getInstance().push();
|
|
|
|
return result;
|
|
});
|
|
}
|
|
|
|
return removePromise
|
|
// Before remove
|
|
.then(function() {
|
|
fireCustomEvent("BX.Landing.Block:Card:beforeRemove", [
|
|
self.createEvent({card: card.node})
|
|
]);
|
|
|
|
removePanels(card.node);
|
|
})
|
|
// Remove
|
|
.then(function() {
|
|
self.cards.remove(card);
|
|
card.node.remove();
|
|
self.initEntities();
|
|
self.adjustCardRemoveButton(selector);
|
|
})
|
|
// After remove
|
|
.then(function() {
|
|
var afterEvent = self.createEvent({data: {selector: selector}});
|
|
fireCustomEvent("BX.Landing.Block:Card:remove", [afterEvent]);
|
|
hideButtonLoader(removeButton);
|
|
})
|
|
.catch(function() {
|
|
hideButtonLoader(removeButton);
|
|
return Promise.reject();
|
|
});
|
|
},
|
|
|
|
|
|
adjustCardRemoveButton: function(selector)
|
|
{
|
|
var card = this.cards.getBySelector(selector);
|
|
|
|
if (card)
|
|
{
|
|
var cardAction = card.panels.get("cardAction");
|
|
if (cardAction)
|
|
{
|
|
var cardIntoSlider = BX.hasClass(card.node, 'landing-block-card-carousel-element');
|
|
var cardsParent = card.node.closest(".landing-block-node-carousel-container");
|
|
if (!cardIntoSlider || !cardsParent)
|
|
{
|
|
var lastCardInCollection = card.node.parentElement.children.length === 1;
|
|
if (lastCardInCollection)
|
|
{
|
|
cardAction.buttons.get("remove").disable();
|
|
}
|
|
else
|
|
{
|
|
cardAction.buttons.get("remove").enable();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var cardsAmount = cardsParent.querySelectorAll('.landing-block-card-carousel-element').length;
|
|
if (cardsAmount > 1)
|
|
{
|
|
cardAction.buttons.get("remove").enable();
|
|
}
|
|
else
|
|
{
|
|
cardAction.buttons.get("remove").disable();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Adds card
|
|
* @param {{[index]: !int, container: !HTMLElement, content: string, selector: string}} settings
|
|
* @param {boolean} [preventHistory]
|
|
* @return {Promise}
|
|
*/
|
|
addCard: function(settings, preventHistory)
|
|
{
|
|
var selector = settings.selector.split("@")[0] + (settings.index > 0 ? "@"+(settings.index-1) : "");
|
|
|
|
var requestData = {
|
|
block: this.id,
|
|
content: settings.content,
|
|
selector: selector,
|
|
lid: this.lid,
|
|
siteId: this.siteId,
|
|
};
|
|
var queryParams = {code: this.manifest.code};
|
|
var container = settings.container;
|
|
var card = create("div", {html: settings.content}).firstElementChild;
|
|
var self = this;
|
|
|
|
let addPromise = Promise.resolve();
|
|
if ((isBoolean(preventHistory) && !preventHistory) || !isBoolean(preventHistory))
|
|
{
|
|
requestData.preventHistory = 0;
|
|
addPromise = BX.Landing.Backend.getInstance()
|
|
.action("Landing\\Block::addCard", requestData, queryParams)
|
|
.then(result => {
|
|
BX.Landing.History.getInstance().push();
|
|
|
|
return result;
|
|
});
|
|
}
|
|
|
|
return addPromise
|
|
.then(function() {
|
|
fireCustomEvent("BX.Landing.Block:Card:beforeAdd", [
|
|
self.createEvent({card: card})
|
|
]);
|
|
})
|
|
.then(function() {
|
|
var targetCard;
|
|
if (settings.index <= 0)
|
|
{
|
|
targetCard = self.cards.find(function(card) {
|
|
return card.selector.includes(selector.split("@")[0])
|
|
});
|
|
|
|
if (targetCard)
|
|
{
|
|
prepend(card, targetCard.node.parentNode);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
targetCard = self.cards.getBySelector(selector.split("@")[0] + "@" + (settings.index-1));
|
|
|
|
if (targetCard)
|
|
{
|
|
insertAfter(card, targetCard.node);
|
|
}
|
|
}
|
|
|
|
removePanels(container);
|
|
self.initEntities();
|
|
|
|
fireCustomEvent("BX.Landing.Block:Card:add", [
|
|
self.createEvent({card: card})
|
|
]);
|
|
})
|
|
},
|
|
|
|
|
|
/**
|
|
* @callback cardCallback
|
|
* @param {HTMLElement} node
|
|
* @param {string} selector
|
|
* @param {int} index
|
|
*/
|
|
/**
|
|
* Applies callback function for each card node
|
|
* @param {cardCallback} callback
|
|
*/
|
|
forEachCard: function(callback)
|
|
{
|
|
var cardSelectors = Object.keys(this.manifest.cards);
|
|
|
|
cardSelectors.map(function(cardSelector) {
|
|
var cards = slice(this.node.querySelectorAll(cardSelector));
|
|
|
|
cards.forEach(function(node, index) {
|
|
callback.apply(this, [node, cardSelector, index]);
|
|
}, this);
|
|
}, this);
|
|
},
|
|
|
|
|
|
/**
|
|
* Init Nodes of Block.
|
|
*/
|
|
initNodes: function()
|
|
{
|
|
if (this.access < ACCESS_W)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var nodes = [];
|
|
|
|
this.forEachNodeElements(function(element, selector, index) {
|
|
var instance = this.nodes.getByNode(element);
|
|
var nodeSelector = join(selector, "@", index);
|
|
|
|
if (!instance)
|
|
{
|
|
var handler = getClass(this.manifest.nodes[selector].handler);
|
|
var presetNode = element.closest('[data-card-preset]');
|
|
var manifest = clone(this.manifest.nodes[selector]);
|
|
var disallowField = false;
|
|
|
|
manifest.sections = this.sections;
|
|
|
|
if (presetNode)
|
|
{
|
|
var presetId = presetNode.dataset.cardPreset;
|
|
|
|
Object.keys(this.manifest.cards).forEach(function(cardSelector) {
|
|
if (presetNode.matches(cardSelector))
|
|
{
|
|
if (isPlainObject(this.manifest.cards[cardSelector].presets) &&
|
|
isPlainObject(this.manifest.cards[cardSelector].presets[presetId]) &&
|
|
isArray(this.manifest.cards[cardSelector].presets[presetId].disallow))
|
|
{
|
|
var isDisallow = this.manifest.cards[cardSelector].presets[presetId].disallow.find(function(disallowSelector) {
|
|
return selector === disallowSelector;
|
|
});
|
|
|
|
if (isDisallow)
|
|
{
|
|
manifest.allowInlineEdit = false;
|
|
disallowField = true;
|
|
}
|
|
}
|
|
}
|
|
}, this);
|
|
}
|
|
|
|
var isDynamic = this.cards.some(function(currentCard) {
|
|
var cardCode = currentCard.selector.split("@")[0];
|
|
|
|
return (
|
|
this.isDynamicCards(cardCode)
|
|
&& currentCard.node.contains(element)
|
|
);
|
|
}, this);
|
|
|
|
if (isDynamic)
|
|
{
|
|
manifest.allowInlineEdit = false;
|
|
}
|
|
else
|
|
{
|
|
var isCardNode = this.cards.some(function(currentCard) {
|
|
return currentCard.node.contains(element);
|
|
});
|
|
|
|
if (!isCardNode)
|
|
{
|
|
if (this.isDynamic())
|
|
{
|
|
manifest.allowInlineEdit = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
instance = new handler({
|
|
node: element,
|
|
manifest: manifest,
|
|
selector: nodeSelector,
|
|
onChange: this.onNodeChange.bind(this),
|
|
onChangeOptions: this.onNodeOptionsChange.bind(this),
|
|
onAttributeChange: this.onAttributeChange.bind(this),
|
|
onDesignShow: this.onStyleShow.bind(this),
|
|
uploadParams: {
|
|
action: "Block::uploadFile",
|
|
block: this.id
|
|
}
|
|
});
|
|
|
|
if (disallowField)
|
|
{
|
|
instance.getField().layout.hidden = true;
|
|
}
|
|
|
|
this.nodes.add(instance);
|
|
}
|
|
|
|
instance.selector = nodeSelector;
|
|
nodes.push(instance);
|
|
});
|
|
|
|
this.nodes.clear();
|
|
|
|
nodes.forEach(function(node) {
|
|
this.nodes.add(node);
|
|
}, this);
|
|
|
|
this.nodes.sort(function(a, b) {
|
|
return a.getIndex() > b.getIndex();
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* Handles node options change event
|
|
* @param {*} data
|
|
* @return {Promise<Object, Object>}
|
|
*/
|
|
onNodeOptionsChange: function(data)
|
|
{
|
|
if (!isEmpty(data))
|
|
{
|
|
this.initStyles();
|
|
|
|
var queryParams = {code: this.manifest.code};
|
|
var requestBody = {};
|
|
|
|
requestBody.data = data;
|
|
requestBody.block = this.id;
|
|
requestBody.siteId = this.siteId;
|
|
|
|
return BX.Landing.Backend.getInstance()
|
|
.action("Block::changeNodeName", requestBody, queryParams);
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* @callback forEachNodeElementsCallback
|
|
* @param {HTMLElement} [element]
|
|
* @param {string} [selector]
|
|
* @param {int} [index]
|
|
*/
|
|
/**
|
|
* Applies callback for each element of node
|
|
* @param {forEachNodeElementsCallback} callback
|
|
*/
|
|
forEachNodeElements: function(callback)
|
|
{
|
|
Object.keys(this.manifest.nodes).forEach(function(selector) {
|
|
try {
|
|
slice(this.node.querySelectorAll(selector)).forEach(function(element, index) {
|
|
if (!element.matches("[data-id=\"content_edit\"] *"))
|
|
{
|
|
callback.apply(this, [element, selector, index]);
|
|
}
|
|
}, this);
|
|
} catch(err) {}
|
|
}, this);
|
|
},
|
|
|
|
|
|
/**
|
|
* Shows content edit panel
|
|
* @param {{name: string, nodes: BX.Landing.Collection.NodeCollection, [compact]: boolean, [nodesOnly]}} [options]
|
|
*/
|
|
showContentPanel: function(options)
|
|
{
|
|
var nodes = !!options && options.nodes ? options.nodes : null;
|
|
var formName = !!options && options.name ? options.name : null;
|
|
var nodesOnly = !!options && options.nodesOnly ? options.nodesOnly : false;
|
|
var showAll = !!options && options.showAll ? options.showAll : false;
|
|
var compactMode = !!options && options.compact;
|
|
var hideCheckbox = !!options && options.hideCheckbox;
|
|
var contentPanel = this.panels.get("content_edit");
|
|
|
|
if (!contentPanel)
|
|
{
|
|
contentPanel = new ContentEditPanel("content_edit", {
|
|
title: BX.Landing.Loc.getMessage("LANDING_CONTENT_PANEL_TITLE"),
|
|
subTitle: this.manifest.block.name,
|
|
onSaveHandler: this.onContentSave.bind(this),
|
|
onCancelHandler: this.onContentCancel.bind(this),
|
|
});
|
|
|
|
var formId = this.getBlockFormId();
|
|
var type = BX.Text.capitalize(
|
|
BX.Landing.Env.getInstance().getOptions().params.type
|
|
);
|
|
if (
|
|
BX.Type.isPlainObject(formId)
|
|
&& type !== 'SMN'
|
|
)
|
|
{
|
|
var button = new BX.UI.Button({
|
|
text: BX.Landing.Loc.getMessage('LANDING_SHOW_FORM_EDITOR'),
|
|
color: BX.UI.Button.Color.LIGHT_BORDER,
|
|
round: true,
|
|
className: 'landing-ui-panel-top-button',
|
|
onclick: function() {
|
|
contentPanel.hide()
|
|
.then(function() {
|
|
this.onShowContentPanel();
|
|
}.bind(this));
|
|
}.bind(this)
|
|
});
|
|
|
|
BX.Dom.style(button.render(), {
|
|
position: 'absolute',
|
|
right: '50px',
|
|
});
|
|
|
|
BX.Dom.append(button.render(), contentPanel.header);
|
|
}
|
|
|
|
this.addPanel(contentPanel);
|
|
}
|
|
|
|
contentPanel.compact(compactMode);
|
|
contentPanel.clear();
|
|
|
|
var block = this.getBlockFromRepository(this.manifest.code);
|
|
|
|
if (block && block.restricted)
|
|
{
|
|
append(this.getRestrictedMessage(), contentPanel.content);
|
|
}
|
|
|
|
this.tmpContent = create("div", {
|
|
props: {hidden: true}
|
|
});
|
|
|
|
this.content.appendChild(this.tmpContent);
|
|
var html = "";
|
|
|
|
Object.keys(this.manifest.cards).forEach(function(cardSelector) {
|
|
var card = this.manifest.cards[cardSelector];
|
|
|
|
if (isPlainObject(card.presets))
|
|
{
|
|
Object.keys(card.presets).forEach(function(presetId) {
|
|
var preset = card.presets[presetId];
|
|
html += preset.html;
|
|
}, this);
|
|
}
|
|
}, this);
|
|
|
|
this.tmpContent.innerHTML = html;
|
|
this.initEntities();
|
|
this.initCardsLabels();
|
|
|
|
var forms = this.getEditForms({
|
|
nodes: nodes,
|
|
formName: formName,
|
|
nodesOnly: nodesOnly,
|
|
showAll: showAll,
|
|
hideCheckbox: hideCheckbox
|
|
});
|
|
|
|
forms.forEach(function(form) {
|
|
contentPanel.appendForm(form);
|
|
});
|
|
|
|
this.tmpContent.innerHTML = "";
|
|
contentPanel.show();
|
|
BX.Event.bind(contentPanel.layout, 'click', this.onContentPanelClick.bind(this));
|
|
|
|
setTimeout(function() {
|
|
this.lastBlockState = this.fetchRequestData(contentPanel, true);
|
|
}.bind(this), 300);
|
|
},
|
|
|
|
onContentPanelClick: function(event)
|
|
{
|
|
BX.Event.EventEmitter.emit('BX.Landing.UI.Panel.ContentEdit:onClick', { event });
|
|
},
|
|
|
|
createHistoryEntry: function(newState)
|
|
{
|
|
Promise
|
|
.all([
|
|
this.lastBlockState,
|
|
newState
|
|
])
|
|
.then(function(states) {
|
|
var undoState = states[0];
|
|
var redoState = states[1];
|
|
|
|
BX.Landing.History.getInstance().push(
|
|
new BX.Landing.History.Entry({
|
|
block: this.id,
|
|
selector: "#block" + this.id,
|
|
command: "updateBlockState",
|
|
undo: undoState,
|
|
redo: redoState
|
|
})
|
|
);
|
|
}.bind(this));
|
|
|
|
return Promise.resolve(clone(newState));
|
|
},
|
|
|
|
/**
|
|
* Updates block's content.
|
|
* @param {string} content
|
|
* @param {boolean} [preventHistory = false] - Add this action to history or not. By default - add
|
|
*/
|
|
updateContent: function(content, preventHistory)
|
|
{
|
|
let updatePromise = Promise.resolve();
|
|
if ((isBoolean(preventHistory) && !preventHistory) || !isBoolean(preventHistory))
|
|
{
|
|
updatePromise = BX.Landing.Backend.getInstance().action(
|
|
"Block::updateContent",
|
|
{
|
|
lid: this.lid,
|
|
block: this.id,
|
|
content: content.replaceAll(' style="', ' bxstyle="'),
|
|
preventHistory: 0,
|
|
},
|
|
{code: this.manifest.code}
|
|
);
|
|
}
|
|
|
|
const reloadPromise = this.reload();
|
|
|
|
return Promise.all([updatePromise, reloadPromise]);
|
|
},
|
|
|
|
updateBlockState: function(state, preventHistory)
|
|
{
|
|
if (
|
|
BX.type.isPlainObject(state)
|
|
&& BX.type.isPlainObject(state.dynamicParams)
|
|
)
|
|
{
|
|
this.dynamicParams = clone(state.dynamicParams);
|
|
}
|
|
else
|
|
{
|
|
this.dynamicParams = {};
|
|
}
|
|
|
|
Promise.resolve(state)
|
|
.then(function(currentState) {
|
|
return preventHistory ? currentState : this.createHistoryEntry(currentState);
|
|
}.bind(this))
|
|
.then(this.applyMenuChanges.bind(this))
|
|
.then(this.applyContentChanges.bind(this))
|
|
.then(this.applyCardsChanges.bind(this))
|
|
.then(this.applyAttributeChanges.bind(this))
|
|
.then(this.applySettingsChanges.bind(this))
|
|
.then(data => {
|
|
return this.saveChanges.bind(this)(data, preventHistory);
|
|
})
|
|
// Reload only blocks with component
|
|
.then(this.reload.bind(this))
|
|
.catch(console.warn);
|
|
|
|
var contentPanel = this.panels.get('content_edit');
|
|
|
|
if (contentPanel)
|
|
{
|
|
var contentForms = new FormCollection();
|
|
|
|
contentPanel.forms.forEach(function(form) {
|
|
if (form.type !== "attrs")
|
|
{
|
|
contentForms.add(form);
|
|
|
|
if (form.childForms && form.childForms.length > 0)
|
|
{
|
|
form.childForms.forEach(function(childForm) {
|
|
contentForms.add(childForm);
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
contentForms.fetchFields().forEach(function(field) {
|
|
if (field.tag)
|
|
{
|
|
var node = this.nodes.getBySelector(field.selector);
|
|
if (node)
|
|
{
|
|
node.onChangeTag(field.tag);
|
|
}
|
|
}
|
|
}, this);
|
|
}
|
|
},
|
|
|
|
getRestrictedMessage: function()
|
|
{
|
|
return create("div", {
|
|
props: {className: "ui-alert ui-alert-warning"},
|
|
html: this.getRestrictedMessageText(),
|
|
attrs: {style: "margin-bottom: 20px"}
|
|
});
|
|
},
|
|
|
|
getRestrictedMessageText: function()
|
|
{
|
|
if (this.isMainpage())
|
|
{
|
|
return BX.Landing.Loc.getMessage("LANDING_BLOCK_RESTRICTED_TEXT_MAINPAGE");
|
|
}
|
|
|
|
return BX.Landing.Loc.getMessage("LANDING_BLOCK_RESTRICTED_TEXT2");
|
|
},
|
|
|
|
/**
|
|
* Handles event on style panel show
|
|
*/
|
|
onStyleShow: function(selector = null)
|
|
{
|
|
BX.Landing.UI.Panel.EditorPanel.getInstance().hide();
|
|
BX.Landing.PageObject.getInstance().design()
|
|
.then((stylePanel) => {
|
|
if (isPlainObject(this.styleNodes))
|
|
{
|
|
if (stylePanel.isShown() && this.id === stylePanel.blockId)
|
|
{
|
|
stylePanel.forms.forEach((form) => {
|
|
if (form.selector === this.selector)
|
|
{
|
|
stylePanel.scrollElement = form;
|
|
form.collapsed = false;
|
|
BX.Dom.removeClass(form.layout, 'landing-ui-form-style--collapsed');
|
|
setTimeout(() => {
|
|
stylePanel.scrollElement.layout.scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'start',
|
|
inline: 'nearest',
|
|
});
|
|
}, 100);
|
|
}
|
|
else
|
|
{
|
|
form.collapsed = true;
|
|
BX.Dom.addClass(form.layout, 'landing-ui-form-style--collapsed');
|
|
}
|
|
});
|
|
}
|
|
else
|
|
{
|
|
stylePanel.clear();
|
|
const sortedStyleNodes = this.getSortedStyleNodes(this.styleNodes);
|
|
stylePanel.prepareFooter(this.isExistMultiSelectionNode(sortedStyleNodes));
|
|
if (selector === null || typeof selector !== 'string')
|
|
{
|
|
this.showStylePanel(this.selector, stylePanel.blockId);
|
|
sortedStyleNodes.forEach((key) => {
|
|
let currentTarget = null;
|
|
this.styles.forEach((styles) => {
|
|
if (styles.selector === key)
|
|
{
|
|
currentTarget = styles.currentTarget;
|
|
}
|
|
});
|
|
this.showStylePanel(key, stylePanel.blockId, currentTarget, true);
|
|
});
|
|
}
|
|
else
|
|
{
|
|
this.showStylePanel(this.selector, stylePanel.blockId, null, true);
|
|
sortedStyleNodes.forEach((key) => {
|
|
let currentTarget = null;
|
|
this.styles.forEach((styles) => {
|
|
if (styles.selector === key)
|
|
{
|
|
currentTarget = styles.currentTarget;
|
|
}
|
|
});
|
|
this.showStylePanel(key, stylePanel.blockId, currentTarget, true);
|
|
});
|
|
setTimeout(() => {
|
|
stylePanel.forms.forEach((form) => {
|
|
if (form.selector === selector)
|
|
{
|
|
stylePanel.scrollElement = form;
|
|
form.collapsed = false;
|
|
BX.Dom.removeClass(form.layout, 'landing-ui-form-style--collapsed');
|
|
setTimeout(() => {
|
|
stylePanel.scrollElement.layout.scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'start',
|
|
inline: 'nearest',
|
|
});
|
|
}, 500);
|
|
}
|
|
else
|
|
{
|
|
form.collapsed = true;
|
|
BX.Dom.addClass(form.layout, 'landing-ui-form-style--collapsed');
|
|
}
|
|
});
|
|
}, 1000);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this.showStylePanel(this.selector, stylePanel.blockId);
|
|
}
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* Gets className postfix --lg --md --sm
|
|
*/
|
|
getPostfix: function()
|
|
{
|
|
return "";
|
|
},
|
|
|
|
|
|
/**
|
|
* Expands type groups
|
|
* @param {string|string[]} types
|
|
* @returns {string[]}
|
|
*/
|
|
expandTypeGroups: function(types)
|
|
{
|
|
var result = [];
|
|
|
|
if (!BX.type.isArray(types))
|
|
{
|
|
types = [types];
|
|
}
|
|
|
|
types.forEach(function(type) {
|
|
if (isGroup(type))
|
|
{
|
|
getGroupTypes(type).forEach(function(groupType) {
|
|
result.push(groupType);
|
|
});
|
|
}
|
|
else
|
|
{
|
|
result.push(type);
|
|
}
|
|
});
|
|
|
|
return result;
|
|
},
|
|
|
|
|
|
/**
|
|
* Makes style editor form for style node
|
|
* @param {string} selector
|
|
* @param {{
|
|
* type: string|string[],
|
|
* name: string,
|
|
* [props],
|
|
* [title]
|
|
* }} settings
|
|
* @param {boolean} [isBlock = false]
|
|
* @param {HTMLElement} currentTarget
|
|
* @param {boolean} collapsed
|
|
* @returns {?BX.Landing.UI.Form.StyleForm}
|
|
*/
|
|
createStyleForm: function(selector, settings, isBlock, currentTarget, collapsed = false)
|
|
{
|
|
var form = this.forms.get(selector);
|
|
|
|
if (form)
|
|
{
|
|
this.forms.remove(form);
|
|
}
|
|
|
|
var type = !!settings.props ? settings.props : !!settings.type ? settings.type : null;
|
|
var name = !!settings.title ? settings.title : !!settings.name ? settings.name : "";
|
|
|
|
if (!!type && !!name)
|
|
{
|
|
var styleFactory = new StyleFactory({frame: window, postfix: this.getPostfix()});
|
|
|
|
form = new StyleForm({
|
|
id: selector,
|
|
title: name,
|
|
selector,
|
|
iframe: window,
|
|
collapsed: collapsed,
|
|
currentTarget: currentTarget,
|
|
});
|
|
|
|
type = this.expandTypeGroups(type).reduce(function(acc, item) {
|
|
if (!acc.includes(item))
|
|
{
|
|
acc.push(item);
|
|
}
|
|
|
|
return acc;
|
|
}, []);
|
|
|
|
type.forEach(function(type) {
|
|
var typeSettings = getTypeSettings(type);
|
|
if (typeSettings === null)
|
|
{
|
|
return;
|
|
}
|
|
var styleNode = this.styles.get(selector);
|
|
var field = styleFactory.createField({
|
|
block: this,
|
|
styleNode: styleNode,
|
|
selector: !isBlock ? this.makeRelativeSelector(selector) : selector,
|
|
property: typeSettings.property,
|
|
multiple: typeSettings.multiple === true,
|
|
style: type,
|
|
pseudoElement: typeSettings["pseudo-element"],
|
|
pseudoClass: typeSettings["pseudo-class"],
|
|
attrKey: typeSettings.attrKey,
|
|
type: typeSettings.type,
|
|
subtype: typeSettings.subtype,
|
|
title: typeSettings.name,
|
|
items: typeSettings.items,
|
|
help: typeSettings.help,
|
|
onChange: onChange.bind(this),
|
|
onReset: onReset.bind(this),
|
|
});
|
|
|
|
// when field changed
|
|
function onChange(value, items, postfix, affect) {
|
|
// false handler by some fields events
|
|
if (value instanceof BX.Event.BaseEvent)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var exclude = !!typeSettings.exclude ? getTypeSettings(typeSettings.exclude) : null;
|
|
|
|
if (exclude)
|
|
{
|
|
form.fields.forEach(function(field) {
|
|
if (field.style === typeSettings.exclude)
|
|
{
|
|
field.reset();
|
|
}
|
|
});
|
|
}
|
|
|
|
const event = this.createEvent({
|
|
data: {
|
|
selector: selector,
|
|
value: value,
|
|
items: items,
|
|
postfix: postfix,
|
|
affect: affect,
|
|
exclude: exclude
|
|
}
|
|
});
|
|
|
|
fireCustomEvent(window, "BX.Landing.Block:beforeApplyStyleChanges", [event]);
|
|
styleNode.setValue(value, items, postfix, affect, exclude);
|
|
|
|
const data = {node: styleNode.getNode(), data: styleNode.getValue()};
|
|
fireCustomEvent("BX.Landing.Block:updateStyleWithoutDebounce", [
|
|
this.createEvent(data)
|
|
]);
|
|
this.onStyleInputWithDebounce(data, false);
|
|
}
|
|
|
|
// when field reset
|
|
function onReset(items, postfix, affect) {
|
|
// todo: add cache for backend
|
|
BX.Landing.Backend.getInstance()
|
|
.action("Landing\\Block::getContentFromRepository", {
|
|
code: this.manifest.code
|
|
})
|
|
.then(function(response) {
|
|
var repo = document.createElement('div');
|
|
repo.id = 'fake';
|
|
repo.innerHTML = response;
|
|
repo.style.display = 'none';
|
|
window.document.body.append(repo);
|
|
|
|
var targetNode = null;
|
|
var targetSelector = null;
|
|
if (isBlock)
|
|
{
|
|
targetSelector = '#fake > :first-child';
|
|
targetNode = repo.firstElementChild;
|
|
}
|
|
else
|
|
{
|
|
targetSelector = '#fake ' + selector;
|
|
var index = styleNode.getElementIndex(styleNode.getTargetElement());
|
|
targetNode = repo.querySelectorAll(targetSelector)[index];
|
|
}
|
|
var fakeStyleNode = new BX.Landing.UI.Style({
|
|
iframe: window,
|
|
selector: targetSelector,
|
|
relativeSelector: targetSelector,
|
|
node: targetNode
|
|
});
|
|
initFieldByStyleNode(fakeStyleNode);
|
|
|
|
// match new class list
|
|
var resetStyleValue = fakeStyleNode.getValue();
|
|
var resetClasses = [];
|
|
var currStyleValue = styleNode.getValue();
|
|
items.forEach(function(item) {
|
|
if(resetStyleValue.classList.indexOf(item.value) !== -1)
|
|
{
|
|
resetClasses.push(item.value);
|
|
}
|
|
var currIndex = currStyleValue.classList.indexOf(item.value);
|
|
if(currIndex !== -1)
|
|
{
|
|
delete currStyleValue.classList[currIndex];
|
|
}
|
|
});
|
|
resetStyleValue.classList = currStyleValue.classList.concat(resetClasses);
|
|
resetStyleValue.className = resetStyleValue.classList;
|
|
onChange.bind(this)(resetStyleValue, items, postfix, affect);
|
|
repo.remove();
|
|
}.bind(this))
|
|
.catch(function(error){
|
|
// todo: show err panel
|
|
console.error("Error on reset", error);
|
|
});
|
|
}
|
|
|
|
// when field init
|
|
function initFieldByStyleNode(styleNode)
|
|
{
|
|
styleNode.setInlineProperty(field.getInlineProperties());
|
|
styleNode.setComputedProperty(field.getComputedProperties());
|
|
styleNode.setPseudoElement(field.getPseudoElement());
|
|
|
|
var preventEvent = true;
|
|
var styleValue = styleNode.getValue(true);
|
|
if (field.getInlineProperties().length > 0 || field.getComputedProperties().length > 0)
|
|
{
|
|
field.setValue(styleValue.style, preventEvent);
|
|
}
|
|
else
|
|
{
|
|
styleValue.classList.forEach(className => {
|
|
if (typeSettings.items.some(item => item.value === className))
|
|
{
|
|
// buttons group set value via onFrameLoad
|
|
if (!!field.buttons && field.multiple === true)
|
|
{
|
|
return;
|
|
}
|
|
field.setValue(className, preventEvent);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
initFieldByStyleNode(styleNode);
|
|
|
|
form.addField(field);
|
|
}, this);
|
|
|
|
this.forms.add(form);
|
|
}
|
|
|
|
form.fields.forEach(function(field) {
|
|
if (field.popup)
|
|
{
|
|
field.popup.close();
|
|
}
|
|
});
|
|
|
|
return form;
|
|
},
|
|
|
|
|
|
initStyles: function()
|
|
{
|
|
if (this.access < ACCESS_V)
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.styles.clear();
|
|
var node = new BX.Landing.UI.Style({
|
|
id: this.selector,
|
|
iframe: window,
|
|
selector: this.selector,
|
|
relativeSelector: this.selector,
|
|
onClick: this.onStyleClick.bind(this, this.selector)
|
|
});
|
|
|
|
this.styles.add(node);
|
|
|
|
if (isPlainObject(this.manifest.style) &&
|
|
isPlainObject(this.manifest.style.nodes))
|
|
{
|
|
Object.keys(this.manifest.style.nodes).forEach(function(selector) {
|
|
var node = new BX.Landing.UI.Style({
|
|
id: selector,
|
|
iframe: window,
|
|
selector: selector,
|
|
relativeSelector: this.makeRelativeSelector(selector),
|
|
onClick: this.onStyleClick.bind(this, selector)
|
|
});
|
|
|
|
this.styles.add(node);
|
|
}, this);
|
|
}
|
|
},
|
|
|
|
onStyleClick: function(selector)
|
|
{
|
|
BX.Landing.PageObject.getInstance().design()
|
|
.then((stylePanel) => {
|
|
const options = this.getStyleOptions(selector);
|
|
this.styles.forEach((styles) => {
|
|
if (styles.selector.split('@')[0] === selector)
|
|
{
|
|
stylePanel.forms.forEach((form) => {
|
|
if (
|
|
form.selector === selector
|
|
&& form.currentTarget !== styles.currentTarget
|
|
)
|
|
{
|
|
const isBlock = this.isBlockSelector(selector);
|
|
const newForm = this.createStyleForm(selector, options, isBlock, styles.currentTarget, true);
|
|
this.replaceStyleForm(newForm, stylePanel);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
if (this.id === stylePanel.blockId)
|
|
{
|
|
let currentForm = null;
|
|
stylePanel.forms.forEach((form) => {
|
|
if (
|
|
form.selector === selector
|
|
|| (options.type === 'crm-form' && form.specialType === 'crm_forms')
|
|
)
|
|
{
|
|
currentForm = form;
|
|
}
|
|
});
|
|
if (currentForm !== null)
|
|
{
|
|
stylePanel.scrollElement = currentForm;
|
|
currentForm.collapsed = false;
|
|
BX.Dom.removeClass(currentForm.layout, 'landing-ui-form-style--collapsed');
|
|
setTimeout(() => {
|
|
stylePanel.scrollElement.layout.scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'start',
|
|
inline: 'nearest',
|
|
});
|
|
}, 100);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
stylePanel.clear();
|
|
if (selector === this.selector)
|
|
{
|
|
this.showStylePanel(this.selector, stylePanel.blockId);
|
|
}
|
|
else
|
|
{
|
|
this.showStylePanel(this.selector, stylePanel.blockId, null, true);
|
|
}
|
|
const sortedStyleNodes = this.getSortedStyleNodes(this.styleNodes);
|
|
stylePanel.prepareFooter(this.isExistMultiSelectionNode(sortedStyleNodes));
|
|
sortedStyleNodes.forEach((key) => {
|
|
let currentTarget = null;
|
|
this.styles.forEach((styles) => {
|
|
if (styles.selector === key)
|
|
{
|
|
currentTarget = styles.currentTarget;
|
|
}
|
|
});
|
|
const collapsed = key !== selector;
|
|
this.showStylePanel(key, stylePanel.blockId, currentTarget, collapsed);
|
|
});
|
|
if (this.id !== stylePanel.blockId)
|
|
{
|
|
const intervalId = setInterval(() => {
|
|
if (!this.stylePanel.content.hidden && this.scrollElement)
|
|
{
|
|
this.scrollElement.layout.scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'start',
|
|
inline: 'nearest',
|
|
});
|
|
clearInterval(intervalId);
|
|
}
|
|
}, 100);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
replaceStyleForm: function(newForm, stylePanel)
|
|
{
|
|
let oldForm = null;
|
|
stylePanel.forms.forEach((form) => {
|
|
if (newForm.selector === form.id)
|
|
{
|
|
oldForm = form;
|
|
}
|
|
});
|
|
if (oldForm)
|
|
{
|
|
stylePanel.replaceForm(newForm, oldForm);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Sorting nodes as they are found in the DOM
|
|
* @param nodes
|
|
* @return {object}
|
|
*/
|
|
getSortedStyleNodes: function(nodes) {
|
|
const contentHtml = this.content.innerHTML;
|
|
const indexMap = {};
|
|
const negativeIndexMap = {};
|
|
Object.keys(nodes).forEach(key => {
|
|
const index = contentHtml.indexOf(key.substring(1));
|
|
if (index !== -1)
|
|
{
|
|
indexMap[key] = index;
|
|
}
|
|
else
|
|
{
|
|
negativeIndexMap[key] = index;
|
|
}
|
|
});
|
|
let sortedNodes = Object.keys(indexMap).sort((a, b) => indexMap[a] - indexMap[b]);
|
|
const negativeNodes = Object.values(Object.keys(negativeIndexMap));
|
|
for (let i = 0; i < negativeNodes.length; i++) {
|
|
sortedNodes.push(negativeNodes[i]);
|
|
}
|
|
return sortedNodes;
|
|
},
|
|
|
|
/**
|
|
* Check if exist multi selection node
|
|
* @param nodes
|
|
* @return {boolean}
|
|
*/
|
|
isExistMultiSelectionNode: function(nodes) {
|
|
return nodes.some(node => this.content.querySelectorAll(node).length > 1);
|
|
},
|
|
|
|
|
|
/**
|
|
* Makes selector relative this block
|
|
* @param {string} selector
|
|
* @return {string}
|
|
*/
|
|
makeRelativeSelector: function(selector)
|
|
{
|
|
return join(this.selector, " ", selector);
|
|
},
|
|
|
|
|
|
/**
|
|
* Makes absolute selector
|
|
* @param {string} selector
|
|
* @return {string}
|
|
*/
|
|
makeAbsoluteSelector: function(selector)
|
|
{
|
|
selector = selector || this.selector;
|
|
selector = trim(selector);
|
|
var find = selector === this.selector ? " > :first-child" : this.selector;
|
|
return trim(selector.replace(find, "").replace("!", ""));
|
|
},
|
|
|
|
|
|
/**
|
|
* Saves block style changes
|
|
* @param {boolean} [preventHistory = false] - Add this action to history or not. By default - add
|
|
*/
|
|
saveStyles: function(preventHistory)
|
|
{
|
|
const styles = this.styles.fetchChanges();
|
|
|
|
if (styles.length)
|
|
{
|
|
styles.forEach(function(style) {
|
|
if (style.selector === this.selector)
|
|
{
|
|
style.selector = style.selector.replace(" > :first-child", "");
|
|
}
|
|
|
|
if (!style.isSelectGroup() && style.selector !== this.makeAbsoluteSelector(this.selector))
|
|
{
|
|
style.selector = join(style.selector.split("@")[0], "@", style.getElementIndex(style.getNode()[0]));
|
|
}
|
|
|
|
if (style.isSelectGroup())
|
|
{
|
|
style.selector = style.selector.split("@")[0];
|
|
}
|
|
}, this);
|
|
|
|
if ((isBoolean(preventHistory) && !preventHistory) || !isBoolean(preventHistory))
|
|
{
|
|
const post = styles.fetchValues();
|
|
BX.Landing.Backend.getInstance()
|
|
.action(
|
|
"Landing\\Block::updateStyles",
|
|
{block: this.id, data: post, lid: this.lid, siteId: this.siteId, preventHistory: 0},
|
|
{code: this.manifest.code},
|
|
)
|
|
.then(() => {
|
|
BX.Landing.History.getInstance().push();
|
|
});
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Shows style editor panel
|
|
*/
|
|
showStylePanel: function(selector, blockId, currentTarget = null, collapsed = false)
|
|
{
|
|
var FormSettingsPanel = BX.Reflection.getClass('BX.Landing.UI.Panel.FormSettingsPanel');
|
|
var formMode = (
|
|
FormSettingsPanel
|
|
&& FormSettingsPanel.getInstance().isShown()
|
|
|| BX.Landing.Main.getInstance().isControlsExternal()
|
|
);
|
|
var isBlock = this.isBlockSelector(selector);
|
|
var options = this.getStyleOptions(selector);
|
|
|
|
BX.Landing.PageObject.getInstance().design()
|
|
.then(function(stylePanel) {
|
|
stylePanel.clearContent();
|
|
stylePanel.blockId = this.id;
|
|
|
|
if (options.type === 'crm-form')
|
|
{
|
|
var rootWindow = BX.Landing.PageObject.getRootWindow();
|
|
|
|
return Promise
|
|
.all([
|
|
rootWindow.BX.Runtime.loadExtension('landing.formstyleadapter'),
|
|
BX.Runtime.loadExtension('landing.formstyleadapter')
|
|
])
|
|
.then(function(result) {
|
|
var FormStyleAdapter = result[1].FormStyleAdapter;
|
|
var formStyleAdapter = new FormStyleAdapter({
|
|
formId: this.getBlockFormId().id,
|
|
instanceId: this.getBlockFormId().instanceId,
|
|
currentBlock: this,
|
|
});
|
|
|
|
return Promise.all([
|
|
stylePanel.show(formMode),
|
|
formStyleAdapter.load()
|
|
]);
|
|
}.bind(this))
|
|
.catch(function(error) {
|
|
console.error(error);
|
|
});
|
|
}
|
|
|
|
return stylePanel
|
|
.show(formMode)
|
|
.then(function(result) {
|
|
return [result];
|
|
});
|
|
}.bind(this))
|
|
.then(function(result) {
|
|
if (!result)
|
|
{
|
|
return;
|
|
}
|
|
var stylePanel = result[0];
|
|
this.stylePanel = stylePanel;
|
|
var formStyleAdapter = result[1];
|
|
|
|
if (formStyleAdapter)
|
|
{
|
|
const form = formStyleAdapter.getStyleForm(collapsed);
|
|
stylePanel.appendForm(form);
|
|
if (collapsed === false)
|
|
{
|
|
this.scrollElement = form;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (isArray(options.type) || isString(options.type))
|
|
{
|
|
if (options.type.length)
|
|
{
|
|
const form = this.createStyleForm(selector, options, isBlock, currentTarget, collapsed);
|
|
stylePanel.appendForm(form);
|
|
if (collapsed === false)
|
|
{
|
|
this.scrollElement = form;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isPlainObject(options.additional))
|
|
{
|
|
selector = options.selector ? options.selector : selector;
|
|
stylePanel.appendForm(
|
|
this.createAdditionalForm({
|
|
form: StyleForm,
|
|
selector: selector,
|
|
group: options.additional,
|
|
attrsType: options.additional.attrsType,
|
|
onChange: this.onAttributeChange.bind(this),
|
|
name: options.additional.name,
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (isArray(options.additional))
|
|
{
|
|
options.additional.forEach(function(group) {
|
|
stylePanel.appendForm(
|
|
this.createAdditionalForm({
|
|
form: StyleForm,
|
|
selector: selector,
|
|
group: group,
|
|
onChange: this.onAttributeChange.bind(this),
|
|
name: options.additional[0].name,
|
|
})
|
|
);
|
|
}, this);
|
|
}
|
|
}.bind(this))
|
|
.catch(function(error) {
|
|
if (BX.Type.isArrayFilled(error))
|
|
{
|
|
var accessDeniedCode = 510;
|
|
var isAccessDenied = error.some(function(error) {
|
|
return String(error.code) === String(accessDeniedCode);
|
|
});
|
|
|
|
if (isAccessDenied)
|
|
{
|
|
BX.Dom.append(
|
|
this.getAccessMessage(),
|
|
BX.Landing.UI.Panel.StylePanel.getInstance().content
|
|
);
|
|
}
|
|
}
|
|
}.bind(this));
|
|
},
|
|
|
|
getAccessMessage: function()
|
|
{
|
|
if (!this.accessMessage)
|
|
{
|
|
this.accessMessage = BX.create({
|
|
tag: 'div',
|
|
props: {className: 'landing-ui-access-error-message'},
|
|
children: [
|
|
BX.create({
|
|
tag: 'div',
|
|
props: {className: 'landing-ui-access-error-message-text'},
|
|
text: BX.Landing.Loc.getMessage('LANDING_CRM_ACCESS_ERROR_MESSAGE')
|
|
})
|
|
]
|
|
})
|
|
}
|
|
|
|
return this.accessMessage;
|
|
},
|
|
|
|
|
|
/**
|
|
* Gets style options for selector
|
|
* @param {!string} selector
|
|
* @return {object}
|
|
*/
|
|
getStyleOptions: function(selector)
|
|
{
|
|
if (this.isBlockSelector(selector))
|
|
{
|
|
return this.prepareBlockOptions(this.manifest.style.block);
|
|
}
|
|
|
|
return this.manifest.style.nodes[selector];
|
|
},
|
|
|
|
|
|
/**
|
|
* Creates additional form
|
|
* @param {object} options
|
|
* @return {BX.Landing.UI.Form.StyleForm}
|
|
*/
|
|
createAdditionalForm: function(options)
|
|
{
|
|
var form = new options.form({ title: options.name, type: 'attrs', collapsed: true });
|
|
|
|
var attrsSet = [];
|
|
if (!BX.Type.isUndefined(options.group.attrs))
|
|
{
|
|
attrsSet = options.group.attrs;
|
|
}
|
|
else
|
|
{
|
|
options.attrsType.forEach((atr) => {
|
|
let attrSetItem = getAttrsTypeSettings(atr);
|
|
if (attrSetItem)
|
|
{
|
|
attrsSet.push(attrSetItem);
|
|
}
|
|
})
|
|
}
|
|
attrsSet.forEach(function(attrOptions) {
|
|
var currentSelector = attrOptions.selector || options.selector;
|
|
var field;
|
|
|
|
if (isArray(attrOptions.tabs))
|
|
{
|
|
var card = new TabCard({
|
|
tabs: attrOptions.tabs.map(function(tabOptions) {
|
|
return {
|
|
id: random(),
|
|
name: tabOptions.name,
|
|
active: tabOptions.active,
|
|
fields: tabOptions.attrs.map(function(attrOptions) {
|
|
return this.createAttributeField(
|
|
attrOptions,
|
|
attrOptions.selector || options.selector,
|
|
options.onChange
|
|
);
|
|
}, this)
|
|
};
|
|
}, this)
|
|
});
|
|
|
|
form.addCard(card);
|
|
return;
|
|
}
|
|
|
|
field = this.createAttributeField(attrOptions, currentSelector, options.onChange);
|
|
form.addField(field);
|
|
}, this);
|
|
|
|
BX.Event.EventEmitter.subscribe('BX.Landing.UI.Form.StyleForm:attributeChange', (event) => {
|
|
var eventData = event.data;
|
|
this.prepareAttributeValue(eventData, form);
|
|
});
|
|
|
|
return form;
|
|
},
|
|
|
|
prepareAttributeValue: function(eventData, form) {
|
|
var dependencySet = eventData.data.dependency;
|
|
if (dependencySet)
|
|
{
|
|
dependencySet.forEach((dependency) => {
|
|
var value = eventData.getValue();
|
|
var index = dependency['conditions'].indexOf(value);
|
|
if (index >= 0)
|
|
{
|
|
form.fields.forEach((field) => {
|
|
if (field.attribute === dependency['attribute'])
|
|
{
|
|
//action 'changeValue'
|
|
if (dependency['action'] === 'changeValue')
|
|
{
|
|
var value = field.getValue();
|
|
var index = dependency['attributeCurrentValues'].indexOf(value);
|
|
if (index >= 0)
|
|
{
|
|
field.setValue(dependency['attributeNewValue'], true);
|
|
this.onAttributeChange(field);
|
|
}
|
|
}
|
|
//action 'hideSetting' need to do
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
},
|
|
|
|
prepareBlockOptions: function(options)
|
|
{
|
|
options = isPlainObject(options) ? options : {};
|
|
options = clone(options);
|
|
options.name = BX.Landing.Loc.getMessage("BLOCK_STYLE_OPTIONS");
|
|
|
|
if (!isPlainObject(options.type) && !isString(options.type) && !isArray(options.type))
|
|
{
|
|
options.type = [
|
|
"display",
|
|
"background",
|
|
"padding-top",
|
|
"padding-bottom",
|
|
"padding-left",
|
|
"padding-right",
|
|
"margin-top"
|
|
];
|
|
}
|
|
|
|
return options;
|
|
},
|
|
|
|
|
|
/**
|
|
* Creates attribute field
|
|
* @param {object} options
|
|
* @param {?string} selector
|
|
* @param {function} [onAttributeChange]
|
|
* @return {BX.Landing.UI.Field.BaseField}
|
|
*/
|
|
createAttributeField: function(options, selector, onAttributeChange)
|
|
{
|
|
var fieldFactory = this.createFieldFactory(selector, onAttributeChange);
|
|
var element = this.getElementBySelector(selector);
|
|
|
|
if (!element && selector.includes("@"))
|
|
{
|
|
var selectorFragments = selector.split("@");
|
|
var elements = this.getElementsBySelector(selectorFragments[0]);
|
|
|
|
if (elements.length && elements[parseInt(selectorFragments[1])])
|
|
{
|
|
element = elements[parseInt(selectorFragments[1])];
|
|
}
|
|
}
|
|
|
|
var fieldOptions = clone(options);
|
|
|
|
if (fieldOptions.value === null || fieldOptions.value === undefined)
|
|
{
|
|
fieldOptions.value = '';
|
|
if (fieldOptions['default_value'] !== null)
|
|
{
|
|
fieldOptions.value = fieldOptions['default_value'];
|
|
}
|
|
}
|
|
|
|
if (element)
|
|
{
|
|
var value = data(element, fieldOptions.attribute);
|
|
|
|
if (BX.Type.isNil(value))
|
|
{
|
|
value = attr(element, fieldOptions.attribute);
|
|
}
|
|
|
|
if (value !== null)
|
|
{
|
|
fieldOptions.value = value;
|
|
}
|
|
}
|
|
|
|
return fieldFactory.create(fieldOptions);
|
|
},
|
|
|
|
|
|
onAttributeChange: function(field)
|
|
{
|
|
BX.Event.EventEmitter.emit('BX.Landing.UI.Form.StyleForm:attributeChange', field);
|
|
clearTimeout(this.attributeChangeTimeout);
|
|
|
|
if (!this.requestData)
|
|
{
|
|
this.requestData = {};
|
|
}
|
|
|
|
this.appendAttrFieldValue(this.requestData, field);
|
|
|
|
Promise.resolve(this.requestData)
|
|
.then(this.applyAttributeChanges.bind(this))
|
|
.then(this.saveChanges.bind(this))
|
|
// Reload only blocks with component
|
|
.then(this.reload.bind(this))
|
|
.then(function() {
|
|
this.requestData = null;
|
|
}.bind(this));
|
|
},
|
|
|
|
|
|
appendSettingsFieldValue: function(requestData, field)
|
|
{
|
|
requestData["settings"] = requestData["settings"] || {};
|
|
requestData["settings"][field.attribute] = field.getValue();
|
|
return requestData;
|
|
},
|
|
|
|
|
|
/**
|
|
* @param {object} requestData
|
|
* @param {BX.Landing.UI.Field.BaseField} field
|
|
* @return {object}
|
|
*/
|
|
appendAttrFieldValue: function(requestData, field)
|
|
{
|
|
var selector = this.makeAbsoluteSelector(field.selector);
|
|
var value = field.getValue();
|
|
|
|
requestData[selector] = requestData[selector] || {};
|
|
requestData[selector]["attrs"] = requestData[selector]["attrs"] || {};
|
|
if(BX.Type.isArray(field.attribute))
|
|
{
|
|
field.attribute.forEach(function(attr){
|
|
var attrData = attr.replace('data-', '');
|
|
var itemValue = value[attrData];
|
|
if(itemValue !== undefined)
|
|
{
|
|
try {
|
|
itemValue = encodeDataValue(itemValue);
|
|
} catch(e) {
|
|
itemValue = field.getValue()[attrData];
|
|
}
|
|
requestData[selector]["attrs"][attr] = itemValue;
|
|
}
|
|
});
|
|
}
|
|
else
|
|
{
|
|
try {
|
|
value = encodeDataValue(value);
|
|
} catch(e) {
|
|
value = field.getValue();
|
|
}
|
|
requestData[selector]["attrs"][field.attribute] = value;
|
|
}
|
|
return requestData;
|
|
},
|
|
|
|
|
|
appendMenuValue: function(requestData, menu)
|
|
{
|
|
requestData[menu.code] = menu.serialize();
|
|
return requestData;
|
|
},
|
|
|
|
|
|
/**
|
|
* Gets element by selector
|
|
* @param selector
|
|
* @return {*}
|
|
*/
|
|
getElementBySelector: function(selector)
|
|
{
|
|
if (this.isBlockSelector(selector))
|
|
{
|
|
return this.content;
|
|
}
|
|
|
|
var element;
|
|
|
|
try
|
|
{
|
|
element = this.node.querySelector(selector);
|
|
}
|
|
catch (err)
|
|
{
|
|
element = null;
|
|
}
|
|
|
|
return element;
|
|
},
|
|
|
|
getElementsBySelector: function(selector)
|
|
{
|
|
if (this.isBlockSelector(selector))
|
|
{
|
|
return [this.content];
|
|
}
|
|
|
|
var elements;
|
|
|
|
try
|
|
{
|
|
elements = slice(this.node.querySelectorAll(selector));
|
|
}
|
|
catch (err)
|
|
{
|
|
elements = [];
|
|
}
|
|
|
|
return elements;
|
|
},
|
|
|
|
|
|
/**
|
|
* Checks that this selector is block selector
|
|
* @param {string} selector
|
|
* @return {boolean}
|
|
*/
|
|
isBlockSelector: function(selector)
|
|
{
|
|
return !selector || selector === this.selector || ("#block"+this.id) === selector;
|
|
},
|
|
|
|
|
|
/**
|
|
* Creates FieldFactory instance
|
|
* @param {?string} selector
|
|
* @param {function} [onChange]
|
|
* @return {BX.Landing.UI.Factory.FieldFactory}
|
|
*/
|
|
createFieldFactory: function(selector, onChange)
|
|
{
|
|
return new BX.Landing.UI.Factory.FieldFactory({
|
|
selector: !this.isBlockSelector(selector) ? this.makeRelativeSelector(selector) : selector,
|
|
uploadParams: {
|
|
action: "Block::uploadFile",
|
|
block: this.id,
|
|
lid: BX.Landing.Main.getInstance().id,
|
|
id: BX.Landing.Main.getInstance().options.site_id
|
|
},
|
|
linkOptions: {
|
|
siteId: BX.Landing.Main.getInstance().options.site_id,
|
|
landingId: BX.Landing.Main.getInstance().id,
|
|
filter: {
|
|
"=TYPE": BX.Landing.Main.getInstance().options.params.type
|
|
}
|
|
},
|
|
onValueChange: onChange || (function() {})
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* Delete current block.
|
|
* @param {?boolean} [preventHistory = false]
|
|
* @return {void}
|
|
*/
|
|
deleteBlock: function(preventHistory)
|
|
{
|
|
var button = this.panels.get("block_action").buttons.get("remove");
|
|
button.loader = button.loader || new BX.Loader({target: button.layout, size: 28});
|
|
button.loader.show();
|
|
addClass(button.text, "landing-ui-hide-icon");
|
|
|
|
void style(button.loader.layout.querySelector(".main-ui-loader-svg-circle"), {
|
|
"stroke-width": "4px"
|
|
});
|
|
void style(button.loader.layout.querySelector(".main-ui-loader-svg"), {
|
|
"margin-top": "-10px"
|
|
});
|
|
|
|
BX.Landing.UI.Panel.EditorPanel.getInstance().hide();
|
|
|
|
if (this.blockActionsMenu)
|
|
{
|
|
BX.Main.MenuManager.destroy(this.blockActionsMenu.id);
|
|
}
|
|
|
|
if (this.sidebarActionsMenu)
|
|
{
|
|
BX.Main.MenuManager.destroy(this.sidebarActionsMenu.id);
|
|
}
|
|
|
|
if (String(window.localStorage.getItem("landingBlockId")) === String(this.id))
|
|
{
|
|
window.localStorage.removeItem("landingBlockId");
|
|
}
|
|
|
|
let removePromise = Promise.resolve();
|
|
if ((isBoolean(preventHistory) && !preventHistory) || !isBoolean(preventHistory))
|
|
{
|
|
removePromise = BX.Landing.Backend.getInstance()
|
|
.action(
|
|
"Landing::markDeletedBlock",
|
|
{block: this.id, lid: this.lid, siteId: this.siteId, preventHistory: 0},
|
|
{code: this.manifest.code}
|
|
)
|
|
.then(result => {
|
|
// Change history steps
|
|
BX.Landing.History.getInstance().push();
|
|
|
|
return result;
|
|
});
|
|
}
|
|
removePromise
|
|
.then(() => {
|
|
button.loader.hide();
|
|
removeClass(button.text, "landing-ui-hide-icon");
|
|
|
|
var event = this.createEvent();
|
|
fireCustomEvent("BX.Landing.Block:remove", [event]);
|
|
|
|
slice(this.node.querySelectorAll(".landing-ui-panel")).forEach(remove);
|
|
|
|
BX.Landing.PageObject.getBlocks().remove(this);
|
|
remove(this.node);
|
|
fireCustomEvent("Landing.Block:onAfterDelete", [this]);
|
|
fireCustomEvent("BX.Landing.Block:afterRemove", [event]);
|
|
}, () => {
|
|
button.loader.hide();
|
|
removeClass(button.text, "landing-ui-hide-icon");
|
|
});
|
|
},
|
|
|
|
getFormEditorAddBlockTour: function()
|
|
{
|
|
var rootWindow = BX.Landing.PageObject.getRootWindow();
|
|
return new rootWindow.BX.UI.Tour.Guide({
|
|
steps: [
|
|
{
|
|
target: '[data-id="save_settings"]',
|
|
title: BX.Landing.Loc.getMessage('LANDING_FORM_EDITOR_ADD_BLOCK_TOUR_STEP_1_TITLE'),
|
|
text: BX.Landing.Loc.getMessage('LANDING_FORM_EDITOR_ADD_BLOCK_TOUR_STEP_1_TEXT'),
|
|
},
|
|
],
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Shows blocks list panel
|
|
*/
|
|
addBlockAfterThis: function()
|
|
{
|
|
var formSettingsPanel =
|
|
(BX.Landing.UI && BX.Landing.UI.Panel && BX.Landing.UI.Panel.FormSettingsPanel)
|
|
? BX.Landing.UI.Panel.FormSettingsPanel.getInstance()
|
|
: null;
|
|
if (
|
|
this.isCrmFormPage()
|
|
&& formSettingsPanel
|
|
&& formSettingsPanel.isShown()
|
|
)
|
|
{
|
|
if (!formSettingsPanel.isChanged())
|
|
{
|
|
formSettingsPanel
|
|
.hide()
|
|
.then(function() {
|
|
BX.Landing.Main.getInstance().showBlocksPanel(this, null, null, true);
|
|
}.bind(this));
|
|
}
|
|
else
|
|
{
|
|
this.getFormEditorAddBlockTour().start();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BX.Landing.Main.getInstance().showBlocksPanel(this);
|
|
}
|
|
},
|
|
|
|
addBlockBeforeThis: function()
|
|
{
|
|
var formSettingsPanel = BX.Landing.UI.Panel.FormSettingsPanel.getInstance();
|
|
if (
|
|
this.isCrmFormPage()
|
|
&& formSettingsPanel.isShown()
|
|
)
|
|
{
|
|
if (!formSettingsPanel.isChanged())
|
|
{
|
|
formSettingsPanel
|
|
.hide()
|
|
.then(function() {
|
|
BX.Landing.Main.getInstance().showBlocksPanel(this, null, null, true);
|
|
}.bind(this));
|
|
}
|
|
else
|
|
{
|
|
this.getFormEditorAddBlockTour().start();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BX.Landing.Main.getInstance().showBlocksPanel(this, null, null, true);
|
|
}
|
|
},
|
|
|
|
getFormEditorDesignTour: function()
|
|
{
|
|
var rootWindow = BX.Landing.PageObject.getRootWindow();
|
|
return new rootWindow.BX.UI.Tour.Guide({
|
|
steps: [
|
|
{
|
|
target: '[data-id="save_settings"]',
|
|
title: BX.Landing.Loc.getMessage('LANDING_FORM_EDITOR_FORM_DESIGN_TOUR_STEP_1_TITLE'),
|
|
text: BX.Landing.Loc.getMessage('LANDING_FORM_EDITOR_FORM_DESIGN_TOUR_STEP_1_TEXT'),
|
|
},
|
|
],
|
|
});
|
|
},
|
|
|
|
onFormDesignClick: function()
|
|
{
|
|
var formSelector = Object.entries(this.manifest.style.nodes).reduce(function(acc, item) {
|
|
if (item[1].type === 'crm-form')
|
|
{
|
|
return item[0];
|
|
}
|
|
|
|
return acc;
|
|
}, null);
|
|
|
|
BX.Landing.PageObject.getInstance().design()
|
|
.then((stylePanel) => {
|
|
if (formSelector)
|
|
{
|
|
this.showStylePanel(formSelector, stylePanel.blockId);
|
|
}
|
|
else
|
|
{
|
|
this.showStylePanel(this.selector, stylePanel.blockId);
|
|
}
|
|
});
|
|
},
|
|
|
|
|
|
/**
|
|
* Handles node content change event
|
|
* @param {BX.Landing.Node} node
|
|
* @param {?boolean} [preventHistory = false]
|
|
*/
|
|
onNodeChange: function(node, preventHistory)
|
|
{
|
|
const event = this.createEvent({node: node.node});
|
|
fireCustomEvent("BX.Landing.Block:Node:update", [event]);
|
|
|
|
if (!node.isSavePrevented())
|
|
{
|
|
clearTimeout(this.changeTimeout);
|
|
this.changedNodes.add(node);
|
|
|
|
this.changeTimeout = setTimeout(() => {
|
|
if ((isBoolean(preventHistory) && !preventHistory) || !isBoolean(preventHistory))
|
|
{
|
|
BX.Landing.Backend.getInstance()
|
|
.action(
|
|
"Landing\\Block::updateNodes",
|
|
{
|
|
block: this.id,
|
|
data: this.changedNodes.fetchValues(),
|
|
additional: this.changedNodes.fetchAdditionalValues(),
|
|
lid: this.lid,
|
|
siteId: this.siteId,
|
|
preventHistory: 0,
|
|
},
|
|
{code: this.manifest.code}
|
|
);
|
|
}
|
|
this.changedNodes.clear();
|
|
}, 300);
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Checks that data contains pseudo selector
|
|
* @param {object} data
|
|
* @return {boolean}
|
|
*/
|
|
containsPseudoSelector: function(data)
|
|
{
|
|
return Object.keys(data).some(function(selector) {
|
|
var result;
|
|
|
|
if (selector === "cards")
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (selector === "dynamicState")
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (
|
|
BX.type.isPlainObject(this.manifest.menu)
|
|
&& selector in this.manifest.menu
|
|
)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (selector !== "#block" + this.id && selector !== "")
|
|
{
|
|
result = !this.node.querySelector(selector);
|
|
}
|
|
else
|
|
{
|
|
result = false;
|
|
}
|
|
}
|
|
catch(err)
|
|
{
|
|
result = !isNodeSelector(selector);
|
|
}
|
|
|
|
return result;
|
|
}, this);
|
|
},
|
|
|
|
/**
|
|
* Check if data contains attributes, that require block reload
|
|
* @param {object} data
|
|
* @return {boolean}
|
|
*/
|
|
containsReloadRequireAttributes: function(data)
|
|
{
|
|
if (
|
|
isPlainObject(data)
|
|
&& isPlainObject(this.manifest)
|
|
&& isPlainObject(this.manifest.attrs)
|
|
)
|
|
{
|
|
return Object.keys(this.manifest.attrs).some(function (selector)
|
|
{
|
|
return this.manifest.attrs[selector].some(function (attr)
|
|
{
|
|
if (
|
|
attr.requireReload
|
|
&& isPlainObject(data[selector])
|
|
&& isPlainObject(data[selector].attrs)
|
|
&& data[selector].attrs[attr.attribute]
|
|
)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}, this);
|
|
}, this);
|
|
}
|
|
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* Applies content changes
|
|
* @param {object} data
|
|
* @return {Promise<Object>}
|
|
*/
|
|
applyContentChanges: function(data)
|
|
{
|
|
if (!isPlainObject(data))
|
|
{
|
|
return Promise.reject(
|
|
new TypeError("BX.Landing.Block.applyContentChanges: data isn't object")
|
|
);
|
|
}
|
|
|
|
var eventData = clone(data);
|
|
|
|
Object.keys(eventData).forEach(function(selector) {
|
|
if (!isNodeSelector(selector))
|
|
{
|
|
delete eventData[selector];
|
|
}
|
|
});
|
|
|
|
if (!isEmpty(eventData))
|
|
{
|
|
var event = this.createEvent({data: eventData});
|
|
fireCustomEvent(window, "BX.Landing.Block:beforeApplyContentChanges", [event]);
|
|
}
|
|
|
|
var valuePromises = [];
|
|
|
|
Object.keys(data).forEach(function(selector) {
|
|
if (isNodeSelector(selector))
|
|
{
|
|
var node = this.nodes.getBySelector(selector);
|
|
|
|
if (node)
|
|
{
|
|
var valuePromise = node.setValue(data[selector], true, true);
|
|
node.preventSave(false);
|
|
if (valuePromise)
|
|
{
|
|
valuePromises.push(valuePromise);
|
|
valuePromise.then(function() {
|
|
data[selector] = node.getValue();
|
|
});
|
|
}
|
|
else
|
|
{
|
|
data[selector] = node.getValue();
|
|
}
|
|
}
|
|
}
|
|
}, this);
|
|
|
|
return Promise
|
|
.all(valuePromises)
|
|
.then(function() {
|
|
return data;
|
|
});
|
|
},
|
|
|
|
applyMenuChanges: function(data)
|
|
{
|
|
if (!isPlainObject(data))
|
|
{
|
|
return Promise.reject(
|
|
new TypeError("BX.Landing.Block.applyContentChanges: data isn't object")
|
|
);
|
|
}
|
|
|
|
var menuKeys = Object.keys(this.manifest.menu || {});
|
|
if (menuKeys.length > 0)
|
|
{
|
|
menuKeys.forEach(function(code) {
|
|
if (code in data)
|
|
{
|
|
var menu = this.menu.find(function(menuItem) {
|
|
return menuItem.code === code;
|
|
});
|
|
|
|
menu.rebuild(data[code]);
|
|
}
|
|
}.bind(this));
|
|
|
|
data.forceReload = true;
|
|
}
|
|
|
|
this.initMenu();
|
|
|
|
return Promise.resolve(data);
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @param data
|
|
* @return {Promise}
|
|
*/
|
|
applyCardsChanges: function(data)
|
|
{
|
|
if (!isPlainObject(data))
|
|
{
|
|
return Promise.reject(
|
|
new TypeError("BX.Landing.Block.applyCardsChanges: data isn't object")
|
|
);
|
|
}
|
|
|
|
var nodePromises = [];
|
|
|
|
if ('cards' in data && isPlainObject(data.cards))
|
|
{
|
|
fireCustomEvent("BX.Landing.Block:Cards:beforeUpdate", [
|
|
this.createEvent()
|
|
]);
|
|
|
|
var map = {};
|
|
|
|
Object.keys(data.cards)
|
|
.forEach(function(code) {
|
|
var container = this.node.querySelector(code).parentElement;
|
|
var oldCards = this.node.querySelectorAll(code);
|
|
|
|
// Card data
|
|
var values = data.cards[code].values;
|
|
var presets = data.cards[code].presets;
|
|
var indexes = data.cards[code].indexes;
|
|
var source = data.cards[code].source;
|
|
|
|
// Remove old cards
|
|
container.innerHTML = "";
|
|
|
|
// Make source
|
|
Object.keys(values)
|
|
.forEach(function(index) {
|
|
source[index] = {value: 0, type: "card"};
|
|
|
|
if (!isEmpty(presets) && !isEmpty(presets[index]))
|
|
{
|
|
if (
|
|
!oldCards[indexes[index]]
|
|
|| !BX.type.isString(indexes[index])
|
|
)
|
|
{
|
|
source[index].type = "preset";
|
|
source[index].value = presets[index];
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (oldCards[indexes[index]])
|
|
{
|
|
source[index].type = "card";
|
|
source[index].value = indexes[index];
|
|
}
|
|
}, this);
|
|
|
|
// Make new cards
|
|
Object.keys(values)
|
|
.forEach(function(index) {
|
|
if (source[index].type === "preset")
|
|
{
|
|
var preset = this.manifest.cards[code]["presets"][source[index].value]["html"];
|
|
append(htmlToElement(preset), container);
|
|
return;
|
|
}
|
|
|
|
append(clone(oldCards[source[index].value]), container);
|
|
}, this);
|
|
|
|
// Reinitialize entities
|
|
this.initNodes();
|
|
this.initCards();
|
|
this.initGroups();
|
|
|
|
// Apply nodes values
|
|
Object.keys(values)
|
|
.forEach(function(index) {
|
|
var card = values[index];
|
|
|
|
Object.keys(card)
|
|
.forEach(function(key) {
|
|
map[key] = key in map ? map[key] + 1 : 0;
|
|
|
|
var node = this.nodes.getBySelector(join(key, "@", map[key]));
|
|
|
|
if (node)
|
|
{
|
|
var newValue = card[key];
|
|
var oldValue = node.getValue();
|
|
|
|
if (isPlainObject(newValue) && isString(newValue.url))
|
|
{
|
|
newValue.url = decodeDataValue(newValue.url);
|
|
}
|
|
|
|
if (isPlainObject(oldValue) && isString(oldValue.url))
|
|
{
|
|
oldValue.url = decodeDataValue(oldValue.url);
|
|
}
|
|
|
|
try
|
|
{
|
|
newValue = JSON.stringify(newValue);
|
|
} catch (e)
|
|
{
|
|
newValue = card[key];
|
|
}
|
|
|
|
try
|
|
{
|
|
oldValue = JSON.stringify(oldValue);
|
|
} catch (e)
|
|
{
|
|
oldValue = node.getValue();
|
|
}
|
|
|
|
var nodePromise = node.setValue(card[key], true, true) || Promise.resolve();
|
|
node.preventSave(false);
|
|
nodePromise.then(function(selectorKey, mapKey, cardKey) {
|
|
card[join(selectorKey, "@", mapKey)] = node.getValue();
|
|
|
|
if (node.manifest.type === "img" || node.manifest.type === "icon")
|
|
{
|
|
card[join(selectorKey, "@", mapKey)]["url"] = encodeDataValue(cardKey["url"]);
|
|
}
|
|
|
|
delete card[key];
|
|
}.bind(this, key, map[key], card[key]));
|
|
|
|
nodePromises.push(nodePromise);
|
|
}
|
|
}, this);
|
|
}, this);
|
|
|
|
Promise
|
|
.all(nodePromises)
|
|
.then(function() {
|
|
// Reinitialize additional entities
|
|
this.initCardsLabels();
|
|
this.initStyles();
|
|
|
|
// Remove unnecessary
|
|
delete data.cards[code].presets;
|
|
delete data.cards[code].indexes;
|
|
}.bind(this));
|
|
}, this);
|
|
|
|
Promise
|
|
.all(nodePromises)
|
|
.then(function() {
|
|
fireCustomEvent("BX.Landing.Block:Cards:update", [
|
|
this.createEvent()
|
|
]);
|
|
}.bind(this));
|
|
}
|
|
|
|
return Promise
|
|
.all(nodePromises)
|
|
.then(function() {
|
|
return Promise.resolve(data);
|
|
});
|
|
},
|
|
|
|
|
|
applySettingsChanges: function(requestData)
|
|
{
|
|
if (!isPlainObject(requestData))
|
|
{
|
|
return Promise.reject(
|
|
new TypeError("BX.Landing.Block.applyAttributeChanges: requestData isn't object")
|
|
);
|
|
}
|
|
|
|
if (isPlainObject(requestData.settings) &&
|
|
!isEmpty(requestData.settings))
|
|
{
|
|
if (requestData.settings.id)
|
|
{
|
|
this.content.id = requestData.settings.id;
|
|
}
|
|
}
|
|
|
|
return Promise.resolve(requestData);
|
|
},
|
|
|
|
|
|
/**
|
|
* Applies attributes changes
|
|
* @param {Object} requestData
|
|
*/
|
|
applyAttributeChanges: function(requestData)
|
|
{
|
|
if (!isPlainObject(requestData))
|
|
{
|
|
return Promise.reject(
|
|
new TypeError("BX.Landing.Block.applyAttributeChanges: requestData isn't object")
|
|
);
|
|
}
|
|
|
|
var eventData = clone(requestData);
|
|
|
|
Object.keys(requestData).forEach(function(selector) {
|
|
if (!(isPlainObject(requestData[selector]) && "attrs" in requestData[selector]))
|
|
{
|
|
delete eventData[selector];
|
|
}
|
|
});
|
|
|
|
if (!isEmpty(eventData))
|
|
{
|
|
var event = this.createEvent({data: eventData});
|
|
fireCustomEvent(window, "BX.Landing.Block:beforeApplyAttributesChanges", [event]);
|
|
}
|
|
|
|
var self = this;
|
|
|
|
Object.keys(requestData).forEach(function(selector) {
|
|
if (isPlainObject(requestData[selector]) && "attrs" in requestData[selector])
|
|
{
|
|
var elements = self.getElementsBySelector(selector);
|
|
|
|
if (!elements.length && selector.includes("@"))
|
|
{
|
|
var selectorFragments = selector.split("@");
|
|
|
|
elements = self.getElementsBySelector(selectorFragments[0]);
|
|
|
|
if (elements[parseInt(selectorFragments[1])])
|
|
{
|
|
elements = [elements[parseInt(selectorFragments[1])]];
|
|
}
|
|
}
|
|
|
|
Object.keys(requestData[selector].attrs).forEach(function(attribute) {
|
|
elements.forEach(function(element) {
|
|
var decodedValue = decodeDataValue(requestData[selector]["attrs"][attribute]);
|
|
|
|
if (!attribute.includes("data-"))
|
|
{
|
|
attr(element, attribute, decodedValue);
|
|
}
|
|
else
|
|
{
|
|
data(element, attribute, decodedValue);
|
|
}
|
|
|
|
fireCustomEvent("BX.Landing.Block:Node:updateAttr", [
|
|
self.createEvent({
|
|
node: element,
|
|
data: requestData[selector]["attrs"]
|
|
})
|
|
]);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
|
|
return Promise.resolve(requestData);
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
* Saves changes on backend
|
|
* @param {Object} data
|
|
* @return {Promise<Object>}
|
|
*/
|
|
saveChanges: function(data, preventHistory)
|
|
{
|
|
if (!isPlainObject(data))
|
|
{
|
|
return Promise.reject(
|
|
new TypeError("BX.Landing.Block.saveChanges: data isn't object")
|
|
);
|
|
}
|
|
|
|
if (Object.keys(data).length)
|
|
{
|
|
var updateNodeParams = {code: this.manifest.code};
|
|
var updateNodesData = {block: this.id, data: data, lid: this.lid, siteId: this.siteId};
|
|
var batch = {};
|
|
|
|
if (isPlainObject(data.settings) &&
|
|
!isEmpty(data.settings))
|
|
{
|
|
if (data.settings.id)
|
|
{
|
|
batch.changeAnchor = {
|
|
action: "Block::changeAnchor",
|
|
data: {
|
|
block: this.id,
|
|
lid: this.lid,
|
|
data: data.settings.id
|
|
}
|
|
};
|
|
}
|
|
|
|
delete data.settings;
|
|
}
|
|
|
|
if (!isEmpty(data))
|
|
{
|
|
var nodes = new NodeCollection();
|
|
|
|
Object.keys(updateNodesData).forEach(function(selector) {
|
|
nodes.add(this.nodes.getBySelector(selector));
|
|
}, this);
|
|
|
|
batch.updateNodes = {
|
|
action: "Block::updateNodes",
|
|
data: updateNodesData,
|
|
additional: nodes.fetchAdditionalValues()
|
|
};
|
|
}
|
|
|
|
if (!isEmpty(data.cards))
|
|
{
|
|
var cardsData = clone(data.cards);
|
|
|
|
delete data.cards;
|
|
|
|
var cardsSelectors = BX.Landing.Utils.arrayUnique(Object.keys(cardsData));
|
|
cardsSelectors = cardsSelectors.length === 1 ? cardsSelectors + " *" : cardsSelectors.join(" *, ");
|
|
var cardsNodesAdditionalValues = this.nodes.matches(cardsSelectors).fetchAdditionalValues();
|
|
|
|
batch.updateCards = {
|
|
action: "Block::updateCards",
|
|
data: {
|
|
block: this.id,
|
|
lid: this.lid,
|
|
siteId: this.siteId,
|
|
data: cardsData,
|
|
additional: cardsNodesAdditionalValues
|
|
}
|
|
};
|
|
}
|
|
|
|
if (data.cardsFirst)
|
|
{
|
|
var oldBatch = batch;
|
|
batch = {};
|
|
|
|
if (oldBatch.changeAnchor)
|
|
{
|
|
batch.changeAnchor = oldBatch.changeAnchor;
|
|
}
|
|
|
|
if (oldBatch.updateCards)
|
|
{
|
|
batch.updateCards = oldBatch.updateCards;
|
|
}
|
|
|
|
if (oldBatch.updateNodes)
|
|
{
|
|
batch.updateNodes = oldBatch.updateNodes;
|
|
}
|
|
|
|
delete data.cardsFirst;
|
|
}
|
|
|
|
if ((isBoolean(preventHistory) && !preventHistory) || !isBoolean(preventHistory))
|
|
{
|
|
return BX.Landing.Backend.getInstance()
|
|
.batch("Landing\\Block::updateNodes", batch, updateNodeParams)
|
|
.then(() => {
|
|
BX.Landing.History.getInstance().push();
|
|
})
|
|
.then(function() {
|
|
return Promise.resolve(data);
|
|
});
|
|
}
|
|
}
|
|
|
|
return Promise.resolve(data);
|
|
},
|
|
|
|
|
|
/**
|
|
* Fetches request data from content panel
|
|
* @param {BX.Landing.UI.Panel.BasePanel} panel
|
|
* @param {boolean} all
|
|
* @return {Promise<Object>}
|
|
*/
|
|
fetchRequestData: function(panel, all)
|
|
{
|
|
var requestData = {};
|
|
var forms = {};
|
|
|
|
var fetchFields = function(collection, all) {
|
|
return all ? collection : collection.fetchChanges();
|
|
};
|
|
|
|
forms.attrs = new FormCollection();
|
|
forms.cards = new FormCollection();
|
|
forms.dynamicCards = new FormCollection();
|
|
forms.dynamicBlock = new FormCollection();
|
|
forms.content = new FormCollection();
|
|
forms.settings = new FormCollection();
|
|
forms.menu = new FormCollection();
|
|
|
|
panel.forms
|
|
.forEach(function(form) {
|
|
forms[form.type].push(form);
|
|
});
|
|
|
|
fetchFields(forms.content.fetchFields(), all)
|
|
.reduce(proxy(this.appendContentFieldValue, this), requestData);
|
|
|
|
var attrFields = new BaseCollection();
|
|
|
|
forms.cards.forEach(function(form) {
|
|
form.childForms.forEach(function(childForm) {
|
|
childForm.fields.forEach(function(field) {
|
|
if (field.type === "attr")
|
|
{
|
|
attrFields.add(field);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
fetchFields(attrFields, true)
|
|
.reduce(proxy(this.appendAttrFieldValue, this), requestData);
|
|
|
|
forms.cards
|
|
.reduce(proxy(this.appendCardsFormValue, this), requestData);
|
|
|
|
forms.dynamicCards
|
|
.reduce(proxy(this.appendDynamicCardsFormValue, this), requestData);
|
|
|
|
forms.dynamicBlock
|
|
.reduce(proxy(this.appendDynamicBlockFormValue, this), requestData);
|
|
|
|
fetchFields(forms.attrs.fetchFields(), all)
|
|
.reduce(proxy(this.appendAttrFieldValue, this), requestData);
|
|
|
|
fetchFields(forms.settings.fetchFields(), all)
|
|
.reduce(proxy(this.appendSettingsFieldValue, this), requestData);
|
|
|
|
forms.menu
|
|
.reduce(proxy(this.appendMenuValue, this), requestData);
|
|
|
|
requestData.dynamicState = Object.keys(this.manifest.cards)
|
|
.reduce(function(acc, cardsCode) {
|
|
acc[cardsCode] = (
|
|
BX.type.isPlainObject(requestData.dynamicParams)
|
|
&& cardsCode in requestData.dynamicParams
|
|
);
|
|
return acc;
|
|
}, {});
|
|
|
|
requestData.dynamicState.wrapper = (
|
|
!!requestData.dynamicParams
|
|
&& "wrapper" in requestData.dynamicParams
|
|
);
|
|
|
|
return Promise.resolve(requestData);
|
|
},
|
|
|
|
|
|
/**
|
|
* Appends content field value to request data
|
|
* @param {object} requestData
|
|
* @param {BX.Landing.UI.Field.BaseField} field
|
|
* @return {object}
|
|
*/
|
|
appendContentFieldValue: function(requestData, field)
|
|
{
|
|
return requestData[field.selector] = field.getValue(), requestData;
|
|
},
|
|
|
|
|
|
/**
|
|
* Appends cards value to request data
|
|
* @param {object} requestData
|
|
* @param {BX.Landing.UI.Form.CardsForm} form
|
|
* @return {object}
|
|
*/
|
|
appendCardsFormValue: function(requestData, form)
|
|
{
|
|
requestData.cards = requestData.cards || {};
|
|
requestData.cards[form.code] = {};
|
|
requestData.cards[form.code]['values'] = form.serialize();
|
|
requestData.cards[form.code]['presets'] = form.getUsedPresets();
|
|
requestData.cards[form.code]['indexes'] = form.getIndexesMap();
|
|
requestData.cards[form.code]['source'] = {};
|
|
|
|
return requestData;
|
|
},
|
|
|
|
appendDynamicCardsFormValue: function(requestData, form)
|
|
{
|
|
requestData.dynamicParams = requestData.dynamicParams || {};
|
|
requestData.dynamicParams[form.code] = {};
|
|
requestData.dynamicParams[form.code] = form.serialize();
|
|
|
|
return requestData;
|
|
},
|
|
|
|
appendDynamicBlockFormValue: function(requestData, form)
|
|
{
|
|
requestData.dynamicParams = requestData.dynamicParams || {};
|
|
requestData.dynamicParams.wrapper = form.serialize();
|
|
|
|
return requestData;
|
|
},
|
|
|
|
|
|
/**
|
|
* Reloads block
|
|
* @todo Refactoring
|
|
* @param {object} data
|
|
* @return {Promise}
|
|
*/
|
|
reload: function(data)
|
|
{
|
|
if (isPlainObject(data))
|
|
{
|
|
var isNeedReload = this.containsPseudoSelector(data) || this.containsReloadRequireAttributes(data);
|
|
if (!isNeedReload)
|
|
{
|
|
return Promise.resolve(data);
|
|
}
|
|
}
|
|
|
|
var loader = new BX.Loader({target: this.parent.parentElement, color: "rgba(255, 255, 255, .8)"});
|
|
loader.layout.style.position = "fixed";
|
|
loader.layout.style.zIndex = "999";
|
|
loader.show();
|
|
BX.Landing.Main.getInstance().showOverlay();
|
|
|
|
var self = this;
|
|
return BX.Landing.Backend.getInstance()
|
|
.action("Block::getContent", {
|
|
block: this.id,
|
|
lid: this.lid,
|
|
siteId: this.siteId,
|
|
editMode: 1
|
|
})
|
|
.then(function(response) {
|
|
var event = this.createEvent();
|
|
fireCustomEvent("BX.Landing.Block:remove", [event]);
|
|
|
|
BX.Landing.Main.getInstance().currentBlock = self;
|
|
BX.Landing.Main.getInstance().currentArea = self.parent;
|
|
return BX.Landing.Main.getInstance().addBlock(response, true);
|
|
}.bind(this))
|
|
.then(function(block) {
|
|
self.node = block;
|
|
return Promise.resolve(data);
|
|
})
|
|
.then(function(data) {
|
|
return new Promise(function(resolve) {
|
|
setTimeout(function() {
|
|
resolve(data);
|
|
loader.hide();
|
|
BX.Landing.Main.getInstance().hideOverlay();
|
|
}, 800);
|
|
});
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Handles content save event
|
|
*/
|
|
onContentSave: function()
|
|
{
|
|
var contentPanel = this.panels.get("content_edit");
|
|
|
|
if (contentPanel)
|
|
{
|
|
contentPanel.hide();
|
|
|
|
this.fetchRequestData(contentPanel)
|
|
.then(function(requestData) {
|
|
fireCustomEvent("BX.Landing.Block:onContentSave", [this.id]);
|
|
return Object.assign(
|
|
{},
|
|
requestData,
|
|
{
|
|
cardsFirst: true
|
|
}
|
|
);
|
|
}.bind(this))
|
|
.then(this.updateBlockState.bind(this));
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Handles content cancel edit event
|
|
*/
|
|
onContentCancel: function()
|
|
{
|
|
this.panels.get("content_edit").hide();
|
|
this.tmpContent.innerHTML = "";
|
|
this.anchor = this.savedAnchor;
|
|
},
|
|
|
|
|
|
/**
|
|
* Gets cards CSS selector
|
|
* @return {string}
|
|
*/
|
|
getCardsSelector: function()
|
|
{
|
|
var cardsSelectors = Object.keys(this.manifest.cards);
|
|
var allCards = join(cardsSelectors.join(","), ", ");
|
|
var allCardsChild = join(cardsSelectors.join(" *,"), " *");
|
|
|
|
return join(allCards, allCardsChild);
|
|
},
|
|
|
|
/**
|
|
* Style change handler
|
|
* @param event
|
|
* @param {boolean} [preventHistory = false] - Add this action to history or not. By default - add
|
|
*/
|
|
onStyleInput: function(event, preventHistory)
|
|
{
|
|
this.saveStyles(preventHistory);
|
|
|
|
const styleEvent = this.createEvent(event);
|
|
fireCustomEvent("BX.Landing.Block:updateStyle", [styleEvent]);
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @param {object} options
|
|
* @return {BX.Landing.UI.Form.BaseForm}
|
|
*/
|
|
getBlockEditForm: function(options)
|
|
{
|
|
var preparedOptions = {};
|
|
|
|
if (BX.type.isPlainObject(options))
|
|
{
|
|
preparedOptions = Object.assign({}, options);
|
|
}
|
|
|
|
var blockNodes = preparedOptions.nodes || this.nodes;
|
|
|
|
// exclude nodes from cards
|
|
if (this.cards.length > 0 && !options.hideCheckbox)
|
|
{
|
|
blockNodes = this.nodes.notMatches(
|
|
this.getCardsSelector()
|
|
);
|
|
}
|
|
|
|
var selectors = Object.keys(this.manifest.nodes);
|
|
|
|
blockNodes = selectors
|
|
.reduce(function(acc, selector) {
|
|
if (!selector.includes(':'))
|
|
{
|
|
blockNodes
|
|
.matches(selector)
|
|
.getVisible()
|
|
.filter(function(node) {
|
|
return node.manifest.allowFormEdit !== false;
|
|
})
|
|
.forEach(function(node) {
|
|
acc.push(node);
|
|
});
|
|
}
|
|
|
|
return acc;
|
|
}, new NodeCollection());
|
|
|
|
var onBlockFormTypeChangeHandler = this.onBlockFormTypeChange.bind(this);
|
|
|
|
var dynamicState = !!(
|
|
!options.skipBlockState
|
|
&& BX.type.isPlainObject(this.dynamicParams)
|
|
&& this.dynamicParams.wrapper
|
|
);
|
|
|
|
var help = "";
|
|
var helps = BX.Landing.Main.getInstance().options.helps;
|
|
|
|
if (BX.type.isPlainObject(helps))
|
|
{
|
|
help = helps.DYNAMIC_BLOCKS;
|
|
}
|
|
|
|
var headerCheckbox = {
|
|
text: BX.Landing.Loc.getMessage("LANDING_BLOCK__MAKE_A_DYNAMIC"),
|
|
onChange: onBlockFormTypeChangeHandler,
|
|
state: dynamicState,
|
|
help: help
|
|
};
|
|
|
|
var blockForm = new BaseForm({
|
|
title: options.formName || BX.Landing.Loc.getMessage("BLOCK_ELEMENTS"),
|
|
description: this.manifest.block.formDescription,
|
|
type: "content",
|
|
code: this.id,
|
|
headerCheckbox: (function() {
|
|
if (!options.hideCheckbox && this.manifest.block.dynamic !== false)
|
|
{
|
|
return headerCheckbox;
|
|
}
|
|
|
|
return undefined;
|
|
}.bind(this))()
|
|
});
|
|
|
|
if (dynamicState)
|
|
{
|
|
setTimeout(function() {
|
|
onBlockFormTypeChangeHandler({
|
|
form: blockForm,
|
|
state: true
|
|
});
|
|
});
|
|
}
|
|
|
|
blockNodes.forEach(function(node) {
|
|
blockForm.addField(node.getField());
|
|
});
|
|
|
|
return blockForm;
|
|
},
|
|
|
|
getMenuEditForms: function()
|
|
{
|
|
return this.menu.map(function(menu) {
|
|
return menu.getForm();
|
|
}, this);
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @return {BX.Landing.UI.Form.BaseForm}
|
|
*/
|
|
getAttrsEditForm: function()
|
|
{
|
|
var keys = Object.keys(this.manifest.attrs);
|
|
var fields = [];
|
|
|
|
keys.forEach(function(selector) {
|
|
var attr = this.manifest.attrs[selector];
|
|
|
|
if (!attr.hidden)
|
|
{
|
|
attr = !isArray(attr) ? [attr] : attr;
|
|
|
|
attr.forEach(function(options) {
|
|
if (!options.hidden && isString(options.type))
|
|
{
|
|
fields.push(
|
|
this.createAttributeField(options, options.selector || selector)
|
|
);
|
|
}
|
|
}, this);
|
|
}
|
|
}, this);
|
|
|
|
var attrsForm = new BaseForm({
|
|
id: "attr",
|
|
type: "attrs",
|
|
title: BX.Landing.Loc.getMessage("BLOCK_SETTINGS"),
|
|
description: this.manifest.block.attrsFormDescription,
|
|
descriptionHintStyle: this.manifest.block.attrsFormDescriptionHintStyle,
|
|
});
|
|
|
|
fields.forEach(function(field) {
|
|
attrsForm.addField(field);
|
|
});
|
|
|
|
return attrsForm;
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @return {Array}
|
|
*/
|
|
getAttrsAdditionalEditForms: function()
|
|
{
|
|
var keys = Object.keys(this.manifest.attrs);
|
|
var forms = [];
|
|
|
|
keys.forEach(function(selector) {
|
|
var attr = this.manifest.attrs[selector];
|
|
|
|
if (!attr.hidden)
|
|
{
|
|
attr = !isArray(attr) ? [attr] : attr;
|
|
|
|
attr.forEach(function(options) {
|
|
if (!options.hidden && isString(options.type))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (isString(options.name) && options.attrs)
|
|
{
|
|
forms.push(
|
|
this.createAdditionalForm({
|
|
form: BaseForm,
|
|
selector: selector,
|
|
group: options,
|
|
onChange: (function() {}),
|
|
})
|
|
);
|
|
}
|
|
}, this);
|
|
}
|
|
}, this);
|
|
|
|
return forms;
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @param skipState
|
|
* @return {Array}
|
|
*/
|
|
getCardsEditForms: function(skipState)
|
|
{
|
|
var cardsSelectors = Object.keys(this.manifest.cards);
|
|
var nodesSelectors = Object.keys(this.manifest.nodes);
|
|
var forms = [];
|
|
|
|
var groupedCards = cardsSelectors.reduce(function(acc, selector) {
|
|
var cards = this.cards.filter(function(card) {
|
|
return card.selector.split("@")[0] === selector;
|
|
});
|
|
|
|
if (cards.length > 0)
|
|
{
|
|
cards.sort(function(a, b) {
|
|
return a.sortIndex - b.sortIndex;
|
|
});
|
|
|
|
acc.set(selector, cards);
|
|
}
|
|
|
|
return acc;
|
|
}.bind(this), new Map());
|
|
|
|
groupedCards.forEach(function(cards, selector) {
|
|
var checkboxState = (
|
|
BX.type.isPlainObject(this.dynamicParams)
|
|
&& selector in this.dynamicParams
|
|
&& !skipState
|
|
);
|
|
|
|
var onCardsFormTypeHandler = this.onCardsFormTypeChange.bind(this);
|
|
var groupLabel = this.manifest.cards[selector]['group_label'];
|
|
|
|
var help = "";
|
|
var helps = BX.Landing.Main.getInstance().options.helps;
|
|
|
|
if (BX.type.isPlainObject(helps))
|
|
{
|
|
help = helps.DYNAMIC_BLOCKS;
|
|
}
|
|
|
|
var headerCheckbox = {
|
|
text: BX.Landing.Loc.getMessage("LANDING_CARDS__MAKE_A_DYNAMIC"),
|
|
onChange: onCardsFormTypeHandler,
|
|
state: checkboxState,
|
|
help: help
|
|
};
|
|
|
|
var cardsForm = new CardsForm({
|
|
title: groupLabel || BX.Landing.Loc.getMessage("LANDING_CARDS_FROM_TITLE"),
|
|
code: selector.split("@")[0],
|
|
presets: cards[0].manifest.presets,
|
|
sync: cards[0].manifest.sync,
|
|
description: cards[0].manifest.formDescription,
|
|
forms: forms,
|
|
headerCheckbox: (function() {
|
|
if (this.manifest.block.dynamic !== false)
|
|
{
|
|
return headerCheckbox;
|
|
}
|
|
|
|
return undefined;
|
|
}.bind(this))()
|
|
});
|
|
|
|
forms.push(cardsForm);
|
|
|
|
if (checkboxState)
|
|
{
|
|
setTimeout(function() {
|
|
onCardsFormTypeHandler({
|
|
form: cardsForm,
|
|
state: true
|
|
});
|
|
});
|
|
}
|
|
|
|
cards.forEach(function(card) {
|
|
var cardForm = new CardForm({
|
|
label: card.getLabel() || card.getName(),
|
|
labelBindings: card.manifest.label,
|
|
selector: card.selector,
|
|
preset: card.preset
|
|
});
|
|
|
|
var sortedCardNodes = new NodeCollection();
|
|
|
|
var cardNodes = this.nodes.filter(function(node) {
|
|
return card.node.contains(node.node)
|
|
});
|
|
|
|
if (cardNodes.length)
|
|
{
|
|
nodesSelectors.forEach(function(nodeSelector) {
|
|
var matches = cardNodes.matches(nodeSelector);
|
|
matches.forEach(sortedCardNodes.add, sortedCardNodes);
|
|
}, this);
|
|
|
|
sortedCardNodes.forEach(function(node) {
|
|
if (node.manifest.allowFormEdit !== false)
|
|
{
|
|
cardForm.addField(node.getField());
|
|
}
|
|
});
|
|
|
|
var additional = this.manifest.cards[selector].additional;
|
|
if (isPlainObject(additional))
|
|
{
|
|
if (isArray(additional.attrs))
|
|
{
|
|
additional.attrs.forEach(function(attr) {
|
|
var attrField = this.createAttributeField(attr, card.selector, (function() {}));
|
|
attrField.type = "attr";
|
|
cardForm.addField(attrField);
|
|
}, this);
|
|
}
|
|
}
|
|
|
|
if (this.tmpContent.contains(card.node))
|
|
{
|
|
cardsForm.addPresetForm(cardForm);
|
|
}
|
|
else
|
|
{
|
|
cardsForm.addChildForm(cardForm);
|
|
}
|
|
}
|
|
}, this);
|
|
}, this);
|
|
|
|
return forms;
|
|
},
|
|
|
|
/**
|
|
* @private
|
|
* @return {BX.Landing.UI.Form.BaseForm}
|
|
*/
|
|
getBlockSettingsForm: function()
|
|
{
|
|
var blockSettingsForm = new BaseForm({
|
|
title: BX.Landing.Loc.getMessage("BLOCK_SETTINGS"),
|
|
type: "settings"
|
|
});
|
|
|
|
var fieldFactory = this.createFieldFactory("!" + this.selector);
|
|
var errorMessage = null;
|
|
var baseUrl = BX.Landing.Main.getInstance().options.url;
|
|
|
|
if (baseUrl[0] === "/")
|
|
{
|
|
baseUrl = top.location.origin + baseUrl;
|
|
}
|
|
|
|
this.savedAnchor = (this.anchor || this.node.id);
|
|
|
|
var previewText = join(baseUrl, "#", (this.anchor || this.node.id));
|
|
var anchorField = fieldFactory.create({
|
|
type: "text",
|
|
name: BX.Landing.Loc.getMessage("BLOCK_SETTINGS_ANCHOR_FIELD"),
|
|
description: "<span class='landing-ui-anchor-preview'>"+BX.Text.encode(previewText)+"</span>",
|
|
attribute: "id",
|
|
value: this.anchor || this.node.id,
|
|
onInput: function() {
|
|
var preview = anchorField.layout.querySelector(".landing-ui-anchor-preview");
|
|
|
|
if (preview)
|
|
{
|
|
preview.innerHTML = BX.Text.encode(join(baseUrl, "#", BX.Text.decode(anchorField.getValue())));
|
|
}
|
|
|
|
this.anchor = anchorField.getValue();
|
|
|
|
if (errorMessage)
|
|
{
|
|
remove(errorMessage);
|
|
}
|
|
|
|
if (this.node.id !== anchorField.getValue() &&
|
|
document.getElementById(anchorField.getValue()))
|
|
{
|
|
errorMessage = BX.Landing.UI.Field.BaseField.createDescription(
|
|
BX.Landing.Loc.getMessage("BLOCK_SETTINGS_ANCHOR_FIELD_VALIDATE_ERROR")
|
|
);
|
|
|
|
addClass(errorMessage, "landing-ui-error");
|
|
|
|
append(errorMessage, anchorField.layout);
|
|
}
|
|
|
|
if (!isValidElementId(anchorField.getValue()))
|
|
{
|
|
errorMessage = BX.Landing.UI.Field.BaseField.createDescription(
|
|
BX.Landing.Loc.getMessage("BLOCK_SETTINGS_ANCHOR_FIELD_VALIDATE_INVALID_ID")
|
|
);
|
|
|
|
addClass(errorMessage, "landing-ui-error");
|
|
|
|
append(errorMessage, anchorField.layout);
|
|
}
|
|
}.bind(this)
|
|
});
|
|
|
|
blockSettingsForm.addField(anchorField);
|
|
|
|
return blockSettingsForm;
|
|
},
|
|
|
|
/**
|
|
* Gets content edit forms
|
|
* @param {object} options
|
|
* @return {BX.Landing.UI.Collection.FormCollection}
|
|
*/
|
|
getEditForms: function(options)
|
|
{
|
|
var preparedOptions = {};
|
|
|
|
if (BX.type.isPlainObject(options))
|
|
{
|
|
preparedOptions = Object.assign({}, options);
|
|
}
|
|
|
|
if (arguments.length > 1)
|
|
{
|
|
preparedOptions.nodes = arguments[0];
|
|
preparedOptions.formName = arguments[1];
|
|
preparedOptions.nodesOnly = arguments[2];
|
|
preparedOptions.showAll = arguments[3];
|
|
preparedOptions.skipCardsState = arguments[4];
|
|
preparedOptions.skipBlockState = arguments[5];
|
|
}
|
|
|
|
var forms = new FormCollection();
|
|
|
|
if (this.access >= ACCESS_W)
|
|
{
|
|
var isEditable = !(
|
|
isEmpty(this.manifest.nodes)
|
|
&& isEmpty(this.manifest.attrs)
|
|
&& isEmpty(this.manifest.menu)
|
|
);
|
|
|
|
if (isEditable)
|
|
{
|
|
// Block form
|
|
var blockEditForm = this.getBlockEditForm(preparedOptions);
|
|
if (blockEditForm.fields.length > 0)
|
|
{
|
|
forms.add(blockEditForm);
|
|
}
|
|
|
|
var menuEditForms = this.getMenuEditForms(preparedOptions);
|
|
if (menuEditForms.length > 0)
|
|
{
|
|
menuEditForms.forEach(function(menuForm) {
|
|
forms.add(menuForm);
|
|
});
|
|
}
|
|
|
|
if (!preparedOptions.nodesOnly)
|
|
{
|
|
// Attrs forms
|
|
var attrsEditForm = this.getAttrsEditForm();
|
|
|
|
if (attrsEditForm.fields.length > 0)
|
|
{
|
|
forms.add(attrsEditForm);
|
|
}
|
|
|
|
// Attrs additional forms
|
|
var attrsAdditionalEditForms = this.getAttrsAdditionalEditForms();
|
|
if (attrsAdditionalEditForms.length > 0)
|
|
{
|
|
attrsAdditionalEditForms.forEach(function(form) {
|
|
forms.add(form);
|
|
});
|
|
}
|
|
|
|
// Cards forms
|
|
var cardsEditForms = this.getCardsEditForms(preparedOptions.skipCardsState);
|
|
if (cardsEditForms.length > 0)
|
|
{
|
|
cardsEditForms.forEach(function(form) {
|
|
forms.add(form);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
// Block settings
|
|
const notAllowedTypes = ['MAINPAGE'];
|
|
const landing = BX.Landing.Main.getInstance();
|
|
const type = landing.options.params.type;
|
|
if (!notAllowedTypes.includes(type))
|
|
{
|
|
const blockSettingsForm = this.getBlockSettingsForm();
|
|
if (blockSettingsForm.fields.length > 0)
|
|
{
|
|
forms.push(blockSettingsForm);
|
|
}
|
|
}
|
|
}
|
|
|
|
return forms;
|
|
},
|
|
|
|
/**
|
|
* @return {boolean}
|
|
*/
|
|
isLastBlockInArea: function()
|
|
{
|
|
return this.parent.querySelectorAll(".block-wrapper").length < 2;
|
|
},
|
|
|
|
|
|
/**
|
|
* Handles block remove event
|
|
*/
|
|
onBlockRemove: function()
|
|
{
|
|
this.adjustSortButtonsState();
|
|
},
|
|
|
|
|
|
/**
|
|
* Adjusts sort buttons state (disable/enable)
|
|
*/
|
|
adjustSortButtonsState: function()
|
|
{
|
|
var actionPanel = this.panels.get("block_action");
|
|
|
|
if (actionPanel)
|
|
{
|
|
if (this.isLastBlockInArea())
|
|
{
|
|
actionPanel.buttons.get("up").disable();
|
|
actionPanel.buttons.get("down").disable();
|
|
}
|
|
else
|
|
{
|
|
actionPanel.buttons.get("up").enable();
|
|
actionPanel.buttons.get("down").enable();
|
|
}
|
|
}
|
|
},
|
|
|
|
getFieldType: function(field)
|
|
{
|
|
var node = this.nodes.getBySelector(field.selector);
|
|
|
|
if (node)
|
|
{
|
|
return node.type;
|
|
}
|
|
|
|
return null;
|
|
},
|
|
|
|
getTypeReferences: function(references, type)
|
|
{
|
|
return references.filter(function(reference) {
|
|
return reference.type === type;
|
|
});
|
|
},
|
|
|
|
convertReferencesToDropdownItems: function(references)
|
|
{
|
|
var items = references.map(function(reference) {
|
|
return {name: reference.name, value: reference.id};
|
|
});
|
|
|
|
items.push({
|
|
name: BX.Landing.Loc.getMessage('LANDING_BLOCK__DYNAMIC_REFERENCE_HIDE'),
|
|
html: (
|
|
"<span class=\"landing-ui-field-dropdown-sep\"></span>" + BX.Landing.Loc.getMessage('LANDING_BLOCK__DYNAMIC_REFERENCE_HIDE')
|
|
),
|
|
value: '@hide'
|
|
});
|
|
|
|
return items;
|
|
},
|
|
|
|
getDefaultDropdownItems: function()
|
|
{
|
|
return [
|
|
{name: BX.Landing.Loc.getMessage("LANDING_CARDS__DYNAMIC_FIELD_NOT_SET"), value: ""}
|
|
];
|
|
},
|
|
|
|
getDynamicFiledValue: function(cardsCode, fieldSelector)
|
|
{
|
|
var state = this.dynamicParams || {};
|
|
|
|
if (
|
|
BX.type.isPlainObject(state[cardsCode])
|
|
&& BX.type.isPlainObject(state[cardsCode].references)
|
|
)
|
|
{
|
|
return state[cardsCode].references[fieldSelector];
|
|
}
|
|
},
|
|
|
|
convertToDynamicFields: function(fields, cardCode, references)
|
|
{
|
|
return fields.map(function(field) {
|
|
var type = this.getFieldType(field);
|
|
|
|
if (
|
|
type !== "text"
|
|
&& type !== "img"
|
|
&& type !== "link"
|
|
&& type !== "link_ref"
|
|
)
|
|
{
|
|
return field;
|
|
}
|
|
|
|
var typeReferences = this.getTypeReferences(references, type);
|
|
var dropDownItems = this.convertReferencesToDropdownItems(typeReferences);
|
|
var value = this.getDynamicFiledValue(cardCode, field.selector);
|
|
|
|
if (type === "link")
|
|
{
|
|
if (
|
|
BX.type.isPlainObject(typeReferences[0])
|
|
&& BX.type.isArray(typeReferences[0].actions)
|
|
)
|
|
{
|
|
return new BX.Landing.UI.Field.ClickAction({
|
|
title: field.title,
|
|
selector: field.selector,
|
|
reference: typeReferences[0],
|
|
linkField: field,
|
|
value: value
|
|
});
|
|
}
|
|
|
|
return field;
|
|
}
|
|
|
|
if (dropDownItems.length === 0)
|
|
{
|
|
dropDownItems = this.getDefaultDropdownItems();
|
|
}
|
|
|
|
if (type === "img")
|
|
{
|
|
return new BX.Landing.UI.Field.DynamicImage({
|
|
title: field.title,
|
|
selector: field.selector,
|
|
dropdownItems: dropDownItems,
|
|
value: BX.type.isString(value) ? {id: value} : value,
|
|
hideCheckbox: cardCode === "wrapper"
|
|
});
|
|
}
|
|
|
|
return new BX.Landing.UI.Field.DynamicDropdown({
|
|
title: field.title,
|
|
selector: field.selector,
|
|
dropdownItems: dropDownItems,
|
|
value: BX.type.isString(value) ? {id: value} : value,
|
|
hideCheckbox: cardCode === "wrapper" || type === "link_ref"
|
|
});
|
|
}, this);
|
|
},
|
|
|
|
createDynamicCardsForm: function(options)
|
|
{
|
|
var help = "";
|
|
var helps = BX.Landing.Main.getInstance().options.helps;
|
|
|
|
if (BX.type.isPlainObject(helps))
|
|
{
|
|
help = helps.DYNAMIC_BLOCKS;
|
|
}
|
|
|
|
var dynamicForm = new BX.Landing.UI.Form.DynamicCardsForm({
|
|
title: options.title,
|
|
code: options.code,
|
|
type: "dynamicCards",
|
|
dynamicParams: options.dynamicParams,
|
|
headerCheckbox: {
|
|
text: BX.Landing.Loc.getMessage("LANDING_CARDS__MAKE_A_DYNAMIC"),
|
|
onChange: this.onCardsFormTypeChange.bind(this),
|
|
state: true,
|
|
help: help
|
|
},
|
|
onSourceChange: function(source)
|
|
{
|
|
var dynamicFields = this.convertToDynamicFields(
|
|
options.form.childForms[0].fields,
|
|
options.code,
|
|
source.references
|
|
);
|
|
|
|
var dynamicGroup = new DynamicFieldsGroup({
|
|
id: "references",
|
|
items: dynamicFields
|
|
});
|
|
|
|
var detailPageField = dynamicForm.detailPageGroup.fields[0];
|
|
if (!BX.Type.isStringFilled(detailPageField.getValue().href))
|
|
{
|
|
var content = {text: '', href: ''};
|
|
if (source && source.default && source.default.detail)
|
|
{
|
|
content.href = source.default.detail;
|
|
}
|
|
|
|
detailPageField.setValue(content);
|
|
detailPageField.hrefInput.makeDisplayedHrefValue();
|
|
}
|
|
|
|
var oldCard = dynamicForm.cards.get('references');
|
|
dynamicForm.replaceCard(oldCard, dynamicGroup);
|
|
}.bind(this)
|
|
});
|
|
|
|
return dynamicForm;
|
|
},
|
|
|
|
onCardsFormTypeChange: function(event)
|
|
{
|
|
var contentPanel = this.panels.get("content_edit");
|
|
var isDynamicEnabled = !!event.state;
|
|
|
|
if (isDynamicEnabled)
|
|
{
|
|
var dynamicCardParams = {};
|
|
|
|
if (
|
|
BX.type.isPlainObject(this.dynamicParams)
|
|
&& this.dynamicParams[event.form.code]
|
|
)
|
|
{
|
|
dynamicCardParams = this.dynamicParams[event.form.code];
|
|
}
|
|
|
|
var value = Object.assign(
|
|
{},
|
|
dynamicCardParams
|
|
);
|
|
|
|
if (BX.type.isPlainObject(value.settings))
|
|
{
|
|
if (!('pagesCount' in value.settings))
|
|
{
|
|
value.settings.pagesCount = event.form.childForms.length;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
value.settings = {
|
|
pagesCount: event.form.childForms.length
|
|
};
|
|
}
|
|
|
|
var dynamicForm = this.createDynamicCardsForm({
|
|
title: event.form.title,
|
|
code: event.form.code,
|
|
form: event.form,
|
|
dynamicParams: value
|
|
});
|
|
|
|
contentPanel.replaceForm(event.form, dynamicForm);
|
|
return;
|
|
}
|
|
|
|
delete this.dynamicParams[event.form.code];
|
|
|
|
var staticForm = this.getCardsEditForms(true)
|
|
.find(function(item) {
|
|
return item.code === event.form.code;
|
|
});
|
|
|
|
contentPanel.replaceForm(event.form, staticForm);
|
|
},
|
|
|
|
isDynamicCards: function(cardsCode)
|
|
{
|
|
return cardsCode in this.dynamicParams;
|
|
},
|
|
|
|
onBlockFormTypeChange: function(event)
|
|
{
|
|
var contentPanel = this.panels.get("content_edit");
|
|
var isDynamicEnabled = !!event.state;
|
|
|
|
let restrictMessage = this.content.parentElement.querySelector('.landing-html-lock');
|
|
if (restrictMessage)
|
|
{
|
|
if (!isDynamicEnabled)
|
|
{
|
|
this.content.style.display = 'flex';
|
|
restrictMessage.style.display = 'none';
|
|
}
|
|
else
|
|
{
|
|
this.content.style.display = 'none';
|
|
restrictMessage.style.display = 'flex';
|
|
}
|
|
}
|
|
|
|
if (isDynamicEnabled)
|
|
{
|
|
var dynamicForm = this.createDynamicBlockForm({
|
|
title: event.form.title,
|
|
code: event.form.code,
|
|
form: event.form,
|
|
dynamicParams: this.dynamicParams
|
|
});
|
|
|
|
contentPanel.replaceForm(event.form, dynamicForm);
|
|
return;
|
|
}
|
|
|
|
delete this.dynamicParams.wrapper;
|
|
|
|
var staticForm = this.getBlockEditForm({
|
|
skipBlockState: true
|
|
});
|
|
|
|
contentPanel.replaceForm(event.form, staticForm);
|
|
},
|
|
|
|
createDynamicBlockForm: function(options)
|
|
{
|
|
var help = "";
|
|
var helps = BX.Landing.Main.getInstance().options.helps;
|
|
|
|
if (BX.type.isPlainObject(helps))
|
|
{
|
|
help = helps.DYNAMIC_BLOCKS;
|
|
}
|
|
|
|
var dynamicForm = new BX.Landing.UI.Form.DynamicBlockForm({
|
|
title: options.title,
|
|
code: this.id,
|
|
type: "dynamicBlock",
|
|
dynamicParams: options.dynamicParams,
|
|
headerCheckbox: {
|
|
text: BX.Landing.Loc.getMessage("LANDING_BLOCK__MAKE_A_DYNAMIC"),
|
|
onChange: this.onBlockFormTypeChange.bind(this),
|
|
state: true,
|
|
help: help
|
|
},
|
|
onSourceChange: function(source)
|
|
{
|
|
var oldCard = dynamicForm.cards.get('references');
|
|
|
|
if (BX.type.isPlainObject(source))
|
|
{
|
|
var dynamicFields = this.convertToDynamicFields(
|
|
options.form.fields,
|
|
"wrapper",
|
|
source.references
|
|
);
|
|
|
|
var dynamicGroup = new DynamicFieldsGroup({
|
|
id: "references",
|
|
items: dynamicFields
|
|
});
|
|
|
|
dynamicForm.replaceCard(oldCard, dynamicGroup);
|
|
return;
|
|
}
|
|
|
|
dynamicForm.removeCard(oldCard);
|
|
}.bind(this)
|
|
});
|
|
|
|
return dynamicForm;
|
|
},
|
|
|
|
isDynamic: function(code)
|
|
{
|
|
code = code || this.id;
|
|
var panel = this.panels.get('content_edit');
|
|
|
|
if (panel)
|
|
{
|
|
var form = panel.forms.toArray().find(function(form) {
|
|
return form.code === code;
|
|
});
|
|
|
|
if (form)
|
|
{
|
|
return form.isCheckboxChecked();
|
|
}
|
|
}
|
|
|
|
code = code === this.id ? "wrapper" : code;
|
|
|
|
return (
|
|
!!this.dynamicParams
|
|
&& code in this.dynamicParams
|
|
);
|
|
},
|
|
|
|
isShowFeedbackButton: function()
|
|
{
|
|
if (
|
|
BX.Type.isArray(this.manifest.block.type)
|
|
&& this.manifest.block.type.length === 1
|
|
&& this.manifest.block.type.includes('mainpage')
|
|
)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
},
|
|
};
|
|
})();
|