commit
0708081868
|
@ -87,7 +87,7 @@
|
|||
"hammerjs": "2.0.8",
|
||||
"jszip": "3.7.1",
|
||||
"mathjax": "2.7.7",
|
||||
"moment": "2.29.0",
|
||||
"moment": "2.29.2",
|
||||
"nl.kingsquare.cordova.background-audio": "1.0.1",
|
||||
"rxjs": "6.5.5",
|
||||
"ts-md5": "1.2.7",
|
||||
|
@ -20984,9 +20984,9 @@
|
|||
"optional": true
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.29.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz",
|
||||
"integrity": "sha512-z6IJ5HXYiuxvFTI6eiQ9dm77uE0gyy1yXNApVHqTcnIKfY9tIwEjlzsZ6u1LQXvVgKeTnv9Xm7NDvJ7lso3MtA==",
|
||||
"version": "2.29.2",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz",
|
||||
"integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
|
@ -47321,9 +47321,9 @@
|
|||
"optional": true
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.29.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz",
|
||||
"integrity": "sha512-z6IJ5HXYiuxvFTI6eiQ9dm77uE0gyy1yXNApVHqTcnIKfY9tIwEjlzsZ6u1LQXvVgKeTnv9Xm7NDvJ7lso3MtA=="
|
||||
"version": "2.29.2",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz",
|
||||
"integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg=="
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
|
|
|
@ -116,7 +116,7 @@
|
|||
"hammerjs": "2.0.8",
|
||||
"jszip": "3.7.1",
|
||||
"mathjax": "2.7.7",
|
||||
"moment": "2.29.0",
|
||||
"moment": "2.29.2",
|
||||
"nl.kingsquare.cordova.background-audio": "1.0.1",
|
||||
"rxjs": "6.5.5",
|
||||
"ts-md5": "1.2.7",
|
||||
|
|
|
@ -56,6 +56,8 @@
|
|||
<core-format-text [text]="discussion.subject" contextLevel="module" [contextInstanceId]="module && module.id"
|
||||
[courseId]="courseId">
|
||||
</core-format-text>
|
||||
<ion-icon name="fas-lock" *ngIf="discussion.locked" class="addon-mod-forum-locked-icon"
|
||||
[attr.aria-label]="'addon.mod_forum.discussionlocked' | translate"></ion-icon>
|
||||
</p>
|
||||
<ion-button *ngIf="canPin || discussion.canlock || discussion.canfavourite" fill="clear"
|
||||
[attr.aria-label]="('core.displayoptions' | translate)" (click)="showOptionsMenu($event, discussion)">
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
|
||||
ion-icon {
|
||||
@include margin(0, 6px, 0, 0);
|
||||
|
||||
&.addon-mod-forum-locked-icon {
|
||||
@include margin-horizontal(4px, 0px);
|
||||
color: var(--gray-500);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,11 +12,6 @@
|
|||
<p class="item-heading" *ngIf="offlinePost">{{ 'core.discard' | translate }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item class="ion-text-wrap" *ngIf="wordCount">
|
||||
<ion-label>
|
||||
<p class="item-heading">{{ 'core.numwords' | translate: {'$a': wordCount} }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item class="ion-text-wrap" [href]="url" *ngIf="url" core-link capture="false" button detail="false" [showBrowserWarning]="false">
|
||||
<ion-icon name="fas-external-link-alt" slot="start" aria-hidden="true"></ion-icon>
|
||||
<ion-label>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,9 @@
|
|||
<core-format-text [component]="component" [componentId]="componentId" [text]="post.message" contextLevel="module"
|
||||
[contextInstanceId]="forum && forum.cmid" [courseId]="courseId">
|
||||
</core-format-text>
|
||||
<p *ngIf="post.haswordcount && post.wordcount">
|
||||
<em>{{ 'core.numwords' | translate: {'$a': post.wordcount} }}</em>
|
||||
</p>
|
||||
<div *ngIf="post.attachments && post.attachments.length > 0">
|
||||
<core-files [files]="post.attachments" [component]="component" [componentId]="componentId" showInline="true">
|
||||
</core-files>
|
||||
|
|
|
@ -41,6 +41,10 @@ const appRoutes: Routes = [
|
|||
canActivate: [CoreMainMenuAuthGuard],
|
||||
canLoad: [CoreMainMenuAuthGuard],
|
||||
},
|
||||
{
|
||||
path: 'reload',
|
||||
loadChildren: () => import('./pages/reload/reload.module').then( m => m.CoreMainMenuReloadPageModule),
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
|
|
@ -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, {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<ion-content>
|
||||
<core-loading></core-loading>
|
||||
</ion-content>
|
|
@ -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 {}
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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".
|
||||
|
|
|
@ -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(' ');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue