UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

467 lines (395 loc) • 14.6 kB
"use strict"; var $ = require("../core/renderer"), eventsEngine = require("../events/core/events_engine"), windowUtils = require("../core/utils/window"), extend = require("./utils/extend").extend, config = require("./config"), errors = require("./errors"), getPublicElement = require("../core/utils/dom").getPublicElement, windowResizeCallbacks = require("../core/utils/resize_callbacks"), commonUtils = require("./utils/common"), each = require("./utils/iterator").each, typeUtils = require("./utils/type"), inArray = require("./utils/array").inArray, publicComponentUtils = require("./utils/public_component"), dataUtils = require("./element_data"), Component = require("./component"), abstract = Component.abstract; var RTL_DIRECTION_CLASS = "dx-rtl", VISIBILITY_CHANGE_CLASS = "dx-visibility-change-handler", VISIBILITY_CHANGE_EVENTNAMESPACE = "VisibilityChange"; /** * @name domcomponent * @section uiWidgets * @publicName DOMComponent * @type object * @inherits Component * @namespace DevExpress * @module core/dom_component * @export default * @hidden */ var DOMComponent = Component.inherit({ _getDefaultOptions: function _getDefaultOptions() { return extend(this.callBase(), { /** * @name domcomponentoptions.onOptionChanged * @publicName onOptionChanged * @type function * @type_function_param1 e:object * @type_function_param1_field4 name:string * @type_function_param1_field5 fullName:string * @type_function_param1_field6 value:any * @action * @extends Action * @inheritdoc */ /** * @name domcomponentoptions.onDisposing * @publicName onDisposing * @action * @extends Action * @inheritdoc */ /** * @name domcomponentoptions.width * @publicName width * @type number|string|function * @default undefined * @type_function_return number|string */ width: undefined, /** * @name domcomponentoptions.height * @publicName height * @type number|string|function * @default undefined * @type_function_return number|string */ height: undefined, /** * @name domcomponentoptions.rtlEnabled * @publicName rtlEnabled * @type boolean * @default false */ rtlEnabled: config().rtlEnabled, /** * @name domcomponentoptions.elementAttr * @publicName elementAttr * @type object * @default {} */ elementAttr: {}, disabled: false, integrationOptions: {} }); }, /** * @name DOMComponentMethods.ctor * @publicName ctor(element,options) * @param1 element:Node|JQuery * @param2 options:DOMComponentOptions|undefined * @hidden */ ctor: function ctor(element, options) { this._$element = $(element); publicComponentUtils.attachInstanceToElement(this._$element, this, this._dispose); this.callBase(options); }, _visibilityChanged: abstract, _dimensionChanged: abstract, _init: function _init() { this.callBase(); this._attachWindowResizeCallback(); }, _setOptionsByDevice: function _setOptionsByDevice(instanceCustomRules) { this.callBase([].concat(this.constructor._classCustomRules || [], instanceCustomRules || [])); }, _isInitialOptionValue: function _isInitialOptionValue(name) { var isCustomOption = this.constructor._classCustomRules && this._convertRulesToOptions(this.constructor._classCustomRules).hasOwnProperty(name); return !isCustomOption && this.callBase(name); }, _attachWindowResizeCallback: function _attachWindowResizeCallback() { if (this._isDimensionChangeSupported()) { var windowResizeCallBack = this._windowResizeCallBack = this._dimensionChanged.bind(this); windowResizeCallbacks.add(windowResizeCallBack); } }, _isDimensionChangeSupported: function _isDimensionChangeSupported() { return this._dimensionChanged !== abstract; }, _renderComponent: function _renderComponent() { this._initMarkup(); if (windowUtils.hasWindow()) { this._render(); } }, _initMarkup: function _initMarkup() { this._renderElementAttributes(); this._toggleRTLDirection(this.option("rtlEnabled")); this._renderVisibilityChange(); this._renderDimensions(); }, _render: function _render() { this._attachVisibilityChangeHandlers(); }, _renderElementAttributes: function _renderElementAttributes() { var attributes = extend({}, this.option("elementAttr")), classNames = attributes.class; delete attributes.class; this.$element().attr(attributes).addClass(classNames); }, _renderVisibilityChange: function _renderVisibilityChange() { if (this._isDimensionChangeSupported()) { this._attachDimensionChangeHandlers(); } if (!this._isVisibilityChangeSupported()) { return; } this.$element().addClass(VISIBILITY_CHANGE_CLASS); }, _renderDimensions: function _renderDimensions() { var $element = this.$element(); var element = $element.get(0); var width = this._getOptionValue("width", element); var height = this._getOptionValue("height", element); if (this._isCssUpdateRequired(element, height, width)) { $element.css({ width: width, height: height }); } }, _isCssUpdateRequired: function _isCssUpdateRequired(element, height, width) { return !!(width || height || element.style.width || element.style.height); }, _attachDimensionChangeHandlers: function _attachDimensionChangeHandlers() { var that = this; var resizeEventName = "dxresize." + this.NAME + VISIBILITY_CHANGE_EVENTNAMESPACE; eventsEngine.off(that.$element(), resizeEventName); eventsEngine.on(that.$element(), resizeEventName, function () { that._dimensionChanged(); }); }, _attachVisibilityChangeHandlers: function _attachVisibilityChangeHandlers() { if (!this._isVisibilityChangeSupported()) { return; } var that = this; var hidingEventName = "dxhiding." + this.NAME + VISIBILITY_CHANGE_EVENTNAMESPACE; var shownEventName = "dxshown." + this.NAME + VISIBILITY_CHANGE_EVENTNAMESPACE; that._isHidden = !that._isVisible(); eventsEngine.off(that.$element(), hidingEventName); eventsEngine.on(that.$element(), hidingEventName, function () { that._checkVisibilityChanged("hiding"); }); eventsEngine.off(that.$element(), shownEventName); eventsEngine.on(that.$element(), shownEventName, function () { that._checkVisibilityChanged("shown"); }); }, _isVisible: function _isVisible() { return this.$element().is(":visible"); }, _checkVisibilityChanged: function _checkVisibilityChanged(event) { if (event === "hiding" && this._isVisible() && !this._isHidden) { this._visibilityChanged(false); this._isHidden = true; } else if (event === "shown" && this._isVisible() && this._isHidden) { this._isHidden = false; this._visibilityChanged(true); } }, _isVisibilityChangeSupported: function _isVisibilityChangeSupported() { return this._visibilityChanged !== abstract && windowUtils.hasWindow(); }, _clean: commonUtils.noop, _modelByElement: function _modelByElement() { var modelByElement = this.option("modelByElement") || commonUtils.noop; return modelByElement(this.$element()); }, _invalidate: function _invalidate() { if (!this._updateLockCount) { throw errors.Error("E0007"); } this._requireRefresh = true; }, _refresh: function _refresh() { this._clean(); this._renderComponent(); }, _dispose: function _dispose() { this.callBase(); this._clean(); this._detachWindowResizeCallback(); }, _detachWindowResizeCallback: function _detachWindowResizeCallback() { if (this._isDimensionChangeSupported()) { windowResizeCallbacks.remove(this._windowResizeCallBack); } }, _toggleRTLDirection: function _toggleRTLDirection(rtl) { this.$element().toggleClass(RTL_DIRECTION_CLASS, rtl); }, _createComponent: function _createComponent(element, component, config) { var that = this; config = config || {}; var synchronizableOptions = commonUtils.grep(["rtlEnabled", "disabled"], function (value) { return !(value in config); }); var nestedComponentOptions = that.option("nestedComponentOptions") || commonUtils.noop; that._extendConfig(config, extend({ integrationOptions: this.option("integrationOptions"), rtlEnabled: this.option("rtlEnabled"), disabled: this.option("disabled") }, nestedComponentOptions(this))); var instance; if (typeUtils.isString(component)) { var $element = $(element)[component](config); instance = $element[component]("instance"); } else if (element) { instance = component.getInstance(element); if (instance) { instance.option(config); } else { instance = new component(element, config); } } if (instance) { var optionChangedHandler = function optionChangedHandler(args) { if (inArray(args.name, synchronizableOptions) >= 0) { instance.option(args.name, args.value); } }; that.on("optionChanged", optionChangedHandler); instance.on("disposing", function () { that.off("optionChanged", optionChangedHandler); }); } return instance; }, _extendConfig: function _extendConfig(config, extendConfig) { each(extendConfig, function (key, value) { config[key] = config.hasOwnProperty(key) ? config[key] : value; }); }, _defaultActionConfig: function _defaultActionConfig() { return extend(this.callBase(), { context: this._modelByElement(this.$element()) }); }, /** * @pseudo Action * @section Utils * @type function * @default null * @type_function_param1 e:object * @type_function_param1_field1 component:DOMComponent * @type_function_param1_field2 element:dxElement * @type_function_param1_field3 model:object **/ _defaultActionArgs: function _defaultActionArgs() { var model = this._modelByElement(this.$element()); return extend(this.callBase(), { element: this.element(), model: model }); }, _optionChanged: function _optionChanged(args) { switch (args.name) { case "width": case "height": this._renderDimensions(); break; case "rtlEnabled": case "elementAttr": this._invalidate(); break; case "disabled": case "integrationOptions": break; default: this.callBase(args); break; } }, _removeAttributes: function _removeAttributes(element) { var i = element.attributes.length - 1; for (; i >= 0; i--) { var attribute = element.attributes[i]; if (!attribute) { return; } var attributeName = attribute.name; if (attributeName.indexOf("aria-") === 0 || attributeName.indexOf("dx-") !== -1 || attributeName === "role" || attributeName === "style" || attributeName === "tabindex") { element.removeAttribute(attributeName); } } }, _removeClasses: function _removeClasses(element) { var classes = element.className.split(" ").filter(function (cssClass) { return cssClass.lastIndexOf("dx-", 0) !== 0; }); element.className = classes.join(" "); }, endUpdate: function endUpdate() { var requireRender = !this._initializing && !this._initialized; this.callBase.apply(this, arguments); if (!this._updateLockCount) { if (requireRender) { this._renderComponent(); } else if (this._requireRefresh) { this._requireRefresh = false; this._refresh(); } } }, $element: function $element() { return this._$element; }, /** * @name domcomponentmethods.element * @publicName element() * @return dxElement */ element: function element() { return getPublicElement(this.$element()); }, /** * @name domcomponentmethods.dispose * @publicName dispose() */ dispose: function dispose() { var element = this.$element().get(0); dataUtils.cleanDataRecursive(element, true); element.textContent = ""; this._removeAttributes(element); this._removeClasses(element); } }); /** * @name domcomponentmethods.getInstance * @static * @section uiWidgets * @publicName getInstance(element) * @param1 element:Node|JQuery * @return DOMComponent */ DOMComponent.getInstance = function (element) { return publicComponentUtils.getInstanceByElement($(element), this); }; /** * @name domcomponentmethods.defaultOptions * @static * @section uiWidgets * @publicName defaultOptions(rule) * @param1 rule:Object * @param1_field1 device:Device|Array<Device>|function * @param1_field2 options:Object */ DOMComponent.defaultOptions = function (rule) { this._classCustomRules = this._classCustomRules || []; this._classCustomRules.push(rule); }; module.exports = DOMComponent;