diff --git a/src/addons/mod/forum/components/post-options-menu/post-options-menu.ts b/src/addons/mod/forum/components/post-options-menu/post-options-menu.ts
index ad13a1e84..257d8ec78 100644
--- a/src/addons/mod/forum/components/post-options-menu/post-options-menu.ts
+++ b/src/addons/mod/forum/components/post-options-menu/post-options-menu.ts
@@ -34,7 +34,6 @@ export class AddonModForumPostOptionsMenuComponent implements OnInit, OnDestroy
@Input() cmId!: number;
@Input() forumId!: number; // The forum Id.
- wordCount?: number | null; // Number of words when available.
canEdit = false;
canDelete = false;
loaded = false;
@@ -89,7 +88,6 @@ export class AddonModForumPostOptionsMenuComponent implements OnInit, OnDestroy
this.canDelete = !!this.post.capabilities.delete && AddonModForum.isDeletePostAvailable();
this.canEdit = !!this.post.capabilities.edit && AddonModForum.isUpdatePostAvailable();
- this.wordCount = (this.post.haswordcount && this.post.wordcount) || null;
this.loaded = true;
}
diff --git a/src/addons/mod/forum/components/post/post.html b/src/addons/mod/forum/components/post/post.html
index 9812ff26f..ab1f83cfe 100644
--- a/src/addons/mod/forum/components/post/post.html
+++ b/src/addons/mod/forum/components/post/post.html
@@ -63,6 +63,9 @@
+
+ {{ 'core.numwords' | translate: {'$a': post.wordcount} }}
+
0">
diff --git a/src/core/features/mainmenu/mainmenu.module.ts b/src/core/features/mainmenu/mainmenu.module.ts
index ae4136604..3ff9bf494 100644
--- a/src/core/features/mainmenu/mainmenu.module.ts
+++ b/src/core/features/mainmenu/mainmenu.module.ts
@@ -41,6 +41,10 @@ const appRoutes: Routes = [
canActivate: [CoreMainMenuAuthGuard],
canLoad: [CoreMainMenuAuthGuard],
},
+ {
+ path: 'reload',
+ loadChildren: () => import('./pages/reload/reload.module').then( m => m.CoreMainMenuReloadPageModule),
+ },
];
@NgModule({
diff --git a/src/core/features/mainmenu/pages/menu/menu.ts b/src/core/features/mainmenu/pages/menu/menu.ts
index 35b0edd55..bf6b92219 100644
--- a/src/core/features/mainmenu/pages/menu/menu.ts
+++ b/src/core/features/mainmenu/pages/menu/menu.ts
@@ -30,6 +30,7 @@ import { NavigationEnd } from '@angular/router';
import { trigger, state, style, transition, animate } from '@angular/animations';
import { CoreSites } from '@services/sites';
import { CoreDom } from '@singletons/dom';
+import { CoreLogger } from '@singletons/logger';
const ANIMATION_DURATION = 500;
@@ -84,6 +85,7 @@ export class CoreMainMenuPage implements OnInit, OnDestroy {
protected urlToOpen?: string;
protected redirectPath?: string;
protected redirectOptions?: CoreNavigationOptions;
+ protected logger: CoreLogger;
@ViewChild('mainTabs') mainTabs?: IonTabs;
@@ -92,6 +94,7 @@ export class CoreMainMenuPage implements OnInit, OnDestroy {
constructor() {
this.backButtonFunction = this.backButtonClicked.bind(this);
this.tabAction = new CoreMainMenuRoleTab(this);
+ this.logger = CoreLogger.getInstance('CoreMainMenuPage');
// Listen navigation events to show or hide tabs.
this.navSubscription = Router.events
@@ -193,6 +196,7 @@ export class CoreMainMenuPage implements OnInit, OnDestroy {
const tabPage = this.tabs[0] ? this.tabs[0].page : this.morePageName;
const tabPageParams = this.tabs[0] ? this.tabs[0].pageParams : {};
+ this.logger.debug(`Select first tab: ${tabPage}.`, this.tabs);
// Use navigate instead of mainTabs.select to be able to pass page params.
CoreNavigator.navigate(tabPage, {
diff --git a/src/core/features/mainmenu/pages/reload/reload.html b/src/core/features/mainmenu/pages/reload/reload.html
new file mode 100644
index 000000000..5e5ea6d14
--- /dev/null
+++ b/src/core/features/mainmenu/pages/reload/reload.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/core/features/mainmenu/pages/reload/reload.module.ts b/src/core/features/mainmenu/pages/reload/reload.module.ts
new file mode 100644
index 000000000..74a1fb7aa
--- /dev/null
+++ b/src/core/features/mainmenu/pages/reload/reload.module.ts
@@ -0,0 +1,37 @@
+// (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 { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { CoreSharedModule } from '@/core/shared.module';
+import { CoreMainMenuReloadPage } from './reload';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: CoreMainMenuReloadPage,
+ },
+];
+
+@NgModule({
+ imports: [
+ RouterModule.forChild(routes),
+ CoreSharedModule,
+ ],
+ declarations: [
+ CoreMainMenuReloadPage,
+ ],
+ exports: [RouterModule],
+})
+export class CoreMainMenuReloadPageModule {}
diff --git a/src/core/features/mainmenu/pages/reload/reload.ts b/src/core/features/mainmenu/pages/reload/reload.ts
new file mode 100644
index 000000000..9a9b52a2f
--- /dev/null
+++ b/src/core/features/mainmenu/pages/reload/reload.ts
@@ -0,0 +1,36 @@
+// (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, OnInit } from '@angular/core';
+import { CoreNavigator } from '@services/navigator';
+
+/**
+ * Page that displays a loading and then opens the main menu again.
+ */
+@Component({
+ selector: 'page-core-mainmenu-reload',
+ templateUrl: 'reload.html',
+})
+export class CoreMainMenuReloadPage implements OnInit {
+
+ /**
+ * @inheritdoc
+ */
+ ngOnInit(): void {
+ CoreNavigator.navigate('/main', {
+ reset: true,
+ });
+ }
+
+}
diff --git a/src/core/features/settings/pages/general/general.ts b/src/core/features/settings/pages/general/general.ts
index a1487f255..9db912420 100644
--- a/src/core/features/settings/pages/general/general.ts
+++ b/src/core/features/settings/pages/general/general.ts
@@ -26,6 +26,7 @@ import { Diagnostic, Translate } from '@singletons';
import { CoreSites } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { AlertButton } from '@ionic/angular';
+import { CoreNavigator } from '@services/navigator';
/**
* Page that displays the general settings.
@@ -168,7 +169,10 @@ export class CoreSettingsGeneralPage {
await CoreUtils.ignoreErrors(Promise.all(sites.map((site) => site.invalidateWsCache())));
CoreEvents.trigger(CoreEvents.LANGUAGE_CHANGED, this.selectedLanguage);
- window.location.reload();
+
+ CoreNavigator.navigate('/reload', {
+ reset: true,
+ });
}
/**
diff --git a/src/core/services/utils/time.ts b/src/core/services/utils/time.ts
index a771a6a21..446181a79 100644
--- a/src/core/services/utils/time.ts
+++ b/src/core/services/utils/time.ts
@@ -76,7 +76,7 @@ export class CoreTimeUtilsProvider {
moment.relativeTimeThreshold('s', 60);
moment.relativeTimeThreshold('m', 60);
moment.relativeTimeThreshold('h', 24);
- moment.relativeTimeThreshold('d', 31);
+ moment.relativeTimeThreshold('d', 30);
moment.relativeTimeThreshold('M', 12);
moment.relativeTimeThreshold('y', 365);
moment.relativeTimeThreshold('ss', 0); // To display exact number of seconds instead of just "a few seconds".
diff --git a/src/core/singletons/time.ts b/src/core/singletons/time.ts
index e3a0f0435..6b222937b 100644
--- a/src/core/singletons/time.ts
+++ b/src/core/singletons/time.ts
@@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import moment from 'moment';
+import { Translate } from '@singletons';
+import { CoreConstants } from '../constants';
/**
* Singleton with helper functions for time operations.
@@ -27,37 +28,54 @@ export class CoreTime {
* @return Seconds in a human readable format.
*/
static formatTime(seconds: number, precision = 2): string {
- precision = precision || 6; // Use max precision if 0 is passed.
+ precision = precision || 5; // Use max precision if 0 is passed.
- const eventDuration = moment.duration(Math.abs(seconds), 'seconds');
- let durationString = '';
+ const totalSecs = Math.abs(seconds);
+ if (!totalSecs) {
+ return Translate.instant('core.now');
+ }
- if (precision && eventDuration.years() > 0) {
- durationString += ' ' + moment.duration(eventDuration.years(), 'years').humanize();
+ const years = Math.floor(totalSecs / CoreConstants.SECONDS_YEAR);
+ let remainder = totalSecs - (years * CoreConstants.SECONDS_YEAR);
+ const days = Math.floor(remainder / CoreConstants.SECONDS_DAY);
+
+ remainder = totalSecs - (days * CoreConstants.SECONDS_DAY);
+
+ const hours = Math.floor(remainder / CoreConstants.SECONDS_HOUR);
+ remainder = remainder - (hours * CoreConstants.SECONDS_HOUR);
+
+ const mins = Math.floor(remainder / CoreConstants.SECONDS_MINUTE);
+ const secs = remainder - (mins * CoreConstants.SECONDS_MINUTE);
+
+ const secondsUnit = Translate.instant('core.' + (secs === 1 ? 'sec' : 'secs'));
+ const minutesUnit = Translate.instant('core.' + (mins === 1 ? 'min' : 'mins'));
+ const hoursUnit = Translate.instant('core.' + (hours === 1 ? 'hour' : 'hours'));
+ const daysUnit = Translate.instant('core.' + (days === 1 ? 'day' : 'days'));
+ const yearsUnit = Translate.instant('core.' + (years === 1 ? 'year' : 'years'));
+ const parts: string[] = [];
+
+ if (precision && years) {
+ parts.push(`${years} ${yearsUnit}`);
precision--;
}
- if (precision && eventDuration.months() > 0) {
- durationString += ' ' + moment.duration(eventDuration.months(), 'months').humanize();
+ if (precision && days) {
+ parts.push(`${days} ${daysUnit}`);
precision--;
}
- if (precision && eventDuration.days() > 0) {
- durationString += ' ' + moment.duration(eventDuration.days(), 'days').humanize();
+ if (precision && hours) {
+ parts.push(`${hours} ${hoursUnit}`);
precision--;
}
- if (precision && eventDuration.hours() > 0) {
- durationString += ' ' + moment.duration(eventDuration.hours(), 'hours').humanize();
+ if (precision && mins) {
+ parts.push(`${mins} ${minutesUnit}`);
precision--;
}
- if (precision && eventDuration.minutes() > 0) {
- durationString += ' ' + moment.duration(eventDuration.minutes(), 'minutes').humanize();
- precision--;
- }
- if (precision && (eventDuration.seconds() > 0 || !durationString)) {
- durationString += ' ' + moment.duration(eventDuration.seconds(), 'seconds').humanize();
+ if (precision && secs) {
+ parts.push(`${secs} ${secondsUnit}`);
precision--;
}
- return durationString.trim();
+ return parts.join(' ');
}
/**