|
|
@@ -0,0 +1,360 @@
|
|
|
+sap.ui.define([
|
|
|
+ "./BaseController",
|
|
|
+ "sap/ui/model/json/JSONModel",
|
|
|
+ "sap/ui/model/Filter",
|
|
|
+ "sap/ui/model/FilterOperator",
|
|
|
+ "sap/ui/model/Sorter",
|
|
|
+ "sap/m/GroupHeaderListItem",
|
|
|
+ "sap/ui/Device",
|
|
|
+ "sap/ui/core/Fragment",
|
|
|
+ "../model/formatter",
|
|
|
+ "sap/ui/core/format/DateFormat"
|
|
|
+], function (BaseController, JSONModel, Filter, FilterOperator, Sorter, GroupHeaderListItem, Device, Fragment, formatter, DateFormat) {
|
|
|
+ "use strict";
|
|
|
+
|
|
|
+ return BaseController.extend("sap.ui.demo.orderbrowser.controller.Master", {
|
|
|
+
|
|
|
+ formatter: formatter,
|
|
|
+
|
|
|
+ /* =========================================================== */
|
|
|
+ /* lifecycle methods */
|
|
|
+ /* =========================================================== */
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Called when the master list controller is instantiated. It sets up the event handling for the master/detail communication and other lifecycle tasks.
|
|
|
+ * @public
|
|
|
+ */
|
|
|
+ onInit : function () {
|
|
|
+ // Control state model
|
|
|
+ var oList = this.byId("list"),
|
|
|
+ oViewModel = this._createViewModel(),
|
|
|
+ // Put down master list's original value for busy indicator delay,
|
|
|
+ // so it can be restored later on. Busy handling on the master list is
|
|
|
+ // taken care of by the master list itself.
|
|
|
+ iOriginalBusyDelay = oList.getBusyIndicatorDelay();
|
|
|
+
|
|
|
+ this._oGroupFunctions = {
|
|
|
+ CompanyName: function (oContext) {
|
|
|
+ var sCompanyName = oContext.getProperty("Customer/CompanyName");
|
|
|
+ return {
|
|
|
+ key: sCompanyName,
|
|
|
+ text: sCompanyName
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ OrderDate: function (oContext) {
|
|
|
+ var oDate = oContext.getProperty("OrderDate"),
|
|
|
+ iYear = oDate.getFullYear(),
|
|
|
+ iMonth = oDate.getMonth() + 1,
|
|
|
+ sMonthName = this._oMonthNameFormat.format(oDate);
|
|
|
+
|
|
|
+ return {
|
|
|
+ key: iYear + "-" + iMonth,
|
|
|
+ text: this.getResourceBundle().getText("masterGroupTitleOrderedInPeriod", [sMonthName, iYear])
|
|
|
+ };
|
|
|
+ }.bind(this),
|
|
|
+
|
|
|
+ ShippedDate: function (oContext) {
|
|
|
+ var oDate = oContext.getProperty("ShippedDate");
|
|
|
+ // Special handling needed because shipping date may be empty (=> not yet shipped).
|
|
|
+ if (oDate != null) {
|
|
|
+ var iYear = oDate.getFullYear(),
|
|
|
+ iMonth = oDate.getMonth() + 1,
|
|
|
+ sMonthName = this._oMonthNameFormat.format(oDate);
|
|
|
+
|
|
|
+ return {
|
|
|
+ key: iYear + "-" + iMonth,
|
|
|
+ text: this.getResourceBundle().getText("masterGroupTitleShippedInPeriod", [sMonthName, iYear])
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ return {
|
|
|
+ key: 0,
|
|
|
+ text: this.getResourceBundle().getText("masterGroupTitleNotShippedYet")
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }.bind(this)
|
|
|
+ };
|
|
|
+ this._oMonthNameFormat = DateFormat.getInstance({ pattern: "MMMM"});
|
|
|
+
|
|
|
+ this._oList = oList;
|
|
|
+
|
|
|
+ // keeps the filter and search state
|
|
|
+ this._oListFilterState = {
|
|
|
+ aFilter : [],
|
|
|
+ aSearch : []
|
|
|
+ };
|
|
|
+
|
|
|
+ this.setModel(oViewModel, "masterView");
|
|
|
+ // Make sure, busy indication is showing immediately so there is no
|
|
|
+ // break after the busy indication for loading the view's meta data is
|
|
|
+ // ended (see promise 'oWhenMetadataIsLoaded' in AppController)
|
|
|
+ oList.attachEventOnce("updateFinished", function(){
|
|
|
+ // Restore original busy indicator delay for the list
|
|
|
+ oViewModel.setProperty("/delay", iOriginalBusyDelay);
|
|
|
+ });
|
|
|
+
|
|
|
+ this.getView().addEventDelegate({
|
|
|
+ onBeforeFirstShow: function () {
|
|
|
+ this.getOwnerComponent().oListSelector.setBoundMasterList(oList);
|
|
|
+ }.bind(this)
|
|
|
+ });
|
|
|
+
|
|
|
+ this.getRouter().getRoute("master").attachPatternMatched(this._onMasterMatched, this);
|
|
|
+ this.getRouter().attachBypassed(this.onBypassed, this);
|
|
|
+ },
|
|
|
+
|
|
|
+ /* =========================================================== */
|
|
|
+ /* event handlers */
|
|
|
+ /* =========================================================== */
|
|
|
+
|
|
|
+ /**
|
|
|
+ * After list data is available, this handler method updates the
|
|
|
+ * master list counter
|
|
|
+ * @param {sap.ui.base.Event} oEvent the update finished event
|
|
|
+ * @public
|
|
|
+ */
|
|
|
+ onUpdateFinished : function (oEvent) {
|
|
|
+ // update the master list object counter after new data is loaded
|
|
|
+ this._updateListItemCount(oEvent.getParameter("total"));
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Event handler for the master search field. Applies current
|
|
|
+ * filter value and triggers a new search. If the search field's
|
|
|
+ * 'refresh' button has been pressed, no new search is triggered
|
|
|
+ * and the list binding is refresh instead.
|
|
|
+ * @param {sap.ui.base.Event} oEvent the search event
|
|
|
+ * @public
|
|
|
+ */
|
|
|
+ onSearch : function (oEvent) {
|
|
|
+ if (oEvent.getParameters().refreshButtonPressed) {
|
|
|
+ // Search field's 'refresh' button has been pressed.
|
|
|
+ // This is visible if you select any master list item.
|
|
|
+ // In this case no new search is triggered, we only
|
|
|
+ // refresh the list binding.
|
|
|
+ this.onRefresh();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var sQuery = oEvent.getParameter("query");
|
|
|
+
|
|
|
+ if (sQuery) {
|
|
|
+ this._oListFilterState.aSearch = [new Filter("CustomerName", FilterOperator.Contains, sQuery)];
|
|
|
+ } else {
|
|
|
+ this._oListFilterState.aSearch = [];
|
|
|
+ }
|
|
|
+ this._applyFilterSearch();
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Event handler for refresh event. Keeps filter, sort
|
|
|
+ * and group settings and refreshes the list binding.
|
|
|
+ * @public
|
|
|
+ */
|
|
|
+ onRefresh : function () {
|
|
|
+ this._oList.getBinding("items").refresh();
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Event handler for the filter, sort and group buttons to open the ViewSettingsDialog.
|
|
|
+ * @param {sap.ui.base.Event} oEvent the button press event
|
|
|
+ * @public
|
|
|
+ */
|
|
|
+ onOpenViewSettings : function (oEvent) {
|
|
|
+ var sDialogTab = "filter";
|
|
|
+ if (oEvent.getSource().isA("sap.m.Button")) {
|
|
|
+ var sButtonId = oEvent.getSource().getId();
|
|
|
+ if (sButtonId.match("sort")) {
|
|
|
+ sDialogTab = "sort";
|
|
|
+ } else if (sButtonId.match("group")) {
|
|
|
+ sDialogTab = "group";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // load asynchronous XML fragment
|
|
|
+ if (!this._pViewSettingsDialog) {
|
|
|
+ this._pViewSettingsDialog = Fragment.load({
|
|
|
+ id: this.getView().getId(),
|
|
|
+ name: "sap.ui.demo.orderbrowser.view.ViewSettingsDialog",
|
|
|
+ controller: this
|
|
|
+ }).then(function(oDialog){
|
|
|
+ // connect dialog to the root view of this component (models, lifecycle)
|
|
|
+ this.getView().addDependent(oDialog);
|
|
|
+ oDialog.addStyleClass(this.getOwnerComponent().getContentDensityClass());
|
|
|
+ return oDialog;
|
|
|
+ }.bind(this));
|
|
|
+ }
|
|
|
+ this._pViewSettingsDialog.then(function(oDialog) {
|
|
|
+ oDialog.open(sDialogTab);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Event handler called when ViewSettingsDialog has been confirmed, i.e.
|
|
|
+ * has been closed with 'OK'. In the case, the currently chosen filters or groupers
|
|
|
+ * are applied to the master list, which can also mean that they
|
|
|
+ * are removed from the master list, in case they are
|
|
|
+ * removed in the ViewSettingsDialog.
|
|
|
+ * @param {sap.ui.base.Event} oEvent the confirm event
|
|
|
+ * @public
|
|
|
+ */
|
|
|
+ onConfirmViewSettingsDialog : function (oEvent) {
|
|
|
+ var aFilterItems = oEvent.getParameter("filterItems"),
|
|
|
+ aFilters = [],
|
|
|
+ aCaptions = [];
|
|
|
+ aFilterItems.forEach(function (oItem) {
|
|
|
+ switch (oItem.getKey()) {
|
|
|
+ case "Shipped":
|
|
|
+ aFilters.push(new Filter("ShippedDate", FilterOperator.NE, null));
|
|
|
+ break;
|
|
|
+ case "NotShipped":
|
|
|
+ aFilters.push(new Filter("ShippedDate", FilterOperator.EQ, null));
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ aCaptions.push(oItem.getText());
|
|
|
+ });
|
|
|
+ this._oListFilterState.aFilter = aFilters;
|
|
|
+ this._updateFilterBar(aCaptions.join(", "));
|
|
|
+ this._applyFilterSearch();
|
|
|
+ this._applyGrouper(oEvent);
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Apply the chosen grouper to the master list
|
|
|
+ * @param {sap.ui.base.Event} oEvent the confirm event
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+ _applyGrouper: function (oEvent) {
|
|
|
+ var mParams = oEvent.getParameters(),
|
|
|
+ sPath,
|
|
|
+ bDescending,
|
|
|
+ aSorters = [];
|
|
|
+ // apply sorter to binding
|
|
|
+ if (mParams.groupItem) {
|
|
|
+ mParams.groupItem.getKey() === "CompanyName" ?
|
|
|
+ sPath = "Customer/" + mParams.groupItem.getKey() : sPath = mParams.groupItem.getKey();
|
|
|
+ bDescending = mParams.groupDescending;
|
|
|
+ var vGroup = this._oGroupFunctions[mParams.groupItem.getKey()];
|
|
|
+ aSorters.push(new Sorter(sPath, bDescending, vGroup));
|
|
|
+ }
|
|
|
+ this._oList.getBinding("items").sort(aSorters);
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Event handler for the list selection event
|
|
|
+ * @param {sap.ui.base.Event} oEvent the list selectionChange event
|
|
|
+ * @public
|
|
|
+ */
|
|
|
+ onSelectionChange : function (oEvent) {
|
|
|
+ var oList = oEvent.getSource(),
|
|
|
+ bSelected = oEvent.getParameter("selected");
|
|
|
+
|
|
|
+ // skip navigation when deselecting an item in multi selection mode
|
|
|
+ if (!(oList.getMode() === "MultiSelect" && !bSelected)) {
|
|
|
+ // get the list item, either from the listItem parameter or from the event's source itself (will depend on the device-dependent mode).
|
|
|
+ this._showDetail(oEvent.getParameter("listItem") || oEvent.getSource());
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Event handler for the bypassed event, which is fired when no routing pattern matched.
|
|
|
+ * If there was an object selected in the master list, that selection is removed.
|
|
|
+ * @public
|
|
|
+ */
|
|
|
+ onBypassed : function () {
|
|
|
+ this._oList.removeSelections(true);
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Used to create GroupHeaders with non-capitalized caption.
|
|
|
+ * These headers are inserted into the master list to
|
|
|
+ * group the master list's items.
|
|
|
+ * @param {Object} oGroup group whose text is to be displayed
|
|
|
+ * @public
|
|
|
+ * @returns {sap.m.GroupHeaderListItem} group header with non-capitalized caption.
|
|
|
+ */
|
|
|
+ createGroupHeader : function (oGroup) {
|
|
|
+ return new GroupHeaderListItem({
|
|
|
+ title : oGroup.text
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ /* =========================================================== */
|
|
|
+ /* begin: internal methods */
|
|
|
+ /* =========================================================== */
|
|
|
+
|
|
|
+
|
|
|
+ _createViewModel : function() {
|
|
|
+ return new JSONModel({
|
|
|
+ isFilterBarVisible: false,
|
|
|
+ filterBarLabel: "",
|
|
|
+ delay: 0,
|
|
|
+ titleCount: 0,
|
|
|
+ noDataText: this.getResourceBundle().getText("masterListNoDataText")
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ _onMasterMatched : function() {
|
|
|
+ //Set the layout property of the FCL control to 'OneColumn'
|
|
|
+ this.getModel("appView").setProperty("/layout", "OneColumn");
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Shows the selected item on the detail page
|
|
|
+ * On phones a additional history entry is created
|
|
|
+ * @param {sap.m.ObjectListItem} oItem selected Item
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+ _showDetail : function (oItem) {
|
|
|
+ var bReplace = !Device.system.phone;
|
|
|
+ // set the layout property of FCL control to show two columns
|
|
|
+ this.getModel("appView").setProperty("/layout", "TwoColumnsMidExpanded");
|
|
|
+ this.getRouter().navTo("object", {
|
|
|
+ objectId : oItem.getBindingContext().getProperty("OrderID")
|
|
|
+ }, bReplace);
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Sets the item count on the master list header
|
|
|
+ * @param {int} iTotalItems the total number of items in the list
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+ _updateListItemCount : function (iTotalItems) {
|
|
|
+ // only update the counter if the length is final
|
|
|
+ if (this._oList.getBinding("items").isLengthFinal()) {
|
|
|
+ this.getModel("masterView").setProperty("/titleCount", iTotalItems);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Internal helper method to apply both filter and search state together on the list binding
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+ _applyFilterSearch : function () {
|
|
|
+ var aFilters = this._oListFilterState.aSearch.concat(this._oListFilterState.aFilter),
|
|
|
+ oViewModel = this.getModel("masterView");
|
|
|
+ this._oList.getBinding("items").filter(aFilters, "Application");
|
|
|
+ // changes the noDataText of the list in case there are no filter results
|
|
|
+ if (aFilters.length !== 0) {
|
|
|
+ oViewModel.setProperty("/noDataText", this.getResourceBundle().getText("masterListNoDataWithFilterOrSearchText"));
|
|
|
+ } else if (this._oListFilterState.aSearch.length > 0) {
|
|
|
+ // only reset the no data text to default when no new search was triggered
|
|
|
+ oViewModel.setProperty("/noDataText", this.getResourceBundle().getText("masterListNoDataText"));
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Internal helper method that sets the filter bar visibility property and the label's caption to be shown
|
|
|
+ * @param {string} sFilterBarText the selected filter value
|
|
|
+ * @private
|
|
|
+ */
|
|
|
+ _updateFilterBar : function (sFilterBarText) {
|
|
|
+ var oViewModel = this.getModel("masterView");
|
|
|
+ oViewModel.setProperty("/isFilterBarVisible", (this._oListFilterState.aFilter.length > 0));
|
|
|
+ oViewModel.setProperty("/filterBarLabel", this.getResourceBundle().getText("masterFilterBarText", [sFilterBarText]));
|
|
|
+ }
|
|
|
+
|
|
|
+ });
|
|
|
+});
|