UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

310 lines (309 loc) • 11.7 kB
/** * DevExtreme (core/dom_component.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"), 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"; var DOMComponent = Component.inherit({ _getDefaultOptions: function() { return extend(this.callBase(), { width: void 0, height: void 0, rtlEnabled: config().rtlEnabled, elementAttr: {}, disabled: false, integrationOptions: {} }) }, ctor: function(element, options) { this._$element = $(element); publicComponentUtils.attachInstanceToElement(this._$element, this, this._dispose); this.callBase(options) }, _visibilityChanged: abstract, _dimensionChanged: abstract, _init: function() { this.callBase(); this._attachWindowResizeCallback() }, _setOptionsByDevice: function(instanceCustomRules) { this.callBase([].concat(this.constructor._classCustomRules || [], instanceCustomRules || [])) }, _isInitialOptionValue: function(name) { var isCustomOption = this.constructor._classCustomRules && this._convertRulesToOptions(this.constructor._classCustomRules).hasOwnProperty(name); return !isCustomOption && this.callBase(name) }, _attachWindowResizeCallback: function() { if (this._isDimensionChangeSupported()) { var windowResizeCallBack = this._windowResizeCallBack = this._dimensionChanged.bind(this); windowResizeCallbacks.add(windowResizeCallBack) } }, _isDimensionChangeSupported: function() { return this._dimensionChanged !== abstract }, _renderComponent: function() { this._initMarkup(); if (windowUtils.hasWindow()) { this._render() } }, _initMarkup: function() { this._renderElementAttributes(); this._toggleRTLDirection(this.option("rtlEnabled")); this._renderVisibilityChange(); this._renderDimensions() }, _render: function() { this._attachVisibilityChangeHandlers() }, _renderElementAttributes: function() { var attributes = extend({}, this.option("elementAttr")), classNames = attributes.class; delete attributes.class; this.$element().attr(attributes).addClass(classNames) }, _renderVisibilityChange: function() { if (this._isDimensionChangeSupported()) { this._attachDimensionChangeHandlers() } if (!this._isVisibilityChangeSupported()) { return } this.$element().addClass(VISIBILITY_CHANGE_CLASS) }, _renderDimensions: function() { 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(element, height, width) { return !!(width || height || element.style.width || element.style.height) }, _attachDimensionChangeHandlers: function() { 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() { 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() { return this.$element().is(":visible") }, _checkVisibilityChanged: function(event) { if ("hiding" === event && this._isVisible() && !this._isHidden) { this._visibilityChanged(false); this._isHidden = true } else { if ("shown" === event && this._isVisible() && this._isHidden) { this._isHidden = false; this._visibilityChanged(true) } } }, _isVisibilityChangeSupported: function() { return this._visibilityChanged !== abstract && windowUtils.hasWindow() }, _clean: commonUtils.noop, _modelByElement: function() { var modelByElement = this.option("modelByElement") || commonUtils.noop; return modelByElement(this.$element()) }, _invalidate: function() { if (!this._updateLockCount) { throw errors.Error("E0007") } this._requireRefresh = true }, _refresh: function() { this._clean(); this._renderComponent() }, _dispose: function() { this.callBase(); this._clean(); this._detachWindowResizeCallback() }, _detachWindowResizeCallback: function() { if (this._isDimensionChangeSupported()) { windowResizeCallbacks.remove(this._windowResizeCallBack) } }, _toggleRTLDirection: function(rtl) { this.$element().toggleClass(RTL_DIRECTION_CLASS, rtl) }, _createComponent: function(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(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(config, extendConfig) { each(extendConfig, function(key, value) { config[key] = config.hasOwnProperty(key) ? config[key] : value }) }, _defaultActionConfig: function() { return extend(this.callBase(), { context: this._modelByElement(this.$element()) }) }, _defaultActionArgs: function() { var model = this._modelByElement(this.$element()); return extend(this.callBase(), { element: this.element(), model: model }) }, _optionChanged: function(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) } }, _removeAttributes: function(element) { var i = element.attributes.length - 1; for (; i >= 0; i--) { var attribute = element.attributes[i]; if (!attribute) { return } var attributeName = attribute.name; if (0 === attributeName.indexOf("aria-") || attributeName.indexOf("dx-") !== -1 || "role" === attributeName || "style" === attributeName || "tabindex" === attributeName) { element.removeAttribute(attributeName) } } }, _removeClasses: function(element) { var classes = element.className.split(" ").filter(function(cssClass) { return 0 !== cssClass.lastIndexOf("dx-", 0) }); element.className = classes.join(" ") }, endUpdate: function() { 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() { return this._$element }, element: function() { return getPublicElement(this.$element()) }, dispose: function() { var element = this.$element().get(0); dataUtils.cleanDataRecursive(element, true); element.textContent = ""; this._removeAttributes(element); this._removeClasses(element) } }); DOMComponent.getInstance = function(element) { return publicComponentUtils.getInstanceByElement($(element), this) }; DOMComponent.defaultOptions = function(rule) { this._classCustomRules = this._classCustomRules || []; this._classCustomRules.push(rule) }; module.exports = DOMComponent;