commit
c485afee02
|
@ -124,18 +124,8 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
this.selectedGroup = this.group || 0;
|
||||
|
||||
this.loadContent(false, true).then(() => {
|
||||
if (!this.data || !this.data.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dataProvider.logView(this.data.id, this.data.name).then(() => {
|
||||
this.courseProvider.checkModuleCompletion(this.courseId, this.module.completiondata);
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
return this.logView(true);
|
||||
});
|
||||
|
||||
// Setup search modal.
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -362,7 +352,10 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
this.loaded = false;
|
||||
this.search.page = page;
|
||||
|
||||
return this.fetchEntriesData().catch((message) => {
|
||||
return this.fetchEntriesData().then(() => {
|
||||
// Log activity view for coherence with Moodle web.
|
||||
return this.logView();
|
||||
}).catch((message) => {
|
||||
this.domUtils.showErrorModalDefault(message, 'core.course.errorgetmodule', true);
|
||||
}).finally(() => {
|
||||
this.loaded = true;
|
||||
|
@ -392,7 +385,10 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
this.selectedGroup = groupId;
|
||||
this.search.page = 0;
|
||||
|
||||
return this.fetchEntriesData().catch((message) => {
|
||||
return this.fetchEntriesData().then(() => {
|
||||
// Log activity view for coherence with Moodle web.
|
||||
return this.logView();
|
||||
}).catch((message) => {
|
||||
this.domUtils.showErrorModalDefault(message, 'core.course.errorgetmodule', true);
|
||||
|
||||
return Promise.reject(null);
|
||||
|
@ -454,6 +450,26 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
return result.updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log viewing the activity.
|
||||
*
|
||||
* @param checkCompletion Whether to check completion.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected logView(checkCompletion?: boolean): Promise<any> {
|
||||
if (!this.data || !this.data.id) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return this.dataProvider.logView(this.data.id, this.data.name).then(() => {
|
||||
if (checkCompletion) {
|
||||
this.courseProvider.checkModuleCompletion(this.courseId, this.module.completiondata);
|
||||
}
|
||||
}).catch(() => {
|
||||
// Ignore errors, the user could be offline.
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being destroyed.
|
||||
*/
|
||||
|
|
|
@ -96,7 +96,9 @@ export class AddonModDataEntryPage implements OnDestroy {
|
|||
*/
|
||||
ionViewDidLoad(): void {
|
||||
this.commentsEnabled = !this.commentsProvider.areCommentsDisabledInSite();
|
||||
this.fetchEntryData();
|
||||
this.fetchEntryData().then(() => {
|
||||
this.logView();
|
||||
});
|
||||
|
||||
// Refresh data if this discussion is synchronized automatically.
|
||||
this.syncObserver = this.eventsProvider.on(AddonModDataSyncProvider.AUTO_SYNCED, (data) => {
|
||||
|
@ -199,7 +201,9 @@ export class AddonModDataEntryPage implements OnDestroy {
|
|||
this.entry = null;
|
||||
this.entryLoaded = false;
|
||||
|
||||
return this.fetchEntryData();
|
||||
return this.fetchEntryData().then(() => {
|
||||
this.logView();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -258,7 +262,9 @@ export class AddonModDataEntryPage implements OnDestroy {
|
|||
this.entryId = null;
|
||||
this.entryLoaded = false;
|
||||
|
||||
return this.fetchEntryData();
|
||||
return this.fetchEntryData().then(() => {
|
||||
this.logView();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -363,6 +369,21 @@ export class AddonModDataEntryPage implements OnDestroy {
|
|||
this.dataProvider.invalidateEntryData(this.data.id, this.entryId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log viewing the activity.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected logView(): Promise<any> {
|
||||
if (!this.data || !this.data.id) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return this.dataProvider.logView(this.data.id, this.data.name).catch(() => {
|
||||
// Ignore errors, the user could be offline.
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being destroyed.
|
||||
*/
|
||||
|
|
|
@ -150,20 +150,25 @@ export class CoreFileUploaderProvider {
|
|||
* @return Options.
|
||||
*/
|
||||
getCameraUploadOptions(uri: string, isFromAlbum?: boolean): CoreFileUploaderOptions {
|
||||
const extension = this.mimeUtils.getExtension(uri),
|
||||
mimetype = this.mimeUtils.getMimeType(extension),
|
||||
isIOS = this.platform.is('ios'),
|
||||
options: CoreFileUploaderOptions = {
|
||||
const extension = this.mimeUtils.guessExtensionFromUrl(uri);
|
||||
const mimetype = this.mimeUtils.getMimeType(extension);
|
||||
const isIOS = this.platform.is('ios');
|
||||
const options: CoreFileUploaderOptions = {
|
||||
deleteAfterUpload: !isFromAlbum,
|
||||
mimeType: mimetype
|
||||
};
|
||||
const fileName = this.fileProvider.getFileAndDirectoryFromPath(uri).name;
|
||||
|
||||
if (isIOS && (mimetype == 'image/jpeg' || mimetype == 'image/png')) {
|
||||
// In iOS, the pictures can have repeated names, even if they come from the album.
|
||||
options.fileName = 'image_' + this.timeUtils.readableTimestamp() + '.' + extension;
|
||||
// Add a timestamp to the filename to make it unique.
|
||||
const split = fileName.split('.');
|
||||
split[0] += '_' + this.timeUtils.readableTimestamp();
|
||||
|
||||
options.fileName = split.join('.');
|
||||
} else {
|
||||
// Use the same name that the file already has.
|
||||
options.fileName = this.fileProvider.getFileAndDirectoryFromPath(uri).name;
|
||||
options.fileName = fileName;
|
||||
}
|
||||
|
||||
if (isFromAlbum) {
|
||||
|
|
|
@ -128,10 +128,12 @@ export class CoreFileUploaderHelperProvider {
|
|||
* @param defaultExt Defaut extension to use if the file doesn't have any.
|
||||
* @return Promise resolved with the copied file.
|
||||
*/
|
||||
protected copyToTmpFolder(path: string, shouldDelete: boolean, maxSize?: number, defaultExt?: string): Promise<any> {
|
||||
let fileName = this.fileProvider.getFileAndDirectoryFromPath(path).name,
|
||||
promise,
|
||||
fileTooLarge;
|
||||
protected copyToTmpFolder(path: string, shouldDelete: boolean, maxSize?: number, defaultExt?: string,
|
||||
options?: CoreFileUploaderOptions): Promise<any> {
|
||||
|
||||
const fileName = (options && options.fileName) || this.fileProvider.getFileAndDirectoryFromPath(path).name;
|
||||
let promise;
|
||||
let fileTooLarge;
|
||||
|
||||
// Check that size isn't too large.
|
||||
if (typeof maxSize != 'undefined' && maxSize != -1) {
|
||||
|
@ -154,9 +156,6 @@ export class CoreFileUploaderHelperProvider {
|
|||
}
|
||||
|
||||
// File isn't too large.
|
||||
// Picking an image from album in Android adds a timestamp at the end of the file. Delete it.
|
||||
fileName = fileName.replace(/(\.[^\.]*)\?[^\.]*$/, '$1');
|
||||
|
||||
// Get a unique name in the folder to prevent overriding another file.
|
||||
return this.fileProvider.getUniqueNameInFolder(CoreFileProvider.TMPFOLDER, fileName, defaultExt);
|
||||
}).then((newName) => {
|
||||
|
@ -468,11 +467,13 @@ export class CoreFileUploaderHelperProvider {
|
|||
path = 'file://' + path;
|
||||
}
|
||||
|
||||
const options = this.fileUploaderProvider.getMediaUploadOptions(media);
|
||||
|
||||
if (upload) {
|
||||
return this.uploadFile(path, maxSize, true, this.fileUploaderProvider.getMediaUploadOptions(media));
|
||||
return this.uploadFile(path, maxSize, true, options);
|
||||
} else {
|
||||
// Copy or move the file to our temporary folder.
|
||||
return this.copyToTmpFolder(path, true, maxSize);
|
||||
return this.copyToTmpFolder(path, true, maxSize, undefined, options);
|
||||
}
|
||||
}, (error) => {
|
||||
const defaultError = isAudio ? 'core.fileuploader.errorcapturingaudio' : 'core.fileuploader.errorcapturingvideo';
|
||||
|
@ -552,11 +553,13 @@ export class CoreFileUploaderHelperProvider {
|
|||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
const options = this.fileUploaderProvider.getCameraUploadOptions(path, fromAlbum);
|
||||
|
||||
if (upload) {
|
||||
return this.uploadFile(path, maxSize, true, this.fileUploaderProvider.getCameraUploadOptions(path, fromAlbum));
|
||||
return this.uploadFile(path, maxSize, true, options);
|
||||
} else {
|
||||
// Copy or move the file to our temporary folder.
|
||||
return this.copyToTmpFolder(path, !fromAlbum, maxSize, 'jpg');
|
||||
return this.copyToTmpFolder(path, !fromAlbum, maxSize, 'jpg', options);
|
||||
}
|
||||
}, (error) => {
|
||||
const defaultError = fromAlbum ? 'core.fileuploader.errorgettingimagealbum' : 'core.fileuploader.errorcapturingimage';
|
||||
|
|
|
@ -503,7 +503,7 @@ export class CoreH5PContentValidator {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Find semantics for name=$key
|
||||
// Find semantics for name=key.
|
||||
let found = false,
|
||||
fn = null,
|
||||
field = null;
|
||||
|
@ -729,7 +729,7 @@ export class CoreH5PContentValidator {
|
|||
}
|
||||
|
||||
if (slash != '') {
|
||||
return '</$elem>';
|
||||
return '</' + elem + '>';
|
||||
}
|
||||
|
||||
// Is there a closing XHTML slash at the end of the attributes?
|
||||
|
@ -871,8 +871,8 @@ export class CoreH5PContentValidator {
|
|||
* Processes an HTML attribute value and strips dangerous protocols from URLs.
|
||||
*
|
||||
* @param str The string with the attribute value.
|
||||
* @param decode Whether to decode entities in the $string.
|
||||
* @return Cleaned up and HTML-escaped version of $string.
|
||||
* @param decode Whether to decode entities in the str.
|
||||
* @return Cleaned up and HTML-escaped version of str.
|
||||
*/
|
||||
filterXssBadProtocol(str: string, decode: boolean = true): string {
|
||||
// Get the plain text representation of the attribute value (i.e. its meaning).
|
||||
|
|
Loading…
Reference in New Issue