Current Path : /var/www/www-root/data/www/info.monolith-realty.ru/bitrix/js/ui/hint/ |
Current File : /var/www/www-root/data/www/info.monolith-realty.ru/bitrix/js/ui/hint/ui.hint.js |
;(function () { "use strict"; BX.namespace("BX.UI"); if (BX.UI.Hint) { return; } /** * Check is hovered element or not. * @param {Object} cursorPosition * @param {HTMLElement} element * @returns */ var isHovered = function(cursorPosition, element) { var elementRect = element.getBoundingClientRect(); var xMarginLeft = elementRect.x; var xMarginRight = elementRect.x + elementRect.width; var yMarginLeft = elementRect.y; var yMarginRight = elementRect.y + elementRect.height; return xMarginLeft <= cursorPosition.x && cursorPosition.x <= xMarginRight && yMarginLeft <= cursorPosition.y && cursorPosition.y <= yMarginRight; }; /** * Hint manager. * * @param {object} [parameters] - Parameters. * @param {string} [parameters.id] - Id hint instance and id popup window. * @param {string} [parameters.attributeName] - Name of hint attribute. * @param {string} [parameters.attributeInitName] - Name of init hint attribute. * @param {string} [parameters.classNameIcon] * @param {string} [parameters.className] * @param {Element} [parameters.content] - Content node for text of hint. * @param {BX.PopupWindow} [parameters.popup] - Custom popup instance. * @param {object} [parameters.popupParameters] - Parameters for standard popup. * @constructor */ function Manager (parameters) { parameters = parameters || {}; this.id = 'ui-hint-popup-' + (+new Date()); if (parameters.id) { this.id = parameters.id; } if (parameters.attributeName) { this.attributeName = parameters.attributeName; } if (parameters.classNameIcon) { this.classNameIcon = parameters.classNameIcon; } if (parameters.className) { this.className = parameters.className; } if (parameters.attributeInitName) { this.attributeInitName = parameters.attributeInitName; } if (parameters.content) { if (!BX.type.isDomNode(parameters.content)) { throw new Error('Parameter `content` should be a DOM Node.'); } this.content = parameters.content; } if (parameters.popup) { if (!(parameters.popup instanceof BX.PopupWindow)) { throw new Error('Parameter `popup` should be an instance of BX.PopupWindow.'); } this.popup = parameters.popup; } if (parameters.popupParameters) { this.popupParameters = parameters.popupParameters; } this.initByClassName(); BX.ready(this.initByClassName.bind(this)); } Manager.prototype = { attributeName: 'data-hint', attributeHtmlName: 'data-hint-html', attributeInitName: 'data-hint-init', attributeInteractivityName: 'data-hint-interactivity', className: 'ui-hint', classNameIcon: 'ui-hint-icon', classNameContent: 'ui-hint-content', classNamePopup: 'ui-hint-popup', classNamePopupInteractivity: 'ui-hint-popup-interactivity', popup: null, content: null, popupParameters: null, ownerDocument: null, cursorPosition: {x:0, y:0}, anchorNode: null, /** * Create instance of manager. Use for customization purposes. * * @param {object} [parameters] - Parameters. * @returns {Manager} */ createInstance: function (parameters) { return new Manager(parameters); }, /** * Init all hints founded by class name on document. */ initByClassName: function () { var nodes = document.getElementsByClassName(this.className); nodes = BX.convert.nodeListToArray(nodes); nodes.forEach(this.initNode, this); }, /** * Init hints that was found in context. Use for mass initialization of hints. * * @param {HTMLElement} [context] - Context. */ init: function (context) { context = context || document.body; var nodes = context.querySelectorAll('[' + this.attributeName + ']'); nodes = BX.convert.nodeListToArray(nodes); nodes.forEach(this.initNode, this); this.initOwnerDocument(context); }, /** * Init the owner document to track the cursor position. * @param {HTMLElement} element * @returns */ initOwnerDocument: function (element) { if (element.ownerDocument === this.ownerDocument) { return; } this.ownerDocument = element.ownerDocument; BX.bind(this.ownerDocument, 'mousemove', (e) => { this.cursorPosition.x = e.x; this.cursorPosition.y = e.y; }); }, /** * Create hint node. Use in js-generated layout. * Return node with styles, icon and bound event handlers. * * @param {string} text - Text of hint. * @returns {Element|*} */ createNode: function (text) { var node = document.createElement('span'); node.setAttribute(this.attributeName, text); this.initNode(node); return node; }, /** * Init hind node. Add styles, icon, event handlers. * * @param {Element} node - Element node of hint. */ initNode: function (node) { if (node.getAttribute(this.attributeInitName)) { return; } node.setAttribute(this.attributeInitName, 'y'); var text = node.getAttribute(this.attributeName); if (!BX.type.isNotEmptyString(text)) { return; } if (!node.hasAttribute(this.attributeHtmlName)) { text = BX.util.htmlspecialchars(text); } if (!node.hasAttribute('data-hint-no-icon')) { BX.addClass(node, this.className); node.innerHTML = ''; var iconNode = document.createElement('span'); BX.addClass(iconNode, this.classNameIcon); node.appendChild(iconNode); } if (node.hasAttribute('data-hint-center')) { BX.bind(node, 'mouseenter', this.show.bind(this, node, text, true)); } else { BX.bind(node, 'mouseenter', this.show.bind(this, node, text, false)); } BX.bind(node, 'mouseleave', this.hide.bind(this, node)); }, /** * Show hint window. Automatically calls on `mouseenter` event. * * @param {Element} anchorNode - Anchor node for popup with text. * @param {string } html - Html of hint. * @param {boolean } centerPos - Position center for hint. */ show: function (anchorNode, html, centerPos) { this.anchorNode = anchorNode; if (!this.content) { this.content= document.createElement('div'); BX.addClass(this.content, this.classNameContent); } if (!this.popup) { var parameters = this.popupParameters || {}; if (typeof parameters.zIndex === "undefined") { parameters.zIndex = 1000; } if (typeof parameters.darkMode === "undefined") { parameters.darkMode = true; } if (typeof parameters.animationOptions === "undefined") { /* // bug with fast hide/show parameters.animationOptions = { show: { type: "opacity" }, close: { type: "opacity" } }; */ } if (typeof parameters.animation === "undefined") { parameters.animation = "fading-slide"; } if (typeof parameters.content === "undefined") { parameters.content = this.content; } if (typeof parameters.className === "undefined") { parameters.className = this.classNamePopup; } if (centerPos === true) { if (typeof parameters.offsetLeft === "undefined") { parameters.offsetLeft = 0; } if (typeof parameters.angle === "undefined") { parameters.angle = { offset: 0, }; } if (typeof parameters.events === "undefined") { parameters.events = { onPopupShow: function () { this.offsetLeft = this.getPopupContainer().offsetWidth ? 23 + (anchorNode.offsetWidth - this.getPopupContainer().offsetWidth) / 2 : false; setTimeout(function() { this.angle.offset = this.getPopupContainer().offsetWidth ? (this.getPopupContainer().offsetWidth / 2) - 16 : false; this.angle.element.style.left = this.angle.offset ? this.angle.offset + 'px': false; }.bind(this), 0); }, } } } else { if (typeof parameters.angle === "undefined") { parameters.angle = { offset: anchorNode.offsetWidth ? (23 + anchorNode.offsetWidth / 2) : false, }; } } this.popup = new BX.PopupWindow(this.id, anchorNode, parameters); BX.bind(this.popup.getPopupContainer(), 'mouseleave', this.hide.bind(this, this.popup.getPopupContainer())); } if (anchorNode.hasAttribute(this.attributeInteractivityName)) { BX.Dom.addClass(this.popup.getPopupContainer(), this.classNamePopupInteractivity); } else { BX.Dom.removeClass(this.popup.getPopupContainer(), this.classNamePopupInteractivity); } this.content.innerHTML = html; this.popup.setBindElement(anchorNode); this.popup.show(); if (centerPos === true) { this.popup.getPopupContainer().style.visibility = 'hidden'; setTimeout(function() { this.popup.getPopupContainer().style.visibility = ''; }.bind(this), 10); } this.timer = null; }, /** * Hide hint window. Automatically calls on `mouseleave` event. */ hide: function (anchorNode) { if (!this.popup) { return; } if (anchorNode && anchorNode.hasAttribute(this.attributeInteractivityName)) { // exit from flow with a short pause, so that when the mouse is moved diagonally, the popup does not disappear. setTimeout(() => { if (this.popup && !isHovered(this.cursorPosition, this.popup.getPopupContainer())) { this.popup.close(); } }, 100); } else { this.popup.close(); } } }; BX.UI.Hint = new Manager(); })();