UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

791 lines (689 loc) • 25.4 kB
"use strict"; var $ = require("../core/renderer"), window = require("../core/utils/window").getWindow(), translator = require("../animation/translator"), camelize = require("../core/utils/inflector").camelize, noop = require("../core/utils/common").noop, getPublicElement = require("../core/utils/dom").getPublicElement, each = require("../core/utils/iterator").each, isDefined = require("../core/utils/type").isDefined, inArray = require("../core/utils/array").inArray, extend = require("../core/utils/extend").extend, messageLocalization = require("../localization/message"), devices = require("../core/devices"), registerComponent = require("../core/component_registrator"), Button = require("./button"), themes = require("./themes"), Overlay = require("./overlay"), EmptyTemplate = require("./widget/empty_template"), domUtils = require("../core/utils/dom"), windowUtils = require("../core/utils/window"); require("./toolbar/ui.toolbar.base"); var POPUP_CLASS = "dx-popup", POPUP_WRAPPER_CLASS = "dx-popup-wrapper", POPUP_FULL_SCREEN_CLASS = "dx-popup-fullscreen", POPUP_FULL_SCREEN_WIDTH_CLASS = "dx-popup-fullscreen-width", POPUP_NORMAL_CLASS = "dx-popup-normal", POPUP_CONTENT_CLASS = "dx-popup-content", POPUP_DRAGGABLE_CLASS = "dx-popup-draggable", POPUP_TITLE_CLASS = "dx-popup-title", POPUP_TITLE_CLOSEBUTTON_CLASS = "dx-closebutton", POPUP_BOTTOM_CLASS = "dx-popup-bottom", TEMPLATE_WRAPPER_CLASS = "dx-template-wrapper", ALLOWED_TOOLBAR_ITEM_ALIASES = ["cancel", "clear", "done"]; var getButtonPlace = function getButtonPlace(name) { var device = devices.current(), platform = device.platform, toolbar = "bottom", location = "before"; if (platform === "ios") { switch (name) { case "cancel": toolbar = "top"; break; case "clear": toolbar = "top"; location = "after"; break; case "done": location = "after"; break; } } else if (platform === "win") { location = "after"; } else if (platform === "android" && device.version && parseInt(device.version[0]) > 4) { switch (name) { case "cancel": location = "after"; break; case "done": location = "after"; break; } } else if (platform === "android") { location = "center"; } return { toolbar: toolbar, location: location }; }; /** * @name dxPopup * @publicName dxPopup * @inherits dxOverlay * @module ui/popup * @export default */ var Popup = Overlay.inherit({ _getDefaultOptions: function _getDefaultOptions() { return extend(this.callBase(), { /** * @name dxPopupOptions.fullScreen * @publicName fullScreen * @type boolean * @default false */ fullScreen: false, /** * @name dxPopupOptions.title * @publicName title * @type string * @default "" */ title: "", /** * @name dxPopupOptions.showtitle * @publicName showTitle * @type boolean * @default true */ showTitle: true, /** * @name dxPopupOptions.container * @publicName container * @type string|Node|jQuery * @default undefined */ /** * @name dxPopupOptions.titleTemplate * @publicName titleTemplate * @type template|function * @default "title" * @type_function_param1 titleElement:dxElement * @type_function_return string|Node|jQuery */ titleTemplate: "title", /** * @name dxPopupOptions.onTitleRendered * @publicName onTitleRendered * @extends Action * @type function(e) * @type_function_param1 e:object * @type_function_param1_field4 titleElement:dxElement * @action */ onTitleRendered: null, /** * @name dxPopupOptions.dragEnabled * @publicName dragEnabled * @type boolean * @default false */ dragEnabled: false, /** * @name dxPopupOptions.position * @publicName position * @type Enums.PositionAlignment|positionConfig|function * @inheritdoc */ /** * @name dxPopupOptions.resizeEnabled * @publicName resizeEnabled * @type boolean * @default false */ /** * @name dxPopupOptions.onResizeStart * @publicName onResizeStart * @extends Action * @action */ /** * @name dxPopupOptions.onResize * @publicName onResize * @extends Action * @action */ /** * @name dxPopupOptions.onResizeEnd * @publicName onResizeEnd * @extends Action * @action */ /** * @name dxPopupOptions.width * @publicName width * @fires dxPopupOptions.onResize * @inheritdoc */ /** * @name dxPopupOptions.height * @publicName height * @fires dxPopupOptions.onResize * @inheritdoc */ /** * @name dxPopupOptions.toolbarItems * @publicName toolbarItems * @type Array<Object> */ /** * @name dxPopupOptions.toolbarItems.toolbar * @publicName toolbar * @type Enums.Toolbar * @default 'top' */ /** * @name dxPopupOptions.toolbarItems.html * @publicName html * @type String */ /** * @name dxPopupOptions.toolbarItems.text * @publicName text * @type String */ /** * @name dxPopupOptions.toolbarItems.visible * @publicName visible * @type boolean * @default true */ /** * @name dxPopupOptions.toolbarItems.disabled * @publicName disabled * @type boolean * @default false */ /** * @name dxPopupOptions.toolbarItems.template * @publicName template * @type template */ /** * @name dxPopupOptions.toolbarItems.widget * @publicName widget * @type Enums.ToolbarItemWidget */ /** * @name dxPopupOptions.toolbarItems.options * @publicName options * @type object */ /** * @name dxPopupOptions.toolbarItems.location * @publicName location * @type Enums.ToolbarItemLocation * @default 'center' */ toolbarItems: [], /** * @name dxPopupOptions.showCloseButton * @publicName showCloseButton * @type boolean * @default false */ showCloseButton: false, bottomTemplate: "bottom" }); }, _defaultOptionsRules: function _defaultOptionsRules() { return this.callBase().concat([{ device: function device(_device) { var currentTheme = (themes.current() || "").split(".")[0]; return _device.phone && currentTheme === "win8"; }, options: { position: { my: "top center", at: "top center", offset: "0 0" } } }, { device: { platform: "ios" }, options: { /** * @name dxPopupOptions.animation * @publicName animation * @default { show: { type: 'slide', duration: 400, from: { position: { my: 'top', at: 'bottom', of: window } }, to: { position: { my: 'center', at: 'center', of: window } } }, hide: { type: 'slide', duration: 400, from: { position: { my: 'center', at: 'center', of: window } }, to: { position: { my: 'top', at: 'bottom', of: window } } }} @for iOS * @inheritdoc */ /** * @name dxPopupOptions.animation.show * @publicName show * @default { type: 'slide', duration: 400, from: { position: { my: 'top', at: 'bottom', of: window } }, to: { position: { my: 'center', at: 'center', of: window } }} @for iOS * @inheritdoc */ /** * @name dxPopupOptions.animation.hide * @publicName hide * @default { type: 'slide', duration: 400, from: { position: { my: 'center', at: 'center', of: window } }, to: { position: { my: 'top', at: 'bottom', of: window } }} @for iOS * @inheritdoc */ animation: this._iosAnimation } }, { device: { platform: "android" }, options: { animation: this._androidAnimation } }, { device: { platform: "generic" }, options: { /** * @name dxPopupOptions.showCloseButton * @publicName showCloseButton * @default true @for desktop */ showCloseButton: true } }, { device: function device(_device2) { return devices.real().platform === "generic" && _device2.platform === "generic"; }, options: { /** * @name dxPopupOptions.dragEnabled * @publicName dragEnabled * @default true @for desktop */ dragEnabled: true } }, { device: function device() { return devices.real().deviceType === "desktop" && !devices.isSimulator(); }, options: { /** * @name dxPopupOptions.focusStateEnabled * @publicName focusStateEnabled * @type boolean * @default true @for desktop * @inheritdoc */ focusStateEnabled: true } }]); }, _iosAnimation: { show: { type: "slide", duration: 400, from: { position: { my: "top", at: "bottom" } }, to: { position: { my: "center", at: "center" } } }, hide: { type: "slide", duration: 400, from: { opacity: 1, position: { my: "center", at: "center" } }, to: { opacity: 1, position: { my: "top", at: "bottom" } } } }, _androidAnimation: function _androidAnimation() { var fullScreenConfig = { show: { type: "slide", duration: 300, from: { top: "30%", opacity: 0 }, to: { top: 0, opacity: 1 } }, hide: { type: "slide", duration: 300, from: { top: 0, opacity: 1 }, to: { top: "30%", opacity: 0 } } }, defaultConfig = { show: { type: "fade", duration: 400, from: 0, to: 1 }, hide: { type: "fade", duration: 400, from: 1, to: 0 } }; return this.option("fullScreen") ? fullScreenConfig : defaultConfig; }, _init: function _init() { this.callBase(); this.$element().addClass(POPUP_CLASS); this._wrapper().addClass(POPUP_WRAPPER_CLASS); this._$popupContent = this._$content.wrapInner($("<div>").addClass(POPUP_CONTENT_CLASS)).children().eq(0); }, _render: function _render() { var isFullscreen = this.option("fullScreen"); this._toggleFullScreenClass(isFullscreen); this.callBase(); }, _toggleFullScreenClass: function _toggleFullScreenClass(value) { this._$content.toggleClass(POPUP_FULL_SCREEN_CLASS, value).toggleClass(POPUP_NORMAL_CLASS, !value); }, _initTemplates: function _initTemplates() { this.callBase(); this._defaultTemplates["title"] = new EmptyTemplate(this); this._defaultTemplates["bottom"] = new EmptyTemplate(this); }, _renderContentImpl: function _renderContentImpl() { this.callBase(); this._renderTitle(); this._renderBottom(); }, _renderTitle: function _renderTitle() { var items = this._getToolbarItems("top"), titleText = this.option("title"), showTitle = this.option("showTitle"); if (showTitle && !!titleText) { items.unshift({ location: devices.current().ios ? "center" : "before", text: titleText }); } if (showTitle || items.length > 0) { this._$title && this._$title.remove(); var $title = $("<div>").addClass(POPUP_TITLE_CLASS).insertBefore(this.$content()); this._$title = this._renderTemplateByType("titleTemplate", items, $title).addClass(POPUP_TITLE_CLASS); this._renderDrag(); this._executeTitleRenderAction(this._$title); } else if (this._$title) { this._$title.detach(); } }, _renderTemplateByType: function _renderTemplateByType(optionName, data, $container) { var template = this._getTemplateByOption(optionName), toolbarTemplate = template instanceof EmptyTemplate; if (toolbarTemplate) { var toolbarOptions = { items: data, rtlEnabled: this.option("rtlEnabled") }; this._getTemplate("dx-polymorph-widget").render({ container: $container, model: { widget: "dxToolbarBase", options: toolbarOptions } }); var $toolbar = $container.children("div"); $container.replaceWith($toolbar); return $toolbar; } else { var $result = $(template.render({ container: getPublicElement($container) })); if ($result.hasClass(TEMPLATE_WRAPPER_CLASS)) { $container.replaceWith($result); $container = $result; } return $container; } }, _executeTitleRenderAction: function _executeTitleRenderAction($titleElement) { this._getTitleRenderAction()({ titleElement: getPublicElement($titleElement) }); }, _getTitleRenderAction: function _getTitleRenderAction() { return this._titleRenderAction || this._createTitleRenderAction(); }, _createTitleRenderAction: function _createTitleRenderAction() { return this._titleRenderAction = this._createActionByOption("onTitleRendered", { element: this.element(), excludeValidators: ["designMode", "disabled", "readOnly"] }); }, _getCloseButton: function _getCloseButton() { return { toolbar: "top", location: "after", template: this._getCloseButtonRenderer() }; }, _getCloseButtonRenderer: function _getCloseButtonRenderer() { return function (_, __, container) { var $button = $("<div>").addClass(POPUP_TITLE_CLOSEBUTTON_CLASS); this._createComponent($button, Button, { icon: 'close', onClick: this._createToolbarItemAction(undefined), integrationOptions: {} }); $(container).append($button); }.bind(this); }, _getToolbarItems: function _getToolbarItems(toolbar) { var toolbarItems = this.option("toolbarItems"); var toolbarsItems = []; this._toolbarItemClasses = []; var currentPlatform = devices.current().platform, index = 0; each(toolbarItems, function (_, data) { var isShortcut = isDefined(data.shortcut), item = isShortcut ? getButtonPlace(data.shortcut) : data; if (isShortcut && currentPlatform === "ios" && index < 2) { item.toolbar = "top"; index++; } item.toolbar = data.toolbar || item.toolbar || "top"; if (item && item.toolbar === toolbar) { if (isShortcut) { extend(item, { location: data.location }, this._getToolbarItemByAlias(data)); } var isLTROrder = currentPlatform === "win" || currentPlatform === "generic"; if (data.shortcut === "done" && isLTROrder || data.shortcut === "cancel" && !isLTROrder) { toolbarsItems.unshift(item); } else { toolbarsItems.push(item); } } }.bind(this)); if (toolbar === "top" && this.option("showCloseButton") && this.option("showTitle")) { toolbarsItems.push(this._getCloseButton()); } return toolbarsItems; }, _getToolbarItemByAlias: function _getToolbarItemByAlias(data) { var that = this, itemType = data.shortcut; if (inArray(itemType, ALLOWED_TOOLBAR_ITEM_ALIASES) < 0) { return false; } var itemConfig = extend({ text: messageLocalization.format(camelize(itemType, true)), onClick: this._createToolbarItemAction(data.onClick), integrationOptions: {} }, data.options || {}); var itemClass = POPUP_CLASS + "-" + itemType; this._toolbarItemClasses.push(itemClass); return { template: function template(_, __, container) { var $toolbarItem = $("<div>").addClass(itemClass).appendTo(container); that._createComponent($toolbarItem, Button, itemConfig); } }; }, _createToolbarItemAction: function _createToolbarItemAction(clickAction) { return this._createAction(clickAction, { afterExecute: function afterExecute(e) { e.component.hide(); } }); }, _renderBottom: function _renderBottom() { var items = this._getToolbarItems("bottom"); if (items.length) { this._$bottom && this._$bottom.remove(); var $bottom = $("<div>").addClass(POPUP_BOTTOM_CLASS).insertAfter(this.$content()); this._$bottom = this._renderTemplateByType("bottomTemplate", items, $bottom).addClass(POPUP_BOTTOM_CLASS); this._toggleClasses(); } else { this._$bottom && this._$bottom.detach(); } }, _toggleClasses: function _toggleClasses() { var aliases = ALLOWED_TOOLBAR_ITEM_ALIASES; each(aliases, function (_, alias) { var className = POPUP_CLASS + "-" + alias; if (inArray(className, this._toolbarItemClasses) >= 0) { this._wrapper().addClass(className + "-visible"); this._$bottom.addClass(className); } else { this._wrapper().removeClass(className + "-visible"); this._$bottom.removeClass(className); } }.bind(this)); }, _getDragTarget: function _getDragTarget() { return this._$title; }, _renderGeometryImpl: function _renderGeometryImpl() { this._resetContentHeight(); this.callBase.apply(this, arguments); this._setContentHeight(); }, _resetContentHeight: function _resetContentHeight() { this._$popupContent.css({ "height": "auto" }); }, _renderDrag: function _renderDrag() { this.callBase(); this._$content.toggleClass(POPUP_DRAGGABLE_CLASS, this.option("dragEnabled")); }, _renderResize: function _renderResize() { this.callBase(); this._resizable.option("onResize", function () { this._setContentHeight(); this._actions.onResize(arguments); }.bind(this)); }, _setContentHeight: function _setContentHeight() { (this.option("forceApplyBindings") || noop)(); if (this._disallowUpdateContentHeight()) { return; } var contentPaddings = this._$content.outerHeight() - this._$content.height(), contentHeight = this._$content.get(0).getBoundingClientRect().height - contentPaddings; if (this._$title && this._$title.is(":visible")) { contentHeight -= this._$title.get(0).getBoundingClientRect().height || 0; } if (this._$bottom && this._$bottom.is(":visible")) { contentHeight -= this._$bottom.get(0).getBoundingClientRect().height || 0; } this._$popupContent.css("height", contentHeight < 0 ? 0 : contentHeight); }, _disallowUpdateContentHeight: function _disallowUpdateContentHeight() { var isHeightAuto = this._$content.get(0).style.height === "auto", maxHeightSpecified = this._$content.css("maxHeight") !== "none", minHeightSpecified = parseInt(this._$content.css("minHeight")) > 0; return isHeightAuto && !(maxHeightSpecified || minHeightSpecified); }, _renderDimensions: function _renderDimensions() { if (this.option("fullScreen")) { this._$content.css({ width: "100%", height: "100%" }); } else { this.callBase.apply(this, arguments); } if (windowUtils.hasWindow()) { this._renderFullscreenWidthClass(); } }, _renderFullscreenWidthClass: function _renderFullscreenWidthClass() { this.overlayContent().toggleClass(POPUP_FULL_SCREEN_WIDTH_CLASS, this.overlayContent().outerWidth() === $(window).width()); }, _renderShadingDimensions: function _renderShadingDimensions() { if (this.option("fullScreen")) { this._wrapper().css({ width: "100%", height: "100%" }); } else { this.callBase.apply(this, arguments); } }, refreshPosition: function refreshPosition() { this._renderPosition(); }, _renderPosition: function _renderPosition() { if (this.option("fullScreen")) { translator.move(this._$content, { top: 0, left: 0 }); } else { (this.option("forceApplyBindings") || noop)(); return this.callBase.apply(this, arguments); } }, _optionChanged: function _optionChanged(args) { switch (args.name) { case "showTitle": case "title": case "titleTemplate": this._renderTitle(); this._renderGeometry(); break; case "bottomTemplate": this._renderBottom(); this._renderGeometry(); break; case "onTitleRendered": this._createTitleRenderAction(args.value); break; case "toolbarItems": var isPartialUpdate = args.fullName.search(".options") !== -1; this._renderTitle(); this._renderBottom(); if (!isPartialUpdate) { this._renderGeometry(); } break; case "dragEnabled": this._renderDrag(); break; case "fullScreen": this._toggleFullScreenClass(args.value); this._renderGeometry(); domUtils.triggerResizeEvent(this._$content); break; case "showCloseButton": this._renderTitle(); break; default: this.callBase(args); } }, bottomToolbar: function bottomToolbar() { return this._$bottom; }, $content: function $content() { return this._$popupContent; }, content: function content() { return getPublicElement(this._$popupContent); }, overlayContent: function overlayContent() { return this._$content; } }); registerComponent("dxPopup", Popup); module.exports = Popup;