UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

572 lines (473 loc) • 20.9 kB
"use strict"; (function(root, factory) { /* global define, DevExpress, jQuery */ if (typeof define === 'function' && define.amd) { define(function(require, exports, module) { module.exports = factory( require("jquery"), require("knockout"), require("core/class"), require("framework/errors"), require("framework/html/presets").layoutSets, require("framework/html/layout_controller").DefaultLayoutController, require("../Empty/EmptyLayout.js"), require("../Simple/SimpleLayout.js"), require("animation/fx"), require("ui/toolbar") ); }); } else { root.DevExpress.layouts = root.DevExpress.layouts || {}; root.DevExpress.layouts.SplitLayout = factory( jQuery, window.ko, DevExpress.Class, DevExpress.framework.errors, DevExpress.framework.html.layoutSets, DevExpress.framework.html.DefaultLayoutController, DevExpress.layouts.EmptyLayout, DevExpress.layouts.SimpleLayout, DevExpress.fx ); root.DevExpress.framework.html.MultipaneLayoutController = root.DevExpress.layouts.SplitLayout.MultipaneLayoutController; root.DevExpress.framework.html.IOSSplitLayoutController = root.DevExpress.layouts.SplitLayout.IOSSplitLayoutController; root.DevExpress.framework.html.ToolbarController = root.DevExpress.layouts.SplitLayout.ToolbarController; root.DevExpress.framework.html.AndroidSplitLayoutController = root.DevExpress.layouts.SplitLayout.AndroidSplitLayoutController; root.DevExpress.framework.html.WinSplitLayoutController = root.DevExpress.layouts.SplitLayout.WinSplitLayoutController; root.DevExpress.framework.html.Win8SplitLayoutController = root.DevExpress.layouts.SplitLayout.Win8SplitLayoutController; } }(window, function($, ko, Class, errors, layoutSets, DefaultLayoutController, EmptyLayoutControllerModule, SimpleLayoutControllerModule, fx) { var exports = {}, APPBAR_TOUCH_AREA_HEIGHT = 50, APPBAR_TOUCH_THRESHOLD = 50, EVENTS_NAMESPACE = ".dxSplitLayout", KEYCODE_WIN = 91, KEYCODE_Z = 90, POINTER_DOWN_EVENT_NAME, POINTER_UP_EVENT_NAME, POINTER_MOVE_EVENT_NAME; if (window.PointerEvent) { POINTER_DOWN_EVENT_NAME = "pointerdown"; POINTER_UP_EVENT_NAME = "pointerup"; POINTER_MOVE_EVENT_NAME = "pointermove"; } else if (window.MSPointerEvent) { POINTER_DOWN_EVENT_NAME = "MSPointerDown"; POINTER_UP_EVENT_NAME = "MSPointerUp"; POINTER_MOVE_EVENT_NAME = "MSPointerMove"; } else { POINTER_DOWN_EVENT_NAME = "mousedown"; POINTER_UP_EVENT_NAME = "mouseup"; POINTER_MOVE_EVENT_NAME = "mousemove"; } var SplitLayoutEventHelper = Class.inherit({ ctor: function(splitLayout) { this.root = splitLayout; }, init: function() { this.root._$viewPort.on(POINTER_UP_EVENT_NAME + EVENTS_NAMESPACE, $.proxy(this._pointerUpHandler, this)); this.root._$viewPort.on(POINTER_DOWN_EVENT_NAME + EVENTS_NAMESPACE, $.proxy(this._pointerDownHandler, this)); $(document).on("keydown" + EVENTS_NAMESPACE, $.proxy(this._keyDownHandler, this)); $(document).on("keyup" + EVENTS_NAMESPACE, $.proxy(this._keyUpHandler, this)); this._startTouchPoint = false; this._winKeyPressed = false; this._moveEvent = false; this._appBarBehavior = true; }, _pointerDownHandler: function(e) { var originalEvent = e.originalEvent; if (this._isTouch(originalEvent) && this._startedInAppBarArea(originalEvent)) { this._startTouchPoint = { x: originalEvent.clientX, y: originalEvent.clientY }; this.root._$viewPort.on(POINTER_MOVE_EVENT_NAME + EVENTS_NAMESPACE, $.proxy(this._pointerMoveHandler, this)); } }, _pointerMoveHandler: function(e) { var originalEvent = e.originalEvent; if (this._thresholdExceeded(originalEvent)) { this._moveEvent = true; this.root._$viewPort.off(POINTER_MOVE_EVENT_NAME + EVENTS_NAMESPACE); if (this._isVerticalDirection(originalEvent.clientX, originalEvent.clientY)) { this._toggleAppBarState(true); } } }, _pointerUpHandler: function(e) { this.root._$viewPort.off(POINTER_MOVE_EVENT_NAME + EVENTS_NAMESPACE); var $appBar = this.root._$viewPort.find(".dx-app-bar"); if (e.originalEvent.button === 2) { this._toggleAppBarState(); } else if (!this._moveEvent && $appBar[0] && !$appBar[0].contains(e.target)) { this._toggleAppBarState(false); } this._moveEvent = false; }, _keyDownHandler: function(e) { if (e.keyCode === KEYCODE_WIN) { this._winKeyPressed = true; } }, _keyUpHandler: function(e) { if (this._winKeyPressed && (e.keyCode === KEYCODE_Z)) { this._toggleAppBarState(); } else if (e.keyCode === KEYCODE_WIN) { this._winKeyPressed = false; } }, _toggleAppBarState: function(state) { if (!this.root._appBarHasCommands()) { return; } this.root._$viewPort.find(".dx-app-bar").toggleClass("dx-app-bar-visible", !this._appBarBehavior || state); }, _isVerticalDirection: function(x, y) { return Math.abs(y - this._startTouchPoint.y) > Math.abs(x - this._startTouchPoint.x); }, _isTouch: function(event) { return event.pointerType === event.MSPOINTER_TYPE_TOUCH || event.pointerType === event.MSPOINTER_TYPE_PEN; }, _startedInAppBarArea: function(event) { return (this.root._$viewPort.height() - APPBAR_TOUCH_AREA_HEIGHT) < event.clientY; }, _thresholdExceeded: function(originalEvent) { return originalEvent.clientY < (this._startTouchPoint.y - APPBAR_TOUCH_THRESHOLD); } }); var MultipaneLayoutController = DefaultLayoutController.inherit({ ctor: function(options) { options = options || {}; options.name = options.name || "split"; this._detailPaneName = options.detailPaneName || "detail"; this._masterPaneName = options.masterPaneName || "master"; options.defaultPaneName = this._detailPaneName; this.callBase(options); this._panesConfig = options.panesConfig; this._activeViews = {}; this._stateStorageKey = "dxSplitLayoutState"; }, init: function(options) { options = options || {}; this.callBase(options); this._router = options.app && options.app.router; this._onNavigatingHandler = $.proxy(this._onNavigating, this); this._onNavigatedHandler = $.proxy(this._onNavigated, this); this._navigationManager = options.navigationManager; this._ensurePanesConfig(); this._initChildControllers(options); }, activate: function() { var tasks = []; this.callBase(); this._navigationManager.on("navigating", this._onNavigatingHandler); this._navigationManager.on("navigated", this._onNavigatedHandler); this._navigationManager.on("navigatingBack", this._onNavigatingBackHandler); $.each(this._panesConfig, function(_, paneConfig) { tasks.push(paneConfig.controller.activate()); }); return $.when.apply($, tasks); }, deactivate: function() { var that = this, tasks = []; $.each(this._panesConfig, function(_, paneConfig) { tasks.push(paneConfig.controller.deactivate()); }); this._navigationManager.off("navigating", this._onNavigatingHandler); this._navigationManager.off("navigated", this._onNavigatedHandler); this.callBase(); return $.when.apply($, tasks).done(function() { that._activeViews = {}; }); }, showView: function(viewInfo, direction) { var that = this, paneConfig = that._getPaneConfig(viewInfo); var paneName = that._getViewPaneName(viewInfo.viewTemplateInfo); if (!this._masterPaneCurrentStackKey && paneName === this._masterPaneName) { this._masterPaneCurrentStackKey = viewInfo.navigateOptions.stack; } return paneConfig.controller.showView(viewInfo, direction).done(function() { that._activeViews[that._getViewPaneName(viewInfo.viewTemplateInfo)] = viewInfo; }); }, activeViewInfo: function() { return this._activeViews[this._masterPaneName]; }, _updateLayoutTitle: function(viewInfo, defaultTitle) { if (this._getViewPaneName(viewInfo.viewTemplateInfo) === this._masterPaneName) { var title; if (viewInfo.model !== undefined) { title = ko.utils.unwrapObservable(viewInfo.model.title); } else { title = (viewInfo.viewTemplateInfo || {}).title; } this._layoutModel.title(title || defaultTitle || ""); } }, _ensurePanesConfig: function() { if (!this._panesConfig) { this._panesConfig = this._createPanesConfig(); } }, _createPanesConfig: function() { return {}; }, _initChildControllers: function(options) { var that = this; $.each(that._panesConfig, function(_, paneConfig) { var controller = paneConfig.controller; controller.init($.extend({}, options, { $viewPort: that._$mainLayout.find(paneConfig.selector) })); $.each(["viewRendered", "viewShowing", "viewReleased", "viewHidden"], function(_, callbacksPropertyName) { controller.on(callbacksPropertyName, function(args) { that.fireEvent(callbacksPropertyName, [args]); }); }); }); }, _onNavigating: function(args) { var options = args.options, $sourceElement = this._getEventSourceElement(args.options.event); var routeValues = this._router.parse(args.uri), viewTemplateInfo = this._viewEngine.getViewTemplateInfo(routeValues.view).option(), pane = this._getViewPaneName(viewTemplateInfo); if (pane === this._detailPaneName) { options.stack = this._detailPaneName + "_pane"; options.root = options.root === undefined ? $sourceElement.is(this._panesConfig[this._masterPaneName].selector + " *") : options.root; options.keepPositionInStack = false; } else { options.stack = options.stack || this._masterPaneCurrentStackKey; } args.options.pane = pane; }, _onNavigated: function(args) { if (args.options.pane === this._masterPaneName) { this._masterPaneCurrentStackKey = this._navigationManager.currentStackKey; } }, _getEventSourceElement: function(jQueryEvent) { return jQueryEvent ? $(jQueryEvent.target) : $(); }, _getPaneConfig: function(viewInfo) { return this._panesConfig[this._getViewPaneName(viewInfo.viewTemplateInfo)]; }, _getViewPaneName: function(viewTemplateInfo) { return viewTemplateInfo.pane || this._detailPaneName; }, _raiseEvent: function(callback) { callback.fire(); }, _ensureChildController: function(controller, layoutName) { if (!controller) { throw new Error(layoutName + "Controller is not found but it is required by the '" + this.name + "' layout for specified platform and device. Make sure the " + layoutName + ".* files are referenced in your main *.html file or specify other platform and device."); } }, saveState: function(storage) { var state = {}; $.each(this._activeViews, function(pane, viewInfo) { state[pane] = { uri: viewInfo.uri, stack: viewInfo.navigateOptions.stack }; }); var json = JSON.stringify(state); storage.setItem(this._stateStorageKey, json); }, restoreState: function(storage) { var json = storage.getItem(this._stateStorageKey); if (json) { try { var that = this, state = JSON.parse(json); $.each(state, function(pane, navigateOptions) { that._navigationManager.navigate(navigateOptions.uri, { stack: navigateOptions.stack, target: 'current' }); }); } catch (e) { this.removeState(storage); throw errors.Error("E3007"); } } }, removeState: function(storage) { storage.removeItem(this._stateStorageKey); } }); var IOSSplitLayoutController = MultipaneLayoutController.inherit({ _createPanesConfig: function() { return { master: { controller: new SimpleLayoutControllerModule.SimpleLayoutController(), selector: ".master-pane" }, detail: { controller: new SimpleLayoutControllerModule.SimpleLayoutController(), selector: ".detail-pane" } }; } }); var ToolbarController = Class.inherit({ ctor: function($toolbar, commandManager) { this._commandManager = commandManager; this._$toolbar = $toolbar; this._toolbar = $toolbar.dxToolbar("instance"); this._commandContainer = $toolbar.dxCommandContainer("instance"); }, showViews: function(viewInfos) { var that = this, commands = this._mergeCommands(viewInfos), toolbarItems = that._toolbar.option("items"); var newItems = $.map(toolbarItems, function(item) { return item.command ? undefined : item; }); that._toolbar.option("items", newItems); fx.off = true; that._commandManager.renderCommandsToContainers(commands, [that._commandContainer]); fx.off = false; }, _mergeCommands: function(viewInfos) { var result = [], idHash = {}; $.each(viewInfos, function(_, viewInfo) { if (viewInfo.commands) { $.each(viewInfo.commands, function(_, command) { var id = command.option("id"); if (!(id in idHash)) { idHash[id] = true; result.push(command); } }); } }); return result; } }); var AndroidSplitLayoutController = MultipaneLayoutController.inherit({ ctor: function(options) { options = options || {}; options.layoutModel = options.layoutModel || this._createLayoutModel(); this.callBase(options); }, init: function(options) { this.callBase(options); this.toolbarController = new ToolbarController(this._$mainLayout.find(".header-toolbar"), this._commandManager); }, _createLayoutModel: function() { return { title: ko.observable("") }; }, showView: function(viewInfo, direction) { var that = this; that._updateLayoutTitle(viewInfo); return that.callBase(viewInfo, direction).done(function() { that.toolbarController.showViews(that._activeViews); }); }, _createPanesConfig: function() { return { master: { controller: new EmptyLayoutControllerModule.EmptyLayoutController(), selector: ".master-pane" }, detail: { controller: new EmptyLayoutControllerModule.EmptyLayoutController(), selector: ".detail-pane" } }; } }); var WinSplitLayoutController = MultipaneLayoutController.inherit({ ctor: function(options) { options = options || {}; this._eventHelper = new SplitLayoutEventHelper(this); options.layoutModel = options.layoutModel || this._createLayoutModel(); this.callBase(options); }, init: function(options) { this.callBase(options); this._eventHelper.init(); this.headerToolbarController = new ToolbarController(this._$mainLayout.find(".header-toolbar"), this._commandManager); }, showView: function(viewInfo, direction) { var that = this; that._updateLayoutTitle(viewInfo); return that.callBase(viewInfo, direction).done(function() { that.headerToolbarController.showViews(that._activeViews); }); }, _createLayoutModel: function() { return { title: ko.observable("") }; }, _createPanesConfig: function() { return { master: { controller: new EmptyLayoutControllerModule.EmptyLayoutController(), selector: ".left-content" }, detail: { controller: new EmptyLayoutControllerModule.EmptyLayoutController(), selector: ".right-content" } }; }, _appBarHasCommands: function() { var footerToolbar = this._$viewPort.find(".footer-toolbar").data("dxToolbar"); return footerToolbar ? footerToolbar.option("items").length : false; } }); var Win8SplitLayoutController = WinSplitLayoutController.inherit({ init: function(options) { this.callBase(options); this.footerToolbarController = new ToolbarController(this._$mainLayout.find(".footer-toolbar"), this._commandManager); }, showView: function(viewInfo, direction) { var that = this; return that.callBase(viewInfo, direction).done(function() { that.footerToolbarController.showViews(that._activeViews); }); }, }); layoutSets["split"] = layoutSets["split"] || []; layoutSets["split"].push({ platform: "ios", tablet: true, controller: new IOSSplitLayoutController() }); layoutSets["split"].push({ platform: "android", tablet: true, controller: new AndroidSplitLayoutController() }); layoutSets["split"].push({ platform: "generic", tablet: true, controller: new IOSSplitLayoutController() }); layoutSets["split"].push({ platform: "win", phone: false, controller: new WinSplitLayoutController() }); layoutSets["split"].push({ platform: "win", version: [8], phone: false, controller: new Win8SplitLayoutController() }); exports.MultipaneLayoutController = MultipaneLayoutController; exports.IOSSplitLayoutController = IOSSplitLayoutController; exports.ToolbarController = ToolbarController; exports.AndroidSplitLayoutController = AndroidSplitLayoutController; exports.WinSplitLayoutController = WinSplitLayoutController; exports.Win8SplitLayoutController = Win8SplitLayoutController; return exports; }));