UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

462 lines (388 loc) • 14.2 kB
"use strict"; var $ = require("../core/renderer"), eventsEngine = require("../events/core/events_engine"), noop = require("../core/utils/common").noop, fx = require("../animation/fx"), clickEvent = require("../events/click"), translator = require("../animation/translator"), getPublicElement = require("../core/utils/dom").getPublicElement, hideTopOverlayCallback = require("../mobile/hide_top_overlay").hideCallback, registerComponent = require("../core/component_registrator"), extend = require("../core/utils/extend").extend, Widget = require("./widget/ui.widget"), Swipeable = require("../events/gesture/swipeable"), EmptyTemplate = require("./widget/empty_template"), Deferred = require("../core/utils/deferred").Deferred, windowUtils = require("../core/utils/window"); var SLIDEOUTVIEW_CLASS = "dx-slideoutview", SLIDEOUTVIEW_WRAPPER_CLASS = "dx-slideoutview-wrapper", SLIDEOUTVIEW_MENU_CONTENT_CLASS = "dx-slideoutview-menu-content", SLIDEOUTVIEW_CONTENT_CLASS = "dx-slideoutview-content", SLIDEOUTVIEW_SHIELD_CLASS = "dx-slideoutview-shield", INVISIBLE_STATE_CLASS = "dx-state-invisible", ANONYMOUS_TEMPLATE_NAME = "content", ANIMATION_DURATION = 400; var animation = { moveTo: function moveTo($element, position, completeAction) { fx.animate($element, { type: "slide", to: { left: position }, duration: ANIMATION_DURATION, complete: completeAction }); }, complete: function complete($element) { fx.stop($element, true); } }; /** * @name dxSlideOutView * @publicName dxSlideOutView * @inherits Widget * @module ui/slide_out_view * @export default */ var SlideOutView = Widget.inherit({ _getDefaultOptions: function _getDefaultOptions() { return extend(this.callBase(), { /** * @name dxSlideOutViewOptions.menuPosition * @publicName menuPosition * @type Enums.SlideOutMenuPosition * @default "normal" */ menuPosition: "normal", /** * @name dxSlideOutViewOptions.menuVisible * @publicName menuVisible * @type boolean * @default false */ menuVisible: false, /** * @name dxSlideOutViewOptions.swipeEnabled * @publicName swipeEnabled * @type boolean * @default true */ swipeEnabled: true, /** * @name dxSlideOutViewOptions.menuTemplate * @publicName menuTemplate * @type_function_param1 menuElement:dxElement * @type template|function * @default null */ menuTemplate: "menu", /** * @name dxSlideOutViewOptions.contentTemplate * @publicName contentTemplate * @type_function_param1 contentElement:dxElement * @type template|function * @default "content" */ contentTemplate: "content", /** * @name dxSlideOutViewOptions.contentOffset * @publicName contentOffset * @hidden * @inheritdoc */ contentOffset: 45 /** * @name dxSlideOutViewOptions.onContentReady * @publicName onContentReady * @hidden true * @action */ /** * @name dxSlideOutViewOptions.focusStateEnabled * @publicName focusStateEnabled * @hidden * @inheritdoc */ /** * @name dxSlideOutViewOptions.accessKey * @publicName accessKey * @hidden * @inheritdoc */ /** * @name dxSlideOutViewOptions.tabIndex * @publicName tabIndex * @hidden * @inheritdoc */ }); }, _defaultOptionsRules: function _defaultOptionsRules() { return this.callBase().concat([{ device: { android: true }, options: { contentOffset: 54 } }, { device: function device(_device) { return _device.platform === "generic" && _device.deviceType !== "desktop"; }, options: { contentOffset: 56 } }, { device: { win: true, phone: false }, options: { contentOffset: 76 } }]); }, _getAnonymousTemplateName: function _getAnonymousTemplateName() { return ANONYMOUS_TEMPLATE_NAME; }, _init: function _init() { this.callBase(); this.$element().addClass(SLIDEOUTVIEW_CLASS); this._deferredAnimate = undefined; this._initHideTopOverlayHandler(); }, _initHideTopOverlayHandler: function _initHideTopOverlayHandler() { this._hideMenuHandler = this.hideMenu.bind(this); }, _initTemplates: function _initTemplates() { this.callBase(); this._defaultTemplates["menu"] = new EmptyTemplate(this); this._defaultTemplates["content"] = new EmptyTemplate(this); }, _initMarkup: function _initMarkup() { this.callBase(); this._renderMarkup(); var menuTemplate = this._getTemplate(this.option("menuTemplate")), contentTemplate = this._getTemplate(this.option("contentTemplate")); menuTemplate && menuTemplate.render({ container: this.menuContent() }); contentTemplate && contentTemplate.render({ container: this.content(), noModel: true }); this._renderShield(); this._toggleMenuPositionClass(); }, _render: function _render() { this.callBase(); this._initSwipeHandlers(); this._dimensionChanged(); }, _renderMarkup: function _renderMarkup() { var $wrapper = $("<div>").addClass(SLIDEOUTVIEW_WRAPPER_CLASS); this._$menu = $("<div>").addClass(SLIDEOUTVIEW_MENU_CONTENT_CLASS); this._$container = $("<div>").addClass(SLIDEOUTVIEW_CONTENT_CLASS); $wrapper.append(this._$menu); $wrapper.append(this._$container); this.$element().append($wrapper); // NOTE: B251455 eventsEngine.on(this._$container, "MSPointerDown", noop); }, _renderShield: function _renderShield() { this._$shield = this._$shield || $("<div>").addClass(SLIDEOUTVIEW_SHIELD_CLASS); this._$shield.appendTo(this.content()); eventsEngine.off(this._$shield, clickEvent.name); eventsEngine.on(this._$shield, clickEvent.name, this.hideMenu.bind(this)); this._toggleShieldVisibility(this.option("menuVisible")); }, _initSwipeHandlers: function _initSwipeHandlers() { this._createComponent($(this.content()), Swipeable, { disabled: !this.option("swipeEnabled"), elastic: false, itemSizeFunc: this._getMenuWidth.bind(this), onStart: this._swipeStartHandler.bind(this), onUpdated: this._swipeUpdateHandler.bind(this), onEnd: this._swipeEndHandler.bind(this) }); }, _isRightMenuPosition: function _isRightMenuPosition() { var invertedPosition = this.option("menuPosition") === "inverted", rtl = this.option("rtlEnabled"); return rtl && !invertedPosition || !rtl && invertedPosition; }, _swipeStartHandler: function _swipeStartHandler(e) { animation.complete($(this.content())); var event = e.event, menuVisible = this.option("menuVisible"), rtl = this._isRightMenuPosition(); event.maxLeftOffset = +(rtl ? !menuVisible : menuVisible); event.maxRightOffset = +(rtl ? menuVisible : !menuVisible); this._toggleShieldVisibility(true); }, _swipeUpdateHandler: function _swipeUpdateHandler(e) { var event = e.event, offset = this.option("menuVisible") ? event.offset + 1 * this._getRTLSignCorrection() : event.offset; offset *= this._getRTLSignCorrection(); this._renderPosition(offset, false); }, _swipeEndHandler: function _swipeEndHandler(e) { var targetOffset = e.event.targetOffset * this._getRTLSignCorrection() + this.option("menuVisible"), menuVisible = targetOffset !== 0; if (this.option("menuVisible") === menuVisible) { this._renderPosition(this.option("menuVisible"), true); } else { this.option("menuVisible", menuVisible); } }, _toggleMenuPositionClass: function _toggleMenuPositionClass() { var left = SLIDEOUTVIEW_CLASS + "-left", right = SLIDEOUTVIEW_CLASS + "-right", menuPosition = this._isRightMenuPosition() ? "right" : "left"; this._$menu.removeClass(left + " " + right); this._$menu.addClass(SLIDEOUTVIEW_CLASS + "-" + menuPosition); }, _renderPosition: function _renderPosition(offset, animate) { if (!windowUtils.hasWindow()) return; var pos = this._calculatePixelOffset(offset) * this._getRTLSignCorrection(); this._toggleHideMenuCallback(offset); if (animate) { this._toggleShieldVisibility(true); animation.moveTo($(this.content()), pos, this._animationCompleteHandler.bind(this)); } else { translator.move($(this.content()), { left: pos }); } }, _calculatePixelOffset: function _calculatePixelOffset(offset) { offset = offset || 0; return offset * this._getMenuWidth(); }, _getMenuWidth: function _getMenuWidth() { if (!this._menuWidth) { var maxMenuWidth = this.$element().width() - this.option("contentOffset"), menuContent = $(this.menuContent()); menuContent.css("maxWidth", maxMenuWidth < 0 ? 0 : maxMenuWidth); var currentMenuWidth = menuContent.width(); this._menuWidth = Math.min(currentMenuWidth, maxMenuWidth); } return this._menuWidth; }, _animationCompleteHandler: function _animationCompleteHandler() { this._toggleShieldVisibility(this.option("menuVisible")); if (this._deferredAnimate) { this._deferredAnimate.resolveWith(this); } }, _toggleHideMenuCallback: function _toggleHideMenuCallback(subscribe) { if (subscribe) { hideTopOverlayCallback.add(this._hideMenuHandler); } else { hideTopOverlayCallback.remove(this._hideMenuHandler); } }, _getRTLSignCorrection: function _getRTLSignCorrection() { return this._isRightMenuPosition() ? -1 : 1; }, _dispose: function _dispose() { animation.complete($(this.content())); this._toggleHideMenuCallback(false); this.callBase(); }, _visibilityChanged: function _visibilityChanged(visible) { if (visible) { this._dimensionChanged(); } }, _dimensionChanged: function _dimensionChanged() { delete this._menuWidth; this._renderPosition(this.option("menuVisible"), false); }, _toggleShieldVisibility: function _toggleShieldVisibility(visible) { this._$shield.toggleClass(INVISIBLE_STATE_CLASS, !visible); }, _optionChanged: function _optionChanged(args) { switch (args.name) { case "width": this.callBase(args); this._dimensionChanged(); break; case "contentOffset": this._dimensionChanged(); break; case "menuVisible": this._renderPosition(args.value, true); break; case "menuPosition": this._renderPosition(this.option("menuVisible"), true); this._toggleMenuPositionClass(); break; case "swipeEnabled": this._initSwipeHandlers(); break; case "contentTemplate": case "menuTemplate": this._invalidate(); break; default: this.callBase(args); } }, /** * @name dxSlideOutViewMethods.menuContent * @publicName menuContent() * @return dxElement */ menuContent: function menuContent() { return getPublicElement(this._$menu); }, /** * @name dxSlideOutViewMethods.content * @publicName content() * @return dxElement */ content: function content() { return getPublicElement(this._$container); }, /** * @name dxSlideOutViewMethods.showMenu * @publicName showMenu() * @return Promise<void> */ showMenu: function showMenu() { return this.toggleMenuVisibility(true); }, /** * @name dxSlideOutViewMethods.hideMenu * @publicName hideMenu() * @return Promise<void> */ hideMenu: function hideMenu() { return this.toggleMenuVisibility(false); }, /** * @name dxSlideOutViewMethods.toggleMenuVisibility * @publicName toggleMenuVisibility() * @return Promise<void> */ toggleMenuVisibility: function toggleMenuVisibility(showing) { showing = showing === undefined ? !this.option("menuVisible") : showing; this._deferredAnimate = new Deferred(); this.option("menuVisible", showing); return this._deferredAnimate.promise(); } /** * @name dxSlideOutViewMethods.registerKeyHandler * @publicName registerKeyHandler(key, handler) * @hidden * @inheritdoc */ /** * @name dxSlideOutViewMethods.focus * @publicName focus() * @hidden * @inheritdoc */ }); registerComponent("dxSlideOutView", SlideOutView); module.exports = SlideOutView; ///#DEBUG module.exports.animation = animation; ///#ENDDEBUG