| Current Path : /var/www/homesaver/www/bitrix/js/landing/ui/panel/ |
| Current File : /var/www/homesaver/www/bitrix/js/landing/ui/panel/editor_panel.js |
;(function() {
"use strict";
BX.namespace("BX.Landing.UI.Panel");
var proxy = BX.Landing.Utils.proxy;
var getSelectedElement = BX.Landing.Utils.getSelectedElement;
/**
* Implements interface of editor actions panel.
* Implements singleton pattern.
*
* Not use as constructor
*
* @extends {BX.Landing.UI.Panel.BaseButtonPanel}
*
* @param bool outOfFrame - if panel place out of editor window
*
* @constructor
*/
BX.Landing.UI.Panel.EditorPanel = function()
{
BX.Landing.UI.Panel.BaseButtonPanel.apply(this, arguments);
this.layout.classList.add("landing-ui-panel-editor");
this.position = "absolute";
this.currentElement = null;
this.outOfFrame = true;
this.onKeydown = this.onKeydown.bind(this);
this.onTabDown = this.onTabDown.bind(this);
this.onScroll = this.onScroll.bind(this);
};
/**
* Stores instance of BX.Landing.UI.Panel.EditorPanel
* @static
* @type {?BX.Landing.UI.Panel.EditorPanel}
*/
BX.Landing.UI.Panel.EditorPanel.instance = null;
/**
* Gets instance on BX.Landing.UI.Panel.EditorPanel
* @static
* @return {BX.Landing.UI.Panel.EditorPanel}
*/
BX.Landing.UI.Panel.EditorPanel.getInstance = function()
{
if (!BX.Landing.UI.Panel.EditorPanel.instance)
{
BX.Landing.UI.Panel.EditorPanel.instance = new BX.Landing.UI.Panel.EditorPanel();
BX.Landing.UI.Panel.EditorPanel.instance.init();
}
return BX.Landing.UI.Panel.EditorPanel.instance;
};
var scrollHandler = null;
var target = null;
/**
* Makes editor as draggable
* @param {BX.Landing.UI.Panel.EditorPanel} editor
*/
function makeDraggable(editor)
{
var dragButton = new BX.Landing.UI.Button.EditorAction("drag", {
html: "<strong class=\"landing-ui-drag\"> </strong>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_DRAG")}
});
dragButton.layout.onbxdrag = onDrag.bind(this);
dragButton.layout.onbxdragstop = onDragEnd.bind(this);
jsDD.registerObject(dragButton.layout);
editor.prependButton(dragButton);
var offsetCalculates;
var offsetLeft;
var offsetTop;
var topValue;
function onDrag(x, y)
{
if (!offsetCalculates)
{
var pos = BX.pos(jsDD.current_node);
offsetLeft = Math.max(Math.abs(x - pos.left), 0);
offsetTop = Math.max(Math.abs(y - pos.top), 0);
offsetCalculates = true;
}
BX.DOM.write(function() {
editor.layout.classList.remove("landing-ui-transition");
if (BX.Landing.PageObject.getEditorWindow().scrollY > 0)
{
topValue = y - offsetTop;
}
else
{
topValue = y + offsetTop;
}
editor.layout.style.top = topValue + "px";
editor.layout.style.left = (x - offsetLeft) + "px";
}.bind(this));
}
function onDragEnd()
{
offsetCalculates = false;
editor.layout.classList.add("landing-ui-transition");
}
}
/**
* Register base editor actions
* @param {BX.Landing.UI.Panel.EditorPanel} editor
*/
function registerBaseActions(editor)
{
editor.addButton(new BX.Landing.UI.Button.EditorAction("bold", {
html: "<span class=\"landing-ui-icon-editor-bold\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_BOLD")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.EditorAction("italic", {
html: "<span class=\"landing-ui-icon-editor-italic\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_ITALIC")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.EditorAction("underline", {
html: "<span class=\"landing-ui-icon-editor-underline\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_UNDERLINE")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.EditorAction("strikeThrough", {
html: "<span class=\"landing-ui-icon-editor-strike\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_STRIKE")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.EditorAction("justifyLeft", {
html: "<span class=\"landing-ui-icon-editor-left\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_ALIGN_LEFT")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.EditorAction("justifyCenter", {
html: "<span class=\"landing-ui-icon-editor-center\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_ALIGN_CENTER")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.EditorAction("justifyRight", {
html: "<span class=\"landing-ui-icon-editor-right\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_ALIGN_RIGHT")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.EditorAction("justifyFull", {
html: "<span class=\"landing-ui-icon-editor-justify\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_ALIGN_JUSTIFY")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.CreateLink("createLink", {
html: "<span class=\"landing-ui-icon-editor-link\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_CREATE_LINK")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
var rights = BX.Landing.Env.getInstance().getOptions().rights;
if (
rights
&& rights.includes('edit')
&& BX.Landing.Env.getInstance().getType() !== 'MAINPAGE'
)
{
editor.addButton(new BX.Landing.UI.Button.CreatePage("createPage", {
html: "<span class=\"landing-ui-icon-editor-new-page\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_CREATE_PAGE")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
}
editor.addButton(new BX.Landing.UI.Button.EditorAction("unlink", {
html: "<span class=\"landing-ui-icon-editor-unlink\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_UNLINK")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.EditorAction("insertUnorderedList", {
html: "<span class=\"fa fa-list-ul\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_UL")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.EditorAction("insertOrderedList", {
html: "<span class=\"fa fa-list-ol\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_OL")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.EditorAction("removeFormat", {
html: "<span class=\"landing-ui-icon-editor-eraser\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_CLEAR")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.ColorAction("foreColor", {
text: BX.Landing.Loc.getMessage("EDITOR_ACTION_SET_FORE_COLOR"),
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_COLOR")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.TextBackgroundAction("hiliteColor", {
html: "<span class=\"landing-ui-icon-editor-text-background\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_TEXT_BACKGROUND")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.CreateTable("createTable", {
html: "<span class=\"landing-ui-icon-editor-table\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_CREATE_TABLE")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
editor.addButton(new BX.Landing.UI.Button.PasteTable("pasteTable", {
html: "<span class=\"landing-ui-icon-editor-copy\"></span>",
attrs: {title: BX.Landing.Loc.getMessage("LANDING_TITLE_OF_EDITOR_ACTION_PASTE_TABLE")},
onClick: proxy(editor.adjustButtonsState, editor)
}));
if (BX.Landing.Main.getInstance()["options"]["copilot_available"])
{
editor.addButton(new BX.Landing.UI.Button.AiCopilot.getInstance("ai_copilot", {
html: 'CoPilot',
editor,
onReplace(value) {
const fieldInput = editor.currentElement.querySelector('.landing-ui-field-input');
if (fieldInput)
{
fieldInput.innerHTML = `<div>${value}</div>`;
}
else if (editor.currentElement)
{
editor.currentElement.innerHTML = `<div>${value}</div>`;
}
},
onReplaceContext(value)
{
const range = window.getSelection().getRangeAt(0);
range.deleteContents();
range.insertNode(document.createTextNode(value));
},
onAddBelow(value) {
const fieldInput = editor.currentElement.querySelector('.landing-ui-field-input');
if (fieldInput)
{
fieldInput.innerHTML = `${fieldInput.innerHTML}<div>${value}</div>`;
}
else if (editor.currentElement)
{
editor.currentElement.innerHTML = `${editor.currentElement.innerHTML}<div>${value}</div>`;
}
},
}));
}
}
var lastPosition = {top: 0, left: 0};
function adjustAbsolutePosition(editor, node, force)
{
var nodeRect = node.getBoundingClientRect();
var left = nodeRect.left + (nodeRect.width / 2) - (editor.rect.width / 2);
var top = (nodeRect.top - editor.rect.height - 4);
var position = 'absolute';
var windowScope = editor.outOfFrame
? window.parent
: window;
var bodyContent = node.closest('.landing-ui-panel-content-body-content');
if (bodyContent)
{
if (node.classList.contains('landing-ui-field'))
{
top += windowScope.pageYOffset;
}
else
{
top = bodyContent.getBoundingClientRect().top + 5;
position = 'fixed';
}
}
else if (BX.Landing.Main.getInstance().isControlsExternal())
{
top += 71;
}
else
{
if (
top <= 5
&& (
nodeRect.bottom > windowScope.innerHeight
|| nodeRect.height > (windowScope.innerHeight / 1.5)
)
)
{
top = 5;
position = 'fixed';
}
else
{
if (top > 5)
{
top += windowScope.pageYOffset + 66;
}
else
{
top = nodeRect.bottom + 4 + windowScope.pageYOffset;
}
}
}
if (
editor.outOfFrame
&& editor.contextDocument !== top.document
&& editor.contextDocument.defaultView.frameElement
)
{
left += editor.contextDocument.defaultView.frameElement.getBoundingClientRect().left;
}
if ((left + editor.rect.width) > (windowScope.innerWidth - 20))
{
left -= ((left + editor.rect.width) - (windowScope.innerWidth - 20));
}
left = Math.max(20, left);
if (lastPosition.top !== top || lastPosition.left !== left || force)
{
BX.DOM.write(function() {
editor.layout.style.position = position;
editor.layout.style.top = top + "px";
editor.layout.style.left = left + "px";
});
lastPosition.top = top;
lastPosition.left = left;
hideButtonsPopups(editor);
}
}
/**
* Appends editor to document body
* @param {BX.Landing.UI.Panel.EditorPanel} editor
*/
function appendToBody(editor)
{
if (editor.outOfFrame)
{
window.parent.document.body.appendChild(editor.layout);
}
else
{
window.document.body.appendChild(editor.layout);
}
}
var mouseTarget = null;
function onMousedown(event)
{
mouseTarget = event.target;
}
var preventClick = false;
function onMouseUp(event)
{
preventClick = mouseTarget !== event.target
}
function onClick(event)
{
if (preventClick)
{
event.preventDefault();
event.stopPropagation();
}
}
function closePopup(button)
{
if (button.popup)
{
button.popup.close();
}
if (button.menu)
{
button.menu.close();
}
}
function hideButtonsPopups(editor)
{
editor.buttons.forEach(closePopup);
if (editor.additionalButtons)
{
editor.additionalButtons.forEach(closePopup);
}
BX.Landing.UI.Tool.ColorPicker.hideAll();
}
BX.Landing.UI.Panel.EditorPanel.prototype = {
constructor: BX.Landing.UI.Panel.EditorPanel,
__proto__: BX.Landing.UI.Panel.BaseButtonPanel.prototype,
/**
* Method for separate init actions from object create
*/
init: function()
{
makeDraggable(this);
registerBaseActions(this);
appendToBody(this);
this.rect = this.layout.getBoundingClientRect();
},
/**
* Shows editor
* @param {HTMLElement} element - Editable element
* @param {?string} [position = "absolute"]
* @param {BX.Landing.UI.Button.BaseButton[]} [additionalButtons]
* @param {boolean} isTable
* @param {array} hideButtons - List base buttons
*/
show: function(
element,
position,
additionalButtons,
isTable,
hideButtons
)
{
if (!isTable)
{
this.showBaseButtons();
}
else
{
if (hideButtons)
{
if (hideButtons.length > 0)
{
this.showBaseButtons();
this.hideBaseButtons(hideButtons);
}
else
{
this.hideAllBaseButtons();
}
}
else
{
this.hideAllBaseButtons();
}
}
this.currentElement = element;
this.setContextDocument(this.currentElement ? this.currentElement.ownerDocument : document);
if (this.additionalButtons)
{
this.additionalButtons.forEach(function(button) {
this.buttons.remove(button);
closePopup(button);
BX.remove(button.layout);
}, this);
this.additionalButtons = null;
}
if (additionalButtons)
{
this.additionalButtons = additionalButtons;
this.additionalButtons.forEach(function(button) {
if (button.insertAfter)
{
var prevSibling = this.layout.querySelector("[data-id=\""+button.insertAfter+"\"]");
if (prevSibling)
{
BX.insertAfter(button.layout, prevSibling);
this.buttons.add(button);
}
}
else
{
this.addButton(button);
}
if (button.insertBefore)
{
const nextSibling = this.layout.querySelector(`[data-id="${button.insertBefore}"]`);
if (nextSibling)
{
BX.insertBefore(button.layout, nextSibling);
this.buttons.add(button);
}
else
{
this.addButton(button);
}
}
}, this);
}
if (!this.isShown())
{
BX.onCustomEvent("BX.Landing.Editor:enable", [element]);
this.contextDocument.addEventListener("mousedown", onMousedown, true);
this.contextDocument.addEventListener("mouseup", onMouseUp, true);
this.contextDocument.addEventListener("click", onClick, true);
this.currentElement.addEventListener("click", proxy(this.adjustButtonsState, this), true);
setTimeout(function() {
this.layout.classList.add("landing-ui-transition");
}.bind(this), 100);
}
BX.Landing.UI.Panel.BaseButtonPanel.prototype.show.call(this, arguments);
BX.DOM.write(function() {
this.rect = this.layout.getBoundingClientRect();
this.adjustPosition(element, position, true);
}.bind(this));
this.onShow(element);
this.adjustButtonsState();
this.adjustButtonsContextDocument();
},
onShow: function(node)
{
target = node;
scrollHandler = scrollHandler || this.onScroll.bind(null, node);
this.contextDocument.addEventListener("keydown", this.onKeydown);
this.contextWindow.addEventListener("resize", scrollHandler);
try {
this.contextDocument.addEventListener("scroll", scrollHandler, {passive: true});
} catch (err) {
this.contextDocument.addEventListener("scroll", scrollHandler);
}
},
hide: function()
{
if (this.isShown())
{
BX.onCustomEvent("BX.Landing.Editor:disable", [null]);
this.contextDocument.removeEventListener("mousedown", onMousedown, true);
this.contextDocument.removeEventListener("mouseup", onMouseUp, true);
this.contextDocument.removeEventListener("click", onClick, true);
this.currentElement.removeEventListener("click", proxy(this.adjustButtonsState, this), true);
setTimeout(function() {
this.rect = this.layout.getBoundingClientRect();
this.layout.classList.remove("landing-ui-transition");
}.bind(this), 100);
}
BX.Landing.UI.Panel.BaseButtonPanel.prototype.hide.call(this, arguments);
this.onHide();
},
onHide: function()
{
this.contextDocument.removeEventListener("keydown", this.onKeydown);
this.contextWindow.removeEventListener("resize", scrollHandler);
try {
this.contextDocument.removeEventListener("scroll", scrollHandler, {passive: true});
} catch (err) {
this.contextDocument.removeEventListener("scroll", scrollHandler);
}
},
onKeydown: function(event)
{
// TAB key
if (
event.key === 'Tab'
&& event.target.nodeName !== "LI"
)
{
event.preventDefault();
if (!event.shiftKey)
{
if (event.code === 'Tab')
{
this.onTabDown();
}
else
{
this.contextDocument.execCommand('indent');
}
}
else
{
this.contextDocument.execCommand('outdent');
}
}
// ENTER key
if (
event.key === 'Enter'
&& event.target.nodeName !== "LI"
&& event.target.nodeName !== "UL"
&& event.metaKey === true
)
{
event.preventDefault();
const range = this.contextWindow.getSelection().getRangeAt(0);
const br = BX.create("br");
range.deleteContents();
range.insertNode(br);
const newRange = this.contextDocument.createRange();
newRange.setStartAfter(br);
newRange.collapse(true);
const sel = this.contextWindow.getSelection();
sel.removeAllRanges();
sel.addRange(newRange);
}
setTimeout(function() {
BX.Landing.UI.Panel.EditorPanel.getInstance().adjustPosition(target);
}, 10);
},
onTabDown: function()
{
var TAB_COUNT = 10;
var isAllowedTab = true;
var parentNode = this.contextWindow.getSelection().focusNode.parentNode.parentNode;
while (parentNode.tagName === 'DIV')
{
parentNode = parentNode.parentNode;
}
var countUlTag = 0;
var parentsNodeArr = [];
var allowedTagName = ['UL', 'LI', 'BLOCKQUOTE', 'DIV'];
while (allowedTagName.indexOf(parentNode.tagName) !== -1)
{
if (parentNode.tagName !== 'DIV')
{
countUlTag++;
parentsNodeArr.push(parentNode);
}
parentNode = parentNode.parentNode;
}
if (countUlTag > TAB_COUNT)
{
if (parentsNodeArr[parentsNodeArr.length - 1].tagName === 'BLOCKQUOTE')
{
var previousElement = parentsNodeArr[parentsNodeArr.length - 1].previousSibling;
while ((previousElement !== null) && (previousElement.nodeType !== 1))
{
previousElement = previousElement.previousSibling;
}
var countBlockquote = 0;
while (previousElement && previousElement.tagName === 'BLOCKQUOTE')
{
previousElement = previousElement.firstChild;
countBlockquote++;
}
if ((countUlTag - countBlockquote) > 0)
{
isAllowedTab = false;
}
}
else
{
for (var i = 1; i < parentsNodeArr.length; i++) {
if (parentsNodeArr[i].childNodes.length < 2)
{
isAllowedTab = false;
break;
}
}
if (parentsNodeArr[0].firstChild.nextSibling === null)
{
isAllowedTab = false;
}
}
}
if (isAllowedTab)
{
this.contextDocument.execCommand('indent');
}
},
onScroll: function()
{
BX.Landing.UI.Panel.EditorPanel.getInstance().adjustPosition(target);
},
adjustButtonsState: function()
{
var getAction = function(value) {
return (!value ? "de" : "") + "activate";
};
var button = function(key) {
return this.buttons.get(key);
}.bind(this);
requestAnimationFrame(function() {
var format = this.getFormat();
void (button("bold") && button("bold")[getAction(format.bold)]());
void (button("italic") && button("italic")[getAction(format.italic)]());
void (button("underline") && button("underline")[getAction(format.underline)]());
void (button("strikeThrough") && button("strikeThrough")[getAction(format.strike)]());
void (button("justifyLeft") && button("justifyLeft")[getAction(format.align === "left")]());
void (button("justifyCenter") && button("justifyCenter")[getAction(format.align === "center")]());
void (button("justifyRight") && button("justifyRight")[getAction(format.align === "right")]());
void (button("justifyFull") && button("justifyFull")[getAction(format.align === "justify")]());
}.bind(this));
},
adjustButtonsContextDocument: function()
{
this.buttons.forEach(button => {
if ('setContextDocument' in button)
{
button.setContextDocument(this.contextDocument);
}
});
},
getFormat: function()
{
var element = getSelectedElement(this.contextDocument);
var format = {};
if (element)
{
var style = getComputedStyle(element);
switch (style.getPropertyValue("font-weight"))
{
case "bold":
case "bolder":
case "500":
case "600":
case "700":
case "800":
case "900":
format["bold"] = true;
break;
}
if (element.tagName === 'B')
{
format["bold"] = true;
}
if (style.getPropertyValue("font-style") === "italic")
{
format["italic"] = true;
}
if (style.getPropertyValue("text-decoration").includes("underline") ||
style.getPropertyValue("text-decoration-line").includes("underline"))
{
format["underline"] = true;
}
if (style.getPropertyValue("text-decoration").includes("line-through") ||
style.getPropertyValue("text-decoration-line").includes("line-through"))
{
format["strike"] = true;
}
var align = style.getPropertyValue("text-align") || "left";
if (align.match(/[left|center|rigth|custiffy]/))
{
format["align"] = align;
}
if (this.currentElement.nodeName === "A" || this.currentElement.closest("a"))
{
format["link"] = true;
}
}
return format;
},
adjustPosition: function(node, position, force)
{
adjustAbsolutePosition(this, node, force);
},
isFixed: function()
{
return this.position === "fixed-top" || this.position === "fixed-right";
},
hideAllBaseButtons: function()
{
this.layout.childNodes.forEach(function(button){
if (button.dataset.id !== 'drag')
{
button.hidden = true;
}
});
},
hideBaseButtons: function(hideButtons)
{
this.layout.childNodes.forEach(function(button){
if (hideButtons.indexOf(button.dataset.id) !== -1)
{
button.hidden = true;
}
});
},
showBaseButtons: function()
{
this.layout.childNodes.forEach(button => {
if (button.dataset.id === 'pasteTable')
{
if (top.window.copiedTable)
{
button.hidden = false;
}
else
{
button.hidden = true;
}
}
else
{
button.hidden = false;
}
});
},
isOutOfFrame: function()
{
return this.outOfFrame;
}
};
})();