MOBILE-2334 assign: Implement assign index page
parent
7ab247cf7c
commit
0bb96f0e80
|
@ -14,6 +14,7 @@
|
|||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CoreCronDelegate } from '@providers/cron';
|
||||
import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate';
|
||||
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
|
||||
import { AddonModAssignProvider } from './providers/assign';
|
||||
import { AddonModAssignOfflineProvider } from './providers/assign-offline';
|
||||
|
@ -23,6 +24,7 @@ import { AddonModAssignFeedbackDelegate } from './providers/feedback-delegate';
|
|||
import { AddonModAssignSubmissionDelegate } from './providers/submission-delegate';
|
||||
import { AddonModAssignDefaultFeedbackHandler } from './providers/default-feedback-handler';
|
||||
import { AddonModAssignDefaultSubmissionHandler } from './providers/default-submission-handler';
|
||||
import { AddonModAssignModuleHandler } from './providers/module-handler';
|
||||
import { AddonModAssignPrefetchHandler } from './providers/prefetch-handler';
|
||||
import { AddonModAssignSyncCronHandler } from './providers/sync-cron-handler';
|
||||
|
||||
|
@ -38,13 +40,16 @@ import { AddonModAssignSyncCronHandler } from './providers/sync-cron-handler';
|
|||
AddonModAssignSubmissionDelegate,
|
||||
AddonModAssignDefaultFeedbackHandler,
|
||||
AddonModAssignDefaultSubmissionHandler,
|
||||
AddonModAssignModuleHandler,
|
||||
AddonModAssignPrefetchHandler,
|
||||
AddonModAssignSyncCronHandler
|
||||
]
|
||||
})
|
||||
export class AddonModAssignModule {
|
||||
constructor(prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModAssignPrefetchHandler,
|
||||
constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModAssignModuleHandler,
|
||||
prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModAssignPrefetchHandler,
|
||||
cronDelegate: CoreCronDelegate, syncHandler: AddonModAssignSyncCronHandler) {
|
||||
moduleDelegate.registerHandler(moduleHandler);
|
||||
prefetchDelegate.registerHandler(prefetchHandler);
|
||||
cronDelegate.register(syncHandler);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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 { CommonModule } from '@angular/common';
|
||||
import { IonicModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
import { CoreCourseComponentsModule } from '@core/course/components/components.module';
|
||||
import { AddonModAssignIndexComponent } from './index/index';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModAssignIndexComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
IonicModule,
|
||||
TranslateModule.forChild(),
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
CoreCourseComponentsModule
|
||||
],
|
||||
providers: [
|
||||
],
|
||||
exports: [
|
||||
AddonModAssignIndexComponent
|
||||
],
|
||||
entryComponents: [
|
||||
AddonModAssignIndexComponent
|
||||
]
|
||||
})
|
||||
export class AddonModAssignComponentsModule {}
|
|
@ -0,0 +1,87 @@
|
|||
<!-- Buttons to add to the header. -->
|
||||
<core-navbar-buttons end>
|
||||
<core-context-menu>
|
||||
<core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="assign && (description || (assign.introattachments && assign.introattachments.length))" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="loaded && hasOffline && isOnline" [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="size" [iconDescription]="'cube'" (action)="removeFiles()" [iconAction]="'trash'"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
<!-- Content. -->
|
||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||
|
||||
<!-- Description and intro attachments. -->
|
||||
<ion-card *ngIf="description">
|
||||
<ion-item text-wrap>
|
||||
<core-format-text [text]="description" [component]="component" [componentId]="componentId" maxHeight="120" (click)="expandDescription($event)"></core-format-text>
|
||||
<ion-note *ngIf="note" item-end>{{ note }}</ion-note>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
|
||||
<ion-card *ngIf="assign && assign.introattachments && assign.introattachments.length">
|
||||
<core-file *ngFor="let file of assign.introattachments" [file]="file" [component]="component" [componentId]="componentId"></core-file>
|
||||
</ion-card>
|
||||
|
||||
<!-- Assign has something offline. -->
|
||||
<div *ngIf="hasOffline" class="core-warning-card" icon-start>
|
||||
<ion-icon name="warning"></ion-icon>
|
||||
{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}
|
||||
</div>
|
||||
|
||||
<!-- User can view all submissions (teacher). -->
|
||||
<ion-card *ngIf="assign && canViewSubmissions" class="core-list-align-detail-right">
|
||||
<ion-item text-wrap *ngIf="timeRemaining">
|
||||
<h2>{{ 'addon.mod_assign.timeremaining' | translate }}</h2>
|
||||
<p>{{ timeRemaining }}</p>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="lateSubmissions">
|
||||
<h2>{{ 'addon.mod_assign.latesubmissions' | translate }}</h2>
|
||||
<p>{{ lateSubmissions }}</p>
|
||||
</ion-item>
|
||||
|
||||
<!-- Summary of all submissions. -->
|
||||
<a ion-item text-wrap *ngIf="summary && summary.participantcount" (click)="goToSubmissionList()">
|
||||
<h2 *ngIf="assign.teamsubmission">{{ 'addon.mod_assign.numberofteams' | translate }}</h2>
|
||||
<h2 *ngIf="!assign.teamsubmission">{{ 'addon.mod_assign.numberofparticipants' | translate }}</h2>
|
||||
<ion-badge item-end *ngIf="showNumbers" color="primary">
|
||||
{{ summary.participantcount }}
|
||||
</ion-badge>
|
||||
</a>
|
||||
|
||||
<!-- Summary of submissions with draft status. -->
|
||||
<a ion-item text-wrap *ngIf="assign.submissiondrafts && summary && summary.submissionsenabled" [attr.detail-none]="(showNumbers && !summary.submissiondraftscount) ? true : null" (click)="goToSubmissionList(submissionStatusDraft, summary.submissiondraftscount)">
|
||||
<h2>{{ 'addon.mod_assign.numberofdraftsubmissions' | translate }}</h2>
|
||||
<ion-badge item-end *ngIf="showNumbers" color="primary">
|
||||
{{ summary.submissiondraftscount }}
|
||||
</ion-badge>
|
||||
</a>
|
||||
|
||||
<!-- Summary of submissions with submitted status. -->
|
||||
<a ion-item text-wrap *ngIf="summary && summary.submissionsenabled" [attr.detail-none]="(showNumbers && !summary.submissionssubmittedcount) ? true : null" (click)="goToSubmissionList(submissionStatusSubmitted, summary.submissionssubmittedcount)">
|
||||
<h2>{{ 'addon.mod_assign.numberofsubmittedassignments' | translate }}</h2>
|
||||
<ion-badge item-end *ngIf="showNumbers" color="primary">
|
||||
{{ summary.submissionssubmittedcount }}
|
||||
</ion-badge>
|
||||
</a>
|
||||
|
||||
<!-- Summary of submissions that need grading. -->
|
||||
<a ion-item text-wrap *ngIf="summary && summary.submissionsenabled && !assign.teamsubmission && showNumbers" [attr.detail-none]="needsGradingAvalaible ? null : true" (click)="goToSubmissionList(needGrading, needsGradingAvalaible)">
|
||||
<h2>{{ 'addon.mod_assign.numberofsubmissionsneedgrading' | translate }}</h2>
|
||||
<ion-badge item-end color="primary">
|
||||
{{ summary.submissionsneedgradingcount }}
|
||||
</ion-badge>
|
||||
</a>
|
||||
|
||||
<!-- Ungrouped users. -->
|
||||
<div *ngIf="assign.teamsubmission && summary && summary.warnofungroupedusers" class="core-info-card" icon-start>
|
||||
<ion-icon name="information"></ion-icon>
|
||||
{{ 'addon.mod_assign.ungroupedusers' | translate }}
|
||||
</div>
|
||||
</ion-card>
|
||||
|
||||
<!-- @todo <addon-mod-assign-submission *ngIf="!canViewSubmissions" [courseId]="courseId" [moduleId]="module.id"></addon-mod-assign-submission> -->
|
||||
|
||||
</core-loading>
|
|
@ -0,0 +1,312 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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, Optional, Injector } from '@angular/core';
|
||||
import { Content, NavController } from 'ionic-angular';
|
||||
import { CoreGroupsProvider } from '@providers/groups';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
|
||||
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';
|
||||
|
||||
/**
|
||||
* Component that displays an assignment.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-assign-index',
|
||||
templateUrl: 'index.html',
|
||||
})
|
||||
export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityComponent {
|
||||
component = AddonModAssignProvider.COMPONENT;
|
||||
moduleName = 'assign';
|
||||
|
||||
assign: any; // The assign object.
|
||||
canViewSubmissions: boolean; // Whether the user can view all submissions.
|
||||
timeRemaining: string; // Message about time remaining to submit.
|
||||
lateSubmissions: string; // Message about late submissions.
|
||||
showNumbers = true; // Whether to show number of submissions with each status.
|
||||
summary: any; // The summary.
|
||||
needsGradingAvalaible: boolean; // Whether we can see the submissions that need grading.
|
||||
|
||||
// Status.
|
||||
submissionStatusSubmitted = AddonModAssignProvider.SUBMISSION_STATUS_SUBMITTED;
|
||||
submissionStatusDraft = AddonModAssignProvider.SUBMISSION_STATUS_DRAFT;
|
||||
needGrading = AddonModAssignProvider.NEED_GRADING;
|
||||
|
||||
protected userId: number; // Current user ID.
|
||||
protected syncEventName = AddonModAssignSyncProvider.AUTO_SYNCED;
|
||||
|
||||
// Observers.
|
||||
protected savedObserver;
|
||||
protected submittedObserver;
|
||||
protected gradedObserver;
|
||||
|
||||
constructor(injector: Injector, protected assignProvider: AddonModAssignProvider, @Optional() content: Content,
|
||||
protected assignHelper: AddonModAssignHelperProvider, protected assignOffline: AddonModAssignOfflineProvider,
|
||||
protected syncProvider: AddonModAssignSyncProvider, protected timeUtils: CoreTimeUtilsProvider,
|
||||
protected groupsProvider: CoreGroupsProvider, protected navCtrl: NavController) {
|
||||
super(injector, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
super.ngOnInit();
|
||||
|
||||
this.userId = this.sitesProvider.getCurrentSiteUserId();
|
||||
|
||||
this.loadContent(false, true).then(() => {
|
||||
this.assignProvider.logView(this.assign.id).then(() => {
|
||||
this.courseProvider.checkModuleCompletion(this.courseId, this.module.completionstatus);
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
|
||||
if (!this.canViewSubmissions) {
|
||||
// User can only see his submission, log view the user submission.
|
||||
this.assignProvider.logSubmissionView(this.assign.id).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
} else {
|
||||
// User can see all submissions, log grading view.
|
||||
this.assignProvider.logGradingView(this.assign.id).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Listen to events.
|
||||
this.savedObserver = this.eventsProvider.on(AddonModAssignProvider.SUBMISSION_SAVED_EVENT, (data) => {
|
||||
if (this.assign && data.assignmentId == this.assign.id && data.userId == this.userId) {
|
||||
// Assignment submission saved, refresh data.
|
||||
this.showLoadingAndRefresh(true, false);
|
||||
}
|
||||
}, this.siteId);
|
||||
|
||||
this.submittedObserver = this.eventsProvider.on(AddonModAssignProvider.SUBMITTED_FOR_GRADING_EVENT, (data) => {
|
||||
if (this.assign && data.assignmentId == this.assign.id && data.userId == this.userId) {
|
||||
// Assignment submitted, check completion.
|
||||
this.courseProvider.checkModuleCompletion(this.courseId, this.module.completionstatus);
|
||||
}
|
||||
}, this.siteId);
|
||||
|
||||
this.gradedObserver = this.eventsProvider.on(AddonModAssignProvider.GRADED_EVENT, (data) => {
|
||||
if (this.assign && data.assignmentId == this.assign.id && data.userId == this.userId) {
|
||||
// Assignment graded, refresh data.
|
||||
this.showLoadingAndRefresh(true, false);
|
||||
}
|
||||
}, this.siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the description.
|
||||
*/
|
||||
expandDescription(ev?: Event): void {
|
||||
ev && ev.preventDefault();
|
||||
ev && ev.stopPropagation();
|
||||
|
||||
if (this.assign && (this.description || this.assign.introattachments)) {
|
||||
this.textUtils.expandText(this.translate.instant('core.description'), this.description, this.component,
|
||||
this.module.id, this.assign.introattachments);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get assignment data.
|
||||
*
|
||||
* @param {boolean} [refresh=false] If it's refreshing content.
|
||||
* @param {boolean} [sync=false] If the refresh is needs syncing.
|
||||
* @param {boolean} [showErrors=false] If show errors to the user of hide them.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
protected fetchContent(refresh: boolean = false, sync: boolean = false, showErrors: boolean = false): Promise<any> {
|
||||
|
||||
// Get assignment data.
|
||||
return this.assignProvider.getAssignment(this.courseId, this.module.id).then((assignData) => {
|
||||
this.assign = assignData;
|
||||
|
||||
this.dataRetrieved.emit(this.assign);
|
||||
this.description = this.assign.intro || this.description;
|
||||
|
||||
if (sync) {
|
||||
// Try to synchronize the assign.
|
||||
return this.syncActivity(showErrors).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
}
|
||||
}).then(() => {
|
||||
// Check if there's any offline data for this assign.
|
||||
return this.assignOffline.hasAssignOfflineData(this.assign.id);
|
||||
}).then((hasOffline) => {
|
||||
this.hasOffline = hasOffline;
|
||||
|
||||
// Get assignment submissions.
|
||||
return this.assignProvider.getSubmissions(this.assign.id).then((data) => {
|
||||
const time = this.timeUtils.timestamp();
|
||||
|
||||
this.canViewSubmissions = data.canviewsubmissions;
|
||||
|
||||
if (data.canviewsubmissions) {
|
||||
|
||||
// Calculate the messages to display about time remaining and late submissions.
|
||||
if (this.assign.duedate > 0) {
|
||||
if (this.assign.duedate - time <= 0) {
|
||||
this.timeRemaining = this.translate.instant('addon.mod_assign.assignmentisdue');
|
||||
} else {
|
||||
this.timeRemaining = this.timeUtils.formatDuration(this.assign.duedate - time, 3);
|
||||
|
||||
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)});
|
||||
} else {
|
||||
this.lateSubmissions = this.translate.instant('addon.mod_assign.nomoresubmissionsaccepted');
|
||||
}
|
||||
} else {
|
||||
this.lateSubmissions = '';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.timeRemaining = '';
|
||||
this.lateSubmissions = '';
|
||||
}
|
||||
|
||||
// Check if groupmode is enabled to avoid showing wrong numbers.
|
||||
return this.groupsProvider.activityHasGroups(this.assign.cmid).then((hasGroups) => {
|
||||
this.showNumbers = !hasGroups;
|
||||
|
||||
return this.assignProvider.getSubmissionStatus(this.assign.id).then((response) => {
|
||||
this.summary = response.gradingsummary;
|
||||
|
||||
this.needsGradingAvalaible = response.gradingsummary.submissionsneedgradingcount > 0 &&
|
||||
this.sitesProvider.getCurrentSite().isVersionGreaterEqualThan('3.2');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}).then(() => {
|
||||
// All data obtained, now fill the context menu.
|
||||
this.fillContextMenu(refresh);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to view a list of submissions.
|
||||
*
|
||||
* @param {string} status Status to see.
|
||||
* @param {number} count Number of submissions with the status.
|
||||
*/
|
||||
goToSubmissionList(status: string, count: number): void {
|
||||
if (typeof status == 'undefined') {
|
||||
this.navCtrl.push('AddonModAssignSubmissionListPage', {
|
||||
courseId: this.courseId,
|
||||
moduleId: this.module.id,
|
||||
moduleName: this.moduleName
|
||||
});
|
||||
} else if (count || !this.showNumbers) {
|
||||
this.navCtrl.push('AddonModAssignSubmissionListPage', {
|
||||
status: status,
|
||||
courseId: this.courseId,
|
||||
moduleId: this.module.id,
|
||||
moduleName: this.moduleName
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if sync has succeed from result sync data.
|
||||
*
|
||||
* @param {any} result Data returned by the sync function.
|
||||
* @return {boolean} If succeed or not.
|
||||
*/
|
||||
protected hasSyncSucceed(result: any): boolean {
|
||||
if (result.updated) {
|
||||
// Sync done, trigger event.
|
||||
this.eventsProvider.trigger(AddonModAssignSyncProvider.MANUAL_SYNCED, {
|
||||
assignId: this.assign.id,
|
||||
warnings: result.warnings
|
||||
}, this.siteId);
|
||||
}
|
||||
|
||||
return result.updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the invalidate content function.
|
||||
*
|
||||
* @return {Promise<any>} Resolved when done.
|
||||
*/
|
||||
protected invalidateContent(): Promise<any> {
|
||||
const promises = [];
|
||||
|
||||
promises.push(this.assignProvider.invalidateAssignmentData(this.courseId));
|
||||
|
||||
if (this.assign) {
|
||||
promises.push(this.assignProvider.invalidateAllSubmissionData(this.assign.id));
|
||||
|
||||
if (this.canViewSubmissions) {
|
||||
promises.push(this.assignProvider.invalidateSubmissionStatusData(this.assign.id));
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises).finally(() => {
|
||||
// @todo $scope.$broadcast(mmaModAssignSubmissionInvalidatedEvent);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares sync event data with current data to check if refresh content is needed.
|
||||
*
|
||||
* @param {any} syncEventData Data receiven on sync observer.
|
||||
* @return {boolean} True if refresh is needed, false otherwise.
|
||||
*/
|
||||
protected isRefreshSyncNeeded(syncEventData: any): boolean {
|
||||
if (this.assign && syncEventData.assignId == this.assign.id) {
|
||||
if (syncEventData.warnings && syncEventData.warnings.length) {
|
||||
// Show warnings.
|
||||
this.domUtils.showErrorModal(syncEventData.warnings[0]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the sync of the activity.
|
||||
*
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
protected sync(): Promise<any> {
|
||||
return this.syncProvider.syncAssign(this.assign.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being destroyed.
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
super.ngOnDestroy();
|
||||
|
||||
this.savedObserver && this.savedObserver.off();
|
||||
this.submittedObserver && this.submittedObserver.off();
|
||||
this.gradedObserver && this.gradedObserver.off();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
{
|
||||
"acceptsubmissionstatement": "Please accept the submission statement.",
|
||||
"addattempt": "Allow another attempt",
|
||||
"addnewattempt": "Add a new attempt",
|
||||
"addnewattemptfromprevious": "Add a new attempt based on previous submission",
|
||||
"addsubmission": "Add submission",
|
||||
"allowsubmissionsfromdate": "Allow submissions from",
|
||||
"allowsubmissionsfromdatesummary": "This assignment will accept submissions from <strong>{{$a}}</strong>",
|
||||
"allowsubmissionsanddescriptionfromdatesummary": "The assignment details and submission form will be available from <strong>{{$a}}</strong>",
|
||||
"applytoteam": "Apply grades and feedback to entire group",
|
||||
"assignmentisdue": "Assignment is due",
|
||||
"attemptnumber": "Attempt number",
|
||||
"attemptreopenmethod": "Attempts reopened",
|
||||
"attemptreopenmethod_manual": "Manually",
|
||||
"attemptreopenmethod_untilpass": "Automatically until pass",
|
||||
"attemptsettings": "Attempt settings",
|
||||
"cannotgradefromapp": "Certain grading methods are not yet supported by the app and cannot be modified.",
|
||||
"cannoteditduetostatementsubmission": "You can't add or edit a submission in the app because the submission statement could not be retrieved from the site.",
|
||||
"cannotsubmitduetostatementsubmission": "You can't make a submission in the app because the submission statement could not be retrieved from the site.",
|
||||
"confirmsubmission": "Are you sure you want to submit your work for grading? You will not be able to make any more changes.",
|
||||
"currentgrade": "Current grade in gradebook",
|
||||
"cutoffdate": "Cut-off date",
|
||||
"currentattempt": "This is attempt {{$a}}.",
|
||||
"currentattemptof": "This is attempt {{$a.attemptnumber}} ( {{$a.maxattempts}} attempts allowed ).",
|
||||
"defaultteam": "Default group",
|
||||
"duedate": "Due date",
|
||||
"duedateno": "No due date",
|
||||
"duedatereached": "The due date for this assignment has now passed",
|
||||
"editingstatus": "Editing status",
|
||||
"editsubmission": "Edit submission",
|
||||
"erroreditpluginsnotsupported": "You can't add or edit a submission in the app because certain plugins are not yet supported for editing.",
|
||||
"errorshowinginformation": "Submission information cannot be displayed.",
|
||||
"extensionduedate": "Extension due date",
|
||||
"feedbacknotsupported": "This feedback is not supported by the app and may not contain all the information.",
|
||||
"grade": "Grade",
|
||||
"graded": "Graded",
|
||||
"gradedby": "Graded by",
|
||||
"gradenotsynced": "Grade not synced",
|
||||
"gradedon": "Graded on",
|
||||
"gradeoutof": "Grade out of {{$a}}",
|
||||
"gradingstatus": "Grading status",
|
||||
"groupsubmissionsettings": "Group submission settings",
|
||||
"hiddenuser": "Participant",
|
||||
"latesubmissions": "Late submissions",
|
||||
"latesubmissionsaccepted": "Allowed until {{$a}}",
|
||||
"markingworkflowstate": "Marking workflow state",
|
||||
"markingworkflowstateinmarking": "In marking",
|
||||
"markingworkflowstateinreview": "In review",
|
||||
"markingworkflowstatenotmarked": "Not marked",
|
||||
"markingworkflowstatereadyforreview": "Marking completed",
|
||||
"markingworkflowstatereadyforrelease": "Ready for release",
|
||||
"markingworkflowstatereleased": "Released",
|
||||
"multipleteams": "Member of more than one group",
|
||||
"noattempt": "No attempt",
|
||||
"nomoresubmissionsaccepted": "Only allowed for participants who have been granted an extension",
|
||||
"noonlinesubmissions": "This assignment does not require you to submit anything online",
|
||||
"nosubmission": "Nothing has been submitted for this assignment",
|
||||
"notallparticipantsareshown": "Participants who have not made a submission are not shown.",
|
||||
"noteam": "Not a member of any group",
|
||||
"notgraded": "Not graded",
|
||||
"numberofdraftsubmissions": "Drafts",
|
||||
"numberofparticipants": "Participants",
|
||||
"numberofsubmittedassignments": "Submitted",
|
||||
"numberofsubmissionsneedgrading": "Needs grading",
|
||||
"numberofteams": "Groups",
|
||||
"numwords": "({{$a}} words)",
|
||||
"outof": "{{$a.current}} out of {{$a.total}}",
|
||||
"overdue": "<font color=\"red\">Assignment is overdue by: {{$a}}</font>",
|
||||
"savechanges": "Save changes",
|
||||
"submissioneditable": "Student can edit this submission",
|
||||
"submissionnoteditable": "Student cannot edit this submission",
|
||||
"submissionnotsupported": "This submission is not supported by the app and may not contain all the information.",
|
||||
"submission": "Submission",
|
||||
"submissionslocked": "This assignment is not accepting submissions",
|
||||
"submissionstatus_draft": "Draft (not submitted)",
|
||||
"submissionstatusheading": "Submission status",
|
||||
"submissionstatus_marked": "Graded",
|
||||
"submissionstatus_new": "No submission",
|
||||
"submissionstatus_reopened": "Reopened",
|
||||
"submissionstatus_submitted": "Submitted for grading",
|
||||
"submissionstatus_": "No submission",
|
||||
"submissionstatus": "Submission status",
|
||||
"submissionstatusheading": "Submission status",
|
||||
"submissionteam": "Group",
|
||||
"submitassignment_help": "Once this assignment is submitted you will not be able to make any more changes.",
|
||||
"submitassignment": "Submit assignment",
|
||||
"submittedearly": "Assignment was submitted {{$a}} early",
|
||||
"submittedlate": "Assignment was submitted {{$a}} late",
|
||||
"timemodified": "Last modified",
|
||||
"timeremaining": "Time remaining",
|
||||
"ungroupedusers": "The setting 'Require group to make submission' is enabled and some users are either not a member of any group, or are a member of more than one group, so are unable to make submissions.",
|
||||
"unlimitedattempts": "Unlimited",
|
||||
"userwithid": "User with ID {{id}}",
|
||||
"userswhoneedtosubmit": "Users who need to submit: {{$a}}",
|
||||
"viewsubmission": "View submission",
|
||||
"warningsubmissionmodified": "The user submission was modified on the site.",
|
||||
"warningsubmissiongrademodified": "The submission grade was modified on the site.",
|
||||
"wordlimit": "Word limit"
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-title><core-format-text [text]="title"></core-format-text></ion-title>
|
||||
|
||||
<ion-buttons end>
|
||||
<!-- The buttons defined by the component will be added in here. -->
|
||||
</ion-buttons>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-refresher [enabled]="assignComponent.loaded" (ionRefresh)="assignComponent.doRefresh($event)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
|
||||
<addon-mod-assign-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)"></addon-mod-assign-index>
|
||||
</ion-content>
|
|
@ -0,0 +1,33 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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 { IonicPageModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
import { AddonModAssignComponentsModule } from '../../components/components.module';
|
||||
import { AddonModAssignIndexPage } from './index';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModAssignIndexPage,
|
||||
],
|
||||
imports: [
|
||||
CoreDirectivesModule,
|
||||
AddonModAssignComponentsModule,
|
||||
IonicPageModule.forChild(AddonModAssignIndexPage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
})
|
||||
export class AddonModAssignIndexPageModule {}
|
|
@ -0,0 +1,48 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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, ViewChild } from '@angular/core';
|
||||
import { IonicPage, NavParams } from 'ionic-angular';
|
||||
import { AddonModAssignIndexComponent } from '../../components/index/index';
|
||||
|
||||
/**
|
||||
* Page that displays an assign.
|
||||
*/
|
||||
@IonicPage({ segment: 'addon-mod-assign-index' })
|
||||
@Component({
|
||||
selector: 'page-addon-mod-assign-index',
|
||||
templateUrl: 'index.html',
|
||||
})
|
||||
export class AddonModAssignIndexPage {
|
||||
@ViewChild(AddonModAssignIndexComponent) assignComponent: AddonModAssignIndexComponent;
|
||||
|
||||
title: string;
|
||||
module: any;
|
||||
courseId: number;
|
||||
|
||||
constructor(navParams: NavParams) {
|
||||
this.module = navParams.get('module') || {};
|
||||
this.courseId = navParams.get('courseId');
|
||||
this.title = this.module.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update some data based on the assign instance.
|
||||
*
|
||||
* @param {any} assign Assign instance.
|
||||
*/
|
||||
updateData(assign: any): void {
|
||||
this.title = assign.name || this.title;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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 { Injectable } from '@angular/core';
|
||||
import { CoreContentLinksModuleIndexHandler } from '@core/contentlinks/classes/module-index-handler';
|
||||
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
|
||||
|
||||
/**
|
||||
* Handler to treat links to assign index page.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonModAssignIndexLinkHandler extends CoreContentLinksModuleIndexHandler {
|
||||
name = 'AddonModAssignIndexLinkHandler';
|
||||
|
||||
constructor(courseHelper: CoreCourseHelperProvider) {
|
||||
super(courseHelper, 'AddonModAssign', 'assign');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// 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 { Injectable } from '@angular/core';
|
||||
import { NavController, NavOptions } from 'ionic-angular';
|
||||
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { AddonModAssignProvider } from './assign';
|
||||
import { AddonModAssignIndexComponent } from '../components/index/index';
|
||||
|
||||
/**
|
||||
* Handler to support assign modules.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonModAssignModuleHandler implements CoreCourseModuleHandler {
|
||||
name = 'AddonModAssign';
|
||||
modName = 'assign';
|
||||
|
||||
constructor(private courseProvider: CoreCourseProvider, private assignProvider: AddonModAssignProvider) { }
|
||||
|
||||
/**
|
||||
* Check if the handler is enabled on a site level.
|
||||
*
|
||||
* @return {boolean} Whether or not the handler is enabled on a site level.
|
||||
*/
|
||||
isEnabled(): boolean {
|
||||
return this.assignProvider.isPluginEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data required to display the module in the course contents view.
|
||||
*
|
||||
* @param {any} module The module object.
|
||||
* @param {number} courseId The course ID.
|
||||
* @param {number} sectionId The section ID.
|
||||
* @return {CoreCourseModuleHandlerData} Data to render the module.
|
||||
*/
|
||||
getData(module: any, courseId: number, sectionId: number): CoreCourseModuleHandlerData {
|
||||
return {
|
||||
icon: this.courseProvider.getModuleIconSrc('assign'),
|
||||
title: module.name,
|
||||
class: 'addon-mod_assign-handler',
|
||||
showDownloadButton: true,
|
||||
action(event: Event, navCtrl: NavController, module: any, courseId: number, options: NavOptions): void {
|
||||
navCtrl.push('AddonModAssignIndexPage', {module: module, courseId: courseId}, options);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the component to render the module. This is needed to support singleactivity course format.
|
||||
* The component returned must implement CoreCourseModuleMainComponent.
|
||||
*
|
||||
* @param {any} course The course object.
|
||||
* @param {any} module The module object.
|
||||
* @return {any} The component to use, undefined if not found.
|
||||
*/
|
||||
getMainComponent(course: any, module: any): any {
|
||||
return AddonModAssignIndexComponent;
|
||||
}
|
||||
}
|
|
@ -48,9 +48,9 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
protected hasAnsweredOnline = false;
|
||||
protected now: number;
|
||||
|
||||
constructor(injector: Injector, private choiceProvider: AddonModChoiceProvider, @Optional() private content: Content,
|
||||
constructor(injector: Injector, private choiceProvider: AddonModChoiceProvider, @Optional() content: Content,
|
||||
private choiceOffline: AddonModChoiceOfflineProvider, private choiceSync: AddonModChoiceSyncProvider) {
|
||||
super(injector);
|
||||
super(injector, content);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -65,11 +65,11 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
|||
|
||||
protected submitObserver: any;
|
||||
|
||||
constructor(injector: Injector, private feedbackProvider: AddonModFeedbackProvider, @Optional() private content: Content,
|
||||
constructor(injector: Injector, private feedbackProvider: AddonModFeedbackProvider, @Optional() content: Content,
|
||||
private feedbackOffline: AddonModFeedbackOfflineProvider, private groupsProvider: CoreGroupsProvider,
|
||||
private feedbackSync: AddonModFeedbackSyncProvider, private navCtrl: NavController,
|
||||
private feedbackHelper: AddonModFeedbackHelperProvider) {
|
||||
super(injector);
|
||||
super(injector, content);
|
||||
|
||||
// Listen for form submit events.
|
||||
this.submitObserver = this.eventsProvider.on(AddonModFeedbackProvider.FORM_SUBMITTED, (data) => {
|
||||
|
|
|
@ -68,12 +68,12 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
protected finishedObserver: any; // It will observe attempt finished events.
|
||||
protected hasPlayed = false; // Whether the user has gone to the quiz player (attempted).
|
||||
|
||||
constructor(injector: Injector, protected quizProvider: AddonModQuizProvider, @Optional() protected content: Content,
|
||||
constructor(injector: Injector, protected quizProvider: AddonModQuizProvider, @Optional() content: Content,
|
||||
protected quizHelper: AddonModQuizHelperProvider, protected quizOffline: AddonModQuizOfflineProvider,
|
||||
protected quizSync: AddonModQuizSyncProvider, protected behaviourDelegate: CoreQuestionBehaviourDelegate,
|
||||
protected prefetchHandler: AddonModQuizPrefetchHandler, protected navCtrl: NavController,
|
||||
protected prefetchDelegate: CoreCourseModulePrefetchDelegate) {
|
||||
super(injector);
|
||||
super(injector, content);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,10 +38,10 @@ export class AddonModSurveyIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
protected userId: number;
|
||||
protected syncEventName = AddonModSurveySyncProvider.AUTO_SYNCED;
|
||||
|
||||
constructor(injector: Injector, private surveyProvider: AddonModSurveyProvider, @Optional() private content: Content,
|
||||
constructor(injector: Injector, private surveyProvider: AddonModSurveyProvider, @Optional() content: Content,
|
||||
private surveyHelper: AddonModSurveyHelperProvider, private surveyOffline: AddonModSurveyOfflineProvider,
|
||||
private surveySync: AddonModSurveySyncProvider) {
|
||||
super(injector);
|
||||
super(injector, content);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -83,8 +83,6 @@ export class AddonModSurveyIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
*/
|
||||
protected isRefreshSyncNeeded(syncEventData: any): boolean {
|
||||
if (this.survey && syncEventData.surveyId == this.survey.id && syncEventData.userId == this.userId) {
|
||||
this.content.scrollToTop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -189,9 +187,7 @@ export class AddonModSurveyIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
}
|
||||
|
||||
return this.surveyProvider.submitAnswers(this.survey.id, this.survey.name, this.courseId, answers).then(() => {
|
||||
this.content.scrollToTop();
|
||||
|
||||
return this.refreshContent(false);
|
||||
return this.showLoadingAndRefresh(false);
|
||||
}).finally(() => {
|
||||
modal.dismiss();
|
||||
});
|
||||
|
|
|
@ -50,6 +50,7 @@ export class AddonModSurveyModuleHandler implements CoreCourseModuleHandler {
|
|||
icon: this.courseProvider.getModuleIconSrc('survey'),
|
||||
title: module.name,
|
||||
class: 'addon-mod_survey-handler',
|
||||
showDownloadButton: true,
|
||||
action(event: Event, navCtrl: NavController, module: any, courseId: number, options: NavOptions): void {
|
||||
navCtrl.push('AddonModSurveyIndexPage', {module: module, courseId: courseId}, options);
|
||||
}
|
||||
|
|
|
@ -636,6 +636,11 @@ canvas[core-chart] {
|
|||
background-image: url("data:image/svg+xml;charset=utf-8,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2012%2020'><path%20d='M2,20l-2-2l8-8L0,2l2-2l10,10L2,20z'%20fill='%23FFFFFF'/></svg>") !important;
|
||||
}
|
||||
|
||||
// For list where some items have detail icon and some others don't.
|
||||
.core-list-align-detail-right .item .item-inner {
|
||||
@include padding-horizontal(null, 32px);
|
||||
}
|
||||
|
||||
[ion-fixed] {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Injector } from '@angular/core';
|
||||
import { Content } from 'ionic-angular';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
|
||||
|
@ -47,7 +48,7 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR
|
|||
protected eventsProvider: CoreEventsProvider;
|
||||
protected modulePrefetchProvider: CoreCourseModulePrefetchDelegate;
|
||||
|
||||
constructor(injector: Injector) {
|
||||
constructor(injector: Injector, protected content?: Content) {
|
||||
super(injector);
|
||||
|
||||
this.sitesProvider = injector.get(CoreSitesProvider);
|
||||
|
@ -118,10 +119,8 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR
|
|||
*/
|
||||
protected autoSyncEventReceived(syncEventData: any): void {
|
||||
if (this.isRefreshSyncNeeded(syncEventData)) {
|
||||
this.loaded = false;
|
||||
|
||||
// Refresh the data.
|
||||
this.refreshContent(false);
|
||||
this.showLoadingAndRefresh(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,6 +145,22 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show loading and perform the refresh content function.
|
||||
*
|
||||
* @param {boolean} [sync=false] If the refresh needs syncing.
|
||||
* @param {boolean} [showErrors=false] Wether to show errors to the user or hide them.
|
||||
* @return {Promise<any>} Resolved when done.
|
||||
*/
|
||||
protected showLoadingAndRefresh(sync: boolean = false, showErrors: boolean = false): Promise<any> {
|
||||
this.refreshIcon = 'spinner';
|
||||
this.syncIcon = 'spinner';
|
||||
this.loaded = false;
|
||||
this.content && this.content.scrollToTop();
|
||||
|
||||
return this.refreshContent(true, showErrors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the component contents.
|
||||
*
|
||||
|
|
|
@ -11,4 +11,8 @@
|
|||
</ion-header>
|
||||
<ion-content padding>
|
||||
<core-format-text [text]="content" [component]="component" [componentId]="componentId"></core-format-text>
|
||||
|
||||
<ion-card *ngIf="files && files.length">
|
||||
<core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="componentId"></core-file>
|
||||
</ion-card>
|
||||
</ion-content>
|
||||
|
|
|
@ -16,6 +16,7 @@ import { NgModule } from '@angular/core';
|
|||
import { IonicPageModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreViewerTextPage } from './text';
|
||||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
|
||||
/**
|
||||
|
@ -26,6 +27,7 @@ import { CoreDirectivesModule } from '@directives/directives.module';
|
|||
CoreViewerTextPage
|
||||
],
|
||||
imports: [
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
IonicPageModule.forChild(CoreViewerTextPage),
|
||||
TranslateModule.forChild()
|
||||
|
|
|
@ -29,12 +29,14 @@ export class CoreViewerTextPage {
|
|||
content: string; // Page content.
|
||||
component: string; // Component to use in format-text.
|
||||
componentId: string | number; // Component ID to use in format-text.
|
||||
files: any[]; // List of files.
|
||||
|
||||
constructor(private viewCtrl: ViewController, params: NavParams, textUtils: CoreTextUtilsProvider) {
|
||||
this.title = params.get('title');
|
||||
this.content = params.get('content');
|
||||
this.component = params.get('component');
|
||||
this.componentId = params.get('componentId');
|
||||
this.files = params.get('files');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -211,6 +211,11 @@ export class CoreFormatTextDirective implements OnChanges {
|
|||
this.element.style.maxHeight = this.maxHeight + 'px';
|
||||
|
||||
this.element.addEventListener('click', (e) => {
|
||||
if (e.defaultPrevented) {
|
||||
// Ignore it if the event was prevented by some other listener.
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
|
|
|
@ -303,14 +303,16 @@ export class CoreTextUtilsProvider {
|
|||
* @param {string} text Content of the text to be expanded.
|
||||
* @param {string} [component] Component to link the embedded files to.
|
||||
* @param {string|number} [componentId] An ID to use in conjunction with the component.
|
||||
* @param {any[]} [files] List of files to display along with the text.
|
||||
*/
|
||||
expandText(title: string, text: string, component?: string, componentId?: string | number): void {
|
||||
expandText(title: string, text: string, component?: string, componentId?: string | number, files?: any[]): void {
|
||||
if (text.length > 0) {
|
||||
const params: any = {
|
||||
title: title,
|
||||
content: text,
|
||||
component: component,
|
||||
componentId: componentId
|
||||
componentId: componentId,
|
||||
files: files
|
||||
};
|
||||
|
||||
// Open a modal with the contents.
|
||||
|
|
Loading…
Reference in New Issue