commit
49d0b3a121
|
@ -107,14 +107,17 @@ export class AddonMessagesModule {
|
|||
}
|
||||
|
||||
messagesProvider.invalidateDiscussionsCache(notification.site).finally(() => {
|
||||
// Check if group messaging is enabled, to determine which page should be loaded.
|
||||
messagesProvider.isGroupMessagingEnabledInSite(notification.site).then((enabled) => {
|
||||
let pageName = 'AddonMessagesIndexPage';
|
||||
if (messagesProvider.isGroupMessagingEnabled()) {
|
||||
if (enabled) {
|
||||
pageName = 'AddonMessagesGroupConversationsPage';
|
||||
}
|
||||
linkHelper.goInSite(undefined, pageName, undefined, notification.site);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if (appProvider.isDesktop()) {
|
||||
|
@ -125,7 +128,10 @@ export class AddonMessagesModule {
|
|||
// Register push notification clicks.
|
||||
pushNotificationsDelegate.on('click').subscribe((notification) => {
|
||||
if (utils.isFalseOrZero(notification.notif)) {
|
||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||
zone.run(() => {
|
||||
notificationClicked(notification);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1770,17 +1770,32 @@ export class AddonMessagesProvider {
|
|||
/**
|
||||
* Returns whether or not group messaging is supported.
|
||||
*
|
||||
* @return {boolean} If related WS is avalaible on current site.
|
||||
* @return {boolean} If related WS is available on current site.
|
||||
* @since 3.6
|
||||
*/
|
||||
isGroupMessagingEnabled(): boolean {
|
||||
return this.sitesProvider.wsAvailableInCurrentSite('core_message_get_conversations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not group messaging is supported in a certain site.
|
||||
*
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<boolean>} Promise resolved with boolean: whether related WS is available on a certain site.
|
||||
* @since 3.6
|
||||
*/
|
||||
isGroupMessagingEnabledInSite(siteId?: string): Promise<boolean> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return site.wsAvailable('core_message_get_conversations');
|
||||
}).catch(() => {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not we can mark all messages as read.
|
||||
*
|
||||
* @return {boolean} If related WS is avalaible on current site.
|
||||
* @return {boolean} If related WS is available on current site.
|
||||
* @since 3.2
|
||||
*/
|
||||
isMarkAllMessagesReadEnabled(): boolean {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
// limitations under the License.
|
||||
import { Component } from '@angular/core';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||
|
||||
|
@ -27,7 +28,7 @@ export class AddonModDataFieldDateComponent extends AddonModDataFieldPluginCompo
|
|||
|
||||
format: string;
|
||||
|
||||
constructor(protected fb: FormBuilder, protected timeUtils: CoreTimeUtilsProvider) {
|
||||
constructor(protected fb: FormBuilder, protected timeUtils: CoreTimeUtilsProvider, protected translate: TranslateService) {
|
||||
super(fb);
|
||||
}
|
||||
|
||||
|
@ -40,7 +41,10 @@ export class AddonModDataFieldDateComponent extends AddonModDataFieldPluginCompo
|
|||
}
|
||||
|
||||
let val;
|
||||
this.format = this.timeUtils.getLocalizedDateFormat('LL');
|
||||
|
||||
// Calculate format to use. ion-datetime doesn't support escaping characters ([]), so we remove them.
|
||||
this.format = this.timeUtils.convertPHPToMoment(this.translate.instant('core.strftimedatefullshort'))
|
||||
.replace(/[\[\]]/g, '');
|
||||
|
||||
if (this.mode == 'search') {
|
||||
this.addControl('f_' + this.field.id + '_z');
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { NgModule, NgZone } from '@angular/core';
|
||||
import { AddonNotificationsProvider } from './providers/notifications';
|
||||
import { AddonNotificationsMainMenuHandler } from './providers/mainmenu-handler';
|
||||
import { AddonNotificationsSettingsHandler } from './providers/settings-handler';
|
||||
|
@ -47,7 +47,7 @@ export const ADDON_NOTIFICATIONS_PROVIDERS: any[] = [
|
|||
export class AddonNotificationsModule {
|
||||
constructor(mainMenuDelegate: CoreMainMenuDelegate, mainMenuHandler: AddonNotificationsMainMenuHandler,
|
||||
settingsDelegate: CoreSettingsDelegate, settingsHandler: AddonNotificationsSettingsHandler,
|
||||
cronDelegate: CoreCronDelegate, cronHandler: AddonNotificationsCronHandler,
|
||||
cronDelegate: CoreCronDelegate, cronHandler: AddonNotificationsCronHandler, zone: NgZone,
|
||||
appProvider: CoreAppProvider, utils: CoreUtilsProvider, sitesProvider: CoreSitesProvider,
|
||||
notificationsProvider: AddonNotificationsProvider, localNotifications: CoreLocalNotificationsProvider,
|
||||
linkHelper: CoreContentLinksHelperProvider, pushNotificationsDelegate: AddonPushNotificationsDelegate) {
|
||||
|
@ -76,7 +76,10 @@ export class AddonNotificationsModule {
|
|||
// Register push notification clicks.
|
||||
pushNotificationsDelegate.on('click').subscribe((notification) => {
|
||||
if (utils.isTrueOrOne(notification.notif)) {
|
||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||
zone.run(() => {
|
||||
notificationClicked(notification);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -139,13 +139,15 @@ export class AddonNotificationsListPage {
|
|||
this.loadingMarkAllNotificationsAsRead = true;
|
||||
this.notificationsProvider.markAllNotificationsAsRead().catch(() => {
|
||||
// Omit failure.
|
||||
}).finally(() => {
|
||||
}).then(() => {
|
||||
const siteId = this.sitesProvider.getCurrentSiteId();
|
||||
this.eventsProvider.trigger(AddonNotificationsProvider.READ_CHANGED_EVENT, null, siteId);
|
||||
|
||||
this.notificationsProvider.getUnreadNotificationsCount().then((unread) => {
|
||||
this.canMarkAllNotificationsAsRead = unread > 0;
|
||||
this.loadingMarkAllNotificationsAsRead = false;
|
||||
// All marked as read, refresh the list.
|
||||
this.notificationsLoaded = false;
|
||||
|
||||
return this.refreshNotifications().finally(() => {
|
||||
this.notificationsLoaded = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -182,6 +184,7 @@ export class AddonNotificationsListPage {
|
|||
|
||||
return this.notificationsProvider.getUnreadNotificationsCount().then((unread) => {
|
||||
this.canMarkAllNotificationsAsRead = unread > 0;
|
||||
}).finally(() => {
|
||||
this.loadingMarkAllNotificationsAsRead = false;
|
||||
});
|
||||
}
|
||||
|
@ -193,9 +196,10 @@ export class AddonNotificationsListPage {
|
|||
* Refresh notifications.
|
||||
*
|
||||
* @param {any} [refresher] Refresher.
|
||||
* @return Promise<any> Promise resolved when done.
|
||||
*/
|
||||
refreshNotifications(refresher?: any): void {
|
||||
this.notificationsProvider.invalidateNotificationsList().finally(() => {
|
||||
refreshNotifications(refresher?: any): Promise<any> {
|
||||
return this.notificationsProvider.invalidateNotificationsList().finally(() => {
|
||||
return this.fetchNotifications(true).finally(() => {
|
||||
if (refresher) {
|
||||
refresher.complete();
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
|
||||
|
@ -30,7 +31,8 @@ export class AddonUserProfileFieldDatetimeComponent implements OnInit {
|
|||
@Input() disabled = false; // True if disabled. Defaults to false.
|
||||
@Input() form?: FormGroup; // Form where to add the form control.
|
||||
|
||||
constructor(private fb: FormBuilder, private timeUtils: CoreTimeUtilsProvider, protected utils: CoreUtilsProvider) { }
|
||||
constructor(private fb: FormBuilder, private timeUtils: CoreTimeUtilsProvider, protected utils: CoreUtilsProvider,
|
||||
private translate: TranslateService) { }
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
|
@ -44,7 +46,10 @@ export class AddonUserProfileFieldDatetimeComponent implements OnInit {
|
|||
|
||||
// Check if it's only date or it has time too.
|
||||
const hasTime = this.utils.isTrueOrOne(field.param3);
|
||||
field.format = hasTime ? this.timeUtils.getLocalizedDateFormat('LLL') : this.timeUtils.getLocalizedDateFormat('LL');
|
||||
|
||||
// Calculate format to use. ion-datetime doesn't support escaping characters ([]), so we remove them.
|
||||
field.format = this.timeUtils.convertPHPToMoment(this.translate.instant('core.' +
|
||||
(hasTime ? 'strftimedatetimeshort' : 'strftimedatefullshort'))).replace(/[\[\]]/g, '');
|
||||
|
||||
// Check min value.
|
||||
if (field.param1) {
|
||||
|
|
|
@ -152,6 +152,22 @@ export class CoreFileComponent implements OnInit, OnDestroy {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!this.canDownload) {
|
||||
// File cannot be downloaded, just open it.
|
||||
if (this.file.toURL) {
|
||||
// Local file.
|
||||
this.utils.openFile(this.file.toURL());
|
||||
} else if (this.fileUrl) {
|
||||
if (this.fileUrl.indexOf('http') === 0) {
|
||||
this.utils.openOnlineFile(this.fileUrl);
|
||||
} else {
|
||||
this.utils.openFile(this.fileUrl);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.appProvider.isOnline() && (!openAfterDownload || (openAfterDownload && !this.isDownloaded))) {
|
||||
this.domUtils.showErrorModal('core.networkerrormsg', true);
|
||||
|
||||
|
|
|
@ -14,9 +14,11 @@
|
|||
|
||||
import { Component, Optional, ElementRef, Renderer, ViewEncapsulation, forwardRef, ViewChild, Input,
|
||||
OnDestroy } from '@angular/core';
|
||||
import { Tabs, NavController, ViewController, App, Config, Platform, DeepLinker, Keyboard, RootNode } from 'ionic-angular';
|
||||
import {
|
||||
Tabs, Tab, NavController, ViewController, App, Config, Platform, DeepLinker, Keyboard, RootNode, NavOptions
|
||||
} from 'ionic-angular';
|
||||
import { CoreIonTabComponent } from './ion-tab';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreUtilsProvider, PromiseDefer } from '@providers/utils/utils';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
|
||||
/**
|
||||
|
@ -66,6 +68,7 @@ export class CoreIonTabsComponent extends Tabs implements OnDestroy {
|
|||
|
||||
protected firstSelectedTab: string;
|
||||
protected unregisterBackButtonAction: any;
|
||||
protected selectTabPromiseDefer: PromiseDefer;
|
||||
|
||||
constructor(protected utils: CoreUtilsProvider, protected appProvider: CoreAppProvider, @Optional() parent: NavController,
|
||||
@Optional() viewCtrl: ViewController, _app: App, config: Config, elementRef: ElementRef, _plt: Platform,
|
||||
|
@ -148,20 +151,18 @@ export class CoreIonTabsComponent extends Tabs implements OnDestroy {
|
|||
// Tabs initialized. Force select the tab if it's not enabled.
|
||||
if (this.selectedDisabled && typeof this.selectedIndex != 'undefined') {
|
||||
const tab = this.getByIndex(this.selectedIndex);
|
||||
if (tab && (!tab.enabled)) {
|
||||
this.select(tab);
|
||||
}
|
||||
} else {
|
||||
// Select first tab on init.
|
||||
const tab = this._tabs.find((tab) => {
|
||||
return tab.enabled;
|
||||
});
|
||||
if (tab) {
|
||||
if (tab && !tab.enabled) {
|
||||
this.select(tab);
|
||||
}
|
||||
}
|
||||
|
||||
this.firstSelectedTab = this._selectHistory[0] || null;
|
||||
}).finally(() => {
|
||||
// If there was a select promise pending to be resolved, do it now.
|
||||
if (this.selectTabPromiseDefer) {
|
||||
this.selectTabPromiseDefer.resolve();
|
||||
delete this.selectTabPromiseDefer;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Tabs not loaded yet. Set the tab bar position so the tab bar is shown, it'll have a spinner.
|
||||
|
@ -265,21 +266,63 @@ export class CoreIonTabsComponent extends Tabs implements OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a tab.
|
||||
*
|
||||
* @param {number|Tab} tabOrIndex Index, or the Tab instance, of the tab to select.
|
||||
* @param {NavOptions} Nav options.
|
||||
* @param {boolean} [fromUrl=true] Whether to load from a URL.
|
||||
* @return {Promise<any>} Promise resolved when selected.
|
||||
*/
|
||||
select(tabOrIndex: number | Tab, opts: NavOptions = {}, fromUrl: boolean = false): Promise<any> {
|
||||
|
||||
if (this.initialized) {
|
||||
// Tabs have been initialized, select the tab.
|
||||
return super.select(tabOrIndex, opts, fromUrl);
|
||||
} else {
|
||||
// Tabs not initialized yet. Mark it as "selectedIndex" input so it's treated when the tabs are initialized.
|
||||
if (typeof tabOrIndex == 'number') {
|
||||
this.selectedIndex = tabOrIndex;
|
||||
} else {
|
||||
this.selectedIndex = this.getIndex(tabOrIndex);
|
||||
}
|
||||
|
||||
// Don't resolve the Promise until the tab is really selected (tabs are initialized).
|
||||
this.selectTabPromiseDefer = this.selectTabPromiseDefer || this.utils.promiseDefer();
|
||||
|
||||
return this.selectTabPromiseDefer.promise;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a tab by Index. First it will reset the status of the tab.
|
||||
*
|
||||
* @param {number} index Index of the tab.
|
||||
* @return {Promise<any>} Promise resolved when selected.
|
||||
*/
|
||||
selectTabRootByIndex(index: number): void {
|
||||
selectTabRootByIndex(index: number): Promise<any> {
|
||||
if (this.initialized) {
|
||||
const tab = this.getByIndex(index);
|
||||
if (tab) {
|
||||
tab.goToRoot({animate: false, updateUrl: true, isNavRoot: true}).then(() => {
|
||||
return tab.goToRoot({animate: false, updateUrl: true, isNavRoot: true}).then(() => {
|
||||
// Tab not previously selected. Select it after going to root.
|
||||
if (!tab.isSelected) {
|
||||
this.select(tab, {animate: false, updateUrl: true, isNavRoot: true});
|
||||
return this.select(tab, {animate: false, updateUrl: true, isNavRoot: true});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Not found.
|
||||
return Promise.reject(null);
|
||||
} else {
|
||||
// Tabs not initialized yet. Mark it as "selectedIndex" input so it's treated when the tabs are initialized.
|
||||
this.selectedIndex = index;
|
||||
|
||||
// Don't resolve the Promise until the tab is really selected (tabs are initialized).
|
||||
this.selectTabPromiseDefer = this.selectTabPromiseDefer || this.utils.promiseDefer();
|
||||
|
||||
return this.selectTabPromiseDefer.promise;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
<div class="core-button-spinner" *ngIf="courseOptionMenuEnabled">
|
||||
<!-- Download course spinner. -->
|
||||
<ion-spinner *ngIf="prefetchCourseData.prefetchCourseIcon == 'spinner' || showSpinner"></ion-spinner>
|
||||
<ion-spinner *ngIf="(downloadCourseEnabled && prefetchCourseData.prefetchCourseIcon == 'spinner') || showSpinner"></ion-spinner>
|
||||
|
||||
<!-- Options menu. -->
|
||||
<button ion-button icon-only clear color="dark" (click)="showCourseOptionsMenu($event)" *ngIf="!showSpinner">
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<ion-icon name="search"></ion-icon>
|
||||
</button>
|
||||
<core-context-menu>
|
||||
<core-context-menu-item *ngIf="downloadCourseEnabled" [priority]="1000" [content]="'core.settings.showdownloadoptions' | translate" (action)="toggleDownload()" [iconAction]="downloadEnabledIcon"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="downloadCourseEnabled || downloadCoursesEnabled" [priority]="1000" [content]="'core.settings.showdownloadoptions' | translate" (action)="toggleDownload()" [iconAction]="downloadEnabledIcon"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</ion-buttons>
|
||||
</ion-navbar>
|
||||
|
|
|
@ -52,6 +52,7 @@ export class CoreCoursesDashboardPage implements OnDestroy {
|
|||
downloadEnabled: boolean;
|
||||
downloadEnabledIcon = 'square-outline'; // Disabled by default.
|
||||
downloadCourseEnabled: boolean;
|
||||
downloadCoursesEnabled: boolean;
|
||||
|
||||
protected isDestroyed;
|
||||
protected updateSiteObserver;
|
||||
|
@ -69,11 +70,13 @@ export class CoreCoursesDashboardPage implements OnDestroy {
|
|||
ionViewDidLoad(): void {
|
||||
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
|
||||
this.downloadCourseEnabled = !this.coursesProvider.isDownloadCourseDisabledInSite();
|
||||
this.downloadCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
|
||||
|
||||
// Refresh the enabled flags if site is updated.
|
||||
this.updateSiteObserver = this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, () => {
|
||||
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
|
||||
this.downloadCourseEnabled = !this.coursesProvider.isDownloadCourseDisabledInSite();
|
||||
this.downloadCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
|
||||
|
||||
this.switchDownload(this.downloadEnabled);
|
||||
|
||||
|
@ -196,7 +199,7 @@ export class CoreCoursesDashboardPage implements OnDestroy {
|
|||
* @param {boolean} enable If enable or disable.
|
||||
*/
|
||||
protected switchDownload(enable: boolean): void {
|
||||
this.downloadEnabled = this.downloadCourseEnabled && enable;
|
||||
this.downloadEnabled = (this.downloadCourseEnabled || this.downloadCoursesEnabled) && enable;
|
||||
this.downloadEnabledIcon = this.downloadEnabled ? 'checkbox-outline' : 'square-outline';
|
||||
this.eventsProvider.trigger(CoreCoursesProvider.EVENT_DASHBOARD_DOWNLOAD_ENABLED_CHANGED, {enabled: this.downloadEnabled});
|
||||
}
|
||||
|
|
|
@ -203,7 +203,8 @@ export class CoreLoginHelperProvider {
|
|||
return this.requestPasswordReset(siteUrl).then(() => {
|
||||
return true;
|
||||
}).catch((error) => {
|
||||
return error.available == 1 || (error.errorcode != 'invalidrecord' && error.errorcode != '');
|
||||
return error.available == 1 || (typeof error.errorcode != 'undefined' && error.errorcode != 'invalidrecord' &&
|
||||
error.errorcode != '');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -586,18 +587,24 @@ export class CoreLoginHelperProvider {
|
|||
* @param {string} siteId Site to load.
|
||||
*/
|
||||
protected loadSiteAndPage(page: string, params: any, siteId: string): void {
|
||||
const navCtrl = this.appProvider.getRootNavController();
|
||||
|
||||
if (siteId == CoreConstants.NO_SITE_ID) {
|
||||
// Page doesn't belong to a site, just load the page.
|
||||
this.appProvider.getRootNavController().setRoot(page, params);
|
||||
navCtrl.setRoot(page, params);
|
||||
} else {
|
||||
const modal = this.domUtils.showModalLoading();
|
||||
this.sitesProvider.loadSite(siteId, page, params).then((loggedIn) => {
|
||||
if (loggedIn) {
|
||||
this.loadPageInMainMenu(page, params);
|
||||
// Due to DeepLinker, we need to remove the path from the URL before going to main menu.
|
||||
// IonTabs checks the URL to determine which path to load for deep linking, so we clear the URL.
|
||||
this.location.replaceState('');
|
||||
|
||||
navCtrl.setRoot('CoreMainMenuPage', { redirectPage: page, redirectParams: params });
|
||||
}
|
||||
}).catch(() => {
|
||||
}).catch((error) => {
|
||||
// Site doesn't exist.
|
||||
this.appProvider.getRootNavController().setRoot('CoreLoginSitesPage');
|
||||
navCtrl.setRoot('CoreLoginSitesPage');
|
||||
}).finally(() => {
|
||||
modal.dismiss();
|
||||
});
|
||||
|
|
|
@ -43,6 +43,15 @@ export class CoreMainMenuPage implements OnDestroy {
|
|||
|
||||
constructor(private menuDelegate: CoreMainMenuDelegate, private sitesProvider: CoreSitesProvider, navParams: NavParams,
|
||||
private navCtrl: NavController, private eventsProvider: CoreEventsProvider) {
|
||||
|
||||
// Check if the menu was loaded with a redirect.
|
||||
const redirectPage = navParams.get('redirectPage');
|
||||
if (redirectPage) {
|
||||
this.pendingRedirect = {
|
||||
redirectPage: redirectPage,
|
||||
redirectParams: navParams.get('redirectParams')
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -240,6 +240,43 @@ export class CoreLangProvider {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default language.
|
||||
*
|
||||
* @return {string} Default language.
|
||||
*/
|
||||
getDefaultLanguage(): string {
|
||||
return this.defaultLanguage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fallback language.
|
||||
*
|
||||
* @return {string} Fallback language.
|
||||
*/
|
||||
getFallbackLanguage(): string {
|
||||
return this.fallbackLanguage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full list of translations for a certain language.
|
||||
*
|
||||
* @param {string} lang The language to check.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
getTranslationTable(lang: string): Promise<any> {
|
||||
// Create a promise to convert the observable into a promise.
|
||||
return new Promise((resolve, reject): void => {
|
||||
const observer = this.translate.getTranslation(lang).subscribe((table) => {
|
||||
resolve(table);
|
||||
observer.unsubscribe();
|
||||
}, (err) => {
|
||||
reject(err);
|
||||
observer.unsubscribe();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load certain custom strings.
|
||||
*
|
||||
|
|
|
@ -278,6 +278,7 @@ export class CoreTimeUtilsProvider {
|
|||
|
||||
/**
|
||||
* Return the localized ISO format (i.e DDMMYY) from the localized moment format. Useful for translations.
|
||||
* DO NOT USE this function for ion-datetime format. Moment escapes characters with [], but ion-datetime doesn't support it.
|
||||
*
|
||||
* @param {any} localizedFormat Format to use.
|
||||
* @return {string} Localized ISO format
|
||||
|
|
|
@ -561,29 +561,68 @@ export class CoreUtilsProvider {
|
|||
* @return {Promise<any>} Promise resolved with the list of countries.
|
||||
*/
|
||||
getCountryList(): Promise<any> {
|
||||
// Get the current language.
|
||||
return this.langProvider.getCurrentLanguage().then((lang) => {
|
||||
// Get the full list of translations. Create a promise to convert the observable into a promise.
|
||||
return new Promise((resolve, reject): void => {
|
||||
const observer = this.translate.getTranslation(lang).subscribe((table) => {
|
||||
resolve(table);
|
||||
observer.unsubscribe();
|
||||
}, (err) => {
|
||||
reject(err);
|
||||
observer.unsubscribe();
|
||||
});
|
||||
});
|
||||
}).then((table) => {
|
||||
// Get the keys of the countries.
|
||||
return this.getCountryKeysList().then((keys) => {
|
||||
// Now get the code and the translated name.
|
||||
const countries = {};
|
||||
|
||||
keys.forEach((key) => {
|
||||
if (key.indexOf('assets.countries.') === 0) {
|
||||
const code = key.replace('assets.countries.', '');
|
||||
countries[code] = this.translate.instant(key);
|
||||
}
|
||||
});
|
||||
|
||||
return countries;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of language keys of the countries.
|
||||
*
|
||||
* @return {Promise<string[]>} Promise resolved with the countries list. Rejected if not translated.
|
||||
*/
|
||||
protected getCountryKeysList(): Promise<string[]> {
|
||||
// It's possible that the current language isn't translated, so try with default language first.
|
||||
const defaultLang = this.langProvider.getDefaultLanguage();
|
||||
|
||||
return this.getCountryKeysListForLanguage(defaultLang).catch(() => {
|
||||
// Not translated, try to use the fallback language.
|
||||
const fallbackLang = this.langProvider.getFallbackLanguage();
|
||||
|
||||
if (fallbackLang === defaultLang) {
|
||||
// Same language, just reject.
|
||||
return Promise.reject('Countries not found.');
|
||||
}
|
||||
|
||||
return this.getCountryKeysListForLanguage(fallbackLang);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of language keys of the countries, based on the translation table for a certain language.
|
||||
*
|
||||
* @param {string} lang Language to check.
|
||||
* @return {Promise<string[]>} Promise resolved with the countries list. Rejected if not translated.
|
||||
*/
|
||||
protected getCountryKeysListForLanguage(lang: string): Promise<string[]> {
|
||||
// Get the translation table for the language.
|
||||
return this.langProvider.getTranslationTable(lang).then((table): any => {
|
||||
// Gather all the keys for countries,
|
||||
const keys = [];
|
||||
|
||||
for (const name in table) {
|
||||
if (name.indexOf('assets.countries.') === 0) {
|
||||
const code = name.replace('assets.countries.', '');
|
||||
countries[code] = table[name];
|
||||
keys.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
return countries;
|
||||
if (keys.length === 0) {
|
||||
// Not translated, reject.
|
||||
return Promise.reject('Countries not found.');
|
||||
}
|
||||
|
||||
return keys;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -254,14 +254,14 @@ export class CoreWSProvider {
|
|||
if (!data || typeof data != 'object') {
|
||||
return rejectWithError(this.createFakeWSError('core.serverconnection', true));
|
||||
} else if (data.error) {
|
||||
return rejectWithError(data.error);
|
||||
return rejectWithError(data);
|
||||
}
|
||||
|
||||
// Get the first response since only one request was done.
|
||||
data = data[0];
|
||||
|
||||
if (data.error) {
|
||||
return rejectWithError(data.exception);
|
||||
return rejectWithError(data);
|
||||
}
|
||||
|
||||
return data.data;
|
||||
|
|
Loading…
Reference in New Issue