%PDF- %PDF-
| Direktori : /home/bitrix/www/bitrix/js/landing/ui/form/ |
| Current File : /home/bitrix/www/bitrix/js/landing/ui/form/cards_form.js |
;(function() {
"use strict";
BX.namespace("BX.Landing.UI.Form");
var throttle = BX.Landing.Utils.throttle;
var append = BX.Landing.Utils.append;
var create = BX.Landing.Utils.create;
var bind = BX.Landing.Utils.bind;
var unbind = BX.Landing.Utils.unbind;
var proxy = BX.Landing.Utils.proxy;
var addClass = BX.Landing.Utils.addClass;
var removeClass = BX.Landing.Utils.removeClass;
var hasClass = BX.Landing.Utils.hasClass;
var style = BX.Landing.Utils.style;
var slice = BX.Landing.Utils.slice;
var findParent = BX.Landing.Utils.findParent;
var offsetTop = BX.Landing.Utils.offsetTop;
var offsetLeft = BX.Landing.Utils.offsetLeft;
var rect = BX.Landing.Utils.rect;
var remove = BX.Landing.Utils.remove;
var onTransitionEnd = BX.Landing.Utils.onTransitionEnd;
var random = BX.Landing.Utils.random;
var clone = BX.Landing.Utils.clone;
var isString = BX.Landing.Utils.isString;
var isArray = BX.Landing.Utils.isArray;
var isEmpty = BX.Landing.Utils.isEmpty;
var isPlainObject = BX.Landing.Utils.isPlainObject;
var join = BX.Landing.Utils.join;
var onCustomEvent = BX.Landing.Utils.onCustomEvent;
var FormCollection = BX.Landing.UI.Collection.FormCollection;
var BaseButton = BX.Landing.UI.Button.BaseButton;
/**
* Implements interface for works with cards form
*
* @extends {BX.Landing.UI.Form.BaseForm}
* @param {{
* [title]: string,
* [presets]: object,
* [sync]: string|string[],
* [forms]: []
* }} data
* @constructor
*/
BX.Landing.UI.Form.CardsForm = function(data)
{
BX.Landing.UI.Form.BaseForm.apply(this, arguments);
this.layout.classList.add("landing-ui-form-cards");
this.type = "cards";
this.code = data.code;
this.presets = data.presets;
this.childForms = new FormCollection();
this.presetForm = new FormCollection();
this.sync = data.sync;
this.forms = data.forms;
this.onItemClick = throttle(this.onItemClick, 200, this);
this.onRemoveItemClick = proxy(this.onRemoveItemClick, this);
this.onRemoveItemMouseenter = proxy(this.onRemoveItemMouseenter, this);
this.onRemoveItemMouseleave = proxy(this.onRemoveItemMouseleave, this);
this.onAddCardClick = proxy(this.onAddCardClick, this);
this.addButton = this.createAddButton();
this.wheelEventName = this.getWheelEventName();
setTimeout(function() {
this.value = this.serialize();
}.bind(this));
this.adjustLastFormState();
append(this.addButton.layout, this.footer);
};
/**
* Wraps form
* @param {BX.Landing.UI.Form.CardForm} form
* @param {BX.Landing.UI.Form.CardsForm} parentForm
* @return {HTMLElement}
*/
function wrapForm(form, parentForm)
{
return create("div", {
props: {className: "landing-ui-form-cards-item"},
children: [
create("div", {
children: [
create("div", {
props: {className: "landing-ui-form-card-item-header"},
events: {click: parentForm.onItemClick},
children: [
create("div", {
props: {className: "landing-ui-form-card-item-header-left"},
children: [
create("div", {
props: {className: "landing-ui-form-card-item-header-left-inner"},
children: [
create("span", {props: {className: "landing-ui-form-card-item-header-drag landing-ui-drag"}}),
create("span", {props: {className: "landing-ui-form-card-item-header-title"}, children: [form.label]})
]
}),
create("span", {
props: {className: "landing-ui-form-card-item-header-edit"},
children: [create("span", {props: {className: "fa fa-pencil"}})]
})
]
}),
create("div", {
children: [
create("span", {
props: {className: "landing-ui-form-card-item-header-remove"},
children: [create("span", {props: {className: "fa fa-remove"}})],
events: {
click: parentForm.onRemoveItemClick,
mouseenter: parentForm.onRemoveItemMouseenter,
mouseleave: parentForm.onRemoveItemMouseleave
}
})
]
})
]
}),
form.layout
]
})
]
});
}
/**
* Makes item as draggable
* @param {HTMLElement} item
* @param {BX.Landing.UI.Form.CardsForm} parentForm
*/
function makeDraggable(item, parentForm)
{
var dragButton = item.querySelector(".landing-ui-form-card-item-header-drag");
dragButton.onbxdragstart = onDragStart.bind(this);
dragButton.onbxdrag = onDrag.bind(this);
dragButton.onbxdragstop = onDragEnd.bind(this);
jsDD.registerObject(dragButton);
bind(dragButton, "mousedown", onDragButtonMousedown);
bind(dragButton, "mouseup", onDragButtonMouseup);
bind(dragButton, "click", onDragButtonClick);
var scrollContainer = findParent(item, {className: "landing-ui-panel-content-body-content"});
jsDD.setScrollWindow(scrollContainer);
var itemStartRect;
var startOffsetY;
var startScroll;
var dragIndex;
var animationOffset;
var targetItem;
var currentItem;
var minOffset;
var maxOffset;
function onDragStart()
{
scrollContainer = findParent(item, {className: "landing-ui-panel-content-body-content"});
itemStartRect = rect(item);
startOffsetY = Math.max(Math.abs(jsDD.start_y - itemStartRect.top), 0);
startScroll = scrollContainer.scrollTop;
dragIndex = [].indexOf.call(slice(item.parentElement.children), item);
currentItem = findParent(jsDD.current_node, {className: "landing-ui-form-cards-item"});
var itemComputedStyle = getComputedStyle(item);
var marginTop = parseInt(itemComputedStyle.getPropertyValue("margin-top"));
marginTop = marginTop === marginTop ? marginTop : 0;
var marginBottom = parseInt(itemComputedStyle.getPropertyValue("margin-bottom"));
marginBottom = marginBottom === marginBottom ? marginBottom : 0;
animationOffset = itemStartRect.height + ((marginTop + marginBottom) / 2);
minOffset = -offsetTop(currentItem, currentItem.parentElement);
var parentRect = rect(currentItem.parentElement);
maxOffset = parentRect.height - offsetTop(currentItem, currentItem.parentElement) - itemStartRect.height;
}
function onDrag(x, y)
{
var scrollOffset = startScroll - scrollContainer.scrollTop;
var dragItemOffset = (y - itemStartRect.top - startOffsetY - scrollOffset);
dragItemOffset = Math.min(Math.max(dragItemOffset, minOffset), maxOffset);
void style(item, {
zIndex: 999,
transform: "translateY("+dragItemOffset+"px)"
});
slice(item.parentElement.children).forEach(function(current, index) {
if (current !== item)
{
var currentRect = current.getBoundingClientRect();
var currentMiddle = currentRect.top + BX.scrollTop(window) + (currentRect.height / 2);
if (index > dragIndex && y > currentMiddle &&
current.style.transform !== 'translate3d(0px, '+(-animationOffset)+'px, 0px)' &&
current.style.transform !== '')
{
targetItem = current;
void style(current, {
'transform': 'translate3d(0px, '+(-animationOffset)+'px, 0px)',
'transition': '300ms'
});
}
if (index < dragIndex && y < currentMiddle &&
current.style.transform !== 'translate3d(0px, '+(animationOffset)+'px, 0px)' &&
current.style.transform !== '')
{
targetItem = current;
void style(current, {
'transform': 'translate3d(0px, '+(animationOffset)+'px, 0px)',
'transition': '300ms'
});
}
if (((index < dragIndex && y > currentMiddle) ||
(index > dragIndex && y < currentMiddle)) &&
current.style.transform !== 'translate3d(0px, 0px, 0px)')
{
if (currentMiddle > y)
{
targetItem = current.previousElementSibling;
}
else
{
targetItem = current.nextElementSibling;
}
void style(current, {
'transform': 'translate3d(0px, 0px, 0px)',
'transition': '300ms'
});
}
}
});
}
function onDragEnd()
{
slice(item.parentElement.children).forEach(function(currentItem) {
void style(currentItem, {
zIndex: null,
transform: null,
transition: null
});
setTimeout(function() {
removeClass(currentItem, "landing-ui-form-card-item-draggable");
}, 50);
});
if (currentItem && targetItem && currentItem !== targetItem && currentItem.parentNode === targetItem.parentNode)
{
var currentIndex = [].indexOf.call(targetItem.parentElement.children, currentItem);
var targetIndex = [].indexOf.call(targetItem.parentElement.children, targetItem);
if (targetItem.parentElement.children.length === targetIndex)
{
targetItem.parentElement.appendChild(target);
}
if (currentIndex > targetIndex)
{
targetItem.parentElement.insertBefore(currentItem, targetItem);
}
if (currentIndex < targetIndex && targetItem.parentElement.children.length !== targetIndex)
{
targetItem.parentElement.insertBefore(currentItem, targetItem.nextElementSibling);
}
if (parentForm.sync)
{
var syncSelectors = parentForm.sync;
if (isString(parentForm.sync))
{
syncSelectors = [parentForm.sync];
}
if (isArray(syncSelectors))
{
syncSelectors.forEach(function(syncSelector) {
var syncForm = parentForm.forms.find(function(currentForm) {
return currentForm.code === syncSelector;
});
if (syncForm)
{
var syncCurrentItem = syncForm.body.children[currentIndex];
var syncTargetItem = syncForm.body.children[targetIndex];
if (syncTargetItem.parentElement.children.length === targetIndex)
{
syncTargetItem.parentElement.appendChild(target);
}
if (currentIndex > targetIndex)
{
syncTargetItem.parentElement.insertBefore(syncCurrentItem, syncTargetItem);
}
if (currentIndex < targetIndex && syncTargetItem.parentElement.children.length !== targetIndex)
{
syncTargetItem.parentElement.insertBefore(syncCurrentItem, syncTargetItem.nextElementSibling);
}
}
syncForm.childForms.forEach(function(currentSyncForms) {
var index = [].indexOf.call(
currentSyncForms.layout.parentElement.parentElement.parentElement.children,
currentSyncForms.layout.parentElement.parentElement
);
currentSyncForms.oldIndex = getSelectorIndex(currentSyncForms.selector);
currentSyncForms.selector = join(currentSyncForms.selector.split("@")[0], "@", index);
});
syncForm.childForms.sort(function(a, b) {
return parseInt(a.selector.split("@")[1]) < parseInt(b.selector.split("@")[1]) ? -1 : 1;
});
});
}
}
}
parentForm.childForms.forEach(function(form) {
var index = [].indexOf.call(
form.layout.parentElement.parentElement.parentElement.children,
form.layout.parentElement.parentElement
);
form.oldIndex = getSelectorIndex(form.selector);
form.selector = join(form.selector.split("@")[0], "@", index);
});
parentForm.childForms.sort(function(a, b) {
return parseInt(a.selector.split("@")[1]) < parseInt(b.selector.split("@")[1]) ? -1 : 1;
});
}
function onDragButtonClick(event)
{
event.preventDefault();
event.stopPropagation();
}
function onDragButtonMousedown()
{
addClass(item, "landing-ui-form-card-item-draggable");
}
function onDragButtonMouseup()
{
removeClass(item, "landing-ui-form-card-item-draggable");
}
}
/**
* @param {BX.Landing.UI.Form.CardForm} form
*/
function initBindings(form)
{
var labelSelectors = [];
if (isString(form.labelBindings))
{
labelSelectors.push(form.labelBindings);
}
else if (isArray(form.labelBindings))
{
labelSelectors = labelSelectors.concat(form.labelBindings);
}
form.fields.forEach(function(field) {
field.layout.hidden = true;
field.reset();
field.layout.hidden = false;
});
var textItemIndex = -1;
labelSelectors.forEach(function(selector) {
var field = form.fields.find(function(currentField) {
return currentField.selector.split("@")[0] === selector;
});
if (field)
{
var item = findParent(form.layout, {className: "landing-ui-form-cards-item"});
var labelContainer;
if (field instanceof BX.Landing.UI.Field.Link)
{
labelContainer = item.querySelector(".landing-card-title-link");
labelContainer.innerHTML = BX.message("LANDING_CARDS_FORM_ITEM_PLACEHOLDER_TEXT");
onCustomEvent(field, "BX.Landing.UI.Field:change", function(value) {
labelContainer.innerHTML = value.text;
});
return;
}
if (field instanceof BX.Landing.UI.Field.Icon)
{
labelContainer = item.querySelector(".landing-card-title-icon").firstElementChild;
labelContainer.className = "landing-card-title-icon";
onCustomEvent(field, "BX.Landing.UI.Field:change", function(value) {
labelContainer.className = "landing-card-title-icon " + value.classList.join(" ");
});
return;
}
if (field instanceof BX.Landing.UI.Field.Image)
{
labelContainer = item.querySelector(".landing-card-title-img");
labelContainer.style.backgroundColor = "#fafafa";
labelContainer.innerHTML = "";
onCustomEvent(field, "BX.Landing.UI.Field:change", function(value) {
labelContainer.innerHTML = "";
labelContainer.appendChild(create('img', {props: {src: value.src}}));
});
return;
}
if (field instanceof BX.Landing.UI.Field.Text)
{
textItemIndex += 1;
var labelContainers = item.querySelectorAll(".landing-card-title-text");
labelContainer = labelContainers[textItemIndex];
onCustomEvent(field, "BX.Landing.UI.Field:change", function(value) {
labelContainer.innerHTML = create("div", {html: value}).innerText;
});
if (labelContainer === labelContainers[0])
{
labelContainer.innerHTML = BX.message("LANDING_CARDS_FORM_ITEM_PLACEHOLDER_TEXT");
field.setValue(BX.message("LANDING_CARDS_FORM_ITEM_PLACEHOLDER_TEXT"));
}
else
{
labelContainer.innerHTML = "";
}
}
}
});
}
/**
* Gets code from entity selector
* @param selector
* @return {string}
*/
function getCodeFromSelector(selector)
{
return isString(selector) ? selector.split("@")[0] : "";
}
/**
* Gets selector index
* @param selector
* @return {*}
*/
function getSelectorIndex(selector)
{
return isString(selector) ? selector.split("@")[1] : "";
}
/**
* Makes selector from code with index
* @param {string} code
* @param {int} index
* @return {string}
*/
function makeSelector(code, index)
{
return join(code.split("@")[0], "@", index);
}
BX.Landing.UI.Form.CardsForm.prototype = {
constructor: BX.Landing.UI.Form.CardsForm,
__proto__: BX.Landing.UI.Form.BaseForm.prototype,
/**
* Gets wheel event name
* @return {string}
*/
getWheelEventName: function()
{
return !!window.onwheel ? "wheel" : "mousewheel";
},
/**
* Create "add button"
* @return {BX.Landing.UI.Button.BaseButton}
*/
createAddButton: function()
{
return new BaseButton("add-card-" + random(), {
className: "landing-ui-card-add-button",
text: BX.message("LANDING_CARDS_FORM_ADD_BUTTON"),
onClick: this.onAddCardClick
});
},
/**
* Handles item click event
* @param event
*/
onItemClick: function(event)
{
event.preventDefault();
var target = findParent(event.currentTarget, {className: "landing-ui-form-cards-item"});
if (!!target && !hasClass(target, "landing-ui-form-card-item-draggable"))
{
if (!hasClass(target, "landing-ui-form-cards-item-expand"))
{
addClass(target, "landing-ui-form-cards-item-expand");
onTransitionEnd(target).then(function() {
void style(target, {
overflow: "visible"
});
});
void style(target, {
"height": "auto"
});
}
else
{
removeClass(target, "landing-ui-form-cards-item-expand");
void style(target, null);
}
}
},
onRemoveItemClick: function(event, preventSync)
{
event.stopPropagation();
if (this.body.children.length > 1)
{
var item = findParent(event.currentTarget, {className: "landing-ui-form-cards-item"});
remove(item);
var formNode = item.querySelector(".landing-ui-form-card");
var form = this.childForms.find(function(currentForm) {
return currentForm.layout === formNode;
});
this.childForms.remove(form);
if (preventSync !== true)
{
if (this.sync)
{
var syncSelectors = this.sync;
if (isString(this.sync))
{
syncSelectors = [this.sync];
}
if (isArray(syncSelectors))
{
syncSelectors.forEach(function(syncSelector) {
var syncedForm = this.forms.find(function(currentForm) {
return currentForm.code === syncSelector;
});
if (syncedForm)
{
var childForm = syncedForm.childForms.find(function(currentChildForm) {
return currentChildForm.selector.split("@")[1] === form.selector.split("@")[1];
});
syncedForm.onRemoveItemClick({
currentTarget: childForm.layout,
stopPropagation: (function() {})
}, true);
}
}, this);
}
}
}
}
this.adjustLastFormState();
},
onRemoveItemMouseenter: function(event)
{
event.stopPropagation();
event.preventDefault();
var header = findParent(event.currentTarget, {className: "landing-ui-form-card-item-header"});
addClass(header, "landing-ui-form-card-item-header-onremove");
},
onRemoveItemMouseleave: function(event)
{
var header = findParent(event.currentTarget, {className: "landing-ui-form-card-item-header"});
removeClass(header, "landing-ui-form-card-item-header-onremove");
},
addChildForm: function(form)
{
this.childForms.add(form);
var formWrapper = wrapForm(form, this);
append(formWrapper, this.body);
makeDraggable(formWrapper, this);
this.adjustLastFormState();
},
addPresetForm: function(form)
{
this.presetForm.add(form);
var formWrapper = wrapForm(form, this);
formWrapper.hidden = true;
append(formWrapper, this.body);
makeDraggable(formWrapper, this);
this.adjustLastFormState();
},
onAddCardClick: function(preventSync)
{
if (isPlainObject(this.presets) && !isEmpty(this.presets))
{
this.showPresetsPopup();
}
else
{
this.addEmptyCard();
if (preventSync !== true)
{
if (this.sync)
{
var syncSelectors = this.sync;
if (isString(this.sync))
{
syncSelectors = [this.sync];
}
if (isArray(syncSelectors))
{
syncSelectors.forEach(function(syncSelector) {
var form = this.forms.find(function(currentForm) {
return currentForm.code === syncSelector;
});
if (form)
{
form.onAddCardClick(true);
}
}, this);
}
}
}
}
},
onPresetItemClick: function(presetId)
{
var preset = this.presets[presetId];
var newForm = this.presetForm.find(function(form) {
return form.preset.id === presetId;
}).clone();
newForm.selector = join(newForm.selector.split("@")[0], "@", this.childForms.length);
newForm.oldIndex = this.childForms.length;
newForm.preset = clone(preset);
newForm.preset.id = presetId;
this.addChildForm(newForm);
initBindings(newForm);
this.adjustLastFormState();
this.popup.close();
if (isPlainObject(preset.values))
{
newForm.fields.forEach(function(field) {
var code = field.selector.split("@")[0];
if (code in preset.values)
{
field.setValue(preset.values[code]);
if (field instanceof BX.Landing.UI.Field.Text)
{
BX.fireEvent(field.input, "input");
}
}
if (isArray(preset.disallow))
{
var isDisallow = !!preset.disallow.find(function(fieldCode) {
return code === fieldCode;
});
if (isDisallow)
{
field.layout.hidden = true;
}
}
});
}
},
showPresetsPopup: function()
{
if (!this.popup)
{
this.popup = new BX.Landing.UI.Tool.Menu({
id: "catalog_blocks_list",
bindElement: this.addButton.layout,
items: Object.keys(this.presets).map(function(preset) {
return {
text: this.presets[preset].name,
className: "landing-ui-form-cards-preset-popup-item menu-popup-no-icon",
onclick: this.onPresetItemClick.bind(this, preset)
}
}, this),
autoHide: true,
maxHeight: 176,
minHeight: 87
});
bind(this.popup.popupWindow.popupContainer, "mouseover", this.onMouseOver.bind(this));
bind(this.popup.popupWindow.popupContainer, "mouseleave", this.onMouseLeave.bind(this));
bind(top.document, "click", this.onDocumentClick.bind(this));
append(
this.popup.popupWindow.popupContainer,
findParent(this.addButton.layout, {className: "landing-ui-panel-content-body-content"})
);
}
if (this.popup.popupWindow.isShown())
{
this.popup.popupWindow.close();
}
else
{
this.popup.popupWindow.show();
}
this.adjustPopupPosition();
},
/**
* Handles mouse over event
*/
onMouseOver: function()
{
bind(this.popup.popupWindow.popupContainer, this.wheelEventName, this.onMouseWheel.bind(this));
bind(this.popup.popupWindow.popupContainer, "touchmove", this.onMouseWheel.bind(this));
},
/**
* Handles mouse leave event
*/
onMouseLeave: function()
{
unbind(this.popup.popupWindow.popupContainer, this.wheelEventName, this.onMouseWheel.bind(this));
unbind(this.popup.popupWindow.popupContainer, "touchmove", this.onMouseWheel.bind(this));
},
/**
* Handle mouse wheel event
* @param event
*/
onMouseWheel: function(event)
{
event.stopPropagation();
event.preventDefault();
var delta = BX.Landing.UI.Panel.Content.getDeltaFromEvent(event);
var scrollTop = this.popup.popupWindow.contentContainer.scrollTop;
requestAnimationFrame(function() {
this.popup.popupWindow.contentContainer.scrollTop = scrollTop - delta.y;
}.bind(this));
},
/**
* Handles document click event
*/
onDocumentClick: function()
{
if (this.popup.popupWindow)
{
this.popup.popupWindow.close();
}
},
/**
* Adjusts popup position
*/
adjustPopupPosition: function()
{
if (this.popup.popupWindow)
{
requestAnimationFrame(function() {
var offsetParent = findParent(this.addButton.layout, {className: "landing-ui-panel-content-body-content"});
var buttonTop = offsetTop(this.addButton.layout, offsetParent);
var buttonLeft = offsetLeft(this.addButton.layout, offsetParent);
var buttonRect = this.addButton.layout.getBoundingClientRect();
var popupRect = this.popup.popupWindow.popupContainer.getBoundingClientRect();
var yOffset = 14;
this.popup.popupWindow.popupContainer.style.top = buttonTop + buttonRect.height + yOffset + "px";
this.popup.popupWindow.popupContainer.style.left = buttonLeft - (popupRect.width / 2) + (buttonRect.width / 2) + "px";
this.popup.popupWindow.setAngle({
offset: 83,
position: "top"
})
}.bind(this));
}
},
/**
* Adds empty card form
*/
addEmptyCard: function()
{
var newData = clone(this.childForms[0].data);
var newSelector = join(newData.selector.split("@")[0], "@", this.childForms.length);
newData.selector = newSelector;
var newForm = this.childForms[0].clone(newData);
newForm.oldIndex = this.childForms.length;
newForm.selector = newSelector;
this.addChildForm(newForm);
initBindings(newForm);
this.adjustLastFormState();
},
/**
* Adjusts last form state
*/
adjustLastFormState: function()
{
if (this.body.children.length === 1)
{
addClass(this.body.firstElementChild, "landing-ui-disallow-remove");
return;
}
slice(this.body.children).forEach(function(item) {
removeClass(item, "landing-ui-disallow-remove");
});
},
/**
* Serialize forms
* @return {object}
*/
serialize: function()
{
return this.childForms.map(function(form) {
return form.serialize();
});
},
/**
* Gets indexes map
* @return {Object}
*/
getIndexesMap: function()
{
return this.childForms
.reduce(function(res, form, index) {
return res[index] = form.oldIndex, res;
}, {});
},
/**
* Gets used presets
* @return {object}
*/
getUsedPresets: function()
{
return this.childForms
.reduce(function(res, form) {
if (isPlainObject(form.preset))
{
res[getSelectorIndex(form.selector)] = form.preset.id;
}
return res;
}, {});
},
isChanged: function()
{
return JSON.stringify(this.value) !== JSON.stringify(this.serialize());
}
};
})();