diff --git a/www/addons/mod/data/controllers/index.js b/www/addons/mod/data/controllers/index.js index cd3840b7ce2..442ca61b38b 100644 --- a/www/addons/mod/data/controllers/index.js +++ b/www/addons/mod/data/controllers/index.js @@ -22,7 +22,7 @@ angular.module('mm.addons.mod_data') * @name mmaModDataIndexCtrl */ .controller('mmaModDataIndexCtrl', function($scope, $stateParams, $mmaModData, mmaModDataComponent, $mmCourse, $mmCourseHelper, $q, - $mmText, $translate, $mmEvents, mmCoreEventOnlineStatusChanged, $mmApp, $mmUtil, $mmSite) { + $mmText, $translate, $mmEvents, mmCoreEventOnlineStatusChanged, $mmApp, $mmUtil, $mmSite, $mmaModDataHelper, $mmGroups) { var module = $stateParams.module || {}, courseId = $stateParams.courseid, @@ -33,13 +33,12 @@ angular.module('mm.addons.mod_data') $scope.description = module.description; $scope.moduleUrl = module.url; $scope.moduleName = $mmCourse.translateModuleName('data'); - $scope.courseId = courseId; $scope.refreshIcon = 'spinner'; $scope.syncIcon = 'spinner'; $scope.component = mmaModDataComponent; $scope.componentId = module.id; $scope.databaseLoaded = false; - + $scope.selectedGroup = $stateParams.group || 0; function fetchDatabaseData(refresh, sync, showErrors) { $scope.isOnline = $mmApp.isOnline(); @@ -49,10 +48,12 @@ angular.module('mm.addons.mod_data') $scope.title = data.name || $scope.title; $scope.description = data.intro || $scope.description; + $scope.data = databaseData; $scope.database = data; return $mmaModData.getDatabaseAccessInformation(data.id); + }).then(function(accessData) { $scope.access = accessData; @@ -66,13 +67,31 @@ angular.module('mm.addons.mod_data') $scope.timeAvailableTo = data.timeavailableto && time > data.timeavailableto ? parseInt(data.timeavailableto, 10) * 1000 : false; $scope.timeAvailableToReadable = $scope.timeAvailableTo ? moment($scope.timeAvailableTo).format('LLL') : false; - } else { - // TODO: Calculate num entries based on get_entries WS. - $scope.numEntries = accessData.numentries; - $scope.entriesLeftToView = accessData.entrieslefttoview; - $scope.entriesLeftToAdd = accessData.entrieslefttoadd; - $scope.canAdd = accessData.canaddentry; + + $scope.isEmpty = true; + $scope.groupInfo = false; + return false; } + + return $mmGroups.getActivityGroupInfo(data.coursemodule, accessData.canmanageentries).then(function(groupInfo) { + $scope.groupInfo = groupInfo; + + // Check selected group is accessible. + if (groupInfo && groupInfo.groups && groupInfo.groups.length > 0) { + var found = false; + for (var x in groupInfo.groups) { + if (groupInfo.groups[x].id == $scope.selectedGroup) { + found = true; + break; + } + } + if (!found) { + $scope.selectedGroup = groupInfo.groups[0].id; + } + } + + return fetchEntriesData(); + }); }).then(function() { // All data obtained, now fill the context menu. $mmCourseHelper.fillContextMenu($scope, module, courseId, refresh, mmaModDataComponent); @@ -89,10 +108,46 @@ angular.module('mm.addons.mod_data') }); } + function fetchEntriesData() { + return $mmaModData.getDatabaseAccessInformation(data.id, $scope.selectedGroup).then(function(accessData) { + // Update values for current group. + $scope.access.canaddentry = accessData.canaddentry; + + return $mmaModData.getEntries(data.id, $scope.selectedGroup).then(function(entries) { + $scope.isEmpty = !entries || entries.entries.length <= 0; + $scope.entries = ""; + + if (!$scope.isEmpty) { + $scope.cssTemplate = $mmaModDataHelper.prefixCSS(data.csstemplate, '.mma-data-entries-' + data.id); + $scope.entries = entries.listviewcontents; + } + }); + }); + } + + + // Set group to see the database. + $scope.setGroup = function(groupId) { + $scope.selectedGroup = groupId; + return fetchEntriesData().catch(function(message) { + $mmUtil.showErrorModalDefault(message, 'mm.course.errorgetmodule', true); + return $q.reject(); + }); + }; + + + // Convenience function to refresh all the data. function refreshAllData(sync, showErrors) { var promises = []; + promises.push($mmaModData.invalidateDatabaseData(courseId)); + if (data) { + promises.push($mmaModData.invalidateDatabaseAccessInformationData(data.id)); + promises.push($mmGroups.invalidateActivityGroupInfo(data.coursemodule)); + promises.push($mmaModData.invalidateEntriesData(data.id)); + } + return $q.all(promises).finally(function() { return fetchDatabaseData(true, sync, showErrors); }); diff --git a/www/addons/mod/data/main.js b/www/addons/mod/data/main.js index eee37ce60f0..38a967c9627 100644 --- a/www/addons/mod/data/main.js +++ b/www/addons/mod/data/main.js @@ -24,7 +24,8 @@ angular.module('mm.addons.mod_data', ['mm.core']) url: '/mod_data', params: { module: null, - courseid: null + courseid: null, + group: null }, views: { 'site': { @@ -36,7 +37,8 @@ angular.module('mm.addons.mod_data', ['mm.core']) }) -.config(function($mmCourseDelegateProvider, $mmContentLinksDelegateProvider) { +.config(function($mmCourseDelegateProvider, $mmContentLinksDelegateProvider, $mmCoursePrefetchDelegateProvider) { $mmCourseDelegateProvider.registerContentHandler('mmaModData', 'data', '$mmaModDataHandlers.courseContent'); - $mmContentLinksDelegateProvider.registerLinkHandler('mmaModData', '$mmaModDataHandlers.linksHandler'); + $mmCoursePrefetchDelegateProvider.registerPrefetchHandler('mmaModData', 'data', '$mmaModDataPrefetchHandler'); + $mmContentLinksDelegateProvider.registerLinkHandler('mmaModData:index', '$mmaModDataHandlers.indexLinksHandler'); }); \ No newline at end of file diff --git a/www/addons/mod/data/scss/styles.scss b/www/addons/mod/data/scss/styles.scss new file mode 100644 index 00000000000..955e8772526 --- /dev/null +++ b/www/addons/mod/data/scss/styles.scss @@ -0,0 +1,18 @@ + +.mm-site_mod_data { + .recordcheckbox { + display: none; + } +} + +.mm-data-contents { + overflow: visible; + white-space: normal; + word-break: break-all; + padding: $item-padding; + background-color: white; + border-top-width: $item-border-width; + border-bottom-width: $item-border-width; + border-style: solid; + border-color: $item-default-border; +} \ No newline at end of file diff --git a/www/addons/mod/data/services/data.js b/www/addons/mod/data/services/data.js index 4e06dbb4eff..beb2df25881 100644 --- a/www/addons/mod/data/services/data.js +++ b/www/addons/mod/data/services/data.js @@ -21,7 +21,7 @@ angular.module('mm.addons.mod_data') * @ngdoc controller * @name $mmaModData */ -.factory('$mmaModData', function($q, $mmSitesManager, mmaModDataComponent, $mmFilepool) { +.factory('$mmaModData', function($q, $mmSitesManager, mmaModDataComponent, $mmFilepool, $mmSite) { var self = {}; /** @@ -44,14 +44,59 @@ angular.module('mm.addons.mod_data') return 'mmaModData:' + dataId; } + + /** + * Get prefix cache key for all database access information data WS calls. + * + * @param {Number} dataId Data ID. + * @return {String} Cache key. + */ + function getDatabaseAccessInformationDataPrefixCacheKey(dataId) { + return getDatabaseDataPrefixCacheKey(dataId) + ':access:'; + } + /** * Get cache key for database access information data WS calls. * * @param {Number} dataId Data ID. + * @param {Number} [groupId] Group ID. * @return {String} Cache key. */ - function getDatabaseAccessInformationDataCacheKey(dataId) { - return getDatabaseDataPrefixCacheKey(dataId) + ':access'; + function getDatabaseAccessInformationDataCacheKey(dataId, groupId) { + groupId = groupId || 0; + return getDatabaseAccessInformationDataPrefixCacheKey(dataId) + groupId; + } + + /** + * Get prefix cache key for database all entries data WS calls. + * + * @param {Number} dataId Data ID. + * @return {String} Cache key. + */ + function getEntriesPrefixCacheKey(dataId) { + return getDatabaseDataPrefixCacheKey(dataId) + ':entries:'; + } + + /** + * Get cache key for database entries data WS calls. + * + * @param {Number} dataId Data ID. + * @param {Number} [groupId] Group ID. + * @return {String} Cache key. + */ + function getEntriesCacheKey(dataId, groupId) { + groupId = groupId || 0; + return getEntriesPrefixCacheKey(dataId) + groupId; + } + + /** + * Get cache key for database fields data WS calls. + * + * @param {Number} dataId Data ID. + * @return {String} Cache key. + */ + function getFieldsCacheKey(dataId) { + return getDatabaseDataPrefixCacheKey(dataId) + ':fields'; } /** @@ -178,20 +223,25 @@ angular.module('mm.addons.mod_data') * @ngdoc method * @name $mmaModData#getDatabaseAccessInformation * @param {Number} dataId Data ID. + * @param {Number} [groupId] Group ID. * @param {Boolean} offline True if it should return cached data. Has priority over ignoreCache. * @param {Boolean} ignoreCache True if it should ignore cached data (it will always fail in offline or server down). * @param {String} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved when the database is retrieved. */ - self.getDatabaseAccessInformation = function(dataId, offline, ignoreCache, siteId) { + self.getDatabaseAccessInformation = function(dataId, groupId, offline, ignoreCache, siteId) { return $mmSitesManager.getSite(siteId).then(function(site) { var params = { databaseid: dataId }, preSets = { - cacheKey: getDatabaseAccessInformationDataCacheKey(dataId) + cacheKey: getDatabaseAccessInformationDataCacheKey(dataId, groupId) }; + if (typeof groupId !== "undefined") { + params.groupid = groupId; + } + if (offline) { preSets.omitExpires = true; } else if (ignoreCache) { @@ -215,10 +265,189 @@ angular.module('mm.addons.mod_data') */ self.invalidateDatabaseAccessInformationData = function(dataId, siteId) { return $mmSitesManager.getSite(siteId).then(function(site) { - return site.invalidateWsCacheForKey(getDatabaseAccessInformationDataCacheKey(dataId)); + return site.invalidateWsCacheForKeyStartingWith(getDatabaseAccessInformationDataPrefixCacheKey(dataId)); + }); + }; + + /** + * Get entries for a specific database and group. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#getEntries + * @param {Number} dataId Data ID. + * @param {Number} [groupId] Group ID. + * @param {Number} [sort] Sort the records by this field id, reserved ids are: + * 0: timeadded + * -1: firstname + * -2: lastname + * -3: approved + * -4: timemodified. + * Empty for using the default database setting. + * @param {String} [order] The direction of the sorting: 'ASC' or 'DESC'. + * Empty for using the default database setting. + * @param {Number} [page] Page of records to return. + * @param {Number} [perPage] Number of records to return per page. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the database is retrieved. + */ + self.getEntries = function(dataId, groupId, sort, order, page, perPage, forceCache, ignoreCache, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + databaseid: dataId, + returncontents: 1 + }, + preSets = { + cacheKey: getEntriesCacheKey(dataId, groupId) + }; + + if (typeof sort != "undefined") { + params.sort = sort; + } + + if (order) { + params.order = order; + } + + if (page) { + params.page = page; + } + + if (perPage) { + params.perpage = perPage; + } + + if (typeof groupId !== "undefined") { + params.groupid = groupId; + } + + if (forceCache) { + preSets.omitExpires = true; + } else if (ignoreCache) { + preSets.getFromCache = 0; + preSets.emergencyCache = 0; + } + + return site.read('mod_data_get_entries', params, preSets); }); }; + /** + * Invalidates database entries data. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#invalidateEntriesData + * @param {Number} dataId Data ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is invalidated. + */ + self.invalidateEntriesData = function(dataId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.invalidateWsCacheForKeyStartingWith(getEntriesPrefixCacheKey(dataId)); + }); + }; + + /** + * Get the list of configured fields for the given database. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#getFields + * @param {Number} dataId Data ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the database is retrieved. + */ + self.getFields = function(dataId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + var params = { + databaseid: dataId + }, + preSets = { + cacheKey: getFieldsCacheKey(dataId) + }; + + return site.read('mod_data_get_fields', params, preSets).then(function(response) { + if (response && response.fields) { + return response.fields; + } + return $q.reject(); + }); + }); + }; + + /** + * Invalidates database fields data. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModData#invalidateFieldsData + * @param {Number} dataId Data ID. + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when the data is invalidated. + */ + self.invalidateFieldsData = function(dataId, siteId) { + return $mmSitesManager.getSite(siteId).then(function(site) { + return site.invalidateWsCacheForKey(getFieldsCacheKey(dataId)); + }); + }; + + /** + * Performs the whole fetch of the entries in the database. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataPrefetchHandler#fetchAllEntries + * @param {Number} dataId Data ID. + * @param {Number} [groupId] Group ID. + * @param {Number} [sort] Sort the records by this field id. See $mmaModData#getEntries for more information. + * @param {String} [order] The direction of the sorting. See $mmaModData#getEntries for more information. + * @param {Number} [perPage] Number of records to return per page. Default 10. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved when done. + */ + self.fetchAllEntries = function(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, siteId) { + siteId = siteId || $mmSite.getId(); + + if (typeof perPage == 'undefined') { + perPage = 10; + } + + return fetchEntriesRecursive(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, [], 0, siteId); + }; + + /** + * Recursive call on fetch all entries. + * + * @param {Number} dataId Data ID. + * @param {Number} groupId Group ID. + * @param {Number} sort Sort the records by this field id. See $mmaModData#getEntries for more information. + * @param {String} order The direction of the sorting. See $mmaModData#getEntries for more information. + * @param {Number} perPage Number of records to return per page. + * @param {Boolean} forceCache True to always get the value from cache, false otherwise. Default false. + * @param {Boolean} ignoreCache True if it should ignore cached data (it will always fail in offline or server down). + * @param {Array} entries Entries already fetch (just to concatenate them). + * @param {Number} page Page of records to return. + * @param {String} siteId Site ID. + * @return {Promise} Promise resolved when done. + */ + function fetchEntriesRecursive(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, entries, page, siteId) { + return self.getEntries(dataId, groupId, sort, order, page, perPage, forceCache, ignoreCache, siteId).then(function(result) { + entries = entries.concat(result.entries); + + var canLoadMore = ((page + 1) * perPage) < result.totalcount; + if (canLoadMore) { + return fetchEntriesRecursive(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, entries, + page + 1, siteId); + } + return entries; + }); + } + /** * Invalidate the prefetched content except files. * To invalidate files, use $mmaModData#invalidateFiles. diff --git a/www/addons/mod/data/services/helper.js b/www/addons/mod/data/services/helper.js new file mode 100644 index 00000000000..d2647d6c648 --- /dev/null +++ b/www/addons/mod/data/services/helper.js @@ -0,0 +1,51 @@ +// (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. + +angular.module('mm.addons.mod_data') + +/** + * Helper to gather some common functions for database. + * + * @module mm.addons.mod_data + * @ngdoc service + * @name $mmaModDataHelper + */ +.factory('$mmaModDataHelper', function() { + + var self = {}; + + /** + * Add a prefix to all rules in a CSS string. + * + * @module mm.addons.mod_data + * @ngdoc method + * @name $mmaModDataHelper#prefixCSS + * @param {String} css CSS code to be prefixed. + * @param {String} prefix Prefix css selector. + * @return {String} Prefixed CSS. + */ + self.prefixCSS = function(css, prefix) { + if (!css) { + return ""; + } + // Remove comments first. + var regExp = /\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/gm; + css = css.replace(regExp, ""); + // Add prefix. + regExp = /([^]*?)({[^]*?}|,)/g; + return css.replace(regExp, prefix + " $1 $2"); + }; + + return self; +}); \ No newline at end of file diff --git a/www/addons/mod/data/services/prefetch_handler.js b/www/addons/mod/data/services/prefetch_handler.js index 9e3d181ea6c..c9b1e05bab1 100644 --- a/www/addons/mod/data/services/prefetch_handler.js +++ b/www/addons/mod/data/services/prefetch_handler.js @@ -21,12 +21,13 @@ angular.module('mm.addons.mod_data') * @ngdoc service * @name $mmaModDataPrefetchHandler */ -.factory('$mmaModDataPrefetchHandler', function($mmaModData, mmaModDataComponent, $mmFilepool, $q, $mmUtil, $mmPrefetchFactory) { +.factory('$mmaModDataPrefetchHandler', function($mmaModData, mmaModDataComponent, $mmFilepool, $q, $mmUtil, $mmPrefetchFactory, + $mmSite, $mmGroups) { var self = $mmPrefetchFactory.createPrefetchHandler(mmaModDataComponent); // RegExp to check if a module has updates based on the result of $mmCoursePrefetchDelegate#getCourseUpdates. - self.updatesNames = /^configuration$|^.*files$|^entries|^gradeitems$|^outcomes$|^comments$|^ratings/; + self.updatesNames = /^configuration$|^.*files$|^entries$|^gradeitems$|^outcomes$|^comments$|^ratings/; /** * Download the module. @@ -55,17 +56,115 @@ angular.module('mm.addons.mod_data') * @return {Promise} Promise resolved with the list of files. */ self.getFiles = function(module, courseId, siteId) { - var files = []; - return $mmaModData.getDatabase(courseId, module.id, siteId).then(function(database) { - // Get intro files. - files = self.getIntroFilesFromInstance(module, database); - return files; - }).catch(function() { - // Any error, return the list we have. - return files; + siteId = siteId || $mmSite.getId(); + + return getDatabaseInfoHelper(module, courseId, true, undefined, undefined, siteId).then(function(info) { + return info.files; }); }; + /** + * Helper function to get all database info just once. + * + * @param {Object} module Module to get the files. + * @param {Number} courseId Course ID the module belongs to. + * @param {Boolean} [omitFail] True to always return even if fails. Default false. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} siteId Site ID. + * @return {Promise} Promise resolved with the info fetched. + */ + function getDatabaseInfoHelper(module, courseId, omitFail, forceCache, ignoreCache, siteId) { + var database, + groups = [], + entries = [], + files = []; + + return $mmaModData.getDatabase(courseId, module.id, siteId, forceCache).then(function(data) { + files = self.getIntroFilesFromInstance(module, database); + + database = data; + return $mmGroups.getActivityGroupInfo(module.id, false, undefined, siteId).then(function(groupInfo) { + if (!groupInfo.groups || groupInfo.groups.length == 0) { + groupInfo.groups = [{id: 0}]; + } + groups = groupInfo.groups; + + return getAllUniqueEntries(database.id, groups, forceCache, ignoreCache, siteId); + }); + }).then(function(uniqueEntries) { + entries = uniqueEntries; + files = files.concat(getEntriesFiles(entries)); + + return { + database: database, + groups: groups, + entries: entries, + files: files + }; + }).catch(function(message) { + if (omitFail) { + // Any error, return the info we have. + return { + database: database, + groups: groups, + entries: entries, + files: files + }; + } + return $q.reject(message); + }); + } + + /** + * Retrieves all the entries for all the groups and then returns only unique entries. + * + * @param {Number} dataId Database Id. + * @param {Array} groups Array of groups in the activity. + * @param {Boolean} [forceCache] True to always get the value from cache, false otherwise. Default false. + * @param {Boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down). + * @param {String} siteId Site ID. + * @return {Promise} All unique entries. + */ + function getAllUniqueEntries(dataId, groups, forceCache, ignoreCache, siteId) { + var promises = []; + + angular.forEach(groups, function(group) { + promises.push($mmaModData.fetchAllEntries(dataId, group.id, undefined, undefined, undefined, forceCache, + ignoreCache, siteId)); + }); + + return $q.all(promises).then(function(responses) { + var uniqueEntries = {}; + + angular.forEach(responses, function(groupEntries) { + angular.forEach(groupEntries.entries, function(entry) { + uniqueEntries[entry.id] = entry; + }); + }); + + return uniqueEntries; + }); + } + + /** + * Returns the file contained in the entries. + * + * @param {Array} entries List of entries to get files from. + * @return {Array} List of files. + */ + function getEntriesFiles(entries) { + var files = []; + + angular.forEach(entries, function(entry) { + angular.forEach(entry.contents, function(content) { + files = files.concat(content.files); + }); + }); + + return files; + } + /** * Returns database intro files. * @@ -217,16 +316,18 @@ angular.module('mm.addons.mod_data') * @return {Promise} Promise resolved with an object with 'revision' and 'timemod'. */ function prefetchDatabase(module, courseId, single, siteId) { - // Prefetch the database data. - return $mmaModData.getDatabase(courseId, module.id, siteId).then(function(database) { - var promises = []; + siteId = siteId || $mmSite.getId(); - promises.push(self.getFiles(module, courseId, siteId).then(function(files) { - return $mmFilepool.addFilesToQueueByUrl(siteId, files, self.component, module.id); - })); + // Prefetch the database data. + return getDatabaseInfoHelper(module, courseId, false, true, siteId).then(function(info) { + var database = info.database, + promises = []; - promises.push($mmaModData.getDatabaseAccessInformation(database.id, false, true, siteId)); + promises.push($mmFilepool.addFilesToQueueByUrl(siteId, info.files, self.component, module.id)); + angular.forEach(info.groups, function(group) { + promises.push($mmaModData.getDatabaseAccessInformation(database.id, group.id, false, true, siteId)); + }); return $q.all(promises); }).then(function() { // Get revision and timemodified. diff --git a/www/addons/mod/data/templates/index.html b/www/addons/mod/data/templates/index.html index fb4bf06e2ed..3e4cf439b8a 100644 --- a/www/addons/mod/data/templates/index.html +++ b/www/addons/mod/data/templates/index.html @@ -1,18 +1,18 @@ {{ title }} - + - + - +
@@ -20,23 +20,40 @@ {{ description }}
-
+ +
+ {{ 'mm.core.groupsseparate' | translate }} + {{ 'mm.core.groupsvisible' | translate }} + +
+
{{ 'mma.mod_data.notopenyet' | translate:{$a: timeAvailableFromReadable} }}
-
+
{{ 'mma.mod_data.expired' | translate:{$a: timeAvailableToReadable} }}
-
- {{ 'mma.mod_data.entrieslefttoaddtoview' | translate:{$a: {entrieslefttoview: entriesLeftToView} } }} +
+ {{ 'mma.mod_data.entrieslefttoaddtoview' | translate:{$a: {entrieslefttoview: access.entrieslefttoview} } }}
-
- {{ 'mma.mod_data.entrieslefttoadd' | translate:{$a: {entriesleft: entriesLeftToAdd} } }} +
+ {{ 'mma.mod_data.entrieslefttoadd' | translate:{$a: {entriesleft: access.entrieslefttoadd} } }} +
+ +
+ + + + {{ entries }} +
- + diff --git a/www/core/lib/groups.js b/www/core/lib/groups.js index 651af503e29..e549a5866dd 100644 --- a/www/core/lib/groups.js +++ b/www/core/lib/groups.js @@ -93,6 +93,7 @@ angular.module('mm.core') * @name $mmGroups#getActivityGroupInfo * @param {Number} cmId Course Module Id of the feedback. * @param {Boolean} [addAllParts=true] True to add the all participants option, false otherwise. + * Always true for visible groups. * @param {Number} [userId] User ID. If not defined, use current user. * @param {String} [siteId] Site ID. If not defined, current site. * @return {Object} Containing the group info related to the activity. @@ -120,7 +121,7 @@ angular.module('mm.core') groupInfo.separateGroups = false; groupInfo.visibleGroups = false; } else { - if (addAllParts) { + if (addAllParts || groupInfo.visibleGroups) { groupInfo.groups = [ {'id': 0, 'name': $translate.instant('mm.core.allparticipants')} ]; diff --git a/www/core/scss/fontawesome.scss b/www/core/scss/fontawesome.scss new file mode 100644 index 00000000000..ca630e76d74 --- /dev/null +++ b/www/core/scss/fontawesome.scss @@ -0,0 +1,44 @@ +/** This file is intended to translate fontawesome to ionicons while the font is not supported */ + +.fa.icon { + @extend .ion; +} + +.fa { + font-size: $button-icon-size; + width: $button-icon-size; + height: $button-icon-size; +} + +/** Fixed width */ +.fa-fw { + width: (18em / 14); + text-align: center; +} + +/** Uncomment for dev purposes, it will show an asterisk in red where a missing icon is */ +/*.fa:before { + color: red !important; + content: $ionicon-var-asterisk; +}*/ + +/** Icons translation */ +.fa-search-plus:before { + content: $ionicon-var-ios-search-strong; +} + +.fa-cog:before { + content: $ionicon-var-gear-b; +} + +.fa-trash:before { + content: $ionicon-var-trash-a; +} + +.fa-thumbs-up:before { + content: $ionicon-var-thumbsup; +} + +.fa-thumbs-down:before { + content: $ionicon-var-thumbsdown; +} \ No newline at end of file