Merge pull request #1355 from dpalou/MOBILE-2428

Mobile 2428
main
Juan Leyva 2018-06-19 17:01:59 +02:00 committed by GitHub
commit cfabc24545
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1006 additions and 718 deletions

View File

@ -12,11 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreGroupsProvider } from '@providers/groups';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreGradesHelperProvider } from '@core/grades/providers/helper';
@ -30,19 +35,21 @@ import { AddonModAssignSubmissionDelegate } from './submission-delegate';
* Handler to prefetch assigns.
*/
@Injectable()
export class AddonModAssignPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHandlerBase {
name = 'AddonModAssign';
modName = 'assign';
component = AddonModAssignProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^submissions$|^grades$|^gradeitems$|^outcomes$|^comments$/;
constructor(protected injector: Injector, protected assignProvider: AddonModAssignProvider,
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected assignProvider: AddonModAssignProvider,
protected textUtils: CoreTextUtilsProvider, protected feedbackDelegate: AddonModAssignFeedbackDelegate,
protected submissionDelegate: AddonModAssignSubmissionDelegate, protected courseProvider: CoreCourseProvider,
protected courseHelper: CoreCourseHelperProvider, protected filepoolProvider: CoreFilepoolProvider,
protected submissionDelegate: AddonModAssignSubmissionDelegate, protected courseHelper: CoreCourseHelperProvider,
protected groupsProvider: CoreGroupsProvider, protected gradesHelper: CoreGradesHelperProvider,
protected userProvider: CoreUserProvider, protected assignHelper: AddonModAssignHelperProvider) {
super(injector);
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**
@ -65,19 +72,6 @@ export class AddonModAssignPrefetchHandler extends CoreCourseModulePrefetchHandl
});
}
/**
* Download the module.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @return {Promise<any>} Promise resolved when all content is downloaded.
*/
download(module: any, courseId: number, dirPath?: string): Promise<any> {
// Same implementation for download or prefetch.
return this.prefetch(module, courseId, false, dirPath);
}
/**
* Get list of files. If not defined, we'll assume they're in module.contents.
*
@ -207,7 +201,7 @@ export class AddonModAssignPrefetchHandler extends CoreCourseModulePrefetchHandl
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {

View File

@ -12,23 +12,32 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler';
import { AddonModBookProvider } from './book';
/**
* Handler to prefetch books.
*/
@Injectable()
export class AddonModBookPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModBookPrefetchHandler extends CoreCourseResourcePrefetchHandlerBase {
name = 'AddonModBook';
modName = 'book';
component = AddonModBookProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^entries$/;
isResource = true;
constructor(injector: Injector, protected bookProvider: AddonModBookProvider) {
super(injector);
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected bookProvider: AddonModBookProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**

View File

@ -12,8 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModChoiceProvider } from './choice';
import { AddonModChoiceSyncProvider } from './sync';
@ -22,28 +29,18 @@ import { AddonModChoiceSyncProvider } from './sync';
* Handler to prefetch choices.
*/
@Injectable()
export class AddonModChoicePrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModChoicePrefetchHandler extends CoreCourseActivityPrefetchHandlerBase {
name = 'AddonModChoice';
modName = 'choice';
component = AddonModChoiceProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^answers$/;
constructor(protected injector: Injector, protected choiceProvider: AddonModChoiceProvider,
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected choiceProvider: AddonModChoiceProvider,
protected syncProvider: AddonModChoiceSyncProvider, protected userProvider: CoreUserProvider) {
super(injector);
}
/**
* Download the module.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @return {Promise<any>} Promise resolved when all content is downloaded.
*/
download(module: any, courseId: number, dirPath?: string): Promise<any> {
// Same implementation for download or prefetch.
return this.prefetch(module, courseId, false, dirPath);
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**
@ -52,7 +49,7 @@ export class AddonModChoicePrefetchHandler extends CoreCourseModulePrefetchHandl
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {
@ -137,13 +134,4 @@ export class AddonModChoicePrefetchHandler extends CoreCourseModulePrefetchHandl
invalidateModule(module: any, courseId: number): Promise<any> {
return this.choiceProvider.invalidateChoiceData(courseId);
}
/**
* Whether or not the handler is enabled on a site level.
*
* @return {boolean|Promise<boolean>} A boolean, or a promise resolved with a boolean, indicating if the handler is enabled.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
}

View File

@ -12,13 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreGroupsProvider } from '@providers/groups';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreCommentsProvider } from '@core/comments/providers/comments';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { AddonModDataProvider } from './data';
import { AddonModDataHelperProvider } from './helper';
@ -26,63 +31,19 @@ import { AddonModDataHelperProvider } from './helper';
* Handler to prefetch databases.
*/
@Injectable()
export class AddonModDataPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModDataPrefetchHandler extends CoreCourseActivityPrefetchHandlerBase {
name = 'AddonModData';
modName = 'data';
component = AddonModDataProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^entries$|^gradeitems$|^outcomes$|^comments$|^ratings/;
constructor(injector: Injector, protected dataProvider: AddonModDataProvider, protected timeUtils: CoreTimeUtilsProvider,
protected filepoolProvider: CoreFilepoolProvider, protected dataHelper: AddonModDataHelperProvider,
protected groupsProvider: CoreGroupsProvider, protected commentsProvider: CoreCommentsProvider,
protected courseProvider: CoreCourseProvider) {
super(injector);
}
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected dataProvider: AddonModDataProvider,
protected timeUtils: CoreTimeUtilsProvider, protected dataHelper: AddonModDataHelperProvider,
protected groupsProvider: CoreGroupsProvider, protected commentsProvider: CoreCommentsProvider) {
/**
* Download or prefetch the content.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {boolean} [prefetch] True to prefetch, false to download right away.
* @param {string} [dirPath] Path of the directory where to store all the content files. This is to keep the files
* relative paths and make the package work in an iframe. Undefined to download the files
* in the filepool root data.
* @return {Promise<any>} Promise resolved when all content is downloaded. Data returned is not reliable.
*/
downloadOrPrefetch(module: any, courseId: number, prefetch?: boolean, dirPath?: string): Promise<any> {
const promises = [],
siteId = this.sitesProvider.getCurrentSiteId();
promises.push(super.downloadOrPrefetch(module, courseId, prefetch));
promises.push(this.getDatabaseInfoHelper(module, courseId, false, false, true, siteId).then((info) => {
// Prefetch the database data.
const database = info.database,
promises = [];
promises.push(this.dataProvider.getFields(database.id, false, true, siteId));
promises.push(this.filepoolProvider.addFilesToQueue(siteId, info.files, this.component, module.id));
info.groups.forEach((group) => {
promises.push(this.dataProvider.getDatabaseAccessInformation(database.id, group.id, false, true, siteId));
});
info.entries.forEach((entry) => {
promises.push(this.dataProvider.getEntry(database.id, entry.id, siteId));
if (database.comments) {
promises.push(this.commentsProvider.getComments('module', database.coursemodule, 'mod_data', entry.id,
'database_entry', 0, siteId));
}
});
// Add Basic Info to manage links.
promises.push(this.courseProvider.getModuleBasicInfoByInstance(database.id, 'data', siteId));
return Promise.all(promises);
}));
return Promise.all(promises);
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**
@ -282,4 +243,56 @@ export class AddonModDataPrefetchHandler extends CoreCourseModulePrefetchHandler
isEnabled(): boolean | Promise<boolean> {
return this.dataProvider.isPluginEnabled();
}
/**
* Prefetch a module.
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {
return this.prefetchPackage(module, courseId, single, this.prefetchDatabase.bind(this));
}
/**
* Prefetch a database.
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} single True if we're downloading a single module, false if we're downloading a whole section.
* @param {String} siteId Site ID.
* @return {Promise<any>} Promise resolved when done.
*/
protected prefetchDatabase(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
return this.getDatabaseInfoHelper(module, courseId, false, false, true, siteId).then((info) => {
// Prefetch the database data.
const database = info.database,
promises = [];
promises.push(this.dataProvider.getFields(database.id, false, true, siteId));
promises.push(this.filepoolProvider.addFilesToQueue(siteId, info.files, this.component, module.id));
info.groups.forEach((group) => {
promises.push(this.dataProvider.getDatabaseAccessInformation(database.id, group.id, false, true, siteId));
});
info.entries.forEach((entry) => {
promises.push(this.dataProvider.getEntry(database.id, entry.id, siteId));
if (database.comments) {
promises.push(this.commentsProvider.getComments('module', database.coursemodule, 'mod_data', entry.id,
'database_entry', 0, siteId));
}
});
// Add Basic Info to manage links.
promises.push(this.courseProvider.getModuleBasicInfoByInstance(database.id, 'data', siteId));
return Promise.all(promises);
});
}
}

View File

@ -12,11 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { AddonModFeedbackProvider } from './feedback';
import { AddonModFeedbackHelperProvider } from './helper';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreGroupsProvider } from '@providers/groups';
import { CoreUserProvider } from '@core/user/providers/user';
@ -25,101 +31,19 @@ import { CoreUserProvider } from '@core/user/providers/user';
* Handler to prefetch feedbacks.
*/
@Injectable()
export class AddonModFeedbackPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchHandlerBase {
name = 'AddonModFeedback';
modName = 'feedback';
component = AddonModFeedbackProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^attemptsfinished|^attemptsunfinished$/;
constructor(injector: Injector, protected feedbackProvider: AddonModFeedbackProvider, protected userProvider: CoreUserProvider,
protected filepoolProvider: CoreFilepoolProvider, protected feedbackHelper: AddonModFeedbackHelperProvider,
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected feedbackProvider: AddonModFeedbackProvider,
protected userProvider: CoreUserProvider, protected feedbackHelper: AddonModFeedbackHelperProvider,
protected timeUtils: CoreTimeUtilsProvider, protected groupsProvider: CoreGroupsProvider) {
super(injector);
}
/**
* Download or prefetch the content.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {boolean} [prefetch] True to prefetch, false to download right away.
* @param {string} [dirPath] Path of the directory where to store all the content files. This is to keep the files
* relative paths and make the package work in an iframe. Undefined to download the files
* in the filepool root feedback.
* @return {Promise<any>} Promise resolved when all content is downloaded. Data returned is not reliable.
*/
downloadOrPrefetch(module: any, courseId: number, prefetch?: boolean, dirPath?: string): Promise<any> {
const promises = [],
siteId = this.sitesProvider.getCurrentSiteId();
promises.push(super.downloadOrPrefetch(module, courseId, prefetch));
promises.push(this.feedbackProvider.getFeedback(courseId, module.id).then((feedback) => {
const p1 = [];
p1.push(this.getFiles(module, courseId).then((files) => {
return this.filepoolProvider.addFilesToQueue(siteId, files, this.component, module.id);
}));
p1.push(this.feedbackProvider.getFeedbackAccessInformation(feedback.id, false, true, siteId).then((accessData) => {
const p2 = [];
if (accessData.canedititems || accessData.canviewreports) {
// Get all groups analysis.
p2.push(this.feedbackProvider.getAnalysis(feedback.id, undefined, siteId));
p2.push(this.groupsProvider.getActivityGroupInfo(feedback.coursemodule, true, undefined, siteId)
.then((groupInfo) => {
const p3 = [],
userIds = [];
if (!groupInfo.groups || groupInfo.groups.length == 0) {
groupInfo.groups = [{id: 0}];
}
groupInfo.groups.forEach((group) => {
p3.push(this.feedbackProvider.getAnalysis(feedback.id, group.id, siteId));
p3.push(this.feedbackProvider.getAllResponsesAnalysis(feedback.id, group.id, siteId)
.then((responses) => {
responses.attempts.forEach((attempt) => {
userIds.push(attempt.userid);
});
}));
if (!accessData.isanonymous) {
p3.push(this.feedbackProvider.getAllNonRespondents(feedback.id, group.id, siteId)
.then((responses) => {
responses.users.forEach((user) => {
userIds.push(user.userid);
});
}));
}
});
return Promise.all(p3).then(() => {
// Prefetch user profiles.
return this.userProvider.prefetchProfiles(userIds, courseId, siteId);
});
}));
}
p2.push(this.feedbackProvider.getItems(feedback.id, siteId));
if (accessData.cancomplete && accessData.cansubmit && !accessData.isempty) {
// Send empty data, so it will recover last completed feedback attempt values.
p2.push(this.feedbackProvider.processPageOnline(feedback.id, 0, {}, undefined, siteId).finally(() => {
const p4 = [];
p4.push(this.feedbackProvider.getCurrentValues(feedback.id, false, true, siteId));
p4.push(this.feedbackProvider.getResumePage(feedback.id, false, true, siteId));
return Promise.all(p4);
}));
}
return Promise.all(p2);
}));
return Promise.all(p1);
}));
return Promise.all(promises);
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**
@ -224,4 +148,95 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseModulePrefetchHan
isEnabled(): boolean | Promise<boolean> {
return this.feedbackProvider.isPluginEnabled();
}
/**
* Prefetch a module.
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {
return this.prefetchPackage(module, courseId, single, this.prefetchFeedback.bind(this));
}
/**
* Prefetch a feedback.
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} single True if we're downloading a single module, false if we're downloading a whole section.
* @param {String} siteId Site ID.
* @return {Promise<any>} Promise resolved when done.
*/
protected prefetchFeedback(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
// Prefetch the feedback data.
return this.feedbackProvider.getFeedback(courseId, module.id).then((feedback) => {
const p1 = [];
p1.push(this.getFiles(module, courseId).then((files) => {
return this.filepoolProvider.addFilesToQueue(siteId, files, this.component, module.id);
}));
p1.push(this.feedbackProvider.getFeedbackAccessInformation(feedback.id, false, true, siteId).then((accessData) => {
const p2 = [];
if (accessData.canedititems || accessData.canviewreports) {
// Get all groups analysis.
p2.push(this.feedbackProvider.getAnalysis(feedback.id, undefined, siteId));
p2.push(this.groupsProvider.getActivityGroupInfo(feedback.coursemodule, true, undefined, siteId)
.then((groupInfo) => {
const p3 = [],
userIds = [];
if (!groupInfo.groups || groupInfo.groups.length == 0) {
groupInfo.groups = [{id: 0}];
}
groupInfo.groups.forEach((group) => {
p3.push(this.feedbackProvider.getAnalysis(feedback.id, group.id, siteId));
p3.push(this.feedbackProvider.getAllResponsesAnalysis(feedback.id, group.id, siteId)
.then((responses) => {
responses.attempts.forEach((attempt) => {
userIds.push(attempt.userid);
});
}));
if (!accessData.isanonymous) {
p3.push(this.feedbackProvider.getAllNonRespondents(feedback.id, group.id, siteId)
.then((responses) => {
responses.users.forEach((user) => {
userIds.push(user.userid);
});
}));
}
});
return Promise.all(p3).then(() => {
// Prefetch user profiles.
return this.userProvider.prefetchProfiles(userIds, courseId, siteId);
});
}));
}
p2.push(this.feedbackProvider.getItems(feedback.id, siteId));
if (accessData.cancomplete && accessData.cansubmit && !accessData.isempty) {
// Send empty data, so it will recover last completed feedback attempt values.
p2.push(this.feedbackProvider.processPageOnline(feedback.id, 0, {}, undefined, siteId).finally(() => {
const p4 = [];
p4.push(this.feedbackProvider.getCurrentValues(feedback.id, false, true, siteId));
p4.push(this.feedbackProvider.getResumePage(feedback.id, false, true, siteId));
return Promise.all(p4);
}));
}
return Promise.all(p2);
}));
return Promise.all(p1);
});
}
}

View File

@ -12,22 +12,31 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler';
import { AddonModFolderProvider } from './folder';
/**
* Handler to prefetch folders.
*/
@Injectable()
export class AddonModFolderPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModFolderPrefetchHandler extends CoreCourseResourcePrefetchHandlerBase {
name = 'AddonModFolder';
modName = 'folder';
component = AddonModFolderProvider.COMPONENT;
isResource = true;
constructor(injector: Injector, protected folderProvider: AddonModFolderProvider) {
super(injector);
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected folderProvider: AddonModFolderProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**

View File

@ -12,8 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { CoreGroupsProvider } from '@providers/groups';
import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModForumProvider } from './forum';
@ -22,30 +29,24 @@ import { AddonModForumProvider } from './forum';
* Handler to prefetch forums.
*/
@Injectable()
export class AddonModForumPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHandlerBase {
name = 'AddonModForum';
modName = 'forum';
component = AddonModForumProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^discussions$/;
constructor(injector: Injector,
constructor(translate: TranslateService,
appProvider: CoreAppProvider,
utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider,
filepoolProvider: CoreFilepoolProvider,
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
private groupsProvider: CoreGroupsProvider,
private userProvider: CoreUserProvider,
private forumProvider: AddonModForumProvider) {
super(injector);
}
/**
* Download the module.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @return {Promise<any>} Promise resolved when all content is downloaded.
*/
download(module: any, courseId: number, dirPath?: string): Promise<any> {
// Same implementation for download or prefetch.
return this.prefetch(module, courseId, false, dirPath);
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**
@ -137,7 +138,7 @@ export class AddonModForumPrefetchHandler extends CoreCourseModulePrefetchHandle
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {

View File

@ -12,8 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModGlossaryProvider } from './glossary';
@ -21,29 +28,23 @@ import { AddonModGlossaryProvider } from './glossary';
* Handler to prefetch forums.
*/
@Injectable()
export class AddonModGlossaryPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchHandlerBase {
name = 'AddonModGlossary';
modName = 'glossary';
component = AddonModGlossaryProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^entries$/;
constructor(injector: Injector,
constructor(translate: TranslateService,
appProvider: CoreAppProvider,
utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider,
filepoolProvider: CoreFilepoolProvider,
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
private userProvider: CoreUserProvider,
private glossaryProvider: AddonModGlossaryProvider) {
super(injector);
}
/**
* Download the module.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @return {Promise<any>} Promise resolved when all content is downloaded.
*/
download(module: any, courseId: number, dirPath?: string): Promise<any> {
// Glossaries cannot be downloaded right away, only prefetched.
return this.prefetch(module, courseId);
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**
@ -102,7 +103,7 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseModulePrefetchHan
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {

View File

@ -12,36 +12,31 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler';
import { AddonModImscpProvider } from './imscp';
/**
* Handler to prefetch IMSCPs.
*/
@Injectable()
export class AddonModImscpPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModImscpPrefetchHandler extends CoreCourseResourcePrefetchHandlerBase {
name = 'AddonModImscp';
modName = 'imscp';
component = AddonModImscpProvider.COMPONENT;
isResource = true;
constructor(injector: Injector, protected imscpProvider: AddonModImscpProvider,
protected filepoolProvider: CoreFilepoolProvider) {
super(injector);
}
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected imscpProvider: AddonModImscpProvider) {
/**
* Download the module.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @return {Promise<any>} Promise resolved when all content is downloaded.
*/
download(module: any, courseId: number, dirPath?: string): Promise<any> {
return this.prefetch(module, courseId, false, dirPath);
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**

View File

@ -17,6 +17,7 @@ import { IonicPageModule } from 'ionic-angular';
import { AddonModLessonPasswordModalPage } from './password-modal';
import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [
@ -24,6 +25,7 @@ import { CoreComponentsModule } from '@components/components.module';
],
imports: [
CoreComponentsModule,
CoreDirectivesModule,
IonicPageModule.forChild(AddonModLessonPasswordModalPage),
TranslateModule.forChild()
]

View File

@ -12,26 +12,36 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { Injectable } from '@angular/core';
import { ModalController } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreGroupsProvider } from '@providers/groups';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { AddonModLessonProvider } from './lesson';
/**
* Handler to prefetch lessons.
*/
@Injectable()
export class AddonModLessonPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHandlerBase {
name = 'AddonModLesson';
modName = 'lesson';
component = AddonModLessonProvider.COMPONENT;
// Don't check timers to decrease positives. If a user performs some action it will be reflected in other items.
updatesNames = /^configuration$|^.*files$|^grades$|^gradeitems$|^pages$|^answers$|^questionattempts$|^pagesviewed$/;
constructor(protected injector: Injector, protected modalCtrl: ModalController, protected groupsProvider: CoreGroupsProvider,
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected modalCtrl: ModalController, protected groupsProvider: CoreGroupsProvider,
protected lessonProvider: AddonModLessonProvider) {
super(injector);
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**
@ -58,19 +68,6 @@ export class AddonModLessonPrefetchHandler extends CoreCourseModulePrefetchHandl
});
}
/**
* Download the module.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @return {Promise<any>} Promise resolved when all content is downloaded.
*/
download(module: any, courseId: number, dirPath?: string): Promise<any> {
// Same implementation for download and prefetch.
return this.prefetch(module, courseId, false, dirPath);
}
/**
* Get the download size of a module.
*
@ -112,18 +109,6 @@ export class AddonModLessonPrefetchHandler extends CoreCourseModulePrefetchHandl
});
}
/**
* Get list of files. If not defined, we'll assume they're in module.contents.
*
* @param {any} module Module.
* @param {Number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @return {Promise<any[]>} Promise resolved with the list of files.
*/
getFiles(module: any, courseId: number, single?: boolean): Promise<any[]> {
return Promise.resolve([]);
}
/**
* Get the lesson password if needed. If not stored, it can ask the user to enter it.
*
@ -254,7 +239,7 @@ export class AddonModLessonPrefetchHandler extends CoreCourseModulePrefetchHandl
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {

View File

@ -12,9 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler';
import { AddonModPageProvider } from './page';
import { AddonModPageHelperProvider } from './helper';
@ -22,16 +28,18 @@ import { AddonModPageHelperProvider } from './helper';
* Handler to prefetch pages.
*/
@Injectable()
export class AddonModPagePrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModPagePrefetchHandler extends CoreCourseResourcePrefetchHandlerBase {
name = 'AddonModPage';
modName = 'page';
component = AddonModPageProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$/;
isResource = true;
constructor(injector: Injector, protected pageProvider: AddonModPageProvider, protected utils: CoreUtilsProvider,
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected pageProvider: AddonModPageProvider,
protected pageHelper: AddonModPageHelperProvider) {
super(injector);
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**

View File

@ -13,9 +13,16 @@
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreQuestionHelperProvider } from '@core/question/providers/helper';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { AddonModQuizProvider } from './quiz';
import { AddonModQuizHelperProvider } from './helper';
import { AddonModQuizAccessRuleDelegate } from './access-rules-delegate';
@ -26,7 +33,7 @@ import { CoreConstants } from '@core/constants';
* Handler to prefetch quizzes.
*/
@Injectable()
export class AddonModQuizPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandlerBase {
name = 'AddonModQuiz';
modName = 'quiz';
component = AddonModQuizProvider.COMPONENT;
@ -34,23 +41,13 @@ export class AddonModQuizPrefetchHandler extends CoreCourseModulePrefetchHandler
protected syncProvider: AddonModQuizSyncProvider; // It will be injected later to prevent circular dependencies.
constructor(protected injector: Injector, protected quizProvider: AddonModQuizProvider,
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected injector: Injector, protected quizProvider: AddonModQuizProvider,
protected textUtils: CoreTextUtilsProvider, protected quizHelper: AddonModQuizHelperProvider,
protected accessRuleDelegate: AddonModQuizAccessRuleDelegate, protected questionHelper: CoreQuestionHelperProvider) {
super(injector);
}
/**
* Download the module.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @return {Promise<any>} Promise resolved when all content is downloaded.
*/
download(module: any, courseId: number, dirPath?: string): Promise<any> {
// Same implementation for download or prefetch.
return this.prefetch(module, courseId, false, dirPath);
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**
@ -69,18 +66,6 @@ export class AddonModQuizPrefetchHandler extends CoreCourseModulePrefetchHandler
});
}
/**
* Get list of files. If not defined, we'll assume they're in module.contents.
*
* @param {any} module Module.
* @param {Number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @return {Promise<any[]>} Promise resolved with the list of files.
*/
getFiles(module: any, courseId: number, single?: boolean): Promise<any[]> {
return Promise.resolve([]);
}
/**
* Gather some preflight data for an attempt. This function will start a new attempt if needed.
*
@ -190,7 +175,7 @@ export class AddonModQuizPrefetchHandler extends CoreCourseModulePrefetchHandler
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {

View File

@ -12,25 +12,33 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler';
import { AddonModResourceProvider } from './resource';
import { AddonModResourceHelperProvider } from './helper';
import { CoreFilepoolProvider } from '@providers/filepool';
/**
* Handler to prefetch resources.
*/
@Injectable()
export class AddonModResourcePrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModResourcePrefetchHandler extends CoreCourseResourcePrefetchHandlerBase {
name = 'AddonModResource';
modName = 'resource';
component = AddonModResourceProvider.COMPONENT;
isResource = true;
constructor(injector: Injector, protected resourceProvider: AddonModResourceProvider,
protected filepoolProvider: CoreFilepoolProvider, protected resourceHelper: AddonModResourceHelperProvider) {
super(injector);
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected resourceProvider: AddonModResourceProvider,
protected resourceHelper: AddonModResourceHelperProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**

View File

@ -12,10 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreFileProvider } from '@providers/file';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { AddonModScormProvider } from './scorm';
/**
@ -45,15 +52,18 @@ export interface AddonModScormProgressEvent {
* Handler to prefetch SCORMs.
*/
@Injectable()
export class AddonModScormPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModScormPrefetchHandler extends CoreCourseActivityPrefetchHandlerBase {
name = 'AddonModScorm';
modName = 'scorm';
component = AddonModScormProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^tracks$/;
constructor(injector: Injector, protected fileProvider: CoreFileProvider, protected textUtils: CoreTextUtilsProvider,
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected fileProvider: CoreFileProvider, protected textUtils: CoreTextUtilsProvider,
protected scormProvider: AddonModScormProvider) {
super(injector);
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**
@ -359,15 +369,6 @@ export class AddonModScormPrefetchHandler extends CoreCourseModulePrefetchHandle
});
}
/**
* Whether or not the handler is enabled on a site level.
*
* @return {boolean|Promise<boolean>} A boolean, or a promise resolved with a boolean, indicating if the handler is enabled.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
/**
* Prefetch a module.
*

View File

@ -12,8 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { AddonModSurveyProvider } from './survey';
import { AddonModSurveyHelperProvider } from './helper';
@ -21,40 +28,18 @@ import { AddonModSurveyHelperProvider } from './helper';
* Handler to prefetch surveys.
*/
@Injectable()
export class AddonModSurveyPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModSurveyPrefetchHandler extends CoreCourseActivityPrefetchHandlerBase {
name = 'AddonModSurvey';
modName = 'survey';
component = AddonModSurveyProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^answers$/;
constructor(injector: Injector, protected surveyProvider: AddonModSurveyProvider,
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected surveyProvider: AddonModSurveyProvider,
protected surveyHelper: AddonModSurveyHelperProvider) {
super(injector);
}
/**
* Download or prefetch the content.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {boolean} [prefetch] True to prefetch, false to download right away.
* @param {string} [dirPath] Path of the directory where to store all the content files. This is to keep the files
* relative paths and make the package work in an iframe. Undefined to download the files
* in the filepool root survey.
* @return {Promise<any>} Promise resolved when all content is downloaded. Data returned is not reliable.
*/
downloadOrPrefetch(module: any, courseId: number, prefetch?: boolean, dirPath?: string): Promise<any> {
const promises = [];
promises.push(super.downloadOrPrefetch(module, courseId, prefetch));
promises.push(this.surveyProvider.getSurvey(courseId, module.id).then((survey) => {
// If survey isn't answered, prefetch the questions.
if (!survey.surveydone) {
promises.push(this.surveyProvider.getQuestions(survey.id));
}
}));
return Promise.all(promises);
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**
@ -102,4 +87,43 @@ export class AddonModSurveyPrefetchHandler extends CoreCourseModulePrefetchHandl
isEnabled(): boolean | Promise<boolean> {
return true;
}
/**
* Prefetch a module.
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {
return this.prefetchPackage(module, courseId, single, this.prefetchSurvey.bind(this));
}
/**
* Prefetch a survey.
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} single True if we're downloading a single module, false if we're downloading a whole section.
* @param {String} siteId Site ID.
* @return {Promise<any>} Promise resolved when done.
*/
protected prefetchSurvey(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
return this.surveyProvider.getSurvey(courseId, module.id).then((survey) => {
const promises = [],
files = this.getIntroFilesFromInstance(module, survey);
// Prefetch files.
promises.push(this.filepoolProvider.addFilesToQueue(siteId, files, AddonModSurveyProvider.COMPONENT, module.id));
// If survey isn't answered, prefetch the questions.
if (!survey.surveydone) {
promises.push(this.surveyProvider.getQuestions(survey.id));
}
return Promise.all(promises);
});
}
}

View File

@ -12,12 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreGroupsProvider } from '@providers/groups';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreGradesHelperProvider } from '@core/grades/providers/helper';
import { CoreUserProvider } from '@core/user/providers/user';
@ -27,31 +32,19 @@ import { AddonModWikiProvider } from './wiki';
* Handler to prefetch wikis.
*/
@Injectable()
export class AddonModWikiPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModWikiPrefetchHandler extends CoreCourseActivityPrefetchHandlerBase {
name = 'AddonModWiki';
modName = 'wiki';
component = AddonModWikiProvider.COMPONENT;
updatesNames = /^.*files$|^pages$/;
constructor(protected injector: Injector, protected wikiProvider: AddonModWikiProvider,
protected textUtils: CoreTextUtilsProvider, protected courseProvider: CoreCourseProvider,
protected courseHelper: CoreCourseHelperProvider, protected filepoolProvider: CoreFilepoolProvider,
protected groupsProvider: CoreGroupsProvider, protected gradesHelper: CoreGradesHelperProvider,
protected userProvider: CoreUserProvider) {
super(injector);
}
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected wikiProvider: AddonModWikiProvider, protected userProvider: CoreUserProvider,
protected textUtils: CoreTextUtilsProvider, protected courseHelper: CoreCourseHelperProvider,
protected groupsProvider: CoreGroupsProvider, protected gradesHelper: CoreGradesHelperProvider) {
/**
* Download the module.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @return {Promise<any>} Promise resolved when all content is downloaded.
*/
download(module: any, courseId: number, dirPath?: string): Promise<any> {
// Same implementation for download or prefetch.
return this.prefetch(module, courseId, false, dirPath);
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**
@ -156,7 +149,7 @@ export class AddonModWikiPrefetchHandler extends CoreCourseModulePrefetchHandler
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {

View File

@ -12,8 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { CoreGroupsProvider } from '@providers/groups';
import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModWorkshopProvider } from './workshop';
@ -23,32 +30,26 @@ import { AddonModWorkshopHelperProvider } from './helper';
* Handler to prefetch workshops.
*/
@Injectable()
export class AddonModWorkshopPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class AddonModWorkshopPrefetchHandler extends CoreCourseActivityPrefetchHandlerBase {
name = 'AddonModWorkshop';
modName = 'workshop';
component = AddonModWorkshopProvider.COMPONENT;
updatesNames = new RegExp('^configuration$|^.*files$|^completion|^gradeitems$|^outcomes$|^submissions$|^assessments$' +
'|^assessmentgrades$|^usersubmissions$|^userassessments$|^userassessmentgrades$|^userassessmentgrades$');
constructor(injector: Injector,
constructor(translate: TranslateService,
appProvider: CoreAppProvider,
utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider,
filepoolProvider: CoreFilepoolProvider,
sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider,
private groupsProvider: CoreGroupsProvider,
private userProvider: CoreUserProvider,
private workshopProvider: AddonModWorkshopProvider,
private workshopHelper: AddonModWorkshopHelperProvider) {
super(injector);
}
/**
* Download the module.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @return {Promise<any>} Promise resolved when all content is downloaded.
*/
download(module: any, courseId: number, dirPath?: string): Promise<any> {
// Workshop cannot be downloaded right away, only prefetched.
return this.prefetch(module, courseId, false, dirPath);
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
}
/**
@ -210,7 +211,7 @@ export class AddonModWorkshopPrefetchHandler extends CoreCourseModulePrefetchHan
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {

View File

@ -56,7 +56,8 @@ import { CoreDelegate } from '@classes/delegate';
import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler';
import { CoreContentLinksModuleGradeHandler } from '@core/contentlinks/classes/module-grade-handler';
import { CoreContentLinksModuleIndexHandler } from '@core/contentlinks/classes/module-index-handler';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { CoreCourseResourcePrefetchHandlerBase } from '@core/course/classes/resource-prefetch-handler';
// Import all core modules that define components, directives and pipes.
import { CoreComponentsModule } from '@components/components.module';
@ -257,7 +258,8 @@ export class CoreCompileProvider {
instance['CoreContentLinksHandlerBase'] = CoreContentLinksHandlerBase;
instance['CoreContentLinksModuleGradeHandler'] = CoreContentLinksModuleGradeHandler;
instance['CoreContentLinksModuleIndexHandler'] = CoreContentLinksModuleIndexHandler;
instance['CoreCourseModulePrefetchHandlerBase'] = CoreCourseModulePrefetchHandlerBase;
instance['CoreCourseActivityPrefetchHandlerBase'] = CoreCourseActivityPrefetchHandlerBase;
instance['CoreCourseResourcePrefetchHandlerBase'] = CoreCourseResourcePrefetchHandlerBase;
instance['CoreCourseUnsupportedModuleComponent'] = CoreCourseUnsupportedModuleComponent;
instance['CoreCourseFormatSingleActivityComponent'] = CoreCourseFormatSingleActivityComponent;
instance['CoreSitePluginsModuleIndexComponent'] = CoreSitePluginsModuleIndexComponent;

View File

@ -0,0 +1,165 @@
// (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 { CoreConstants } from '../../constants';
import { CoreCourseModulePrefetchHandlerBase } from './module-prefetch-handler';
/**
* A prefetch function to be passed to prefetchPackage.
* This function should NOT call storePackageStatus, downloadPackage or prefetchPakage from filepool.
* It receives the same params as prefetchPackage except the function itself. This includes all extra parameters sent after siteId.
* The string returned by this function will be stored as "extra" data in the filepool package. If you don't need to store
* extra data, don't return anything.
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} single True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} siteId Site ID. If not defined, current site.
* @return {Promise<string>} Promise resolved when the prefetch finishes. The string returned will be stored as "extra" data in the
* filepool package. If you don't need to store extra data, don't return anything.
*/
export type prefetchFunction = (module: any, courseId: number, single: boolean, siteId: string, ...args: any[]) => Promise<string>;
/**
* Base prefetch handler to be registered in CoreCourseModulePrefetchDelegate. It is useful to minimize the amount of
* functions that handlers need to implement. It also provides some helper features like preventing a module to be
* downloaded twice at the same time.
*
* If your handler inherits from this service, you just need to override the functions that you want to change.
*
* This class should be used for ACTIVITIES. You must override the prefetch function, and it's recommended to call
* prefetchPackage in there since it handles the package status.
*/
export class CoreCourseActivityPrefetchHandlerBase extends CoreCourseModulePrefetchHandlerBase {
/**
* Download the module.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when all content is downloaded.
*/
download(module: any, courseId: number, dirPath?: string): Promise<any> {
// Same implementation for download and prefetch.
return this.prefetch(module, courseId, false, dirPath);
}
/**
* Prefetch a module.
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {
// To be overridden. It should call prefetchPackage
return Promise.resolve();
}
/**
* Prefetch the module, setting package status at start and finish.
*
* Example usage from a child instance:
* return this.prefetchPackage(module, courseId, single, this.prefetchModule.bind(this), siteId, someParam, anotherParam);
*
* Then the function "prefetchModule" will receive params:
* prefetchModule(module, courseId, single, siteId, someParam, anotherParam)
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {prefetchFunction} downloadFn Function to perform the prefetch. Please check the documentation of prefetchFunction.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when the module has been downloaded. Data returned is not reliable.
*/
prefetchPackage(module: any, courseId: number, single: boolean, downloadFn: prefetchFunction, siteId?: string, ...args: any[])
: Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
if (!this.appProvider.isOnline()) {
// Cannot prefetch in offline.
return Promise.reject(this.translate.instant('core.networkerrormsg'));
}
if (this.isDownloading(module.id, siteId)) {
// There's already a download ongoing for this module, return the promise.
return this.getOngoingDownload(module.id, siteId);
}
const prefetchPromise = this.setDownloading(module.id, siteId).then(() => {
// Package marked as downloading, call the download function.
// Send all the params except downloadFn. This includes all params passed after siteId.
return downloadFn.apply(downloadFn, [module, courseId, single, siteId].concat(args));
}).then((extra: any) => {
// Only accept string types.
if (typeof extra != 'string') {
extra = '';
}
// Prefetch finished, mark as downloaded.
return this.setDownloaded(module.id, siteId, extra);
}).catch((error) => {
// Error prefetching, go back to previous status and reject the promise.
return this.setPreviousStatusAndReject(module.id, error, siteId);
});
return this.addOngoingDownload(module.id, prefetchPromise, siteId);
}
/**
* Mark the module as downloaded.
*
* @param {number} id Unique identifier per component.
* @param {string} [siteId] Site ID. If not defined, current site.
* @param {string} [extra] Extra data to store.
* @return {Promise<any>} Promise resolved when done.
*/
setDownloaded(id: number, siteId?: string, extra?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.filepoolProvider.storePackageStatus(siteId, CoreConstants.DOWNLOADED, this.component, id, extra);
}
/**
* Mark the module as downloading.
*
* @param {number} id Unique identifier per component.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
setDownloading(id: number, siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.filepoolProvider.storePackageStatus(siteId, CoreConstants.DOWNLOADING, this.component, id);
}
/**
* Set previous status and return a rejected promise.
*
* @param {number} id Unique identifier per component.
* @param {any} [error] Error to return.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<never>} Rejected promise.
*/
setPreviousStatusAndReject(id: number, error?: any, siteId?: string): Promise<never> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.filepoolProvider.setPackagePreviousStatus(siteId, this.component, id).then(() => {
return Promise.reject(error);
});
}
}

View File

@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injector } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
@ -21,36 +20,11 @@ import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '../providers/course';
import { CoreCourseModulePrefetchHandler } from '../providers/module-prefetch-delegate';
import { CoreConstants } from '../../constants';
/**
* A prefetch function to be passed to prefetchPackage.
* This function should NOT call storePackageStatus, downloadPackage or prefetchPakage from filepool.
* It receives the same params as prefetchPackage except the function itself. This includes all extra parameters sent after siteId.
* The string returned by this function will be stored as "extra" data in the filepool package. If you don't need to store
* extra data, don't return anything.
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} single True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} siteId Site ID. If not defined, current site.
* @return {Promise<string>} Promise resolved when the prefetch finishes. The string returned will be stored as "extra" data in the
* filepool package. If you don't need to store extra data, don't return anything.
*/
export type prefetchFunction = (module: any, courseId: number, single: boolean, siteId: string, ...args: any[]) => Promise<string>;
/**
* Base prefetch handler to be registered in CoreCourseModulePrefetchDelegate. It is useful to minimize the amount of
* functions that handlers need to implement. It also provides some helper features like preventing a module to be
* downloaded twice at the same time.
*
* If your handler inherits from this service, you just need to override the functions that you want to change.
*
* The implementation of this default handler is aimed for resources that only need to prefetch files, not WebService calls.
*
* By default, prefetching a module will only download its files (downloadOrPrefetch). This might be enough for resources.
* If you need to prefetch WebServices, then you need to override the "download" and "prefetch" functions. In this case, it's
* recommended to call the prefetchPackage function since it'll handle changing the status of the module.
* Base prefetch handler to be registered in CoreCourseModulePrefetchDelegate. Prefetch handlers should inherit either
* from CoreCourseModuleActivityPrefetchHandlerBase or CoreCourseModuleResourcePrefetchHandlerBase, depending on whether
* they are an activity or a resource. It's not recommended to inherit from this class directly.
*/
export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePrefetchHandler {
/**
@ -78,37 +52,15 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
*/
updatesNames = /^.*files$/;
/**
* Whether the module is a resource (true) or an activity (false).
* @type {boolean}
*/
isResource: boolean;
/**
* List of download promises to prevent downloading the module twice at the same time.
* @type {{[s: string]: {[s: string]: Promise<any>}}}
*/
protected downloadPromises: { [s: string]: { [s: string]: Promise<any> } } = {};
// List of services that will be injected using injector.
// It's done like this so subclasses don't have to send all the services to the parent in the constructor.
protected translate: TranslateService;
protected appProvider: CoreAppProvider;
protected courseProvider: CoreCourseProvider;
protected filepoolProvider: CoreFilepoolProvider;
protected sitesProvider: CoreSitesProvider;
protected domUtils: CoreDomUtilsProvider;
protected utils: CoreUtilsProvider;
constructor(injector: Injector) {
this.translate = injector.get(TranslateService);
this.appProvider = injector.get(CoreAppProvider);
this.courseProvider = injector.get(CoreCourseProvider);
this.filepoolProvider = injector.get(CoreFilepoolProvider);
this.sitesProvider = injector.get(CoreSitesProvider);
this.domUtils = injector.get(CoreDomUtilsProvider);
this.utils = injector.get(CoreUtilsProvider);
}
constructor(protected translate: TranslateService, protected appProvider: CoreAppProvider, protected utils: CoreUtilsProvider,
protected courseProvider: CoreCourseProvider, protected filepoolProvider: CoreFilepoolProvider,
protected sitesProvider: CoreSitesProvider, protected domUtils: CoreDomUtilsProvider) { }
/**
* Add an ongoing download to the downloadPromises list. When the promise finishes it will be removed.
@ -139,57 +91,12 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when all content is downloaded.
*/
download(module: any, courseId: number, dirPath?: string): Promise<any> {
return this.downloadOrPrefetch(module, courseId, false, dirPath);
}
/**
* Download or prefetch the content.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {boolean} [prefetch] True to prefetch, false to download right away.
* @param {string} [dirPath] Path of the directory where to store all the content files. This is to keep the files
* relative paths and make the package work in an iframe. Undefined to download the files
* in the filepool root folder.
* @return {Promise<any>} Promise resolved when all content is downloaded. Data returned is not reliable.
*/
downloadOrPrefetch(module: any, courseId: number, prefetch?: boolean, dirPath?: string): Promise<any> {
if (!this.appProvider.isOnline()) {
// Cannot download in offline.
return Promise.reject(this.translate.instant('core.networkerrormsg'));
}
const siteId = this.sitesProvider.getCurrentSiteId();
// Load module contents (ignore cache so we always have the latest data).
return this.loadContents(module, courseId, true).then(() => {
// Get the intro files.
return this.getIntroFiles(module, courseId);
}).then((introFiles) => {
const downloadFn = prefetch ? this.filepoolProvider.prefetchPackage.bind(this.filepoolProvider) :
this.filepoolProvider.downloadPackage.bind(this.filepoolProvider),
contentFiles = this.getContentDownloadableFiles(module),
promises = [];
if (dirPath) {
// Download intro files in filepool root folder.
promises.push(this.filepoolProvider.downloadOrPrefetchFiles(siteId, introFiles, prefetch, false,
this.component, module.id));
// Download content files inside dirPath.
promises.push(downloadFn(siteId, contentFiles, this.component, module.id, undefined, dirPath));
} else {
// No dirPath, download everything in filepool root folder.
const files = introFiles.concat(contentFiles);
promises.push(downloadFn(siteId, files, this.component, module.id));
}
return Promise.all(promises);
});
// To be overridden.
return Promise.resolve();
}
/**
@ -251,12 +158,8 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* @return {Promise<any[]>} Promise resolved with the list of files.
*/
getFiles(module: any, courseId: number, single?: boolean): Promise<any[]> {
// Load module contents if needed.
return this.loadContents(module, courseId).then(() => {
return this.getIntroFiles(module, courseId).then((files) => {
return files.concat(this.getContentDownloadableFiles(module));
});
});
// To be overridden.
return Promise.resolve([]);
}
/**
@ -329,13 +232,8 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateContent(moduleId: number, courseId: number): Promise<any> {
const promises = [],
siteId = this.sitesProvider.getCurrentSiteId();
promises.push(this.courseProvider.invalidateModule(moduleId));
promises.push(this.filepoolProvider.invalidateFilesByComponent(siteId, this.component, moduleId));
return Promise.all(promises);
// To be overridden.
return Promise.resolve();
}
/**
@ -403,10 +301,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* @return {Promise} Promise resolved when loaded.
*/
loadContents(module: any, courseId: number, ignoreCache?: boolean): Promise<void> {
if (this.isResource) {
return this.courseProvider.loadModuleContents(module, courseId, undefined, false, ignoreCache);
}
// To be overridden.
return Promise.resolve();
}
@ -416,104 +311,12 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {
return this.downloadOrPrefetch(module, courseId, true, dirPath);
}
/**
* Prefetch the module, setting package status at start and finish.
*
* Example usage from a child instance:
* return this.prefetchPackage(module, courseId, single, this.prefetchModule.bind(this), siteId, someParam, anotherParam);
*
* Then the function "prefetchModule" will receive params:
* prefetchModule(module, courseId, single, siteId, someParam, anotherParam)
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {prefetchFunction} downloadFn Function to perform the prefetch. Please check the documentation of prefetchFunction.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when the module has been downloaded. Data returned is not reliable.
*/
prefetchPackage(module: any, courseId: number, single: boolean, downloadFn: prefetchFunction, siteId?: string, ...args: any[])
: Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
if (!this.appProvider.isOnline()) {
// Cannot prefetch in offline.
return Promise.reject(this.translate.instant('core.networkerrormsg'));
}
if (this.isDownloading(module.id, siteId)) {
// There's already a download ongoing for this module, return the promise.
return this.getOngoingDownload(module.id, siteId);
}
const prefetchPromise = this.setDownloading(module.id, siteId).then(() => {
// Package marked as downloading, call the download function.
// Send all the params except downloadFn. This includes all params passed after siteId.
return downloadFn.apply(downloadFn, [module, courseId, single, siteId].concat(args));
}).then((extra: any) => {
// Only accept string types.
if (typeof extra != 'string') {
extra = '';
}
// Prefetch finished, mark as downloaded.
return this.setDownloaded(module.id, siteId, extra);
}).catch((error) => {
// Error prefetching, go back to previous status and reject the promise.
return this.setPreviousStatusAndReject(module.id, error, siteId);
});
return this.addOngoingDownload(module.id, prefetchPromise, siteId);
}
/**
* Mark the module as downloaded.
*
* @param {number} id Unique identifier per component.
* @param {string} [siteId] Site ID. If not defined, current site.
* @param {string} [extra] Extra data to store.
* @return {Promise<any>} Promise resolved when done.
*/
setDownloaded(id: number, siteId?: string, extra?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.filepoolProvider.storePackageStatus(siteId, CoreConstants.DOWNLOADED, this.component, id, extra);
}
/**
* Mark the module as downloading.
*
* @param {number} id Unique identifier per component.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
setDownloading(id: number, siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.filepoolProvider.storePackageStatus(siteId, CoreConstants.DOWNLOADING, this.component, id);
}
/**
* Set previous status and return a rejected promise.
*
* @param {number} id Unique identifier per component.
* @param {any} [error] Error to return.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<never>} Rejected promise.
*/
setPreviousStatusAndReject(id: number, error?: any, siteId?: string): Promise<never> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.filepoolProvider.setPackagePreviousStatus(siteId, this.component, id).then(() => {
return Promise.reject(error);
});
// To be overridden.
return Promise.resolve();
}
/**

View File

@ -0,0 +1,151 @@
// (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 { CoreCourseModulePrefetchHandlerBase } from './module-prefetch-handler';
/**
* Base prefetch handler to be registered in CoreCourseModulePrefetchDelegate. It is useful to minimize the amount of
* functions that handlers need to implement. It also provides some helper features like preventing a module to be
* downloaded twice at the same time.
*
* If your handler inherits from this service, you just need to override the functions that you want to change.
*
* This class should be used for RESOURCES whose main purpose is downloading files present in module.contents.
*/
export class CoreCourseResourcePrefetchHandlerBase extends CoreCourseModulePrefetchHandlerBase {
/**
* Download the module.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when all content is downloaded.
*/
download(module: any, courseId: number, dirPath?: string): Promise<any> {
return this.downloadOrPrefetch(module, courseId, false, dirPath);
}
/**
* Download or prefetch the content.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {boolean} [prefetch] True to prefetch, false to download right away.
* @param {string} [dirPath] Path of the directory where to store all the content files. This is to keep the files
* relative paths and make the package work in an iframe. Undefined to download the files
* in the filepool root folder.
* @return {Promise<any>} Promise resolved when all content is downloaded. Data returned is not reliable.
*/
downloadOrPrefetch(module: any, courseId: number, prefetch?: boolean, dirPath?: string): Promise<any> {
if (!this.appProvider.isOnline()) {
// Cannot download in offline.
return Promise.reject(this.translate.instant('core.networkerrormsg'));
}
const siteId = this.sitesProvider.getCurrentSiteId();
if (this.isDownloading(module.id, siteId)) {
// There's already a download ongoing for this module, return the promise.
return this.getOngoingDownload(module.id, siteId);
}
// Load module contents (ignore cache so we always have the latest data).
const prefetchPromise = this.loadContents(module, courseId, true).then(() => {
// Get the intro files.
return this.getIntroFiles(module, courseId);
}).then((introFiles) => {
const downloadFn = prefetch ? this.filepoolProvider.prefetchPackage.bind(this.filepoolProvider) :
this.filepoolProvider.downloadPackage.bind(this.filepoolProvider),
contentFiles = this.getContentDownloadableFiles(module),
promises = [];
if (dirPath) {
// Download intro files in filepool root folder.
promises.push(this.filepoolProvider.downloadOrPrefetchFiles(siteId, introFiles, prefetch, false,
this.component, module.id));
// Download content files inside dirPath.
promises.push(downloadFn(siteId, contentFiles, this.component, module.id, undefined, dirPath));
} else {
// No dirPath, download everything in filepool root folder.
const files = introFiles.concat(contentFiles);
promises.push(downloadFn(siteId, files, this.component, module.id));
}
return Promise.all(promises);
});
return this.addOngoingDownload(module.id, prefetchPromise, siteId);
}
/**
* Get list of files. If not defined, we'll assume they're in module.contents.
*
* @param {any} module Module.
* @param {Number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @return {Promise<any[]>} Promise resolved with the list of files.
*/
getFiles(module: any, courseId: number, single?: boolean): Promise<any[]> {
// Load module contents if needed.
return this.loadContents(module, courseId).then(() => {
return this.getIntroFiles(module, courseId).then((files) => {
return files.concat(this.getContentDownloadableFiles(module));
});
});
}
/**
* Invalidate the prefetched content.
*
* @param {number} moduleId The module ID.
* @param {number} courseId The course ID the module belongs to.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateContent(moduleId: number, courseId: number): Promise<any> {
const promises = [],
siteId = this.sitesProvider.getCurrentSiteId();
promises.push(this.courseProvider.invalidateModule(moduleId));
promises.push(this.filepoolProvider.invalidateFilesByComponent(siteId, this.component, moduleId));
return Promise.all(promises);
}
/**
* Load module contents into module.contents if they aren't loaded already.
*
* @param {any} module Module to load the contents.
* @param {number} [courseId] The course ID. Recommended to speed up the process and minimize data usage.
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
* @return {Promise} Promise resolved when loaded.
*/
loadContents(module: any, courseId: number, ignoreCache?: boolean): Promise<void> {
return this.courseProvider.loadModuleContents(module, courseId, undefined, false, ignoreCache);
}
/**
* Prefetch a module.
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {
return this.downloadOrPrefetch(module, courseId, true, dirPath);
}
}

View File

@ -96,17 +96,20 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
this.courseIds = courseIds.join(',');
// Load course image of all the courses.
promises.push(this.coursesProvider.getCoursesByField('ids', this.courseIds).then((coursesInfo) => {
coursesInfo = this.utils.arrayToObject(coursesInfo, 'id');
courses.forEach((course) => {
if (coursesInfo[course.id] && coursesInfo[course.id].overviewfiles && coursesInfo[course.id].overviewfiles[0]) {
course.imageThumb = coursesInfo[course.id].overviewfiles[0].fileurl;
} else {
course.imageThumb = false;
}
});
}));
if (this.courseIds) {
// Load course image of all the courses.
promises.push(this.coursesProvider.getCoursesByField('ids', this.courseIds).then((coursesInfo) => {
coursesInfo = this.utils.arrayToObject(coursesInfo, 'id');
courses.forEach((course) => {
if (coursesInfo[course.id] && coursesInfo[course.id].overviewfiles &&
coursesInfo[course.id].overviewfiles[0]) {
course.imageThumb = coursesInfo[course.id].overviewfiles[0].fileurl;
} else {
course.imageThumb = false;
}
});
}));
}
promises.push(this.coursesProvider.getCoursesAdminAndNavOptions(courseIds).then((options) => {
courses.forEach((course) => {
@ -137,7 +140,9 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
promises.push(this.coursesProvider.invalidateUserCourses());
promises.push(this.courseOptionsDelegate.clearAndInvalidateCoursesOptions());
promises.push(this.coursesProvider.invalidateCoursesByField('ids', this.courseIds));
if (this.courseIds) {
promises.push(this.coursesProvider.invalidateCoursesByField('ids', this.courseIds));
}
Promise.all(promises).finally(() => {

View File

@ -217,17 +217,20 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
this.courseIds = courseIds.join(',');
// Load course image of all the courses.
promises.push(this.coursesProvider.getCoursesByField('ids', this.courseIds).then((coursesInfo) => {
coursesInfo = this.utils.arrayToObject(coursesInfo, 'id');
courses.forEach((course) => {
if (coursesInfo[course.id] && coursesInfo[course.id].overviewfiles && coursesInfo[course.id].overviewfiles[0]) {
course.imageThumb = coursesInfo[course.id].overviewfiles[0].fileurl;
} else {
course.imageThumb = false;
}
});
}));
if (this.courseIds) {
// Load course image of all the courses.
promises.push(this.coursesProvider.getCoursesByField('ids', this.courseIds).then((coursesInfo) => {
coursesInfo = this.utils.arrayToObject(coursesInfo, 'id');
courses.forEach((course) => {
if (coursesInfo[course.id] && coursesInfo[course.id].overviewfiles &&
coursesInfo[course.id].overviewfiles[0]) {
course.imageThumb = coursesInfo[course.id].overviewfiles[0].fileurl;
} else {
course.imageThumb = false;
}
});
}));
}
return Promise.all(promises).then(() => {
return courses.sort((a, b) => {
@ -286,7 +289,9 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
promises.push(this.coursesProvider.invalidateUserCourses());
promises.push(this.courseOptionsDelegate.clearAndInvalidateCoursesOptions());
promises.push(this.coursesProvider.invalidateCoursesByField('ids', this.courseIds));
if (this.courseIds) {
promises.push(this.coursesProvider.invalidateCoursesByField('ids', this.courseIds));
}
return Promise.all(promises).finally(() => {
switch (this.tabShown) {

View File

@ -12,19 +12,30 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injector } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreSitePluginsProvider } from '../../providers/siteplugins';
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
/**
* Handler to prefetch a module site plugin.
*/
export class CoreSitePluginsModulePrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
export class CoreSitePluginsModulePrefetchHandler extends CoreCourseActivityPrefetchHandlerBase {
protected ROOT_CACHE_KEY = 'CoreSitePluginsModulePrefetchHandler:';
constructor(injector: Injector, protected sitePluginsProvider: CoreSitePluginsProvider, component: string, name: string,
modName: string, protected handlerSchema: any) {
super(injector);
protected isResource: boolean;
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected sitePluginsProvider: CoreSitePluginsProvider, component: string,
name: string, modName: string, protected handlerSchema: any) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
this.component = component;
this.name = name;
@ -63,7 +74,7 @@ export class CoreSitePluginsModulePrefetchHandler extends CoreCourseModulePrefet
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
* @param {string} [siteId] Site ID. If not defined, current site.
* @param {boolean} [prefetch] True to prefetch, false to download right away.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
protected downloadPrefetchPlugin(module: any, courseId: number, single?: boolean, siteId?: string, prefetch?: boolean,
@ -94,7 +105,7 @@ export class CoreSitePluginsModulePrefetchHandler extends CoreCourseModulePrefet
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {boolean} [prefetch] True to prefetch, false to download right away.
* @param {string} [dirPath] Path of the directory where to store all the content files. @see downloadOrPrefetch.
* @param {string} [dirPath] Path of the directory where to store all the content files.
* @return {Promise<any>} Promise resolved when done.
*/
protected downloadOrPrefetchFiles(siteId: string, module: any, courseId: number, prefetch?: boolean, dirPath?: string)
@ -169,4 +180,20 @@ export class CoreSitePluginsModulePrefetchHandler extends CoreCourseModulePrefet
isEnabled(): boolean | Promise<boolean> {
return true;
}
/**
* Load module contents into module.contents if they aren't loaded already.
*
* @param {any} module Module to load the contents.
* @param {number} [courseId] The course ID. Recommended to speed up the process and minimize data usage.
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
* @return {Promise} Promise resolved when loaded.
*/
loadContents(module: any, courseId: number, ignoreCache?: boolean): Promise<void> {
if (this.isResource) {
return this.courseProvider.loadModuleContents(module, courseId, undefined, false, ignoreCache);
}
return Promise.resolve();
}
}

View File

@ -28,6 +28,7 @@ import { CoreSitePluginsQuestionBehaviourComponent } from './question-behaviour/
import { CoreSitePluginsQuizAccessRuleComponent } from './quiz-access-rule/quiz-access-rule';
import { CoreSitePluginsAssignFeedbackComponent } from './assign-feedback/assign-feedback';
import { CoreSitePluginsAssignSubmissionComponent } from './assign-submission/assign-submission';
import { CoreSitePluginsWorkshopAssessmentStrategyComponent } from './workshop-assessment-strategy/workshop-assessment-strategy';
@NgModule({
declarations: [
@ -40,7 +41,8 @@ import { CoreSitePluginsAssignSubmissionComponent } from './assign-submission/as
CoreSitePluginsQuestionBehaviourComponent,
CoreSitePluginsQuizAccessRuleComponent,
CoreSitePluginsAssignFeedbackComponent,
CoreSitePluginsAssignSubmissionComponent
CoreSitePluginsAssignSubmissionComponent,
CoreSitePluginsWorkshopAssessmentStrategyComponent
],
imports: [
CommonModule,
@ -61,7 +63,8 @@ import { CoreSitePluginsAssignSubmissionComponent } from './assign-submission/as
CoreSitePluginsQuestionBehaviourComponent,
CoreSitePluginsQuizAccessRuleComponent,
CoreSitePluginsAssignFeedbackComponent,
CoreSitePluginsAssignSubmissionComponent
CoreSitePluginsAssignSubmissionComponent,
CoreSitePluginsWorkshopAssessmentStrategyComponent
],
entryComponents: [
CoreSitePluginsModuleIndexComponent,
@ -72,7 +75,8 @@ import { CoreSitePluginsAssignSubmissionComponent } from './assign-submission/as
CoreSitePluginsQuestionBehaviourComponent,
CoreSitePluginsQuizAccessRuleComponent,
CoreSitePluginsAssignFeedbackComponent,
CoreSitePluginsAssignSubmissionComponent
CoreSitePluginsAssignSubmissionComponent,
CoreSitePluginsWorkshopAssessmentStrategyComponent
]
})
export class CoreSitePluginsComponentsModule {}

View File

@ -12,21 +12,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app';
import { CoreEventsProvider } from '@providers/events';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreLangProvider } from '@providers/lang';
import { CoreLoggerProvider } from '@providers/logger';
import { CoreSite } from '@classes/site';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreUrlUtilsProvider } from '@providers/utils/url';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreSitePluginsProvider } from './siteplugins';
import { CoreCompileProvider } from '@core/compile/providers/compile';
import { CoreQuestionProvider } from '@core/question/providers/question';
import { CoreCourseProvider } from '@core/course/providers/course';
// Delegates
import { CoreMainMenuDelegate } from '@core/mainmenu/providers/delegate';
@ -75,7 +78,7 @@ import { CoreSitePluginsWorkshopAssessmentStrategyHandler } from '../classes/han
export class CoreSitePluginsHelperProvider {
protected logger;
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private injector: Injector,
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private domUtils: CoreDomUtilsProvider,
private mainMenuDelegate: CoreMainMenuDelegate, private moduleDelegate: CoreCourseModuleDelegate,
private userDelegate: CoreUserDelegate, private langProvider: CoreLangProvider, private http: Http,
private sitePluginsProvider: CoreSitePluginsProvider, private prefetchDelegate: CoreCourseModulePrefetchDelegate,
@ -87,8 +90,9 @@ export class CoreSitePluginsHelperProvider {
private questionBehaviourDelegate: CoreQuestionBehaviourDelegate, private questionProvider: CoreQuestionProvider,
private messageOutputDelegate: AddonMessageOutputDelegate, private accessRulesDelegate: AddonModQuizAccessRuleDelegate,
private assignSubmissionDelegate: AddonModAssignSubmissionDelegate, private translate: TranslateService,
private assignFeedbackDelegate: AddonModAssignFeedbackDelegate,
private workshopAssessmentStrategyDelegate: AddonWorkshopAssessmentStrategyDelegate) {
private assignFeedbackDelegate: AddonModAssignFeedbackDelegate, private appProvider: CoreAppProvider,
private workshopAssessmentStrategyDelegate: AddonWorkshopAssessmentStrategyDelegate,
private courseProvider: CoreCourseProvider) {
this.logger = logger.getInstance('CoreSitePluginsHelperProvider');
@ -735,8 +739,9 @@ export class CoreSitePluginsHelperProvider {
if (handlerSchema.offlinefunctions && Object.keys(handlerSchema.offlinefunctions).length) {
// Register the prefetch handler.
this.prefetchDelegate.registerHandler(new CoreSitePluginsModulePrefetchHandler(
this.injector, this.sitePluginsProvider, plugin.component, uniqueName, modName, handlerSchema));
this.prefetchDelegate.registerHandler(new CoreSitePluginsModulePrefetchHandler(this.translate, this.appProvider,
this.utils, this.courseProvider, this.filepoolProvider, this.sitesProvider, this.domUtils,
this.sitePluginsProvider, plugin.component, uniqueName, modName, handlerSchema));
}
return modName;

View File

@ -57,6 +57,7 @@ export class CoreFormatTextDirective implements OnChanges {
protected tagsToIgnore = ['AUDIO', 'VIDEO', 'BUTTON', 'INPUT', 'SELECT', 'TEXTAREA', 'A'];
protected element: HTMLElement;
protected clickListener;
constructor(element: ElementRef, private sitesProvider: CoreSitesProvider, private domUtils: CoreDomUtilsProvider,
private textUtils: CoreTextUtilsProvider, private translate: TranslateService, private platform: Platform,
@ -156,6 +157,80 @@ export class CoreFormatTextDirective implements OnChanges {
container.appendChild(anchor);
}
/**
* Calculate the height and check if we need to display show more or not.
*/
protected calculateHeight(): void {
// Height cannot be calculated if the element is not shown while calculating.
// Force shorten if it was previously shortened.
// @todo: Work on calculate this height better.
const height = this.element.style.maxHeight ? 0 : this.getElementHeight(this.element);
// If cannot calculate height, shorten always.
if (!height || height > this.maxHeight) {
if (!this.clickListener) {
this.displayShowMore();
}
} else if (this.clickListener) {
this.hideShowMore();
}
}
/**
* Display the "Show more" in the element.
*/
protected displayShowMore(): void {
const expandInFullview = this.utils.isTrueOrOne(this.fullOnClick) || false,
showMoreDiv = document.createElement('div');
showMoreDiv.classList.add('core-show-more');
showMoreDiv.innerHTML = this.translate.instant('core.showmore');
this.element.appendChild(showMoreDiv);
if (expandInFullview) {
this.element.classList.add('core-expand-in-fullview');
}
this.element.classList.add('core-text-formatted');
this.element.classList.add('core-shortened');
this.element.style.maxHeight = this.maxHeight + 'px';
this.clickListener = this.elementClicked.bind(this, expandInFullview);
this.element.addEventListener('click', this.clickListener);
}
/**
* Listener to call when the element is clicked.
*
* @param {boolean} expandInFullview Whether to expand the text in a new view.
* @param {MouseEvent} e Click event.
*/
protected elementClicked(expandInFullview: boolean, e: MouseEvent): void {
if (e.defaultPrevented) {
// Ignore it if the event was prevented by some other listener.
return;
}
e.preventDefault();
e.stopPropagation();
const target = <HTMLElement> e.target;
if (this.tagsToIgnore.indexOf(target.tagName) === -1 || (target.tagName === 'A' &&
!target.getAttribute('href'))) {
if (!expandInFullview) {
// Change class.
this.element.classList.toggle('core-shortened');
return;
}
}
// Open a new state with the contents.
this.textUtils.expandText(this.fullTitle || this.translate.instant('core.description'), this.text,
this.component, this.componentId);
}
/**
* Finish the rendering, displaying the element again and calling afterRender.
*/
@ -188,53 +263,15 @@ export class CoreFormatTextDirective implements OnChanges {
// Move the children to the current element to be able to calculate the height.
this.domUtils.moveChildren(div, this.element);
// Height cannot be calculated if the element is not shown while calculating.
// Force shorten if it was previously shortened.
// @todo: Work on calculate this height better.
const height = this.element.style.maxHeight ? 0 : this.getElementHeight(this.element);
// Calculate the height now.
this.calculateHeight();
// If cannot calculate height, shorten always.
if (!height || height > this.maxHeight) {
const expandInFullview = this.utils.isTrueOrOne(this.fullOnClick) || false,
showMoreDiv = document.createElement('div');
showMoreDiv.classList.add('core-show-more');
showMoreDiv.innerHTML = this.translate.instant('core.showmore');
this.element.appendChild(showMoreDiv);
if (expandInFullview) {
this.element.classList.add('core-expand-in-fullview');
// Wait for images to load and calculate the height again if needed.
this.waitForImages().then((hasImgToLoad) => {
if (hasImgToLoad) {
this.calculateHeight();
}
this.element.classList.add('core-text-formatted');
this.element.classList.add('core-shortened');
this.element.style.maxHeight = this.maxHeight + 'px';
this.element.addEventListener('click', (e) => {
if (e.defaultPrevented) {
// Ignore it if the event was prevented by some other listener.
return;
}
e.preventDefault();
e.stopPropagation();
const target = <HTMLElement> e.target;
if (this.tagsToIgnore.indexOf(target.tagName) === -1 || (target.tagName === 'A' &&
!target.getAttribute('href'))) {
if (!expandInFullview) {
// Change class.
this.element.classList.toggle('core-shortened');
return;
}
}
// Open a new state with the contents.
this.textUtils.expandText(this.fullTitle || this.translate.instant('core.description'), this.text,
this.component, this.componentId);
});
}
});
} else {
this.domUtils.moveChildren(div, this.element);
}
@ -370,6 +407,25 @@ export class CoreFormatTextDirective implements OnChanges {
return this.domUtils.getElementHeight(element) || 0;
}
/**
* "Hide" the "Show more" in the element if it's shown.
*/
protected hideShowMore(): void {
const showMoreDiv = this.element.querySelector('div.core-show-more');
if (showMoreDiv) {
showMoreDiv.remove();
}
this.element.classList.remove('core-expand-in-fullview');
this.element.classList.remove('core-text-formatted');
this.element.classList.remove('core-shortened');
this.element.style.maxHeight = null;
this.element.removeEventListener('click', this.clickListener);
this.clickListener = null;
}
/**
* Treat video filters. Currently only treating youtube video using video JS.
*
@ -483,6 +539,39 @@ export class CoreFormatTextDirective implements OnChanges {
}
}
/**
* Wait for images to load.
*
* @return {Promise<boolean>} Promise resolved with a boolean: whether there was any image to load.
*/
protected waitForImages(): Promise<boolean> {
const imgs = Array.from(this.element.querySelectorAll('img')),
promises = [];
let hasImgToLoad = false;
imgs.forEach((img) => {
if (img && !img.complete) {
hasImgToLoad = true;
// Wait for image to load or fail.
promises.push(new Promise((resolve, reject): void => {
const imgLoaded = (): void => {
resolve();
img.removeEventListener('loaded', imgLoaded);
img.removeEventListener('error', imgLoaded);
};
img.addEventListener('load', imgLoaded);
img.addEventListener('error', imgLoaded);
}));
}
});
return Promise.all(promises).then(() => {
return hasImgToLoad;
});
}
/**
* Convenience function to extract YouTube Id to translate to embedded video.
* Based on http://stackoverflow.com/questions/3452546/javascript-regex-how-to-get-youtube-video-id-from-url