MOBILE-2754 core: Use Moodle strings for dates

main
Dani Palou 2018-12-13 15:35:47 +01:00
parent 584e1cdb1f
commit d37acccee8
51 changed files with 294 additions and 121 deletions

View File

@ -1654,6 +1654,21 @@
"core.sorry": "local_moodlemobileapp",
"core.sortby": "moodle",
"core.start": "grouptool",
"core.strftimedate": "langconfig",
"core.strftimedatefullshort": "langconfig",
"core.strftimedateshort": "langconfig",
"core.strftimedatetime": "langconfig",
"core.strftimedatetimeshort": "langconfig",
"core.strftimedaydate": "langconfig",
"core.strftimedaydatetime": "langconfig",
"core.strftimedayshort": "langconfig",
"core.strftimedaytime": "langconfig",
"core.strftimemonthyear": "langconfig",
"core.strftimerecent": "langconfig",
"core.strftimerecentfull": "langconfig",
"core.strftimetime": "langconfig",
"core.strftimetime12": "langconfig",
"core.strftimetime24": "langconfig",
"core.submit": "moodle",
"core.success": "moodle",
"core.tablet": "local_moodlemobileapp",

View File

@ -14,9 +14,9 @@
import { Component, OnInit, OnDestroy, ViewChild, Injector } from '@angular/core';
import { Searchbar } from 'ionic-angular';
import * as moment from 'moment';
import { CoreEventsProvider } from '@providers/events';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreSitesProvider } from '@providers/sites';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreCoursesHelperProvider } from '@core/courses/providers/helper';
@ -74,7 +74,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
private courseCompletionProvider: AddonCourseCompletionProvider, private eventsProvider: CoreEventsProvider,
private courseHelper: CoreCourseHelperProvider, private utils: CoreUtilsProvider,
private courseOptionsDelegate: CoreCourseOptionsDelegate, private coursesHelper: CoreCoursesHelperProvider,
private sitesProvider: CoreSitesProvider) {
private sitesProvider: CoreSitesProvider, private timeUtils: CoreTimeUtilsProvider) {
super(injector, 'AddonBlockMyOverviewComponent');
}
@ -251,7 +251,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
this.courses.favourite = [];
this.courses.hidden = [];
const today = moment().unix();
const today = this.timeUtils.timestamp();
courses.forEach((course) => {
if (course.hidden) {
this.courses.hidden.push(course);

View File

@ -1,6 +1,6 @@
<ion-item-group *ngFor="let dayEvents of filteredEvents">
<ion-item-divider [color]="dayEvents.color">
<h2>{{ dayEvents.dayTimestamp * 1000 | coreFormatDate:"LL" }}</h2>
<h2>{{ dayEvents.dayTimestamp * 1000 | coreFormatDate:"strftimedayshort" }}</h2>
</ion-item-divider>
<ng-container *ngFor="let event of dayEvents.events">
<a ion-item text-wrap detail-none class="core-course-module-handler item-media" (click)="action($event, event)" [title]="event.action.actionable ? event.action.name: event.name">
@ -9,7 +9,7 @@
<p *ngIf="showCourse">
<core-format-text [text]="event.course.fullnamedisplay"></core-format-text>
</p>
<ion-badge color="light" item-end>{{event.timesort * 1000 | coreFormatDate:"LT" }}</ion-badge>
<ion-badge color="light" item-end>{{event.timesort * 1000 | coreFormatDate:"strftimetime24" }}</ion-badge>
</a>
</ng-container>
</ion-item-group>

View File

@ -13,8 +13,8 @@
// limitations under the License.
import { Component, OnInit, Injector } from '@angular/core';
import * as moment from 'moment';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreSitesProvider } from '@providers/sites';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreCoursesHelperProvider } from '@core/courses/providers/helper';
@ -51,7 +51,8 @@ export class AddonBlockTimelineComponent extends CoreBlockBaseComponent implemen
constructor(injector: Injector, private coursesProvider: CoreCoursesProvider, private utils: CoreUtilsProvider,
private timelineProvider: AddonBlockTimelineProvider, private courseOptionsDelegate: CoreCourseOptionsDelegate,
private coursesHelper: CoreCoursesHelperProvider, private sitesProvider: CoreSitesProvider) {
private coursesHelper: CoreCoursesHelperProvider, private sitesProvider: CoreSitesProvider,
private timeUtils: CoreTimeUtilsProvider) {
super(injector, 'AddonBlockTimelineComponent');
}
@ -151,7 +152,7 @@ export class AddonBlockTimelineComponent extends CoreBlockBaseComponent implemen
*/
protected fetchMyOverviewTimelineByCourses(): Promise<any> {
return this.coursesHelper.getUserCoursesWithOptions().then((courses) => {
const today = moment().unix();
const today = this.timeUtils.timestamp();
courses = courses.filter((course) => {
return course.startdate <= today && (!course.enddate || course.enddate >= today);
});

View File

@ -28,7 +28,7 @@
<ion-list class="addon-messages-discussion-container safe-area-page" [class.addon-messages-discussion-group]="isGroup" [attr.aria-live]="'polite'">
<ng-container *ngFor="let message of messages; index as index; last as last">
<h6 text-center *ngIf="message.showDate" class="addon-messages-date">
{{ message.timecreated | coreFormatDate: "LL" }}
{{ message.timecreated | coreFormatDate: "strftimedayshort" }}
</h6>
<ion-chip class="addon-messages-unreadfrom" *ngIf="unreadMessageFrom && message.id == unreadMessageFrom" color="light">
@ -43,7 +43,7 @@
<div *ngIf="message.showUserData">{{ members[message.useridfrom].fullname }}</div>
<ion-note *ngIf="!message.pending">{{ message.timecreated | coreFormatDate: "dftimedate" }}</ion-note>
<ion-note *ngIf="!message.pending">{{ message.timecreated | coreFormatDate: "strftimetime" }}</ion-note>
<ion-note *ngIf="message.pending"><ion-icon name="time"></ion-icon></ion-note>
</h2>

View File

@ -22,6 +22,7 @@ import { AddonMessagesProvider } from './messages';
import { CoreUserProvider } from '@core/user/providers/user';
import { CoreEventsProvider } from '@providers/events';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { TranslateService } from '@ngx-translate/core';
import { CoreSyncProvider } from '@providers/sync';
@ -38,8 +39,8 @@ export class AddonMessagesSyncProvider extends CoreSyncBaseProvider {
translate: TranslateService, syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider,
private messagesOffline: AddonMessagesOfflineProvider, private eventsProvider: CoreEventsProvider,
private messagesProvider: AddonMessagesProvider, private userProvider: CoreUserProvider,
private utils: CoreUtilsProvider) {
super('AddonMessagesSync', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
private utils: CoreUtilsProvider, timeUtils: CoreTimeUtilsProvider) {
super('AddonMessagesSync', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate, timeUtils);
}
/**

View File

@ -21,7 +21,6 @@ import { AddonModAssignProvider } from '../../providers/assign';
import { AddonModAssignHelperProvider } from '../../providers/helper';
import { AddonModAssignOfflineProvider } from '../../providers/assign-offline';
import { AddonModAssignSyncProvider } from '../../providers/assign-sync';
import * as moment from 'moment';
import { AddonModAssignSubmissionComponent } from '../submission/submission';
/**
@ -178,10 +177,8 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
if (this.assign.cutoffdate) {
if (this.assign.cutoffdate > time) {
const dateFormat = this.translate.instant('core.dfmediumdate');
this.lateSubmissions = this.translate.instant('addon.mod_assign.latesubmissionsaccepted',
{$a: moment(this.assign.cutoffdate * 1000).format(dateFormat)});
{$a: this.timeUtils.userDate(this.assign.cutoffdate * 1000)});
} else {
this.lateSubmissions = this.translate.instant('addon.mod_assign.nomoresubmissionsaccepted');
}

View File

@ -29,7 +29,7 @@
<!-- Render some data about the submission. -->
<ion-item text-wrap *ngIf="userSubmission && userSubmission.status != statusNew && userSubmission.timemodified">
<h2>{{ 'addon.mod_assign.timemodified' | translate }}</h2>
<p>{{ userSubmission.timemodified * 1000 | coreFormatDate:"dfmediumdate" }}</p>
<p>{{ userSubmission.timemodified * 1000 | coreFormatDate }}</p>
</ion-item>
<ion-item text-wrap *ngIf="timeRemaining" [ngClass]="[timeRemainingClass]">
@ -44,18 +44,18 @@
<ion-item text-wrap *ngIf="assign.duedate && !isSubmittedForGrading">
<h2>{{ 'addon.mod_assign.duedate' | translate }}</h2>
<p *ngIf="assign.duedate" >{{ assign.duedate * 1000 | coreFormatDate:"dfmediumdate" }}</p>
<p *ngIf="assign.duedate" >{{ assign.duedate * 1000 | coreFormatDate }}</p>
<p *ngIf="!assign.duedate" >{{ 'addon.mod_assign.duedateno' | translate }}</p>
</ion-item>
<ion-item text-wrap *ngIf="assign.duedate && assign.cutoffdate && isSubmittedForGrading">
<h2>{{ 'addon.mod_assign.cutoffdate' | translate }}</h2>
<p>{{ assign.cutoffdate * 1000 | coreFormatDate:"dfmediumdate" }}</p>
<p>{{ assign.cutoffdate * 1000 | coreFormatDate }}</p>
</ion-item>
<ion-item text-wrap *ngIf="assign.duedate && lastAttempt && lastAttempt.extensionduedate && !isSubmittedForGrading">
<h2>{{ 'addon.mod_assign.extensionduedate' | translate }}</h2>
<p>{{ lastAttempt.extensionduedate * 1000 | coreFormatDate:"dfmediumdate" }}</p>
<p>{{ lastAttempt.extensionduedate * 1000 | coreFormatDate }}</p>
</ion-item>
<ion-item text-wrap *ngIf="currentAttempt && !isGrading">
@ -212,7 +212,7 @@
<ion-avatar core-user-avatar [user]="grader" item-start></ion-avatar>
<h2>{{ 'addon.mod_assign.gradedby' | translate }}</h2>
<h2>{{ grader.fullname }}</h2>
<p *ngIf="feedback.gradeddate">{{ feedback.gradeddate * 1000 | coreFormatDate:"dfmediumdate" }}</p>
<p *ngIf="feedback.gradeddate">{{ feedback.gradeddate * 1000 | coreFormatDate }}</p>
</a>
<!-- Warning message if cannot save grades. -->

View File

@ -32,7 +32,6 @@ import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModAssignProvider } from '../../providers/assign';
import { AddonModAssignHelperProvider } from '../../providers/helper';
import { AddonModAssignOfflineProvider } from '../../providers/assign-offline';
import * as moment from 'moment';
import { CoreTabsComponent } from '@components/tabs/tabs';
import { CoreSplitViewComponent } from '@components/split-view/split-view';
import { AddonModAssignSubmissionPluginComponent } from '../submission-plugin/submission-plugin';
@ -383,7 +382,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
this.assign = assign;
if (assign.allowsubmissionsfromdate && assign.allowsubmissionsfromdate >= time) {
this.fromDate = moment(assign.allowsubmissionsfromdate * 1000).format(this.translate.instant('core.dfmediumdate'));
this.fromDate = this.timeUtils.userDate(assign.allowsubmissionsfromdate * 1000);
}
this.currentAttempt = 0;

View File

@ -20,6 +20,7 @@ import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites';
import { CoreSyncProvider } from '@providers/sync';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreGradesHelperProvider } from '@core/grades/providers/helper';
@ -60,9 +61,10 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider {
private courseProvider: CoreCourseProvider, private eventsProvider: CoreEventsProvider,
private assignProvider: AddonModAssignProvider, private assignOfflineProvider: AddonModAssignOfflineProvider,
private utils: CoreUtilsProvider, private submissionDelegate: AddonModAssignSubmissionDelegate,
private gradesHelper: CoreGradesHelperProvider) {
private gradesHelper: CoreGradesHelperProvider, timeUtils: CoreTimeUtilsProvider) {
super('AddonModAssignSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
super('AddonModAssignSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils);
this.componentTranslate = courseProvider.translateModuleName('assign');
}

View File

@ -17,7 +17,6 @@ import { NavController } from 'ionic-angular';
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { AddonModChatProvider } from '../../providers/chat';
import * as moment from 'moment';
/**
* Component that displays a chat.
@ -73,7 +72,7 @@ export class AddonModChatIndexComponent extends CoreCourseModuleMainActivityComp
if (chat.chattime && chat.schedule > 0 && span > 0) {
this.chatInfo = {
date: moment(chat.chattime * 1000).format('LLL'),
date: this.timeUtils.userDate(chat.chattime * 1000),
fromnow: this.timeUtils.formatTime(span)
};
} else {

View File

@ -15,19 +15,19 @@
<div text-center *ngIf="showDate(messages[index], messages[index - 1])" class="addon-mod-chat-notice">
<ion-badge text-wrap color="light">
<span>{{ message.timestamp * 1000 | coreFormatDate:"dfdayweekmonth" }}</span>
<span>{{ message.timestamp * 1000 | coreFormatDate:"strftimedayshort" }}</span>
</ion-badge>
</div>
<div text-center *ngIf="message.system && message.message == 'enter'" class="addon-mod-chat-notice">
<ion-badge text-wrap color="light">
<span>{{ message.timestamp * 1000 | coreFormatDate:"dftimedate" }} {{ 'addon.mod_chat.messageenter' | translate:{$a: message.userfullname} }}</span>
<span>{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ 'addon.mod_chat.messageenter' | translate:{$a: message.userfullname} }}</span>
</ion-badge>
</div>
<div text-center *ngIf="message.system && message.message == 'exit'" class="addon-mod-chat-notice">
<ion-badge text-wrap color="light">
<span>{{ message.timestamp * 1000 | coreFormatDate:"dftimedate" }} {{ 'addon.mod_chat.messageexit' | translate:{$a: message.userfullname} }}</span>
<span>{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ 'addon.mod_chat.messageexit' | translate:{$a: message.userfullname} }}</span>
</ion-badge>
</div>
@ -40,7 +40,7 @@
<ion-item text-wrap *ngIf="!message.system && message.message.substr(0, 4) != 'beep'" class="addon-mod-chat-message">
<ion-avatar core-user-avatar [user]="message" item-start></ion-avatar>
<h2>
<p float-end>{{ message.timestamp * 1000 | coreFormatDate:"dftimedate" }}</p>
<p float-end>{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}</p>
<core-format-text [text]="message.userfullname"></core-format-text>
</h2>
<core-format-text [text]="message.message" (afterRender)="last && scrollToBottom()"></core-format-text>

View File

@ -14,11 +14,11 @@
import { Component, Optional, Injector } from '@angular/core';
import { Content } from 'ionic-angular';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
import { AddonModChoiceProvider } from '../../providers/choice';
import { AddonModChoiceOfflineProvider } from '../../providers/offline';
import { AddonModChoiceSyncProvider } from '../../providers/sync';
import * as moment from 'moment';
/**
* Component that displays a choice.
@ -50,7 +50,8 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
protected now: number;
constructor(injector: Injector, private choiceProvider: AddonModChoiceProvider, @Optional() content: Content,
private choiceOffline: AddonModChoiceOfflineProvider, private choiceSync: AddonModChoiceSyncProvider) {
private choiceOffline: AddonModChoiceOfflineProvider, private choiceSync: AddonModChoiceSyncProvider,
private timeUtils: CoreTimeUtilsProvider) {
super(injector, content);
}
@ -122,9 +123,9 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
return this.choiceProvider.getChoice(this.courseId, this.module.id).then((choice) => {
this.choice = choice;
this.choice.timeopen = parseInt(choice.timeopen) * 1000;
this.choice.openTimeReadable = moment(choice.timeopen).format('LLL');
this.choice.openTimeReadable = this.timeUtils.userDate(choice.timeopen);
this.choice.timeclose = parseInt(choice.timeclose) * 1000;
this.choice.closeTimeReadable = moment(choice.timeclose).format('LLL');
this.choice.closeTimeReadable = this.timeUtils.userDate(choice.timeclose);
this.description = choice.intro || choice.description;
this.choiceNotOpenYet = choice.timeopen && choice.timeopen > this.now;

View File

@ -19,6 +19,7 @@ import { CoreSitesProvider } from '@providers/sites';
import { CoreAppProvider } from '@providers/app';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { AddonModChoiceOfflineProvider } from './offline';
import { AddonModChoiceProvider } from './choice';
import { CoreEventsProvider } from '@providers/events';
@ -39,8 +40,10 @@ export class AddonModChoiceSyncProvider extends CoreSyncBaseProvider {
protected appProvider: CoreAppProvider, private choiceOffline: AddonModChoiceOfflineProvider,
private eventsProvider: CoreEventsProvider, private choiceProvider: AddonModChoiceProvider,
translate: TranslateService, private utils: CoreUtilsProvider, protected textUtils: CoreTextUtilsProvider,
courseProvider: CoreCourseProvider, syncProvider: CoreSyncProvider) {
super('AddonModChoiceSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
courseProvider: CoreCourseProvider, syncProvider: CoreSyncProvider, timeUtils: CoreTimeUtilsProvider) {
super('AddonModChoiceSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils);
this.componentTranslate = courseProvider.translateModuleName('choice');
}

View File

@ -24,8 +24,8 @@
<core-comments *ngIf="action == 'comments' && mode == 'list'" contextLevel="module" [instanceId]="database.coursemodule" component="mod_data" [itemId]="entry.id" area="database_entry"></core-comments>
<span *ngIf="action == 'timeadded'">{{ entry.timecreated * 1000 | coreFormatDate:"dffulldate" }}</span>
<span *ngIf="action == 'timemodified'">{{ entry.timemodified * 1000 | coreFormatDate:"dffulldate" }}</span>
<span *ngIf="action == 'timeadded'">{{ entry.timecreated * 1000 | coreFormatDate }}</span>
<span *ngIf="action == 'timemodified'">{{ entry.timemodified * 1000 | coreFormatDate }}</span>
<a *ngIf="action == 'userpicture'" core-user-link [courseId]="database.courseid" [userId]="entry.userid" [title]="entry.fullname">
<img class="avatar-round" [src]="userPicture" [alt]="'core.pictureof' | translate:{$a: entry.fullname}" core-external-content onError="this.src='assets/img/user-avatar.png'" role="presentation">

View File

@ -24,7 +24,6 @@ import { AddonModDataHelperProvider } from '../../providers/helper';
import { AddonModDataOfflineProvider } from '../../providers/offline';
import { AddonModDataSyncProvider } from '../../providers/sync';
import { AddonModDataComponentsModule } from '../components.module';
import * as moment from 'moment';
/**
* Component that displays a data index page.
@ -186,11 +185,10 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
this.timeAvailableFrom = this.data.timeavailablefrom && time < this.data.timeavailablefrom ?
parseInt(this.data.timeavailablefrom, 10) * 1000 : false;
this.timeAvailableFromReadable = this.timeAvailableFrom ?
moment(this.timeAvailableFrom).format('LLL') : false;
this.timeAvailableFromReadable = this.timeAvailableFrom ? this.timeUtils.userDate(this.timeAvailableFrom) : false;
this.timeAvailableTo = this.data.timeavailableto && time > this.data.timeavailableto ?
parseInt(this.data.timeavailableto, 10) * 1000 : false;
this.timeAvailableToReadable = this.timeAvailableTo ? moment(this.timeAvailableTo).format('LLL') : false;
this.timeAvailableToReadable = this.timeAvailableTo ? this.timeUtils.userDate(this.timeAvailableTo) : false;
this.isEmpty = true;
this.groupInfo = null;

View File

@ -10,5 +10,5 @@
</ion-item>
</span>
<core-format-text *ngIf="isShowOrListMode() && value && value.content" [text]="value.content * 1000 | coreFormatDate:'LL'"></core-format-text>
<core-format-text *ngIf="isShowOrListMode() && value && value.content" [text]="value.content * 1000 | coreFormatDate:'strftimedayshort'"></core-format-text>

View File

@ -19,6 +19,7 @@ import { CoreSyncBaseProvider } from '@classes/base-sync';
import { CoreAppProvider } from '@providers/app';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { AddonModDataOfflineProvider } from './offline';
import { AddonModDataProvider } from './data';
import { AddonModDataHelperProvider } from './helper';
@ -40,9 +41,11 @@ export class AddonModDataSyncProvider extends CoreSyncBaseProvider {
protected appProvider: CoreAppProvider, private dataOffline: AddonModDataOfflineProvider,
private eventsProvider: CoreEventsProvider, private dataProvider: AddonModDataProvider,
protected translate: TranslateService, private utils: CoreUtilsProvider, courseProvider: CoreCourseProvider,
syncProvider: CoreSyncProvider, protected textUtils: CoreTextUtilsProvider,
syncProvider: CoreSyncProvider, protected textUtils: CoreTextUtilsProvider, timeUtils: CoreTimeUtilsProvider,
private dataHelper: AddonModDataHelperProvider) {
super('AddonModDataSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
super('AddonModDataSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils);
this.componentTranslate = courseProvider.translateModuleName('data');
}

View File

@ -15,12 +15,12 @@
import { Component, Input, Optional, Injector, ViewChild } from '@angular/core';
import { Content, NavController } from 'ionic-angular';
import { CoreGroupInfo, CoreGroupsProvider } from '@providers/groups';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
import { AddonModFeedbackProvider } from '../../providers/feedback';
import { AddonModFeedbackHelperProvider } from '../../providers/helper';
import { AddonModFeedbackOfflineProvider } from '../../providers/offline';
import { AddonModFeedbackSyncProvider } from '../../providers/sync';
import * as moment from 'moment';
import { CoreTabsComponent } from '@components/tabs/tabs';
/**
@ -71,7 +71,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
constructor(injector: Injector, private feedbackProvider: AddonModFeedbackProvider, @Optional() content: Content,
private feedbackOffline: AddonModFeedbackOfflineProvider, private groupsProvider: CoreGroupsProvider,
private feedbackSync: AddonModFeedbackSyncProvider, private navCtrl: NavController,
private feedbackHelper: AddonModFeedbackHelperProvider) {
private feedbackHelper: AddonModFeedbackHelperProvider, private timeUtils: CoreTimeUtilsProvider) {
super(injector, content);
// Listen for form submit events.
@ -207,11 +207,9 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
if (accessData.canedititems) {
this.overview.timeopen = parseInt(this.feedback.timeopen) * 1000 || 0;
this.overview.openTimeReadable = this.overview.timeopen ?
moment(this.overview.timeopen).format('LLL') : '';
this.overview.openTimeReadable = this.overview.timeopen ? this.timeUtils.userDate(this.overview.timeopen) : '';
this.overview.timeclose = parseInt(this.feedback.timeclose) * 1000 || 0;
this.overview.closeTimeReadable = this.overview.timeclose ?
moment(this.overview.timeclose).format('LLL') : '';
this.overview.closeTimeReadable = this.overview.timeclose ? this.timeUtils.userDate(this.overview.timeclose) : '';
}
if (accessData.canviewanalysis) {
// Get groups (only for teachers).

View File

@ -9,12 +9,12 @@
<a *ngIf="attempt.fullname" ion-item text-wrap core-user-link [userId]="attempt.userid" [attr.aria-label]=" 'core.user.viewprofile' | translate" [courseId]="attempt.courseid" [title]="attempt.fullname">
<ion-avatar core-user-avatar [user]="attempt" item-start></ion-avatar>
<h2>{{attempt.fullname}}</h2>
<p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate:"LLL"}}</p>
<p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate }}</p>
</a>
<ion-item text-wrap *ngIf="!attempt.fullname">
<h2>{{ 'addon.mod_feedback.response_nr' |translate }}: {{attempt.number}} ({{ 'addon.mod_feedback.anonymous' |translate }})</h2>
<p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate:"LLL"}}</p>
<p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate }}</p>
</ion-item >
<ng-container *ngIf="items && items.length">
<ng-container *ngFor="let item of items">

View File

@ -24,7 +24,7 @@
<a *ngFor="let attempt of responses.attempts" ion-item text-wrap (click)="gotoAttempt(attempt)" [class.core-split-item-selected]="attempt.id == attemptId">
<ion-avatar core-user-avatar [user]="attempt" item-start></ion-avatar>
<h2><core-format-text [text]="attempt.fullname"></core-format-text></h2>
<p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate: "LLL"}}</p>
<p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate }}</p>
</a>
<ion-item padding text-center *ngIf="responses.canLoadMore">
<!-- Button and spinner to show more attempts. -->

View File

@ -17,8 +17,8 @@ import { NavController, ViewController } from 'ionic-angular';
import { AddonModFeedbackProvider } from './feedback';
import { CoreUserProvider } from '@core/user/providers/user';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { TranslateService } from '@ngx-translate/core';
import * as moment from 'moment';
/**
* Service that provides helper functions for feedbacks.
@ -31,7 +31,8 @@ export class AddonModFeedbackHelperProvider {
protected MODE_CATEGORY = 3;
constructor(protected feedbackProvider: AddonModFeedbackProvider, protected userProvider: CoreUserProvider,
protected textUtils: CoreTextUtilsProvider, protected translate: TranslateService) {
protected textUtils: CoreTextUtilsProvider, protected translate: TranslateService,
protected timeUtils: CoreTimeUtilsProvider) {
}
/**
@ -278,7 +279,7 @@ export class AddonModFeedbackHelperProvider {
} else if (type == this.MODE_RESPONSETIME) {
item.value = '__CURRENT__TIMESTAMP__';
const tempValue = typeof item.rawValue != 'undefined' ? item.rawValue * 1000 : new Date().getTime();
item.presentation = moment(tempValue).format('LLL');
item.presentation = this.timeUtils.userDate(tempValue);
} else {
// Errors on item, return false.
return false;

View File

@ -19,6 +19,7 @@ import { CoreSyncBaseProvider } from '@classes/base-sync';
import { CoreAppProvider } from '@providers/app';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { AddonModFeedbackOfflineProvider } from './offline';
import { AddonModFeedbackProvider } from './feedback';
import { CoreEventsProvider } from '@providers/events';
@ -39,8 +40,10 @@ export class AddonModFeedbackSyncProvider extends CoreSyncBaseProvider {
protected appProvider: CoreAppProvider, private feedbackOffline: AddonModFeedbackOfflineProvider,
private eventsProvider: CoreEventsProvider, private feedbackProvider: AddonModFeedbackProvider,
protected translate: TranslateService, private utils: CoreUtilsProvider, protected textUtils: CoreTextUtilsProvider,
courseProvider: CoreCourseProvider, syncProvider: CoreSyncProvider) {
super('AddonModFeedbackSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
courseProvider: CoreCourseProvider, syncProvider: CoreSyncProvider, timeUtils: CoreTimeUtilsProvider) {
super('AddonModFeedbackSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils);
this.componentTranslate = courseProvider.translateModuleName('feedback');
}

View File

@ -23,6 +23,7 @@ import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreSyncProvider } from '@providers/sync';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { AddonModForumProvider } from './forum';
import { AddonModForumHelperProvider } from './helper';
@ -47,13 +48,15 @@ export class AddonModForumSyncProvider extends CoreSyncBaseProvider {
sitesProvider: CoreSitesProvider,
syncProvider: CoreSyncProvider,
textUtils: CoreTextUtilsProvider,
timeUtils: CoreTimeUtilsProvider,
private uploaderProvider: CoreFileUploaderProvider,
private utils: CoreUtilsProvider,
private forumProvider: AddonModForumProvider,
private forumHelper: AddonModForumHelperProvider,
private forumOffline: AddonModForumOfflineProvider) {
super('AddonModForumSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
super('AddonModForumSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils);
this.componentTranslate = courseProvider.translateModuleName('forum');
}

View File

@ -23,6 +23,7 @@ import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreSyncProvider } from '@providers/sync';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { AddonModGlossaryProvider } from './glossary';
import { AddonModGlossaryHelperProvider } from './helper';
@ -46,13 +47,15 @@ export class AddonModGlossarySyncProvider extends CoreSyncBaseProvider {
sitesProvider: CoreSitesProvider,
syncProvider: CoreSyncProvider,
textUtils: CoreTextUtilsProvider,
timeUtils: CoreTimeUtilsProvider,
private uploaderProvider: CoreFileUploaderProvider,
private utils: CoreUtilsProvider,
private glossaryProvider: AddonModGlossaryProvider,
private glossaryHelper: AddonModGlossaryHelperProvider,
private glossaryOffline: AddonModGlossaryOfflineProvider) {
super('AddonModGlossarySyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
super('AddonModGlossarySyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils);
this.componentTranslate = courseProvider.translateModuleName('glossary');
}

View File

@ -46,7 +46,7 @@
</ion-item>
<ion-item text-wrap>
<p class="item-heading">{{ 'addon.mod_lesson.completed' | translate }}</p>
<p>{{ retake.userstats.completed * 1000 | coreFormatDate:"dfmediumdate" }}</p>
<p>{{ retake.userstats.completed * 1000 | coreFormatDate }}</p>
</ion-item>
</div>

View File

@ -19,7 +19,6 @@ import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { AddonModLessonProvider } from './lesson';
import * as moment from 'moment';
/**
* Helper service that provides some features for quiz.
@ -430,7 +429,7 @@ export class AddonModLessonHelperProvider {
if (hasGrade) {
data.grade = this.translate.instant('core.percentagenumber', {$a: retake.grade});
}
data.timestart = moment(retake.timestart * 1000).format('LLL');
data.timestart = this.timeUtils.userDate(retake.timestart * 1000);
if (includeDuration) {
data.duration = this.timeUtils.formatTime(retake.timeend - retake.timestart);
}
@ -438,7 +437,7 @@ export class AddonModLessonHelperProvider {
// The user has not completed the retake.
data.grade = this.translate.instant('addon.mod_lesson.notcompleted');
if (retake.timestart) {
data.timestart = moment(retake.timestart * 1000).format('LLL');
data.timestart = this.timeUtils.userDate(retake.timestart * 1000);
}
}

View File

@ -85,10 +85,11 @@ export class AddonModLessonSyncProvider extends CoreSyncBaseProvider {
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
courseProvider: CoreCourseProvider, private eventsProvider: CoreEventsProvider,
private lessonProvider: AddonModLessonProvider, private lessonOfflineProvider: AddonModLessonOfflineProvider,
private prefetchHandler: AddonModLessonPrefetchHandler, private timeUtils: CoreTimeUtilsProvider,
private prefetchHandler: AddonModLessonPrefetchHandler, timeUtils: CoreTimeUtilsProvider,
private utils: CoreUtilsProvider, private urlUtils: CoreUrlUtilsProvider) {
super('AddonModLessonSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
super('AddonModLessonSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils);
this.componentTranslate = courseProvider.translateModuleName('lesson');

View File

@ -17,7 +17,7 @@
<div padding>
<core-format-text [component]="component" [componentId]="componentId" [text]="contents"></core-format-text>
<p padding-bottom class="addon-mod_page-timemodified" *ngIf="displayTimemodified && page && page.timemodified">
{{ 'core.lastmodified' | translate}}: {{ page.timemodified * 1000 | coreFormatDate: "dfmediumdate" }}
{{ 'core.lastmodified' | translate}}: {{ page.timemodified * 1000 | coreFormatDate }}
</p>
</div>

View File

@ -24,7 +24,7 @@
<ion-list>
<ion-item text-wrap>
<p class="item-heading">{{ 'addon.mod_quiz.startedon' | translate }}</p>
<p>{{ attempt.timestart * 1000 | coreFormatDate:"dfmediumdate" }}</p>
<p>{{ attempt.timestart * 1000 | coreFormatDate }}</p>
</ion-item>
<ion-item text-wrap>
<p class="item-heading">{{ 'addon.mod_quiz.attemptstate' | translate }}</p>
@ -32,7 +32,7 @@
</ion-item>
<ion-item text-wrap *ngIf="showCompleted">
<p class="item-heading">{{ 'addon.mod_quiz.completedon' | translate }}</p>
<p>{{ attempt.timefinish * 1000 | coreFormatDate:"dfmediumdate" }}</p>
<p>{{ attempt.timefinish * 1000 | coreFormatDate }}</p>
</ion-item>
<ion-item text-wrap *ngIf="attempt.timeTaken">
<p class="item-heading">{{ 'addon.mod_quiz.timetaken' | translate }}</p>

View File

@ -20,6 +20,7 @@ import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites';
import { CoreSyncProvider } from '@providers/sync';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreQuestionProvider } from '@core/question/providers/question';
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
@ -57,12 +58,13 @@ export class AddonModQuizSyncProvider extends CoreSyncBaseProvider {
constructor(loggerProvider: CoreLoggerProvider, sitesProvider: CoreSitesProvider, appProvider: CoreAppProvider,
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
courseProvider: CoreCourseProvider, private eventsProvider: CoreEventsProvider,
courseProvider: CoreCourseProvider, private eventsProvider: CoreEventsProvider, timeUtils: CoreTimeUtilsProvider,
private quizProvider: AddonModQuizProvider, private quizOfflineProvider: AddonModQuizOfflineProvider,
private prefetchHandler: AddonModQuizPrefetchHandler, private questionProvider: CoreQuestionProvider,
private questionDelegate: CoreQuestionDelegate) {
super('AddonModQuizSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
super('AddonModQuizSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils);
this.componentTranslate = courseProvider.translateModuleName('quiz');
}

View File

@ -26,7 +26,6 @@ import { CoreGradesHelperProvider } from '@core/grades/providers/helper';
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
import { AddonModQuizAccessRuleDelegate } from './access-rules-delegate';
import { AddonModQuizOfflineProvider } from './quiz-offline';
import * as moment from 'moment';
/**
* Service that provides some features for quiz.
@ -287,9 +286,9 @@ export class AddonModQuizProvider {
const dueDate = this.getAttemptDueDate(quiz, attempt);
if (attempt.state === AddonModQuizProvider.ATTEMPT_OVERDUE) {
return this.translate.instant('addon.mod_quiz.overduemustbesubmittedby', {$a: moment(dueDate).format('LLL')});
return this.translate.instant('addon.mod_quiz.overduemustbesubmittedby', {$a: this.timeUtils.userDate(dueDate)});
} else if (dueDate) {
return this.translate.instant('addon.mod_quiz.mustbesubmittedby', {$a: moment(dueDate).format('LLL')});
return this.translate.instant('addon.mod_quiz.mustbesubmittedby', {$a: this.timeUtils.userDate(dueDate)});
}
}
@ -317,7 +316,7 @@ export class AddonModQuizProvider {
if (dueDate) {
sentences.push(this.translate.instant('addon.mod_quiz.stateoverduedetails',
{$a: moment(dueDate).format('LLL')}));
{$a: this.timeUtils.userDate(dueDate)}));
}
return sentences;
@ -326,7 +325,7 @@ export class AddonModQuizProvider {
return [
this.translate.instant('addon.mod_quiz.statefinished'),
this.translate.instant('addon.mod_quiz.statefinisheddetails',
{$a: moment(attempt.timefinish * 1000).format('LLL')})
{$a: this.timeUtils.userDate(attempt.timefinish * 1000)})
];
case AddonModQuizProvider.ATTEMPT_ABANDONED:

View File

@ -22,9 +22,9 @@ import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/cour
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
import { CoreConstants } from '@core/constants';
import * as moment from 'moment';
/**
* Handler to support resource modules.
@ -51,7 +51,7 @@ export class AddonModResourceModuleHandler implements CoreCourseModuleHandler {
constructor(protected resourceProvider: AddonModResourceProvider, private courseProvider: CoreCourseProvider,
protected mimetypeUtils: CoreMimetypeUtilsProvider, private resourceHelper: AddonModResourceHelperProvider,
protected prefetchDelegate: CoreCourseModulePrefetchDelegate, protected textUtils: CoreTextUtilsProvider,
protected translate: TranslateService) {
protected translate: TranslateService, protected timeUtils: CoreTimeUtilsProvider) {
}
/**
@ -185,18 +185,18 @@ export class AddonModResourceModuleHandler implements CoreCourseModuleHandler {
if (options.showdate) {
if (options.filedetails && options.filedetails.modifieddate) {
extra.push(this.translate.instant('addon.mod_resource.modifieddate',
{$a: moment(options.filedetails.modifieddate * 1000).format('LLL')}));
{$a: this.timeUtils.userDate(options.filedetails.modifieddate * 1000, 'core.strftimedatetimeshort') }));
} else if (options.filedetails && options.filedetails.uploadeddate) {
extra.push(this.translate.instant('addon.mod_resource.uploadeddate',
{$a: moment(options.filedetails.uploadeddate * 1000).format('LLL')}));
{$a: this.timeUtils.userDate(options.filedetails.uploadeddate * 1000, 'core.strftimedatetimeshort') }));
} else if (file.timemodified > file.timecreated + CoreConstants.SECONDS_MINUTE * 5) {
/* Modified date may be up to several minutes later than uploaded date just because
teacher did not submit the form promptly. Give teacher up to 5 minutes to do it. */
extra.push(this.translate.instant('addon.mod_resource.modifieddate',
{$a: moment(file.timemodified * 1000).format('LLL')}));
{$a: this.timeUtils.userDate(file.timemodified * 1000, 'core.strftimedatetimeshort') }));
} else {
extra.push(this.translate.instant('addon.mod_resource.uploadeddate',
{$a: moment(file.timecreated * 1000).format('LLL')}));
{$a: this.timeUtils.userDate(file.timecreated * 1000, 'core.strftimedatetimeshort') }));
}
}
}

View File

@ -20,6 +20,7 @@ import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites';
import { CoreSyncProvider } from '@providers/sync';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreSyncBaseProvider } from '@classes/base-sync';
@ -62,11 +63,12 @@ export class AddonModScormSyncProvider extends CoreSyncBaseProvider {
constructor(loggerProvider: CoreLoggerProvider, sitesProvider: CoreSitesProvider, appProvider: CoreAppProvider,
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
courseProvider: CoreCourseProvider, private eventsProvider: CoreEventsProvider,
courseProvider: CoreCourseProvider, private eventsProvider: CoreEventsProvider, timeUtils: CoreTimeUtilsProvider,
private scormProvider: AddonModScormProvider, private scormOfflineProvider: AddonModScormOfflineProvider,
private prefetchHandler: AddonModScormPrefetchHandler, private utils: CoreUtilsProvider) {
super('AddonModScormSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
super('AddonModScormSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils);
this.componentTranslate = courseProvider.translateModuleName('scorm');
}

View File

@ -19,6 +19,7 @@ import { CoreSyncBaseProvider } from '@classes/base-sync';
import { CoreAppProvider } from '@providers/app';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { AddonModSurveyOfflineProvider } from './offline';
import { AddonModSurveyProvider } from './survey';
import { CoreEventsProvider } from '@providers/events';
@ -39,9 +40,10 @@ export class AddonModSurveySyncProvider extends CoreSyncBaseProvider {
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
courseProvider: CoreCourseProvider, private surveyOffline: AddonModSurveyOfflineProvider,
private eventsProvider: CoreEventsProvider, private surveyProvider: AddonModSurveyProvider,
private utils: CoreUtilsProvider) {
private utils: CoreUtilsProvider, timeUtils: CoreTimeUtilsProvider) {
super('AddonModSurveySyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
super('AddonModSurveySyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils);
this.componentTranslate = courseProvider.translateModuleName('survey');
}

View File

@ -21,6 +21,7 @@ import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites';
import { CoreSyncProvider } from '@providers/sync';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreSyncBaseProvider } from '@classes/base-sync';
@ -103,9 +104,10 @@ export class AddonModWikiSyncProvider extends CoreSyncBaseProvider {
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
courseProvider: CoreCourseProvider, private eventsProvider: CoreEventsProvider,
private wikiProvider: AddonModWikiProvider, private wikiOfflineProvider: AddonModWikiOfflineProvider,
private utils: CoreUtilsProvider, private groupsProvider: CoreGroupsProvider) {
private utils: CoreUtilsProvider, private groupsProvider: CoreGroupsProvider, timeUtils: CoreTimeUtilsProvider) {
super('AddonModWikiSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
super('AddonModWikiSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils);
this.componentTranslate = courseProvider.translateModuleName('wiki');
}

View File

@ -22,6 +22,7 @@ import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreSyncProvider } from '@providers/sync';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { AddonModWorkshopProvider } from './workshop';
import { AddonModWorkshopHelperProvider } from './helper';
@ -46,12 +47,14 @@ export class AddonModWorkshopSyncProvider extends CoreSyncBaseProvider {
sitesProvider: CoreSitesProvider,
syncProvider: CoreSyncProvider,
textUtils: CoreTextUtilsProvider,
timeUtils: CoreTimeUtilsProvider,
private utils: CoreUtilsProvider,
private workshopProvider: AddonModWorkshopProvider,
private workshopHelper: AddonModWorkshopHelperProvider,
private workshopOffline: AddonModWorkshopOfflineProvider) {
super('AddonModWorkshopSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
super('AddonModWorkshopSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils);
this.componentTranslate = courseProvider.translateModuleName('workshop');
}

View File

@ -22,6 +22,7 @@ import { AddonNotesProvider } from './notes';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreEventsProvider } from '@providers/events';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { TranslateService } from '@ngx-translate/core';
import { CoreSyncProvider } from '@providers/sync';
@ -38,9 +39,9 @@ export class AddonNotesSyncProvider extends CoreSyncBaseProvider {
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
private notesOffline: AddonNotesOfflineProvider, private utils: CoreUtilsProvider,
private eventsProvider: CoreEventsProvider, private notesProvider: AddonNotesProvider,
private coursesProvider: CoreCoursesProvider) {
private coursesProvider: CoreCoursesProvider, timeUtils: CoreTimeUtilsProvider) {
super('AddonNotesSync', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
super('AddonNotesSync', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate, timeUtils);
}
/**

View File

@ -1,7 +1,7 @@
<!-- Render (no edit). -->
<ion-item *ngIf="!edit && field && field.name">
<h2>{{ field.name }}</h2>
<p>{{ field.value * 1000 | coreFormatDate:"dfmediumdate"}}</p>
<p>{{ field.value * 1000 | coreFormatDate }}</p>
</ion-item>
<!-- Edit. -->
<ion-item *ngIf="edit && field && field.shortname" text-wrap [formGroup]="form">

View File

@ -1655,6 +1655,21 @@
"core.sorry": "Sorry...",
"core.sortby": "Sort by",
"core.start": "Start",
"core.strftimedate": "%d %B %Y",
"core.strftimedatefullshort": "%d/%m/%y",
"core.strftimedateshort": "%d %B",
"core.strftimedatetime": "%d %B %Y, %I:%M %p",
"core.strftimedatetimeshort": "%d/%m/%y, %H:%M",
"core.strftimedaydate": "%A, %d %B %Y",
"core.strftimedaydatetime": "%A, %d %B %Y, %I:%M %p",
"core.strftimedayshort": "%A, %d %B",
"core.strftimedaytime": "%a, %H:%M",
"core.strftimemonthyear": "%B %Y",
"core.strftimerecent": "%d %b, %H:%M",
"core.strftimerecentfull": "%a, %d %b %Y, %I:%M %p",
"core.strftimetime": "%I:%M %p",
"core.strftimetime12": "%I:%M %p",
"core.strftimetime24": "%H:%M",
"core.submit": "Submit",
"core.success": "Success",
"core.tablet": "Tablet",

View File

@ -18,7 +18,7 @@ import { CoreSyncProvider } from '@providers/sync';
import { CoreLoggerProvider } from '@providers/logger';
import { CoreAppProvider } from '@providers/app';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import * as moment from 'moment';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
/**
* Base class to create sync providers. It provides some common functions.
@ -51,7 +51,8 @@ export class CoreSyncBaseProvider {
constructor(component: string, loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider,
protected appProvider: CoreAppProvider, protected syncProvider: CoreSyncProvider,
protected textUtils: CoreTextUtilsProvider, protected translate: TranslateService) {
protected textUtils: CoreTextUtilsProvider, protected translate: TranslateService,
protected timeUtils: CoreTimeUtilsProvider) {
this.logger = loggerProvider.getInstance(component);
this.component = component;
@ -122,7 +123,7 @@ export class CoreSyncBaseProvider {
if (!timestamp) {
return this.translate.instant('core.never');
} else {
return moment(timestamp).format('LLL');
return this.timeUtils.userDate(timestamp);
}
}

View File

@ -2,7 +2,7 @@
<img [src]="fileIcon" alt="" role="presentation" item-start />
<h2>{{fileName}}</h2>
<p *ngIf="fileSizeReadable">{{ fileSizeReadable }}</p>
<p *ngIf="showTime">{{ timemodified * 1000 | coreFormatDate:"dfmediumdate" }}</p>
<p *ngIf="showTime">{{ timemodified * 1000 | coreFormatDate }}</p>
<div class="buttons" item-end>
<button ion-button clear icon-only (click)="download($event)" *ngIf="!isDownloading && showDownload" [attr.aria-label]="'core.download' | translate" color="dark">
<ion-icon [name]="isDownloaded ? 'refresh' : 'cloud-download'"></ion-icon>

View File

@ -18,8 +18,8 @@ import { CoreFileProvider } from '@providers/file';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils';
import * as moment from 'moment';
/**
* Component to handle a local file. Only files inside the app folder can be managed.
@ -50,7 +50,7 @@ export class CoreLocalFileComponent implements OnInit {
constructor(private mimeUtils: CoreMimetypeUtilsProvider, private utils: CoreUtilsProvider, private translate: TranslateService,
private textUtils: CoreTextUtilsProvider, private fileProvider: CoreFileProvider,
private domUtils: CoreDomUtilsProvider) {
private domUtils: CoreDomUtilsProvider, private timeUtils: CoreTimeUtilsProvider) {
this.onDelete = new EventEmitter();
this.onRename = new EventEmitter();
this.onClick = new EventEmitter();
@ -77,7 +77,7 @@ export class CoreLocalFileComponent implements OnInit {
this.size = this.textUtils.bytesToSize(metadata.size, 2);
}
this.timemodified = moment(metadata.modificationTime).format('LLL');
this.timemodified = this.timeUtils.userDate(metadata.modificationTime, 'core.strftimedatetimeshort');
});
}

View File

@ -19,6 +19,7 @@ import { CoreSitesProvider } from '@providers/sites';
import { CoreAppProvider } from '@providers/app';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreCourseOfflineProvider } from './course-offline';
import { CoreCourseProvider } from './course';
import { CoreEventsProvider } from '@providers/events';
@ -38,9 +39,9 @@ export class CoreCourseSyncProvider extends CoreSyncBaseProvider {
protected appProvider: CoreAppProvider, private courseOffline: CoreCourseOfflineProvider,
private eventsProvider: CoreEventsProvider, private courseProvider: CoreCourseProvider,
translate: TranslateService, private utils: CoreUtilsProvider, protected textUtils: CoreTextUtilsProvider,
syncProvider: CoreSyncProvider) {
syncProvider: CoreSyncProvider, timeUtils: CoreTimeUtilsProvider) {
super('CoreCourseSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
super('CoreCourseSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate, timeUtils);
}
/**

View File

@ -17,7 +17,7 @@
<core-icon name="fa-graduation-cap" fixed-width item-start></core-icon>
<h2><core-format-text [text]="course.fullname"></core-format-text></h2>
<p *ngIf="course.categoryname"><core-format-text [text]="course.categoryname"></core-format-text></p>
<p *ngIf="course.startdate">{{course.startdate * 1000 | coreFormatDate:"dfdaymonthyear"}} <span *ngIf="course.enddate"> - {{course.enddate * 1000 | coreFormatDate:"dfdaymonthyear"}}</span></p>
<p *ngIf="course.startdate">{{course.startdate * 1000 | coreFormatDate:"strftimedatefullshort" }} <span *ngIf="course.enddate"> - {{course.enddate * 1000 | coreFormatDate:"strftimedatefullshort" }}</span></p>
</a>
<ion-item text-wrap *ngIf="course.summary" detail-none>

View File

@ -11,7 +11,7 @@
<a ion-item text-wrap *ngFor="let participant of participants" [title]="participant.fullname" (click)="gotoParticipant(participant.id)" [class.core-split-item-selected]="participant.id == participantId">
<ion-avatar core-user-avatar [user]="participant" item-start [userId]="participant.id" [checkOnline]="true"></ion-avatar>
<h2><core-format-text [text]="participant.fullname"></core-format-text></h2>
<p *ngIf="participant.lastaccess"><strong>{{ 'core.lastaccess' | translate }}: </strong>{{ participant.lastaccess * 1000 | coreFormatDate:"dfmediumdate"}}</p>
<p *ngIf="participant.lastaccess"><strong>{{ 'core.lastaccess' | translate }}: </strong>{{ participant.lastaccess * 1000 | coreFormatDate }}</p>
</a>
</ion-list>
<core-infinite-loading [enabled]="canLoadMore" (action)="loadMoreData($event)" [error]="loadMoreError"></core-infinite-loading>

View File

@ -61,8 +61,8 @@
"dfdaymonthyear": "MM-DD-YYYY",
"dfdayweekmonth": "ddd, D MMM",
"dffulldate": "dddd, D MMMM YYYY h[:]mm A",
"dflastweekdate": "ddd",
"dfmediumdate": "LLL",
"dflastweekdate": "ddd",
"dftimedate": "h[:]mm A",
"digitalminor": "Digital minor",
"digitalminor_desc": "To create an account on this site please have your parent/guardian contact the following person.",
@ -216,6 +216,21 @@
"sorry": "Sorry...",
"sortby": "Sort by",
"start": "Start",
"strftimedate": "%d %B %Y",
"strftimedatefullshort": "%d/%m/%y",
"strftimedateshort": "%d %B",
"strftimedatetime": "%d %B %Y, %I:%M %p",
"strftimedatetimeshort": "%d/%m/%y, %H:%M",
"strftimedaydate": "%A, %d %B %Y",
"strftimedaydatetime": "%A, %d %B %Y, %I:%M %p",
"strftimedayshort": "%A, %d %B",
"strftimedaytime": "%a, %H:%M",
"strftimemonthyear": "%B %Y",
"strftimerecent": "%d %b, %H:%M",
"strftimerecentfull": "%a, %d %b %Y, %I:%M %p",
"strftimetime": "%I:%M %p",
"strftimetime12": "%I:%M %p",
"strftimetime24": "%H:%M",
"submit": "Submit",
"success": "Success",
"tablet": "Tablet",

View File

@ -15,6 +15,7 @@
import { Pipe, PipeTransform } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreLoggerProvider } from '@providers/logger';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import * as moment from 'moment';
/**
@ -36,7 +37,7 @@ import * as moment from 'moment';
export class CoreDateDayOrTimePipe implements PipeTransform {
protected logger;
constructor(logger: CoreLoggerProvider, private translate: TranslateService) {
constructor(logger: CoreLoggerProvider, private translate: TranslateService, private timeUtils: CoreTimeUtilsProvider) {
this.logger = logger.getInstance('CoreDateDayOrTimePipe');
}
@ -59,10 +60,10 @@ export class CoreDateDayOrTimePipe implements PipeTransform {
}
return moment(timestamp * 1000).calendar(null, {
sameDay: 'LT',
sameDay: this.timeUtils.convertPHPToMoment(this.translate.instant('core.strftimetime')),
lastDay: this.translate.instant('core.dflastweekdate'),
lastWeek: this.translate.instant('core.dflastweekdate'),
sameElse: 'L'
sameElse: this.timeUtils.convertPHPToMoment(this.translate.instant('core.strftimedatefullshort'))
});
}
}

View File

@ -13,9 +13,8 @@
// limitations under the License.
import { Pipe, PipeTransform } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreLoggerProvider } from '@providers/logger';
import * as moment from 'moment';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
/**
* Filter to format a date.
@ -26,20 +25,21 @@ import * as moment from 'moment';
export class CoreFormatDatePipe implements PipeTransform {
protected logger;
constructor(logger: CoreLoggerProvider, private translate: TranslateService) {
this.logger = logger.getInstance('CoreDateDayOrTimePipe');
constructor(logger: CoreLoggerProvider, private timeUtils: CoreTimeUtilsProvider) {
this.logger = logger.getInstance('CoreFormatDatePipe');
}
/**
* Format a date.
*
* @param {string|number} timestamp Timestamp to format (in milliseconds). If not defined, use current time.
* @param {string} format Format to use. It should be a string code to handle i18n (e.g. core.dftimedate). If the code
* doesn't have a prefix, 'core' will be used by default. E.g. 'dftimedate' -> 'core.dftimedate'.
* @param {string} [format] Format to use. It should be a string code to handle i18n (e.g. core.strftimetime).
* Defaults to strftimedaydatetime.
* @return {string} Formatted date.
*/
transform(timestamp: string | number, format: string): string {
transform(timestamp: string | number, format?: string): string {
timestamp = timestamp || Date.now();
format = format || 'strftimedaydatetime';
if (typeof timestamp == 'string') {
// Convert the value to a number.
@ -52,12 +52,11 @@ export class CoreFormatDatePipe implements PipeTransform {
timestamp = numberTimestamp;
}
if (format.indexOf('df') == 0) {
format = this.translate.instant('core.' + format);
} else if (format.indexOf('.') > 0) {
format = this.translate.instant(format);
// Add "core." if needed.
if (format.indexOf('strf') == 0 || format.indexOf('df') == 0) {
format = 'core.' + format;
}
return moment(timestamp).format(format);
return this.timeUtils.userDate(timestamp, format);
}
}

View File

@ -23,8 +23,79 @@ import { CoreConstants } from '@core/constants';
@Injectable()
export class CoreTimeUtilsProvider {
protected FORMAT_REPLACEMENTS = { // To convert PHP strf format to Moment format.
'%a': 'ddd',
'%A': 'dddd',
'%d': 'DD',
'%e': 'D', // Not exactly the same. PHP adds a space instead of leading zero, Moment doesn't.
'%j': 'DDDD',
'%u': 'E',
'%w': 'e', // It might not behave exactly like PHP, the first day could be calculated differently.
'%U': 'ww', // It might not behave exactly like PHP, the first week could be calculated differently.
'%V': 'WW',
'%W': 'ww', // It might not behave exactly like PHP, the first week could be calculated differently.
'%b': 'MMM',
'%B': 'MMMM',
'%h': 'MMM',
'%m': 'MM',
'%C' : '', // Not supported by Moment.
'%g': 'GG',
'%G': 'GGGG',
'%y': 'YY',
'%Y': 'YYYY',
'%H': 'HH',
'%k': 'H', // Not exactly the same. PHP adds a space instead of leading zero, Moment doesn't.
'%I': 'hh',
'%l': 'h', // Not exactly the same. PHP adds a space instead of leading zero, Moment doesn't.
'%M': 'mm',
'%p': 'A',
'%P': 'a',
'%r': 'hh:mm:ss A',
'%R': 'HH:mm',
'%S': 'ss',
'%T': 'HH:mm:ss',
'%X': 'LTS',
'%z': 'ZZ',
'%Z': 'ZZ', // Not supported by Moment, it was deprecated. Use the same as %z.
'%c': 'LLLL',
'%D': 'MM/DD/YY',
'%F': 'YYYY-MM-DD',
'%s': 'X',
'%x': 'L',
'%n': '\n',
'%t': '\t',
'%%': '%'
};
constructor(private translate: TranslateService) { }
/**
* Convert a PHP format to a Moment format.
*
* @param {string} format PHP format.
* @return {string} Converted format.
*/
convertPHPToMoment(format: string): string {
if (typeof format != 'string') {
// Not valid.
return '';
}
let converted = '';
for (let i = 0; i < format.length; i++) {
let char = format[i];
if (char == '%') {
i++;
char += format[i] || '';
}
converted += typeof this.FORMAT_REPLACEMENTS[char] != 'undefined' ? this.FORMAT_REPLACEMENTS[char] : char;
}
return converted;
}
/**
* Returns hours, minutes and seconds in a human readable format
*
@ -154,6 +225,32 @@ export class CoreTimeUtilsProvider {
return Math.round(Date.now() / 1000);
}
/**
* Convert a timestamp into a readable date.
*
* @param {number} timestamp Timestamp in milliseconds.
* @param {string} [format] The format to use (lang key). Defaults to core.strftimedaydatetime.
* @param {boolean} [fixDay=true] If true (default) then the leading zero from %d is removed.
* @param {boolean} [fixHour=true] If true (default) then the leading zero from %I is removed.
* @return {string} Readable date.
*/
userDate(timestamp: number, format?: string, fixDay: boolean = true, fixHour: boolean = true): string {
format = this.translate.instant(format ? format : 'core.strftimedaydatetime');
if (fixDay) {
format = format.replace(/%d/g, 'D');
}
if (fixHour) {
format = format.replace('%I', 'H');
}
// Format could be in PHP format, convert it to moment.
format = this.convertPHPToMoment(format);
return moment(timestamp).format(format);
}
/**
* Return the localized ISO format (i.e DDMMYY) from the localized moment format. Useful for translations.
*

View File

@ -7,6 +7,12 @@ information provided here is intended especially for developers.
It's also recommended to update ionic cli to v4, otherwise some errors could be raised while building: npm install -g ionic
- The value of the constant CoreCourseProvider.ALL_SECTIONS_ID has changed from -1 to -2.
- Use of completionstatus on the module object has been deprecated, use completiondata instead.
- The following strings have been deprecated:
core.dfdaymonthyear. Please use core.strftimedatefullshort instead.
core.dfdayweekmonth. Please use core.strftimedayshort instead.
core.dffulldate. Please use core.strftimedaydatetime instead.
core.dfmediumdate. Please use core.strftimedaydatetime instead.
core.dftimedate. Please use core.strftimetime instead.
=== 3.5.2 ===