/** * DevExtreme (ui/button.js) * Version: 19.1.16 * Build date: Tue Oct 18 2022 * * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; var $ = require("../core/renderer"); var eventsEngine = require("../events/core/events_engine"); var iconUtils = require("../core/utils/icon"); var domUtils = require("../core/utils/dom"); var devices = require("../core/devices"); var registerComponent = require("../core/component_registrator"); var extend = require("../core/utils/extend").extend; var ValidationMixin = require("./validation/validation_mixin"); var ValidationEngine = require("./validation_engine"); var Widget = require("./widget/ui.widget"); var inkRipple = require("./widget/utils.ink_ripple"); var eventUtils = require("../events/utils"); var themes = require("./themes"); var clickEvent = require("../events/click"); var FunctionTemplate = require("./widget/function_template"); var BUTTON_CLASS = "dx-button"; var BUTTON_CONTENT_CLASS = "dx-button-content"; var BUTTON_HAS_TEXT_CLASS = "dx-button-has-text"; var BUTTON_HAS_ICON_CLASS = "dx-button-has-icon"; var BUTTON_ICON_RIGHT_CLASS = "dx-button-icon-right"; var ICON_RIGHT_CLASS = "dx-icon-right"; var BUTTON_STYLING_MODE_CLASS_PREFIX = "dx-button-mode-"; var ALLOWED_STYLE_CLASSES = [BUTTON_STYLING_MODE_CLASS_PREFIX + "contained", BUTTON_STYLING_MODE_CLASS_PREFIX + "text", BUTTON_STYLING_MODE_CLASS_PREFIX + "outlined"]; var TEMPLATE_WRAPPER_CLASS = "dx-template-wrapper"; var BUTTON_TEXT_CLASS = "dx-button-text"; var ANONYMOUS_TEMPLATE_NAME = "content"; var BUTTON_LEFT_ICON_POSITION = "left"; var BUTTON_FEEDBACK_HIDE_TIMEOUT = 100; var Button = Widget.inherit({ _supportedKeys: function() { var that = this; var click = function(e) { e.preventDefault(); that._executeClickAction(e) }; return extend(this.callBase(), { space: click, enter: click }) }, _setDeprecatedOptions: function() { this.callBase() }, _getDefaultOptions: function() { return extend(this.callBase(), { hoverStateEnabled: true, onClick: null, type: "normal", text: "", icon: "", iconPosition: BUTTON_LEFT_ICON_POSITION, validationGroup: void 0, activeStateEnabled: true, template: "content", useSubmitBehavior: false, useInkRipple: false, stylingMode: "contained" }) }, _defaultOptionsRules: function() { return this.callBase().concat([{ device: function() { return "desktop" === devices.real().deviceType && !devices.isSimulator() }, options: { focusStateEnabled: true } }, { device: function() { var themeName = themes.current(); return themes.isMaterial(themeName) }, options: { useInkRipple: true } }]) }, _getAnonymousTemplateName: function() { return ANONYMOUS_TEMPLATE_NAME }, _feedbackHideTimeout: BUTTON_FEEDBACK_HIDE_TIMEOUT, _initTemplates: function() { this.callBase(); var that = this; this._defaultTemplates.content = new FunctionTemplate(function(options) { var data = options.model; var $iconElement = iconUtils.getImageContainer(data && data.icon); var $textContainer = data && data.text ? $("").text(data.text).addClass(BUTTON_TEXT_CLASS) : void 0; var $container = $(options.container); $container.append($textContainer); if (that.option("iconPosition") === BUTTON_LEFT_ICON_POSITION) { $container.prepend($iconElement) } else { $iconElement.addClass(ICON_RIGHT_CLASS); $container.append($iconElement) } }, this) }, _initMarkup: function() { this.$element().addClass(BUTTON_CLASS); this._renderType(); this._renderStylingMode(); this.option("useInkRipple") && this._renderInkRipple(); this._renderClick(); this.setAria("role", "button"); this._updateAriaLabel(); this.callBase(); this._updateContent() }, _renderInkRipple: function() { var isOnlyIconButton = !this.option("text") && this.option("icon") || "back" === this.option("type"); var config = {}; if (isOnlyIconButton) { extend(config, { waveSizeCoefficient: 1, useHoldAnimation: false, isCentered: true }) } this._inkRipple = inkRipple.render(config) }, _toggleActiveState: function($element, value, e) { this.callBase.apply(this, arguments); if (!this._inkRipple) { return } var config = { element: this._$content, event: e }; if (value) { this._inkRipple.showWave(config) } else { this._inkRipple.hideWave(config) } }, _updateContent: function() { var $element = this.$element(); var data = this._getContentData(); if (this._$content) { this._$content.empty() } else { this._$content = $("
").addClass(BUTTON_CONTENT_CLASS).appendTo($element) } $element.toggleClass(BUTTON_HAS_ICON_CLASS, !!data.icon).toggleClass(BUTTON_ICON_RIGHT_CLASS, !!data.icon && this.option("iconPosition") !== BUTTON_LEFT_ICON_POSITION).toggleClass(BUTTON_HAS_TEXT_CLASS, !!data.text); var transclude = this._getAnonymousTemplateName() === this.option("template"); var template = this._getTemplateByOption("template"); var $result = $(template.render({ model: data, container: domUtils.getPublicElement(this._$content), transclude: transclude })); if ($result.hasClass(TEMPLATE_WRAPPER_CLASS)) { this._$content.replaceWith($result); this._$content = $result; this._$content.addClass(BUTTON_CONTENT_CLASS) } if (this.option("useSubmitBehavior")) { this._renderSubmitInput() } }, _renderSubmitInput: function() { var submitAction = this._createAction(function(args) { var e = args.event; var validationGroup = ValidationEngine.getGroupConfig(args.component._findGroup()); if (validationGroup && !validationGroup.validate().isValid) { e.preventDefault() } e.stopPropagation() }); this._$submitInput = $("").attr("type", "submit").attr("tabindex", -1).addClass("dx-button-submit-input").appendTo(this._$content); eventsEngine.on(this._$submitInput, "click", function(e) { submitAction({ event: e }) }) }, _getContentData: function() { var icon = this.option("icon"); var text = this.option("text"); var back = "back" === this.option("type"); if (back && !icon) { icon = "back" } return { icon: icon, text: text } }, _renderClick: function() { var that = this; var eventName = eventUtils.addNamespace(clickEvent.name, this.NAME); var actionConfig = { excludeValidators: ["readOnly"] }; if (this.option("useSubmitBehavior")) { actionConfig.afterExecute = function(e) { setTimeout(function() { e.component._$submitInput.get(0).click() }) } } this._clickAction = this._createActionByOption("onClick", actionConfig); eventsEngine.off(this.$element(), eventName); eventsEngine.on(this.$element(), eventName, function(e) { that._executeClickAction(e) }) }, _executeClickAction: function(e) { this._clickAction({ event: e, validationGroup: ValidationEngine.getGroupConfig(this._findGroup()) }) }, _updateAriaLabel: function() { var icon = this.option("icon"); var text = this.option("text"); if ("image" === iconUtils.getImageSourceType(icon)) { if (icon.indexOf("base64") === -1) { icon = icon.replace(/.+\/([^.]+)\..+$/, "$1") } else { icon = "Base64" } } var ariaLabel = text || icon || ""; ariaLabel = ariaLabel.toString().trim(); this.setAria("label", ariaLabel.length ? ariaLabel : null) }, _renderType: function() { var type = this.option("type"); if (type) { this.$element().addClass("dx-button-" + type) } }, _renderStylingMode: function() { var _this = this; var optionName = "stylingMode"; ALLOWED_STYLE_CLASSES.forEach(function(className) { return _this.$element().removeClass(className) }); var stylingModeClass = BUTTON_STYLING_MODE_CLASS_PREFIX + this.option(optionName); if (ALLOWED_STYLE_CLASSES.indexOf(stylingModeClass) === -1) { var defaultOptionValue = this._getDefaultOptions()[optionName]; stylingModeClass = BUTTON_STYLING_MODE_CLASS_PREFIX + defaultOptionValue } this.$element().addClass(stylingModeClass) }, _refreshType: function(prevType) { var type = this.option("type"); prevType && this.$element().removeClass("dx-button-" + prevType).addClass("dx-button-" + type); if (!this.$element().hasClass(BUTTON_HAS_ICON_CLASS) && "back" === type) { this._updateContent() } }, _optionChanged: function(args) { switch (args.name) { case "onClick": this._renderClick(); break; case "icon": case "text": this._updateContent(); this._updateAriaLabel(); break; case "type": this._refreshType(args.previousValue); this._updateContent(); this._updateAriaLabel(); break; case "template": case "iconPosition": this._updateContent(); break; case "stylingMode": this._renderStylingMode(); break; case "useInkRipple": case "useSubmitBehavior": this._invalidate(); break; default: this.callBase(args) } }, _clean: function() { delete this._inkRipple; this.callBase(); delete this._$content } }).include(ValidationMixin); registerComponent("dxButton", Button); module.exports = Button; module.exports.default = module.exports;