devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
267 lines (266 loc) • 9.6 kB
JavaScript
/**
* DevExtreme (ui/button.js)
* Version: 18.1.3
* Build date: Tue May 15 2018
*
* Copyright (c) 2012 - 2018 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
"use strict";
var $ = require("../core/renderer"),
eventsEngine = require("../events/core/events_engine"),
iconUtils = require("../core/utils/icon"),
domUtils = require("../core/utils/dom"),
devices = require("../core/devices"),
registerComponent = require("../core/component_registrator"),
extend = require("../core/utils/extend").extend,
ValidationMixin = require("./validation/validation_mixin"),
ValidationEngine = require("./validation_engine"),
Widget = require("./widget/ui.widget"),
inkRipple = require("./widget/utils.ink_ripple"),
eventUtils = require("../events/utils"),
themes = require("./themes"),
clickEvent = require("../events/click"),
FunctionTemplate = require("./widget/function_template");
var BUTTON_CLASS = "dx-button",
BUTTON_CONTENT_CLASS = "dx-button-content",
BUTTON_HAS_TEXT_CLASS = "dx-button-has-text",
BUTTON_HAS_ICON_CLASS = "dx-button-has-icon",
TEMPLATE_WRAPPER_CLASS = "dx-template-wrapper",
BUTTON_TEXT_CLASS = "dx-button-text",
ANONYMOUS_TEMPLATE_NAME = "content",
BUTTON_FEEDBACK_HIDE_TIMEOUT = 100;
var Button = Widget.inherit({
_supportedKeys: function() {
var that = this,
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: "",
validationGroup: void 0,
activeStateEnabled: true,
template: "content",
useSubmitBehavior: false,
useInkRipple: false
})
},
_defaultOptionsRules: function() {
return this.callBase().concat([{
device: function() {
return "desktop" === devices.real().deviceType && !devices.isSimulator()
},
options: {
focusStateEnabled: true
}
}, {
device: function() {
return /(android5|material)/.test(themes.current())
},
options: {
useInkRipple: true
}
}])
},
_getAnonymousTemplateName: function() {
return ANONYMOUS_TEMPLATE_NAME
},
_feedbackHideTimeout: BUTTON_FEEDBACK_HIDE_TIMEOUT,
_initTemplates: function() {
this.callBase();
this._defaultTemplates.content = new FunctionTemplate(function(options) {
var data = options.model,
$iconElement = iconUtils.getImageContainer(data && data.icon),
$textContainer = data && data.text ? $("<span>").text(data.text).addClass(BUTTON_TEXT_CLASS) : void 0;
$(options.container).append($iconElement).append($textContainer)
}, this)
},
_initMarkup: function() {
this.$element().addClass(BUTTON_CLASS);
this._renderType();
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"),
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(),
data = this._getContentData();
if (this._$content) {
this._$content.empty()
} else {
this._$content = $("<div>").addClass(BUTTON_CONTENT_CLASS).appendTo($element)
}
$element.toggleClass(BUTTON_HAS_ICON_CLASS, !!data.icon).toggleClass(BUTTON_HAS_TEXT_CLASS, !!data.text);
var template = this._getTemplateByOption("template"),
$result = $(template.render({
model: data,
container: domUtils.getPublicElement(this._$content)
}));
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,
validationGroup = ValidationEngine.getGroupConfig(args.component._findGroup());
if (validationGroup && !validationGroup.validate().isValid) {
e.preventDefault()
}
e.stopPropagation()
});
this._$submitInput = $("<input>").attr("type", "submit").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"),
text = this.option("text"),
back = "back" === this.option("type");
if (back && !icon) {
icon = "back"
}
return {
icon: icon,
text: text
}
},
_renderClick: function() {
var that = this,
eventName = eventUtils.addNamespace(clickEvent.name, this.NAME),
actionConfig = {};
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"),
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)
},
_renderType: function() {
var type = this.option("type");
if (type) {
this.$element().addClass("dx-button-" + type)
}
},
_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":
this._updateContent();
break;
case "useInkRipple":
this._invalidate();
break;
case "useSubmitBehavior":
this._invalidate();
break;
default:
this.callBase(args)
}
},
_clean: function() {
this.callBase();
delete this._$content;
delete this._inkRipple
}
}).include(ValidationMixin);
registerComponent("dxButton", Button);
module.exports = Button;
module.exports.default = module.exports;