diff --git a/src/addon/mod/scorm/components/index/addon-mod-scorm-index.html b/src/addon/mod/scorm/components/index/addon-mod-scorm-index.html
index 947e4be78..92fb199a2 100644
--- a/src/addon/mod/scorm/components/index/addon-mod-scorm-index.html
+++ b/src/addon/mod/scorm/components/index/addon-mod-scorm-index.html
@@ -24,7 +24,7 @@
-
+
{{ 'addon.mod_scorm.attempts' | translate }}
@@ -75,7 +75,7 @@
- 1)" class="addon-mod_scorm-toc">
+ 1) && !skip" class="addon-mod_scorm-toc">
{{ 'addon.mod_scorm.contents' | translate }}
@@ -128,7 +128,7 @@
0)">
-
+
{{ 'addon.mod_scorm.mode' | translate }}
@@ -143,14 +143,14 @@
-
0 && !scorm.incomplete && scorm.attemptsLeft > 0">
+ 0 && !scorm.incomplete && scorm.attemptsLeft > 0 && !skip">
{{ 'addon.mod_scorm.newattempt' | translate }}
-
+
{{ statusMessage | translate }}
diff --git a/src/addon/mod/scorm/components/index/index.ts b/src/addon/mod/scorm/components/index/index.ts
index fce78f99c..181342b58 100644
--- a/src/addon/mod/scorm/components/index/index.ts
+++ b/src/addon/mod/scorm/components/index/index.ts
@@ -54,6 +54,8 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom
organizations: any[]; // List of organizations.
loadingToc: boolean; // Whether the TOC is being loaded.
toc: any[]; // Table of contents (structure).
+ accessInfo: any; // Access information.
+ skip: boolean; // Launch immediately.
protected fetchContentDefaultError = 'addon.mod_scorm.errorgetscorm'; // Default error to show when loading contents.
protected syncEventName = AddonModScormSyncProvider.AUTO_SYNCED;
@@ -83,6 +85,10 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom
return;
}
+ if (this.skip) {
+ this.open();
+ }
+
this.scormProvider.logView(this.scorm.id, this.scorm.name).then(() => {
this.checkCompletion();
}).catch((error) => {
@@ -181,54 +187,72 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom
this.syncTime = syncTime;
});
- // Get the number of attempts.
- return this.scormProvider.getAttemptCount(this.scorm.id);
- }).then((attemptsData) => {
- this.attempts = attemptsData;
- this.hasOffline = !!this.attempts.offline.length;
-
- // Determine the attempt that will be continued or reviewed.
- return this.scormHelper.determineAttemptToContinue(this.scorm, this.attempts);
- }).then((attempt) => {
- this.lastAttempt = attempt.number;
- this.lastIsOffline = attempt.offline;
-
- if (this.lastAttempt != this.attempts.lastAttempt.number) {
- this.attemptToContinue = this.lastAttempt;
- } else {
- this.attemptToContinue = undefined;
- }
-
- // Check if the last attempt is incomplete.
- return this.scormProvider.isAttemptIncomplete(this.scorm.id, this.lastAttempt, this.lastIsOffline);
- }).then((incomplete) => {
const promises = [];
- this.scorm.incomplete = incomplete;
- this.scorm.numAttempts = this.attempts.total;
- this.scorm.gradeMethodReadable = this.scormProvider.getScormGradeMethod(this.scorm);
- this.scorm.attemptsLeft = this.scormProvider.countAttemptsLeft(this.scorm, this.attempts.lastAttempt.number);
+ // Get access information.
+ promises.push(this.scormProvider.getAccessInformation(this.scorm.id).then((accessInfo) => {
+ this.accessInfo = accessInfo;
+ }));
- if (this.scorm.forcenewattempt == AddonModScormProvider.SCORM_FORCEATTEMPT_ALWAYS ||
- (this.scorm.forcenewattempt && !this.scorm.incomplete)) {
- this.scormOptions.newAttempt = true;
- }
+ // Get the number of attempts.
+ promises.push(this.scormProvider.getAttemptCount(this.scorm.id).then((attemptsData) => {
+ this.attempts = attemptsData;
+ this.hasOffline = !!this.attempts.offline.length;
- promises.push(this.getReportedGrades());
+ // Determine the attempt that will be continued or reviewed.
+ return this.scormHelper.determineAttemptToContinue(this.scorm, this.attempts);
+ }).then((attempt) => {
+ this.lastAttempt = attempt.number;
+ this.lastIsOffline = attempt.offline;
- promises.push(this.fetchStructure());
+ if (this.lastAttempt != this.attempts.lastAttempt.number) {
+ this.attemptToContinue = this.lastAttempt;
+ } else {
+ this.attemptToContinue = undefined;
+ }
- if (!this.scorm.packagesize && this.errorMessage === '') {
- // SCORM is supported but we don't have package size. Try to calculate it.
- promises.push(this.scormProvider.calculateScormSize(this.scorm).then((size) => {
- this.scorm.packagesize = size;
- }));
- }
+ // Check if the last attempt is incomplete.
+ return this.scormProvider.isAttemptIncomplete(this.scorm.id, this.lastAttempt, this.lastIsOffline);
+ }).then((incomplete) => {
+ const promises = [];
- // Handle status.
- this.setStatusListener();
+ this.scorm.incomplete = incomplete;
+ this.scorm.numAttempts = this.attempts.total;
+ this.scorm.gradeMethodReadable = this.scormProvider.getScormGradeMethod(this.scorm);
+ this.scorm.attemptsLeft = this.scormProvider.countAttemptsLeft(this.scorm, this.attempts.lastAttempt.number);
- return Promise.all(promises);
+ if (this.scorm.forcenewattempt == AddonModScormProvider.SCORM_FORCEATTEMPT_ALWAYS ||
+ (this.scorm.forcenewattempt && !this.scorm.incomplete)) {
+ this.scormOptions.newAttempt = true;
+ }
+
+ promises.push(this.getReportedGrades());
+
+ promises.push(this.fetchStructure());
+
+ if (!this.scorm.packagesize && this.errorMessage === '') {
+ // SCORM is supported but we don't have package size. Try to calculate it.
+ promises.push(this.scormProvider.calculateScormSize(this.scorm).then((size) => {
+ this.scorm.packagesize = size;
+ }));
+ }
+
+ // Handle status.
+ promises.push(this.setStatusListener());
+
+ return Promise.all(promises);
+ }));
+
+ return Promise.all(promises).then(() => {
+ // Check whether to launch the SCORM immediately.
+ if (typeof this.skip == 'undefined' && !this.hasOffline && !this.errorMessage &&
+ (!this.scorm.lastattemptlock || this.scorm.attemptsLeft > 0) &&
+ this.accessInfo.canskipview && !this.accessInfo.canviewreport &&
+ this.scorm.skipview >= AddonModScormProvider.SKIPVIEW_FIRST &&
+ (this.scorm.skipview == AddonModScormProvider.SKIPVIEW_ALWAYS || this.lastAttempt == 0)) {
+ this.skip = true;
+ }
+ });
});
}).then(() => {
// All data obtained, now fill the context menu.
@@ -368,6 +392,9 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom
ionViewDidLeave(): void {
super.ionViewDidLeave();
+ // Display the full page when returning to the page.
+ this.skip = false;
+
if (this.navCtrl.getActive().component.name == 'AddonModScormPlayerPage') {
this.hasPlayed = true;
@@ -460,11 +487,17 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom
});
}
- // Open a SCORM. It will download the SCORM package if it's not downloaded or it has changed.
- // The scoId param indicates the SCO that needs to be loaded when the SCORM is opened. If not defined, load first SCO.
- open(e: Event, scoId: number): void {
- e.preventDefault();
- e.stopPropagation();
+ /**
+ * Open a SCORM. It will download the SCORM package if it's not downloaded or it has changed.
+ *
+ * @param {Event} [event] Event.
+ * @param {string} [scoId] SCO that needs to be loaded when the SCORM is opened. If not defined, load first SCO.
+ */
+ open(event?: Event, scoId?: number): void {
+ if (event) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
if (this.downloading) {
// Scope is being downloaded, abort.
diff --git a/src/addon/mod/scorm/providers/prefetch-handler.ts b/src/addon/mod/scorm/providers/prefetch-handler.ts
index d64ad764b..ceb157f56 100644
--- a/src/addon/mod/scorm/providers/prefetch-handler.ts
+++ b/src/addon/mod/scorm/providers/prefetch-handler.ts
@@ -123,6 +123,9 @@ export class AddonModScormPrefetchHandler extends CoreCourseActivityPrefetchHand
// Ignore errors.
}));
+ // Prefetch access information.
+ promises.push(this.scormProvider.getAccessInformation(scorm.id));
+
return Promise.all(promises);
}).then(() => {
// Success, return the hash.
diff --git a/src/addon/mod/scorm/providers/scorm.ts b/src/addon/mod/scorm/providers/scorm.ts
index 9d4c041c4..850875fc9 100644
--- a/src/addon/mod/scorm/providers/scorm.ts
+++ b/src/addon/mod/scorm/providers/scorm.ts
@@ -83,6 +83,10 @@ export class AddonModScormProvider {
static SCORM_FORCEATTEMPT_ONCOMPLETE = 1;
static SCORM_FORCEATTEMPT_ALWAYS = 2;
+ static SKIPVIEW_NEVER = 0;
+ static SKIPVIEW_FIRST = 1;
+ static SKIPVIEW_ALWAYS = 2;
+
// Events.
static LAUNCH_NEXT_SCO_EVENT = 'addon_mod_scorm_launch_next_sco';
static LAUNCH_PREV_SCO_EVENT = 'addon_mod_scorm_launch_prev_sco';
@@ -442,6 +446,44 @@ export class AddonModScormProvider {
return formatted;
}
+ /**
+ * Get access information for a given SCORM.
+ *
+ * @param {number} scormId SCORM ID.
+ * @param {boolean} [forceCache] True to always get the value from cache. false otherwise.
+ * @param {string} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Object with access information.
+ * @since 3.7
+ */
+ getAccessInformation(scormId: number, forceCache?: boolean, siteId?: string): Promise {
+ return this.sitesProvider.getSite(siteId).then((site) => {
+ if (!site.wsAvailable('mod_scorm_get_scorm_access_information')) {
+ // Access information not available for 3.6 or older sites.
+ return Promise.resolve({});
+ }
+
+ const params = {
+ scormid: scormId
+ };
+ const preSets = {
+ cacheKey: this.getAccessInformationCacheKey(scormId),
+ omitExpires: forceCache
+ };
+
+ return site.read('mod_scorm_get_scorm_access_information', params, preSets);
+ });
+ }
+
+ /**
+ * Get cache key for access information WS calls.
+ *
+ * @param {number} scormId SCORM ID.
+ * @return {string} Cache key.
+ */
+ protected getAccessInformationCacheKey(scormId: number): string {
+ return this.ROOT_CACHE_KEY + 'accessInfo:' + scormId;
+ }
+
/**
* Get the number of attempts done by a user in the given SCORM.
*
@@ -1179,6 +1221,19 @@ export class AddonModScormProvider {
}
}
+ /**
+ * Invalidates access information.
+ *
+ * @param {number} forumId SCORM ID.
+ * @param {string} [siteId] Site ID. If not defined, current site.
+ * @return {Promise} Promise resolved when the data is invalidated.
+ */
+ invalidateAccessInformation(scormId: number, siteId?: string): Promise {
+ return this.sitesProvider.getSite(siteId).then((site) => {
+ return site.invalidateWsCacheForKey(this.getAccessInformationCacheKey(scormId));
+ });
+ }
+
/**
* Invalidates all the data related to a certain SCORM.
*
@@ -1193,6 +1248,7 @@ export class AddonModScormProvider {
promises.push(this.invalidateAttemptCount(scormId, siteId, userId));
promises.push(this.invalidateScos(scormId, siteId));
promises.push(this.invalidateScormUserData(scormId, siteId));
+ promises.push(this.invalidateAccessInformation(scormId, siteId));
return Promise.all(promises);
}
diff --git a/src/core/course/classes/main-activity-component.ts b/src/core/course/classes/main-activity-component.ts
index 16b6e8dd4..925f9109b 100644
--- a/src/core/course/classes/main-activity-component.ts
+++ b/src/core/course/classes/main-activity-component.ts
@@ -254,8 +254,10 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR
/**
* Watch for changes on the status.
+ *
+ * @return {Promise} Promise resolved when done.
*/
- protected setStatusListener(): void {
+ protected setStatusListener(): Promise {
if (typeof this.statusObserver == 'undefined') {
// Listen for changes on this module status.
this.statusObserver = this.eventsProvider.on(CoreEventsProvider.PACKAGE_STATUS_CHANGED, (data) => {
@@ -269,11 +271,13 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR
}, this.siteId);
// Also, get the current status.
- this.modulePrefetchDelegate.getModuleStatus(this.module, this.courseId).then((status) => {
+ return this.modulePrefetchDelegate.getModuleStatus(this.module, this.courseId).then((status) => {
this.currentStatus = status;
this.showStatus(status);
});
}
+
+ return Promise.resolve();
}
/**