diff --git a/src/addon/mod/quiz/lang/en.json b/src/addon/mod/quiz/lang/en.json
index ecc2cde5b..9cb5add1e 100644
--- a/src/addon/mod/quiz/lang/en.json
+++ b/src/addon/mod/quiz/lang/en.json
@@ -48,6 +48,7 @@
"preview": "Preview",
"previewquiznow": "Preview quiz now",
"question": "Question",
+ "quiznavigation": "Quiz navigation",
"quizpassword": "Quiz password",
"reattemptquiz": "Re-attempt quiz",
"requirepasswordmessage": "To attempt this quiz you need to know the quiz password",
diff --git a/src/addon/mod/quiz/pages/navigation-modal/navigation-modal.html b/src/addon/mod/quiz/pages/navigation-modal/navigation-modal.html
new file mode 100644
index 000000000..c618530f1
--- /dev/null
+++ b/src/addon/mod/quiz/pages/navigation-modal/navigation-modal.html
@@ -0,0 +1,41 @@
+
+
+ {{ 'addon.mod_quiz.quiznavigation' | translate }}
+
+
+
+
+
+
+
+
diff --git a/src/addon/mod/quiz/pages/navigation-modal/navigation-modal.module.ts b/src/addon/mod/quiz/pages/navigation-modal/navigation-modal.module.ts
new file mode 100644
index 000000000..51d29607a
--- /dev/null
+++ b/src/addon/mod/quiz/pages/navigation-modal/navigation-modal.module.ts
@@ -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 { NgModule } from '@angular/core';
+import { IonicPageModule } from 'ionic-angular';
+import { AddonModQuizNavigationModalPage } from './navigation-modal';
+import { TranslateModule } from '@ngx-translate/core';
+
+@NgModule({
+ declarations: [
+ AddonModQuizNavigationModalPage
+ ],
+ imports: [
+ IonicPageModule.forChild(AddonModQuizNavigationModalPage),
+ TranslateModule.forChild()
+ ]
+})
+export class AddonModQuizNavigationModalPageModule {}
diff --git a/src/addon/mod/quiz/pages/navigation-modal/navigation-modal.scss b/src/addon/mod/quiz/pages/navigation-modal/navigation-modal.scss
new file mode 100644
index 000000000..5abb5c103
--- /dev/null
+++ b/src/addon/mod/quiz/pages/navigation-modal/navigation-modal.scss
@@ -0,0 +1,5 @@
+page-addon-mod-quiz-navigation-modal {
+ .addon-mod_quiz-selected, .item.addon-mod_quiz-selected {
+ background: $blue-light;
+ }
+}
diff --git a/src/addon/mod/quiz/pages/navigation-modal/navigation-modal.ts b/src/addon/mod/quiz/pages/navigation-modal/navigation-modal.ts
new file mode 100644
index 000000000..1d09cd7ce
--- /dev/null
+++ b/src/addon/mod/quiz/pages/navigation-modal/navigation-modal.ts
@@ -0,0 +1,66 @@
+// (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 } from '@angular/core';
+import { IonicPage, ViewController, NavParams } from 'ionic-angular';
+
+/**
+ * Modal that renders the quiz navigation.
+ */
+@IonicPage({ segment: 'addon-mod-quiz-navigation-modal' })
+@Component({
+ selector: 'page-addon-mod-quiz-navigation-modal',
+ templateUrl: 'navigation-modal.html',
+})
+export class AddonModQuizNavigationModalPage {
+
+ /**
+ * The instance of the page that opened the modal. We use the instance instead of the needed attributes for these reasons:
+ * - Some attributes can change dynamically, and we don't want to create the modal everytime the user opens it.
+ * - The onDidDismiss function takes a while to be called, making the app seem slow. This way we can directly call
+ * the functions we need without having to wait for the modal to be dismissed.
+ * @type {any}
+ */
+ pageInstance: any;
+
+ constructor(params: NavParams, protected viewCtrl: ViewController) {
+ this.pageInstance = params.get('page');
+ }
+
+ /**
+ * Close modal.
+ */
+ closeModal(): void {
+ this.viewCtrl.dismiss();
+ }
+
+ /**
+ * Load a certain page.
+ *
+ * @param {number} page The page to load.
+ * @param {number} [slot] Slot of the question to scroll to.
+ */
+ loadPage(page: number, slot: number): void {
+ this.pageInstance.changePage && this.pageInstance.changePage(page, true, slot);
+ this.closeModal();
+ }
+
+ /**
+ * Switch mode in review.
+ */
+ switchMode(): void {
+ this.pageInstance.switchMode && this.pageInstance.switchMode();
+ this.closeModal();
+ }
+}
diff --git a/src/addon/mod/quiz/pages/player/player.html b/src/addon/mod/quiz/pages/player/player.html
index f37140cc8..9d84cf51e 100644
--- a/src/addon/mod/quiz/pages/player/player.html
+++ b/src/addon/mod/quiz/pages/player/player.html
@@ -6,7 +6,9 @@
-
+
diff --git a/src/addon/mod/quiz/pages/player/player.ts b/src/addon/mod/quiz/pages/player/player.ts
index 3d0d02208..c28ae687a 100644
--- a/src/addon/mod/quiz/pages/player/player.ts
+++ b/src/addon/mod/quiz/pages/player/player.ts
@@ -13,7 +13,7 @@
// limitations under the License.
import { Component, OnInit, OnDestroy, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core';
-import { IonicPage, NavParams, Content, PopoverController } from 'ionic-angular';
+import { IonicPage, NavParams, Content, PopoverController, ModalController, Modal } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreEventsProvider } from '@providers/events';
import { CoreLoggerProvider } from '@providers/logger';
@@ -47,7 +47,7 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
quizAborted: boolean; // Whether the quiz was aborted due to an error.
preflightData: any = {}; // Preflight data to attempt the quiz.
offline: boolean; // Whether the quiz is being attempted in offline mode.
- toc: any[]; // TOC to navigate the questions.
+ navigation: any[]; // List of questions to navigate them.
questions: any[]; // Questions of the current page.
nextPage: number; // Next page.
previousPage: number; // Previous page.
@@ -70,13 +70,15 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
protected timeUpCalled: boolean; // Whether the time up function has been called.
protected autoSave: AddonModQuizAutoSave; // Class to auto-save answers every certain time.
protected autoSaveErrorSubscription: Subscription; // To be notified when an error happens in auto-save.
+ protected navigationModal: Modal; // Modal to navigate through the questions.
constructor(navParams: NavParams, element: ElementRef, logger: CoreLoggerProvider, protected translate: TranslateService,
protected eventsProvider: CoreEventsProvider, protected sitesProvider: CoreSitesProvider,
protected syncProvider: CoreSyncProvider, protected domUtils: CoreDomUtilsProvider, popoverCtrl: PopoverController,
protected timeUtils: CoreTimeUtilsProvider, protected quizProvider: AddonModQuizProvider,
protected quizHelper: AddonModQuizHelperProvider, protected quizSync: AddonModQuizSyncProvider,
- protected questionHelper: CoreQuestionHelperProvider, protected cdr: ChangeDetectorRef) {
+ protected questionHelper: CoreQuestionHelperProvider, protected cdr: ChangeDetectorRef,
+ protected modalCtrl: ModalController) {
this.quizId = navParams.get('quizId');
this.courseId = navParams.get('courseId');
@@ -88,6 +90,11 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
// Create the auto save instance.
this.autoSave = new AddonModQuizAutoSave('addon-mod_quiz-player-form', '#addon-mod_quiz-connection-error-button',
logger, popoverCtrl, questionHelper, quizProvider);
+
+ // Create the navigation modal.
+ this.navigationModal = this.modalCtrl.create('AddonModQuizNavigationModalPage', {
+ page: this
+ });
}
/**
@@ -164,10 +171,10 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
* Change the current page. If slot is supplied, try to scroll to that question.
*
* @param {number} page Page to load. -1 means summary.
- * @param {boolean} [fromToc] Whether the page was selected using the TOC.
+ * @param {boolean} [fromModal] Whether the page was selected using the navigation modal.
* @param {number} [slot] Slot of the question to scroll to.
*/
- changePage(page: number, fromToc?: boolean, slot?: number): void {
+ changePage(page: number, fromModal?: boolean, slot?: number): void {
if (page != -1 && (this.attempt.state == AddonModQuizProvider.ATTEMPT_OVERDUE || this.attempt.finishedOffline)) {
// We can't load a page if overdue or the local attempt is finished.
return;
@@ -176,9 +183,9 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
this.scrollToQuestion(slot);
return;
- } else if ((page == this.attempt.currentpage && !this.showSummary) || (fromToc && this.quiz.isSequential && page != -1)) {
+ } else if ((page == this.attempt.currentpage && !this.showSummary) || (fromModal && this.quiz.isSequential && page != -1)) {
// If the user is navigating to the current page we do nothing.
- // Also, in sequential quizzes we don't allow navigating using the TOC except for finishing the quiz (summary).
+ // Also, in sequential quizzes we don't allow navigating using the modal except for finishing the quiz (summary).
return;
} else if (page === -1 && this.showSummary) {
// Summary already shown.
@@ -417,14 +424,14 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
}
/**
- * Load TOC to navigate the questions.
+ * Load data to navigate the questions using the navigation modal.
*
* @return {Promise} Promise resolved when done.
*/
- protected loadToc(): Promise {
- // We use the attempt summary to build the TOC because it contains all the questions.
+ protected loadNavigation(): Promise {
+ // We use the attempt summary to build the navigation because it contains all the questions.
return this.quizProvider.getAttemptSummary(this.attempt.id, this.preflightData, this.offline).then((questions) => {
- this.toc = questions;
+ this.navigation = questions;
});
}
@@ -512,7 +519,7 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
this.attemptAccessInfo = info;
this.attempt = attempt;
- return this.loadToc();
+ return this.loadNavigation();
}).then(() => {
if (this.attempt.state != AddonModQuizProvider.ATTEMPT_OVERDUE && !this.attempt.finishedOffline) {
// Attempt not overdue and not finished in offline, load page.