devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
412 lines (347 loc) • 12.4 kB
JavaScript
"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;
/**
* @name dxbutton
* @publicName dxButton
* @inherits Widget
* @module ui/button
* @export default
*/
var Button = Widget.inherit({
_supportedKeys: function _supportedKeys() {
var that = this,
click = function click(e) {
e.preventDefault();
that._executeClickAction(e);
};
return extend(this.callBase(), {
space: click,
enter: click
});
},
_setDeprecatedOptions: function _setDeprecatedOptions() {
this.callBase();
},
_getDefaultOptions: function _getDefaultOptions() {
return extend(this.callBase(), {
/**
* @name dxButtonOptions.hoverStateEnabled
* @publicName hoverStateEnabled
* @type boolean
* @default true
* @inheritdoc
*/
hoverStateEnabled: true,
/**
* @name dxButtonOptions.onClick
* @publicName onClick
* @type function(e)|string
* @extends Action
* @type_function_param1 e:object
* @type_function_param1_field4 jQueryEvent:jQuery.Event:deprecated(event)
* @type_function_param1_field5 event:event
* @type_function_param1_field6 validationGroup:object
* @action
*/
onClick: null,
/**
* @name dxButtonOptions.type
* @publicName type
* @type Enums.ButtonType
* @default 'normal'
*/
type: "normal",
/**
* @name dxButtonOptions.text
* @publicName text
* @type string
* @default ""
*/
text: "",
/**
* @name dxButtonOptions.icon
* @publicName icon
* @type string
* @default ""
*/
icon: "",
/**
* @name dxButtonOptions.validationgroup
* @publicName validationGroup
* @type string
* @default undefined
*/
validationGroup: undefined,
/**
* @name dxButtonOptions.activeStateEnabled
* @publicName activeStateEnabled
* @type boolean
* @default true
*/
activeStateEnabled: true,
/**
* @name dxButtonOptions.template
* @publicName template
* @type template|function
* @default "content"
* @type_function_param1 buttonData:object
* @type_function_param1_field1 text:string
* @type_function_param1_field2 icon:string
* @type_function_param2 contentElement:dxElement
* @type_function_return string|Node|jQuery
*/
template: "content",
/**
* @name dxButtonOptions.useSubmitBehavior
* @publicName useSubmitBehavior
* @type boolean
* @default false
*/
useSubmitBehavior: false,
useInkRipple: false
/**
* @name dxButtonDefaultTemplate
* @publicName dxButtonDefaultTemplate
* @type object
*/
/**
* @name dxButtonDefaultTemplate.text
* @publicName text
* @type String
*/
/**
* @name dxButtonDefaultTemplate.icon
* @publicName icon
* @type String
*/
});
},
_defaultOptionsRules: function _defaultOptionsRules() {
return this.callBase().concat([{
device: function device() {
return devices.real().deviceType === "desktop" && !devices.isSimulator();
},
options: {
/**
* @name dxButtonOptions.focusStateEnabled
* @publicName focusStateEnabled
* @type boolean
* @default true @for desktop
* @inheritdoc
*/
focusStateEnabled: true
}
}, {
device: function device() {
return (/(android5|material)/.test(themes.current())
);
},
options: {
useInkRipple: true
}
}]);
},
_getAnonymousTemplateName: function _getAnonymousTemplateName() {
return ANONYMOUS_TEMPLATE_NAME;
},
_feedbackHideTimeout: BUTTON_FEEDBACK_HIDE_TIMEOUT,
_initTemplates: function _initTemplates() {
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) : undefined;
$(options.container).append($iconElement).append($textContainer);
}, this);
},
_initMarkup: function _initMarkup() {
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 _renderInkRipple() {
var isOnlyIconButton = !this.option("text") && this.option("icon") || this.option("type") === "back",
config = {};
if (isOnlyIconButton) {
extend(config, {
waveSizeCoefficient: 1,
useHoldAnimation: false,
isCentered: true
});
}
this._inkRipple = inkRipple.render(config);
},
_toggleActiveState: function _toggleActiveState($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 _updateContent() {
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 _renderSubmitInput() {
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 _getContentData() {
var icon = this.option("icon"),
text = this.option("text"),
back = this.option("type") === "back";
if (back && !icon) {
icon = "back";
}
return {
icon: icon,
text: text
};
},
_renderClick: function _renderClick() {
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 _executeClickAction(e) {
this._clickAction({ event: e, validationGroup: ValidationEngine.getGroupConfig(this._findGroup()) });
},
_updateAriaLabel: function _updateAriaLabel() {
var icon = this.option("icon"),
text = this.option("text");
if (iconUtils.getImageSourceType(icon) === "image") {
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 _renderType() {
var type = this.option("type");
if (type) {
this.$element().addClass("dx-button-" + type);
}
},
_refreshType: function _refreshType(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) && type === "back") {
this._updateContent();
}
},
_optionChanged: function _optionChanged(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 _clean() {
this.callBase();
delete this._$content;
delete this._inkRipple;
}
}).include(ValidationMixin);
registerComponent("dxButton", Button);
module.exports = Button;