Current Path : /var/www/www-root/data/www/www.monolith-realty.ru/bitrix/js/ui/buttons/src/ |
Current File : /var/www/www-root/data/www/www.monolith-realty.ru/bitrix/js/ui/buttons/src/base-button.js |
import type IButton from './ibutton'; import ButtonTag from './button/button-tag'; import { Type, Tag, Dom, Event } from 'main.core'; import { type BaseButtonOptions } from './base-button-options'; import './ui.buttons.css'; export default class BaseButton implements IButton { constructor(options: BaseButtonOptions) { options = Type.isPlainObject(options) ? options : {}; this.options = Object.assign(this.getDefaultOptions(), options); /** * 'buttonNode', 'textNode' and counterNode options use only in ButtonManager.createFromNode */ this.button = Type.isDomNode(this.options.buttonNode) ? this.options.buttonNode : null; this.textNode = Type.isDomNode(this.options.textNode) ? this.options.textNode : null; this.counterNode = Type.isDomNode(this.options.counterNode) ? this.options.counterNode : null; this.text = ''; this.counter = null; this.events = {}; this.link = ''; this.maxWidth = null; this.tag = this.isEnumValue(this.options.tag, ButtonTag) ? this.options.tag : ButtonTag.BUTTON; if (Type.isStringFilled(this.options.link)) { this.tag = ButtonTag.LINK; } this.baseClass = Type.isStringFilled(this.options.baseClass) ? this.options.baseClass : ''; this.disabled = false; this.handleEvent = this.handleEvent.bind(this); this.init(); // needs to initialize private properties in derived classes. if (this.options.disabled === true) { this.setDisabled(); } this.setText(this.options.text); this.setCounter(this.options.counter); this.setProps(this.options.props); this.setDataSet(this.options.dataset); this.addClass(this.options.className); this.setLink(this.options.link); this.setMaxWidth(this.options.maxWidth); this.bindEvent('click', this.options.onclick); this.bindEvents(this.options.events); } /** * @protected */ init(): void { // needs to initialize private properties in derived classes. } /** * @protected */ getDefaultOptions(): Object { return {}; } /** * @public * @return {HTMLElement} */ render(): HTMLElement { return this.getContainer(); } /** * @public * @param {HTMLElement} node * @return {?HTMLElement} */ renderTo(node: HTMLElement): HTMLElement | null { if (Type.isDomNode(node)) { return node.appendChild(this.getContainer()); } return null; } /** * @public * @return {HTMLElement} */ getContainer(): HTMLElement { if (this.button !== null) { return this.button; } switch (this.getTag()) { case ButtonTag.BUTTON: default: this.button = Tag.render`<button class="${this.getBaseClass()}"></button>`; break; case ButtonTag.INPUT: this.button = Tag.render`<input class="${this.getBaseClass()}" type="button">`; break; case ButtonTag.LINK: this.button = Tag.render`<a class="${this.getBaseClass()}" href=""></a>`; break; case ButtonTag.SUBMIT: this.button = Tag.render`<input class="${this.getBaseClass()}" type="submit">`; break; case ButtonTag.DIV: this.button = Tag.render`<div class="${this.getBaseClass()}"></div>`; break; case ButtonTag.SPAN: this.button = Tag.render`<span class="${this.getBaseClass()}"></span>`; break; } return this.button; } /** * @protected * @return {string} */ getBaseClass(): string { return this.baseClass; } /** * @public * @param {string} text * @return {this} */ setText(text: string): this { if (Type.isString(text)) { this.text = text; if (this.isInputType()) { this.getContainer().value = text; } else if (text.length > 0) { if (this.textNode === null) { this.textNode = Tag.render`<span class="ui-btn-text"></span>`; } if (!this.textNode.parentNode) { Dom.prepend(this.textNode, this.getContainer()); } this.textNode.textContent = text; } else { if (this.textNode !== null) { Dom.remove(this.textNode); } } } return this; } /** * @public * @return {string} */ getText(): string { return this.text; } /** * * @param {number | string} counter * @return {this} */ setCounter(counter: number | string): this { if ([0, '0', '', null, false].includes(counter)) { if (this.counterNode !== null) { Dom.remove(this.counterNode); this.counterNode = null; } this.counter = null; } else if ((Type.isNumber(counter) && counter > 0) || Type.isStringFilled(counter)) { if (this.isInputType()) { throw new Error('BX.UI.Button: an input button cannot have a counter.'); } if (this.counterNode === null) { this.counterNode = Tag.render`<span class="ui-btn-counter"></span>`; Dom.append(this.counterNode, this.getContainer()); } this.counter = counter; this.counterNode.textContent = counter; } return this; } /** * * @return {number | string | null} */ getCounter(): number | string | null { return this.counter; } /** * * @param {string} link * @return {this} */ setLink(link: string): this { if (Type.isString(link)) { if (this.getTag() !== ButtonTag.LINK) { throw new Error('BX.UI.Button: only an anchor button tag supports a link.'); } this.getContainer().href = link; } return this; } /** * * @return {string} */ getLink(): string { return this.getContainer().href; } setMaxWidth(maxWidth: number): this { if (Type.isNumber(maxWidth) && maxWidth > 0) { this.maxWidth = maxWidth; this.getContainer().style.maxWidth = `${maxWidth}px`; } else if (maxWidth === null) { this.getContainer().style.removeProperty('max-width'); this.maxWidth = null; } return this; } getMaxWidth(): number | null { return this.maxWidth; } /** * @public * @return {ButtonTag} */ getTag(): ButtonTag { return this.tag; } /** * @public * @param {object.<string, string>} props * @return {this} */ setProps(props: { [propertyName: string]: string }): this { if (!Type.isPlainObject(props)) { return this; } for (let propName in props) { const propValue = props[propName]; Dom.attr(this.getContainer(), propName, propValue); } return this; } /** * @public * @return {object.<string, string>} */ getProps(): { [propertyName: string]: string } { const attrs = this.getContainer().attributes; const result = {}; const reserved = this.isInputType() ? ['class', 'type'] : ['class']; for (let i = 0; i < attrs.length; i++) { const { name, value } = attrs[i]; if (reserved.includes(name) || name.startsWith('data-')) { continue; } result[name] = value; } return result; } /** * @public * @param {object.<string, string>} props * @return {this} */ setDataSet(props: { [propertyName: string]: string }): this { if (!Type.isPlainObject(props)) { return this; } for (let propName in props) { const propValue = props[propName]; if (propValue === null) { delete this.getDataSet()[propName]; } else { this.getDataSet()[propName] = propValue; } } return this; } /** * @public * @return {DOMStringMap} */ getDataSet(): DOMStringMap { return this.getContainer().dataset; } /** * @public * @param {string} className * @return {this} */ addClass(className: string): this { if (Type.isStringFilled(className)) { Dom.addClass(this.getContainer(), className); } return this; } /** * @public * @param {string} className * @return {this} */ removeClass(className: string): this { if (Type.isStringFilled(className)) { Dom.removeClass(this.getContainer(), className); } return this; } /** * @public * @param {boolean} [flag=true] * @return {this} */ setDisabled(flag?: boolean): this { if (flag === false) { this.disabled = false; this.setProps({ disabled: null }); } else { this.disabled = true; this.setProps({ disabled: true }); } return this; } /** * * @return {boolean} */ isDisabled(): boolean { return this.disabled; } /** * @public * @return {boolean} */ isInputType(): boolean { return this.getTag() === ButtonTag.SUBMIT || this.getTag() === ButtonTag.INPUT; } /** * @public * @param {object.<string, function>} events * @return {this} */ bindEvents(events: { [event: string]: (button: this, event: MouseEvent) => {} }): this { if (Type.isPlainObject(events)) { for (let eventName in events) { const fn = events[eventName]; this.bindEvent(eventName, fn); } } return this; } /** * @public * @param {string[]} events * @return {this} */ unbindEvents(events: string[]): this { if (Type.isArray(events)) { events.forEach(eventName => { this.unbindEvent(eventName); }); } return this; } /** * @public * @param {string} eventName * @param {function} fn * @return {this} */ bindEvent(eventName: string, fn: (button: this, event: MouseEvent) => {}): this { if (Type.isStringFilled(eventName) && Type.isFunction(fn)) { this.unbindEvent(eventName); this.events[eventName] = fn; Event.bind(this.getContainer(), eventName, this.handleEvent); } return this; } /** * @public * @param {string} eventName * @return {this} */ unbindEvent(eventName: string): this { if (this.events[eventName]) { delete this.events[eventName]; Event.unbind(this.getContainer(), eventName, this.handleEvent); } return this; } /** * @private * @param {MouseEvent} event */ handleEvent(event) { const eventName = event.type; if (this.events[eventName]) { const fn = this.events[eventName]; fn.call(this, this, event); } } /** * @protected */ isEnumValue(value, enumeration): boolean { for (let code in enumeration) { if (enumeration[code] === value) { return true; } } return false; } }