Skip to content

Commit c3b4dab

Browse files
committed
MOBILE-1158 course: Allow auto-navigate to a module in a course
1 parent 817815f commit c3b4dab

File tree

8 files changed

+233
-50
lines changed

8 files changed

+233
-50
lines changed

www/core/components/contentlinks/services/helper.js

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ angular.module('mm.core.contentlinks')
2121
* @ngdoc service
2222
* @name $mmContentLinksHelper
2323
*/
24-
.factory('$mmContentLinksHelper', function($log, $ionicHistory, $state, $mmSite, $mmContentLinksDelegate, $mmUtil, $translate) {
24+
.factory('$mmContentLinksHelper', function($log, $ionicHistory, $state, $mmSite, $mmContentLinksDelegate, $mmUtil, $translate,
25+
$mmCourseHelper) {
2526

2627
$log = $log.getInstance('$mmContentLinksHelper');
2728

@@ -140,7 +141,6 @@ angular.module('mm.core.contentlinks')
140141
* @return {Promise} Promise resolved with a boolean: true if URL was treated, false otherwise.
141142
*/
142143
self.handleLink = function(url) {
143-
144144
// Check if the link should be treated by some component/addon.
145145
return $mmContentLinksDelegate.getActionsFor(url).then(function(actions) {
146146
var action = self.getFirstValidAction(actions);
@@ -165,5 +165,40 @@ angular.module('mm.core.contentlinks')
165165
});
166166
};
167167

168+
/**
169+
* Treats a URL that belongs to a module's index page.
170+
*
171+
* @module mm.core.contentlinks
172+
* @ngdoc method
173+
* @name $mmContentLinksHelper#treatModuleIndexUrl
174+
* @param {String[]} siteIds Site IDs the URL belongs to.
175+
* @param {String} url URL to treat.
176+
* @param {Function} isEnabled Function to check if the module is enabled. @see $mmContentLinksHelper#filterSupportedSites .
177+
* @param {Number} [courseId] Course ID related to the URL.
178+
* @return {Promise} Promise resolved with the list of actions.
179+
*/
180+
self.treatModuleIndexUrl = function(siteIds, url, isEnabled, courseId) {
181+
var params = $mmUtil.extractUrlParams(url);
182+
if (typeof params.id != 'undefined') {
183+
// Pass false because all sites should have the same siteurl.
184+
return self.filterSupportedSites(siteIds, isEnabled, false, courseId).then(function(ids) {
185+
if (!ids.length) {
186+
return [];
187+
} else {
188+
// Return actions.
189+
return [{
190+
message: 'mm.core.view',
191+
icon: 'ion-eye',
192+
sites: ids,
193+
action: function(siteId) {
194+
$mmCourseHelper.navigateToModule(parseInt(params.id, 10), siteId, courseId);
195+
}
196+
}];
197+
}
198+
});
199+
}
200+
return $q.when([]);
201+
};
202+
168203
return self;
169204
});

www/core/components/course/controllers/section.js

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,17 @@ angular.module('mm.core.course')
2222
* @name mmCourseSectionCtrl
2323
*/
2424
.controller('mmCourseSectionCtrl', function($mmCourseDelegate, $mmCourse, $mmUtil, $scope, $stateParams, $translate, $mmSite,
25-
$mmEvents, $ionicScrollDelegate, $mmCourses, $q, mmCoreEventCompletionModuleViewed) {
25+
$mmEvents, $ionicScrollDelegate, $mmCourses, $q, mmCoreEventCompletionModuleViewed, $controller) {
2626

2727
// Default values are course 1 (front page) and all sections.
28-
var courseid = $stateParams.cid || 1,
29-
sectionid = $stateParams.sectionid || -1;
28+
var courseId = $stateParams.cid || 1,
29+
sectionId = $stateParams.sectionid || -1,
30+
moduleId = $stateParams.mid;
3031

31-
$scope.sitehome = (courseid === 1); // Are we visiting the site home?
32+
$scope.sitehome = (courseId === 1); // Are we visiting the site home?
3233
$scope.sections = []; // Reset scope.sections, otherwise an error is shown in console with tablet view.
3334

34-
if (sectionid < 0) {
35+
if (sectionId < 0) {
3536
// Special scenario, we want all sections.
3637
if ($scope.sitehome) {
3738
$scope.title = $translate.instant('mma.frontpage.sitehome');
@@ -42,15 +43,15 @@ angular.module('mm.core.course')
4243
}
4344

4445
// Convenience function to fetch section(s).
45-
function loadContent(sectionid) {
46-
return $mmCourses.getUserCourse(courseid, true).catch(function() {
46+
function loadContent(sectionId) {
47+
return $mmCourses.getUserCourse(courseId, true).catch(function() {
4748
// User not enrolled in the course or an error occurred, ignore the error.
4849
}).then(function(course) {
4950
var promise;
5051
if (course && course.enablecompletion === false) {
5152
promise = $q.when([]); // Completion not enabled, return empty array.
5253
} else {
53-
promise = $mmCourse.getActivitiesCompletionStatus(courseid).catch(function() {
54+
promise = $mmCourse.getActivitiesCompletionStatus(courseId).catch(function() {
5455
return []; // If fail, return empty array (as if there was no completion).
5556
});
5657
}
@@ -59,12 +60,12 @@ angular.module('mm.core.course')
5960
var promise,
6061
sectionnumber;
6162

62-
if (sectionid < 0) {
63+
if (sectionId < 0) {
6364
sectionnumber = 0;
64-
promise = $mmCourse.getSections(courseid);
65+
promise = $mmCourse.getSections(courseId);
6566
} else {
66-
sectionnumber = sectionid;
67-
promise = $mmCourse.getSection(courseid, sectionid).then(function(section) {
67+
sectionnumber = sectionId;
68+
promise = $mmCourse.getSection(courseId, sectionId).then(function(section) {
6869
$scope.title = section.name;
6970
$scope.summary = section.summary;
7071
return [section];
@@ -86,12 +87,21 @@ angular.module('mm.core.course')
8687

8788
angular.forEach(section.modules, function(module) {
8889
module._controller =
89-
$mmCourseDelegate.getContentHandlerControllerFor(module.modname, module, courseid, section.id);
90+
$mmCourseDelegate.getContentHandlerControllerFor(module.modname, module, courseId, section.id);
9091
// Check if activity has completions and if it's marked.
9192
var status = statuses[module.id];
9293
if (typeof status != 'undefined') {
9394
module.completionstatus = status;
9495
}
96+
97+
if (module.id == moduleId) {
98+
// This is the module we're looking for. Open it.
99+
var scope = $scope.$new();
100+
$controller(module._controller, {$scope: scope});
101+
if (scope.action) {
102+
scope.action();
103+
}
104+
}
95105
});
96106
});
97107

@@ -100,7 +110,7 @@ angular.module('mm.core.course')
100110

101111
// Add log in Moodle.
102112
$mmSite.write('core_course_view_course', {
103-
courseid: courseid,
113+
courseid: courseId,
104114
sectionnumber: sectionnumber
105115
});
106116
}, function(error) {
@@ -114,13 +124,13 @@ angular.module('mm.core.course')
114124
});
115125
}
116126

117-
loadContent(sectionid).finally(function() {
127+
loadContent(sectionId).finally(function() {
118128
$scope.sectionLoaded = true;
119129
});
120130

121131
$scope.doRefresh = function() {
122-
$mmCourse.invalidateSections(courseid).finally(function() {
123-
loadContent(sectionid).finally(function() {
132+
$mmCourse.invalidateSections(courseId).finally(function() {
133+
loadContent(sectionId).finally(function() {
124134
$scope.$broadcast('scroll.refreshComplete');
125135
});
126136
});
@@ -134,22 +144,22 @@ angular.module('mm.core.course')
134144
}
135145
$scope.sectionLoaded = false;
136146
$scope.sections = [];
137-
loadContent(sectionid).finally(function() {
147+
loadContent(sectionId).finally(function() {
138148
$scope.sectionLoaded = true;
139149
$scope.loadingPaddingTop = 0;
140150
});
141151
}
142152

143153
// Completion changed for at least one module. Invalidate data and re-load it.
144154
$scope.completionChanged = function() {
145-
$mmCourse.invalidateSections(courseid).finally(function() {
155+
$mmCourse.invalidateSections(courseId).finally(function() {
146156
refreshAfterCompletionChange();
147157
});
148158
};
149159

150160
// Listen for viewed modules. If an automatic completion module is viewed, refresh the whole list.
151161
var observer = $mmEvents.on(mmCoreEventCompletionModuleViewed, function(cid) {
152-
if (cid === courseid) {
162+
if (cid === courseId) {
153163
refreshAfterCompletionChange();
154164
}
155165
});

www/core/components/course/controllers/sections.js

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@ angular.module('mm.core.course')
2323
*/
2424
.controller('mmCourseSectionsCtrl', function($mmCourse, $mmUtil, $scope, $stateParams, $translate, $mmCourseHelper, $mmEvents,
2525
$mmSite, $mmCoursePrefetchDelegate, $mmCourses, $q, $ionicHistory, $ionicPlatform, mmCoreCourseAllSectionsId,
26-
mmCoreEventSectionStatusChanged, $mmConfig, mmCoreSettingsDownloadSection) {
27-
var courseid = $stateParams.courseid,
26+
mmCoreEventSectionStatusChanged, $mmConfig, mmCoreSettingsDownloadSection, $state, $timeout) {
27+
var courseId = $stateParams.courseid,
28+
sectionId = $stateParams.sid,
29+
moduleId = $stateParams.moduleid,
2830
downloadSectionsEnabled;
2931

30-
$scope.courseid = courseid;
32+
$scope.courseId = courseId;
33+
$scope.sectionToLoad = 2; // Load "General" section by default.
3134

3235
function checkDownloadSectionsEnabled() {
3336
return $mmConfig.get(mmCoreSettingsDownloadSection, true).then(function(enabled) {
@@ -40,10 +43,10 @@ angular.module('mm.core.course')
4043

4144
function loadSections(refresh) {
4245
// Get full course data. If not refreshing we'll try to get it from cache to speed up the response.
43-
return $mmCourses.getUserCourse(courseid).then(function(course) {
46+
return $mmCourses.getUserCourse(courseId).then(function(course) {
4447
$scope.fullname = course.fullname;
4548
// Get the sections.
46-
return $mmCourse.getSections(courseid).then(function(sections) {
49+
return $mmCourse.getSections(courseId).then(function(sections) {
4750
// Add a fake first section (all sections).
4851
return $translate('mm.course.allsections').then(function(str) {
4952
// Adding fake first section.
@@ -56,7 +59,7 @@ angular.module('mm.core.course')
5659

5760
if (downloadSectionsEnabled) {
5861
// Calculate status of the sections.
59-
return $mmCourseHelper.calculateSectionsStatus(result, courseid, true, refresh).catch(function() {
62+
return $mmCourseHelper.calculateSectionsStatus(result, courseId, true, refresh).catch(function() {
6063
// Ignore errors (shouldn't happen).
6164
}).then(function(downloadpromises) {
6265
// If we restored any download we'll recalculate the status once all of them have finished.
@@ -68,7 +71,7 @@ angular.module('mm.core.course')
6871
}).finally(function() {
6972
if (!$scope.$$destroyed) {
7073
// Recalculate the status.
71-
$mmCourseHelper.calculateSectionsStatus($scope.sections, courseid, false);
74+
$mmCourseHelper.calculateSectionsStatus($scope.sections, courseId, false);
7275
}
7376
});
7477
}
@@ -88,7 +91,7 @@ angular.module('mm.core.course')
8891
// Prefetch a section. The second parameter indicates if the prefetch was started manually (true)
8992
// or it was automatically started because all modules are being downloaded (false).
9093
function prefetch(section, manual) {
91-
$mmCourseHelper.prefetch(section, courseid, $scope.sections).catch(function() {
94+
$mmCourseHelper.prefetch(section, courseId, $scope.sections).catch(function() {
9295
// Don't show error message if scope is destroyed or it's an automatic download but we aren't in this state.
9396
if ($scope.$$destroyed) {
9497
return;
@@ -105,15 +108,41 @@ angular.module('mm.core.course')
105108
}).finally(function() {
106109
if (!$scope.$$destroyed) {
107110
// Recalculate the status.
108-
$mmCourseHelper.calculateSectionsStatus($scope.sections, courseid, false);
111+
$mmCourseHelper.calculateSectionsStatus($scope.sections, courseId, false);
109112
}
110113
});
111114
}
112115

116+
// Convenience function to autoload a section if sectionId param is set.
117+
function autoloadSection() {
118+
if (sectionId) {
119+
if ($ionicPlatform.isTablet()) {
120+
// Search the position of the section to load.
121+
angular.forEach($scope.sections, function(section, index) {
122+
if (section.id == sectionId) {
123+
$scope.sectionToLoad = index + 1;
124+
}
125+
});
126+
// Set moduleId to pass it to the new state when the section is autoloaded. We unset it after this
127+
// to prevent autoloading the module when the user manually loads a section.
128+
$scope.moduleId = moduleId;
129+
$timeout(function() {
130+
$scope.moduleId = null; // Unset moduleId when
131+
}, 500);
132+
} else {
133+
$state.go('site.mm_course-section', {
134+
sectionid: sectionId,
135+
cid: courseId,
136+
mid: moduleId
137+
});
138+
}
139+
}
140+
}
141+
113142
$scope.doRefresh = function() {
114143
var promises = [];
115144
promises.push($mmCourses.invalidateUserCourses());
116-
promises.push($mmCourse.invalidateSections(courseid));
145+
promises.push($mmCourse.invalidateSections(courseId));
117146

118147
$q.all(promises).finally(function() {
119148
loadSections(true).finally(function() {
@@ -126,13 +155,14 @@ angular.module('mm.core.course')
126155
e.preventDefault();
127156
e.stopPropagation();
128157

129-
$mmCourseHelper.confirmDownloadSize(courseid, section, $scope.sections).then(function() {
158+
$mmCourseHelper.confirmDownloadSize(courseId, section, $scope.sections).then(function() {
130159
prefetch(section, true);
131160
});
132161
};
133162

134163
checkDownloadSectionsEnabled().then(function() {
135164
loadSections().finally(function() {
165+
autoloadSection();
136166
$scope.sectionsLoaded = true;
137167
});
138168
});
@@ -148,7 +178,7 @@ angular.module('mm.core.course')
148178
}
149179

150180
// Recalculate the status.
151-
$mmCourseHelper.calculateSectionsStatus($scope.sections, courseid, false).then(function() {
181+
$mmCourseHelper.calculateSectionsStatus($scope.sections, courseId, false).then(function() {
152182
var section;
153183
angular.forEach($scope.sections, function(s) {
154184
if (s.id === data.sectionid) {

www/core/components/course/main.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ angular.module('mm.core.course', ['mm.core.courses'])
2424
.state('site.mm_course', {
2525
url: '/mm_course',
2626
params: {
27-
courseid: null
27+
courseid: null,
28+
sid: null, // Section to load. Not naming it sectionid because it collides with 'mm_course-section' param in split-view.
29+
moduleid: null // Module to load.
2830
},
2931
views: {
3032
'site': {
@@ -38,7 +40,8 @@ angular.module('mm.core.course', ['mm.core.courses'])
3840
url: '/mm_course-section',
3941
params: {
4042
sectionid: null,
41-
cid: null // Not naming it courseid because it collides with 'site.mm_course' param in split-view.
43+
cid: null, // Not naming it courseid because it collides with 'site.mm_course' param in split-view.
44+
mid: null // Not naming it moduleid because it collides with 'site.mm_course' param in split-view.
4245
},
4346
views: {
4447
'site': {

0 commit comments

Comments
 (0)