Skip to content

Commit 9454bb7

Browse files
Frederic Massartdpalou
authored andcommitted
MOBILE-1279 mmaModGlossary: First implementation of mod_glossary
1 parent bc1999e commit 9454bb7

File tree

9 files changed

+1036
-0
lines changed

9 files changed

+1036
-0
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// (C) Copyright 2015 Martin Dougiamas
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
angular.module('mm.addons.mod_glossary')
16+
17+
/**
18+
* Glossary entry controller.
19+
*
20+
* @module mm.addons.mod_glossary
21+
* @ngdoc controller
22+
* @name mmaModGlossaryEntryCtrl
23+
*/
24+
.controller('mmaModGlossaryEntryCtrl', function($scope, $stateParams, $mmaModGlossary, $translate,
25+
mmUserProfileState) {
26+
var entry = $stateParams.entry || {},
27+
courseid = $stateParams.courseid || 0,
28+
glossary;
29+
30+
// This is a coding error, for now the course ID is required here as we need it for the author link.
31+
if (!courseid) {
32+
notifyErrorOccured();
33+
return;
34+
}
35+
36+
$scope.refreshEntry = function() {
37+
refreshEntry().finally(function() {
38+
$scope.$broadcast('scroll.refreshComplete');
39+
});
40+
};
41+
42+
// Load the glossary first.
43+
$mmaModGlossary.getGlossaryById(courseid, entry.glossaryid).then(function(gloss) {
44+
glossary = gloss;
45+
var displayFormat = glossary.displayformat;
46+
47+
$scope.title = entry.concept;
48+
$scope.entry = entry;
49+
$scope.courseid = courseid;
50+
$scope.userStateName = mmUserProfileState;
51+
52+
if (displayFormat == 'fullwithauthor' || displayFormat == 'encyclopedia') {
53+
$scope.showAuthor = true;
54+
$scope.showDate = true;
55+
56+
} else if (displayFormat == 'fullwithoutauthor') {
57+
$scope.showAuthor = false;
58+
$scope.showDate = true;
59+
60+
// Default, and faq, simple, entrylist, continuous.
61+
} else {
62+
$scope.showAuthor = false;
63+
$scope.showDate = false;
64+
}
65+
66+
$scope.loaded = true;
67+
68+
// Log that the entry was viewed.
69+
$mmaModGlossary.logEntryView(entry.id);
70+
71+
}).catch(function() {
72+
notifyErrorOccured();
73+
});
74+
75+
function fetchEntry() {
76+
return $mmaModGlossary.getEntry(entry.id).then(function(result) {
77+
$scope.entry = result.entry;
78+
$scope.title = result.entry.concept;
79+
});
80+
}
81+
82+
function refreshEntry() {
83+
return $mmaModGlossary.invalidateEntry(entry.id).then(function() {
84+
return fetchEntry();
85+
});
86+
}
87+
88+
function notifyErrorOccured() {
89+
$scope.title = $translate.instant('mm.core.error');
90+
$scope.entry = false;
91+
$scope.loaded = true;
92+
}
93+
94+
});
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
// (C) Copyright 2015 Martin Dougiamas
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
angular.module('mm.addons.mod_glossary')
16+
17+
/**
18+
* Glossary index controller.
19+
*
20+
* @module mm.addons.mod_glossary
21+
* @ngdoc controller
22+
* @name mmaModGlossaryIndexCtrl
23+
*/
24+
.controller('mmaModGlossaryIndexCtrl', function($q, $scope, $stateParams, $ionicPopover, $mmUtil, $mmaModGlossary,
25+
$ionicScrollDelegate) {
26+
27+
var module = $stateParams.module || {},
28+
courseId = $stateParams.courseid,
29+
glossary,
30+
noop = function(){},
31+
limitFrom = 0,
32+
limitNum = 25,
33+
popover,
34+
viewMode, // The archetype of view (letter, date, author, cat).
35+
fetchMode = 'letter_all', // Default.
36+
fetchFunction,
37+
fetchInvalidate,
38+
fetchArguments,
39+
popoverScope = $scope.$new(true),
40+
browseModes = [
41+
{
42+
key: 'letter_all',
43+
langkey: 'mma.mod_glossary.byalphabet'
44+
},
45+
{
46+
key: 'search',
47+
langkey: 'mma.mod_glossary.bysearch'
48+
}
49+
];
50+
51+
$scope.title = module.name;
52+
$scope.description = module.description;
53+
$scope.externalUrl = module.url;
54+
$scope.courseid = courseId;
55+
$scope.loaded = false;
56+
$scope.entries = [];
57+
$scope.getDivider = noop;
58+
$scope.showDivider = noop;
59+
$scope.canLoadMore = false;
60+
$scope.searchData = {
61+
searchQuery: ''
62+
};
63+
64+
$scope.loadMoreEntries = function() {
65+
loadMoreEntries().finally(function() {
66+
$scope.$broadcast('scroll.infiniteScrollComplete');
67+
});
68+
};
69+
$scope.refreshEntries = function() {
70+
refreshEntries().finally(function() {
71+
$scope.$broadcast('scroll.refreshComplete');
72+
});
73+
};
74+
75+
$scope.pickMode = function(e) {
76+
popoverScope.data.selectedMode = fetchMode;
77+
popover.show(e);
78+
};
79+
80+
$scope.search = function(query) {
81+
fetchArguments = [glossary.id, query, 1, 'CONCEPT', 'ASC'];
82+
fetchEntries();
83+
};
84+
85+
$scope.trackBy = function(entry) {
86+
return fetchMode + ':' + entry.id;
87+
};
88+
89+
// Controller run.
90+
$mmaModGlossary.getGlossary(courseId, module.id).then(function(mod) {
91+
glossary = mod;
92+
93+
// Preparing browse modes.
94+
if (glossary.browsemodes.indexOf('date') >= 0) {
95+
browseModes.push({key: 'newest_first', langkey: 'mma.mod_glossary.bynewestfirst'});
96+
browseModes.push({key: 'recently_updated', langkey: 'mma.mod_glossary.byrecentlyupdated'});
97+
}
98+
if (glossary.browsemodes.indexOf('author') >= 0) {
99+
browseModes.push({key: 'author_all', langkey: 'mma.mod_glossary.byauthor'});
100+
}
101+
102+
// Preparing the popover.
103+
popoverScope.modes = browseModes;
104+
popoverScope.modePicked = function(mode) {
105+
$ionicScrollDelegate.$getByHandle('mmaModGlossaryIndex').scrollTop(false);
106+
if (switchMode(mode)) {
107+
$scope.loaded = false;
108+
fetchEntries().finally(function() {
109+
$scope.loaded = true;
110+
});
111+
} else {
112+
// If it's not an instant search, then we reset the values.
113+
$scope.loaded = true;
114+
$scope.entries = [];
115+
$scope.canLoadMore = false;
116+
$scope.showNoEntries = false;
117+
}
118+
popover.hide();
119+
};
120+
popoverScope.data = { selectedMode: '' };
121+
$ionicPopover.fromTemplateUrl('addons/mod_glossary/templates/mode_picker.html', {
122+
scope: popoverScope
123+
}).then(function(po) {
124+
popover = po;
125+
});
126+
$scope.$on('$destroy', function() {
127+
popover.remove();
128+
popoverScope.$destroy();
129+
});
130+
131+
// Preparing the initial mode.
132+
switchMode();
133+
134+
// Do not return the promise here, the error modal is already handled.
135+
fetchEntries().then(function() {
136+
// After a successful fetch, the glossary can be considered as 'viewed'.
137+
$mmaModGlossary.logView(glossary.id, viewMode);
138+
}).finally(function() {
139+
$scope.loaded = true;
140+
});
141+
}).catch(function() {
142+
$mmUtil.showErrorModal('mma.mod_glossary.errorloadingglossary', true);
143+
$scope.loaded = true;
144+
});
145+
146+
// Controller library.
147+
function fetchEntries(append) {
148+
if (!append) {
149+
limitFrom = 0;
150+
}
151+
var args = angular.extend([], fetchArguments);
152+
args.push(limitFrom);
153+
args.push(limitNum);
154+
155+
return fetchFunction.apply(this, args).then(function(result) {
156+
if (append) {
157+
$scope.entries = $scope.entries.concat(result.entries);
158+
} else {
159+
$scope.entries = result.entries;
160+
}
161+
$scope.canLoadMore = (limitFrom + limitNum) < result.count;
162+
$scope.showNoEntries = result.count <= 0;
163+
}).catch(function() {
164+
$mmUtil.showErrorModal('mma.mod_glossary.errorloadingentries', true);
165+
return $q.reject();
166+
});
167+
}
168+
169+
function refreshEntries() {
170+
if (fetchMode == 'search' && !$scope.searchQuery) {
171+
// Ignore search mode that is not set yet.
172+
return $q.when();
173+
}
174+
var args = angular.extend([], fetchArguments);
175+
return fetchInvalidate.apply(this, args).then(function() {
176+
limitFrom = 0;
177+
return fetchEntries();
178+
});
179+
}
180+
181+
function loadMoreEntries() {
182+
limitFrom += limitNum;
183+
return fetchEntries(true);
184+
}
185+
186+
function switchMode(mode) {
187+
if (mode == fetchMode) {
188+
return false;
189+
}
190+
191+
var instantFetch = true;
192+
fetchMode = mode;
193+
$scope.isSearch = false;
194+
195+
// Browse by author.
196+
if (mode == 'author_all') {
197+
viewMode = 'author';
198+
fetchFunction = $mmaModGlossary.getEntriesByAuthor;
199+
fetchInvalidate = $mmaModGlossary.invalidateEntriesByAuthor;
200+
fetchArguments = [glossary.id, 'ALL', 'LASTNAME', 'ASC'];
201+
$scope.getDivider = function(entry) {
202+
return entry.userfullname;
203+
};
204+
$scope.showDivider = function(entry, previous) {
205+
if (typeof previous === 'undefined') {
206+
return true;
207+
}
208+
return entry.userid != previous.userid;
209+
};
210+
211+
// Newest first.
212+
} else if (mode == 'newest_first') {
213+
viewMode = 'date';
214+
fetchFunction = $mmaModGlossary.getEntriesByDate;
215+
fetchInvalidate = $mmaModGlossary.invalidateEntriesByDate;
216+
fetchArguments = [glossary.id, 'CREATION', 'DESC'];
217+
$scope.getDivider = noop;
218+
$scope.showDivider = function() { return false; };
219+
220+
// Recently updated.
221+
} else if (mode == 'recently_updated') {
222+
viewMode = 'date';
223+
fetchFunction = $mmaModGlossary.getEntriesByDate;
224+
fetchInvalidate = $mmaModGlossary.invalidateEntriesByDate;
225+
fetchArguments = [glossary.id, 'UPDATE', 'DESC'];
226+
$scope.getDivider = noop;
227+
$scope.showDivider = function() { return false; };
228+
229+
// Search for entries.
230+
} else if (mode == 'search') {
231+
viewMode = 'search';
232+
fetchFunction = $mmaModGlossary.getEntriesBySearch;
233+
fetchInvalidate = $mmaModGlossary.invalidateEntriesBySearch;
234+
fetchArguments = false; // Dynamically set later.
235+
$scope.isSearch = true;
236+
$scope.getDivider = noop;
237+
$scope.showDivider = function() { return false; };
238+
instantFetch = false;
239+
240+
// Consider it is 'letter_all'.
241+
} else {
242+
viewMode = 'letter';
243+
fetchMode = 'letter_all';
244+
fetchFunction = $mmaModGlossary.getEntriesByLetter;
245+
fetchInvalidate = $mmaModGlossary.invalidateEntriesByLetter;
246+
fetchArguments = [glossary.id, 'ALL'];
247+
$scope.getDivider = function(entry) {
248+
return entry.concept.substr(0, 1).toUpperCase();
249+
};
250+
$scope.showDivider = function(entry, previous) {
251+
if (typeof previous === 'undefined') {
252+
return true;
253+
}
254+
return $scope.getDivider(entry) != $scope.getDivider(previous);
255+
};
256+
}
257+
258+
return instantFetch;
259+
}
260+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"browsemode": "Browse entries",
3+
"byalphabet": "Alphabetically",
4+
"byauthor": "Group by author",
5+
"bynewestfirst": "Newest first",
6+
"byrecentlyupdated": "Recently updated",
7+
"bysearch": "Search",
8+
"entrypendingapproval": "This entry is pending approval.",
9+
"errorloadingentries": "An error occured while loading entries.",
10+
"errorloadingentry": "An error occured while loading the entry.",
11+
"errorloadingglossary": "An error occured while loading the glossary.",
12+
"noentriesfound": "No entries were found.",
13+
"searchquery": "Search query"
14+
}

0 commit comments

Comments
 (0)