249 lines
8.9 KiB
TypeScript
249 lines
8.9 KiB
TypeScript
// (C) Copyright 2015 Moodle Pty Ltd.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import { Component, OnDestroy, ViewChild, ChangeDetectorRef } from '@angular/core';
|
|
import { IonicPage, NavController, NavParams } from 'ionic-angular';
|
|
import { CoreApp } from '@providers/app';
|
|
import { CoreSitesProvider } from '@providers/sites';
|
|
import { CoreEventsProvider } from '@providers/events';
|
|
import { CoreIonTabsComponent } from '@components/ion-tabs/ion-tabs';
|
|
import { CoreMainMenuProvider } from '../../providers/mainmenu';
|
|
import { CoreMainMenuDelegate, CoreMainMenuHandlerToDisplay } from '../../providers/delegate';
|
|
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
|
|
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
|
|
|
|
/**
|
|
* Page that displays the main menu of the app.
|
|
*/
|
|
@IonicPage({segment: 'core-mainmenu'})
|
|
@Component({
|
|
selector: 'page-core-mainmenu',
|
|
templateUrl: 'menu.html',
|
|
})
|
|
export class CoreMainMenuPage implements OnDestroy {
|
|
tabs: CoreMainMenuHandlerToDisplay[] = [];
|
|
allHandlers: CoreMainMenuHandlerToDisplay[];
|
|
loaded = false;
|
|
redirectPage: string;
|
|
redirectParams: any;
|
|
showTabs = false;
|
|
tabsPlacement = 'bottom';
|
|
|
|
protected subscription;
|
|
protected redirectObs: any;
|
|
protected pendingRedirect: any;
|
|
protected urlToOpen: string;
|
|
protected mainMenuId: number;
|
|
protected keyboardObserver: any;
|
|
|
|
@ViewChild('mainTabs') mainTabs: CoreIonTabsComponent;
|
|
|
|
constructor(protected menuDelegate: CoreMainMenuDelegate,
|
|
protected sitesProvider: CoreSitesProvider,
|
|
navParams: NavParams,
|
|
protected navCtrl: NavController,
|
|
protected eventsProvider: CoreEventsProvider,
|
|
protected cdr: ChangeDetectorRef,
|
|
protected mainMenuProvider: CoreMainMenuProvider,
|
|
protected linksDelegate: CoreContentLinksDelegate,
|
|
protected linksHelper: CoreContentLinksHelperProvider,
|
|
) {
|
|
|
|
this.mainMenuId = CoreApp.instance.getMainMenuId();
|
|
|
|
// Check if the menu was loaded with a redirect.
|
|
const redirectPage = navParams.get('redirectPage');
|
|
if (redirectPage) {
|
|
this.pendingRedirect = {
|
|
redirectPage: redirectPage,
|
|
redirectParams: navParams.get('redirectParams')
|
|
};
|
|
}
|
|
|
|
this.urlToOpen = navParams.get('urlToOpen');
|
|
}
|
|
|
|
/**
|
|
* View loaded.
|
|
*/
|
|
ionViewDidLoad(): void {
|
|
if (!this.sitesProvider.isLoggedIn()) {
|
|
this.navCtrl.setRoot('CoreLoginInitPage');
|
|
|
|
return;
|
|
}
|
|
|
|
this.showTabs = true;
|
|
|
|
this.redirectObs = this.eventsProvider.on(CoreEventsProvider.LOAD_PAGE_MAIN_MENU, (data) => {
|
|
if (!this.loaded) {
|
|
// View isn't ready yet, wait for it to be ready.
|
|
this.pendingRedirect = data;
|
|
} else {
|
|
delete this.pendingRedirect;
|
|
this.handleRedirect(data);
|
|
}
|
|
});
|
|
|
|
this.subscription = this.menuDelegate.getHandlers().subscribe((handlers) => {
|
|
// Remove the handlers that should only appear in the More menu.
|
|
this.allHandlers = handlers.filter((handler) => {
|
|
return !handler.onlyInMore;
|
|
});
|
|
|
|
this.initHandlers();
|
|
|
|
if (this.loaded && this.pendingRedirect) {
|
|
// Wait for tabs to be initialized and then handle the redirect.
|
|
setTimeout(() => {
|
|
if (this.pendingRedirect) {
|
|
this.handleRedirect(this.pendingRedirect);
|
|
delete this.pendingRedirect;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
window.addEventListener('resize', this.initHandlers.bind(this));
|
|
|
|
if (CoreApp.instance.isIOS()) {
|
|
// In iOS, the resize event is triggered before the keyboard is opened/closed and not triggered again once done.
|
|
// Init handlers again once keyboard is closed since the resize event doesn't have the updated height.
|
|
this.keyboardObserver = this.eventsProvider.on(CoreEventsProvider.KEYBOARD_CHANGE, (kbHeight) => {
|
|
if (kbHeight === 0) {
|
|
this.initHandlers();
|
|
|
|
// If the device is slow it can take a bit more to update the window height. Retry in a few ms.
|
|
setTimeout(() => {
|
|
this.initHandlers();
|
|
}, 250);
|
|
}
|
|
});
|
|
}
|
|
|
|
CoreApp.instance.setMainMenuOpen(this.mainMenuId, true);
|
|
}
|
|
|
|
/**
|
|
* Init handlers on change (size or handlers).
|
|
*/
|
|
initHandlers(): void {
|
|
if (this.allHandlers) {
|
|
this.tabsPlacement = this.mainMenuProvider.getTabPlacement(this.navCtrl);
|
|
|
|
const handlers = this.allHandlers.slice(0, this.mainMenuProvider.getNumItems()); // Get main handlers.
|
|
|
|
// Re-build the list of tabs. If a handler is already in the list, use existing object to prevent re-creating the tab.
|
|
const newTabs = [];
|
|
|
|
for (let i = 0; i < handlers.length; i++) {
|
|
const handler = handlers[i];
|
|
|
|
// Check if the handler is already in the tabs list. If so, use it.
|
|
const tab = this.tabs.find((tab) => {
|
|
return tab.title == handler.title && tab.icon == handler.icon;
|
|
});
|
|
|
|
tab ? tab.hide = false : null;
|
|
handler.hide = false;
|
|
|
|
newTabs.push(tab || handler);
|
|
}
|
|
|
|
// Maintain tab in phantom mode in case is not visible.
|
|
const selectedTab = this.mainTabs.getSelected();
|
|
if (selectedTab) {
|
|
const oldTab = this.tabs.find((tab) => {
|
|
return tab.page == selectedTab.root && tab.icon == selectedTab.tabIcon;
|
|
});
|
|
|
|
if (oldTab) {
|
|
// Check if the selected handler is visible.
|
|
const isVisible = newTabs.some((newTab) => {
|
|
return oldTab.title == newTab.title && oldTab.icon == newTab.icon;
|
|
});
|
|
|
|
if (!isVisible) {
|
|
oldTab.hide = true;
|
|
newTabs.push(oldTab);
|
|
}
|
|
}
|
|
}
|
|
|
|
this.tabs = newTabs;
|
|
|
|
// Sort them by priority so new handlers are in the right position.
|
|
this.tabs.sort((a, b) => {
|
|
return b.priority - a.priority;
|
|
});
|
|
|
|
this.loaded = this.menuDelegate.areHandlersLoaded();
|
|
}
|
|
|
|
if (this.urlToOpen) {
|
|
// There's a content link to open.
|
|
const url = this.urlToOpen;
|
|
delete this.urlToOpen;
|
|
|
|
this.linksDelegate.getActionsFor(url, undefined).then((actions) => {
|
|
const action = this.linksHelper.getFirstValidAction(actions);
|
|
if (action && action.sites.length) {
|
|
// Action should only have 1 site because we're filtering by username.
|
|
action.action(action.sites[0]);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle a redirect.
|
|
*
|
|
* @param data Data received.
|
|
*/
|
|
protected handleRedirect(data: any): void {
|
|
// Check if the redirect page is the root page of any of the tabs.
|
|
const i = this.tabs.findIndex((tab, i) => {
|
|
return tab.page == data.redirectPage;
|
|
});
|
|
|
|
if (i >= 0) {
|
|
// Tab found. Set the params.
|
|
this.tabs[i].pageParams = Object.assign({}, data.redirectParams);
|
|
} else {
|
|
// Tab not found, use a phantom tab.
|
|
this.redirectPage = data.redirectPage;
|
|
this.redirectParams = data.redirectParams;
|
|
}
|
|
|
|
// Force change detection, otherwise sometimes the tab was selected before the params were applied.
|
|
this.cdr.detectChanges();
|
|
|
|
setTimeout(() => {
|
|
// Let the tab load the params before navigating.
|
|
this.mainTabs.selectTabRootByIndex(i + 1);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Page destroyed.
|
|
*/
|
|
ngOnDestroy(): void {
|
|
this.subscription && this.subscription.unsubscribe();
|
|
this.redirectObs && this.redirectObs.off();
|
|
window.removeEventListener('resize', this.initHandlers.bind(this));
|
|
CoreApp.instance.setMainMenuOpen(this.mainMenuId, false);
|
|
this.keyboardObserver && this.keyboardObserver.off();
|
|
}
|
|
}
|