MOBILE-2084 resource: Add filesize and type info
parent
e5a4fb3412
commit
3d8c68afb5
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
"errorwhileloadingthecontent": "Error while loading the content.",
|
"errorwhileloadingthecontent": "Error while loading the content.",
|
||||||
"openthefile": "Open the file"
|
"openthefile": "Open the file",
|
||||||
|
"uploadeddate": "Uploaded {{$a}}"
|
||||||
}
|
}
|
|
@ -14,14 +14,17 @@
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { NavController, NavOptions } from 'ionic-angular';
|
import { NavController, NavOptions } from 'ionic-angular';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { AddonModResourceProvider } from './resource';
|
import { AddonModResourceProvider } from './resource';
|
||||||
import { AddonModResourceHelperProvider } from './helper';
|
import { AddonModResourceHelperProvider } from './helper';
|
||||||
import { AddonModResourceIndexComponent } from '../components/index/index';
|
import { AddonModResourceIndexComponent } from '../components/index/index';
|
||||||
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate';
|
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate';
|
||||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||||
import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype';
|
import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype';
|
||||||
|
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
|
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
|
||||||
import { CoreConstants } from '@core/constants';
|
import { CoreConstants } from '@core/constants';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler to support resource modules.
|
* Handler to support resource modules.
|
||||||
|
@ -35,7 +38,8 @@ export class AddonModResourceModuleHandler implements CoreCourseModuleHandler {
|
||||||
|
|
||||||
constructor(protected resourceProvider: AddonModResourceProvider, private courseProvider: CoreCourseProvider,
|
constructor(protected resourceProvider: AddonModResourceProvider, private courseProvider: CoreCourseProvider,
|
||||||
protected mimetypeUtils: CoreMimetypeUtilsProvider, private resourceHelper: AddonModResourceHelperProvider,
|
protected mimetypeUtils: CoreMimetypeUtilsProvider, private resourceHelper: AddonModResourceHelperProvider,
|
||||||
protected prefetchDelegate: CoreCourseModulePrefetchDelegate) {
|
protected prefetchDelegate: CoreCourseModulePrefetchDelegate, protected textUtils: CoreTextUtilsProvider,
|
||||||
|
protected translate: TranslateService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,7 +65,7 @@ export class AddonModResourceModuleHandler implements CoreCourseModuleHandler {
|
||||||
this.resourceHelper.isDisplayedInIframe(module);
|
this.resourceHelper.isDisplayedInIframe(module);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlerData = {
|
const handlerData: CoreCourseModuleHandlerData = {
|
||||||
icon: this.courseProvider.getModuleIconSrc('resource'),
|
icon: this.courseProvider.getModuleIconSrc('resource'),
|
||||||
title: module.name,
|
title: module.name,
|
||||||
class: 'addon-mod_resource-handler',
|
class: 'addon-mod_resource-handler',
|
||||||
|
@ -84,8 +88,10 @@ export class AddonModResourceModuleHandler implements CoreCourseModuleHandler {
|
||||||
} ]
|
} ]
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getIcon(module, courseId).then((icon) => {
|
this.getResourceData(module, courseId).then((data) => {
|
||||||
handlerData.icon = icon;
|
handlerData.icon = data.icon;
|
||||||
|
handlerData.extraBadge = data.extra;
|
||||||
|
handlerData.extraBadgeColor = 'light';
|
||||||
});
|
});
|
||||||
|
|
||||||
this.hideOpenButton(module, courseId).then((hideOpenButton) => {
|
this.hideOpenButton(module, courseId).then((hideOpenButton) => {
|
||||||
|
@ -111,23 +117,61 @@ export class AddonModResourceModuleHandler implements CoreCourseModuleHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the activity icon.
|
* Returns the activity icon and data.
|
||||||
*
|
*
|
||||||
* @param {any} module The module object.
|
* @param {any} module The module object.
|
||||||
* @param {number} courseId The course ID.
|
* @param {number} courseId The course ID.
|
||||||
* @return {Promise<string>} Icon URL.
|
* @return {Promise<any>} Resource data.
|
||||||
*/
|
*/
|
||||||
protected getIcon(module: any, courseId: number): Promise<string> {
|
protected getResourceData(module: any, courseId: number): Promise<any> {
|
||||||
return this.courseProvider.loadModuleContents(module, courseId).then(() => {
|
return this.resourceProvider.getResourceData(courseId, module.id).then((info) => {
|
||||||
|
let promise;
|
||||||
|
|
||||||
|
if (info.contentfiles && info.contentfiles.length == 1) {
|
||||||
|
promise = Promise.resolve(info.contentfiles);
|
||||||
|
} else {
|
||||||
|
promise = this.courseProvider.loadModuleContents(module, courseId).then(() => {
|
||||||
if (module.contents.length) {
|
if (module.contents.length) {
|
||||||
const filename = module.contents[0].filename,
|
return module.contents;
|
||||||
extension = this.mimetypeUtils.getFileExtension(filename);
|
}
|
||||||
if (module.contents.length == 1 || (extension != 'html' && extension != 'htm')) {
|
});
|
||||||
return this.mimetypeUtils.getFileIcon(filename);
|
}
|
||||||
|
|
||||||
|
return promise.then((files) => {
|
||||||
|
const resourceData = {
|
||||||
|
icon: '',
|
||||||
|
extra: ''
|
||||||
|
},
|
||||||
|
options = this.textUtils.unserialize(info.displayoptions),
|
||||||
|
extra = [];
|
||||||
|
|
||||||
|
if (files && files.length) {
|
||||||
|
const file = files[0];
|
||||||
|
resourceData.icon = this.mimetypeUtils.getFileIcon(file.filename);
|
||||||
|
|
||||||
|
if (options.showsize) {
|
||||||
|
const size = files.reduce((result, file) => {
|
||||||
|
return result + file.filesize;
|
||||||
|
}, 0);
|
||||||
|
extra.push(this.textUtils.bytesToSize(size, 1));
|
||||||
|
}
|
||||||
|
if (options.showtype) {
|
||||||
|
extra.push(this.mimetypeUtils.getMimetypeDescription(file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.courseProvider.getModuleIconSrc('resource');
|
if (resourceData.icon == '') {
|
||||||
|
resourceData.icon = this.courseProvider.getModuleIconSrc('resource');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.showdate) {
|
||||||
|
extra.push(this.translate.instant('addon.mod_resource.uploadeddate',
|
||||||
|
{$a: moment(info.timemodified * 1000).format('LLL')}));
|
||||||
|
}
|
||||||
|
resourceData.extra += extra.join(' ');
|
||||||
|
|
||||||
|
return resourceData;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="module.visible === 0 || module.availabilityinfo || module.handlerData.extraBadge">
|
<div *ngIf="module.visible === 0 || module.availabilityinfo || module.handlerData.extraBadge">
|
||||||
<ion-badge item-end *ngIf="module.handlerData.extraBadge" [color]="module.handlerData.extraBadgeColor">
|
<ion-badge item-end *ngIf="module.handlerData.extraBadge" [color]="module.handlerData.extraBadgeColor" text-wrap text-start>
|
||||||
<core-format-text [text]="module.handlerData.extraBadge"></core-format-text>
|
<core-format-text [text]="module.handlerData.extraBadge"></core-format-text>
|
||||||
</ion-badge>
|
</ion-badge>
|
||||||
<ion-badge item-end *ngIf="module.visible === 0">{{ 'core.course.hiddenfromstudents' | translate }}</ion-badge>
|
<ion-badge item-end *ngIf="module.visible === 0">{{ 'core.course.hiddenfromstudents' | translate }}</ion-badge>
|
||||||
|
|
|
@ -690,4 +690,223 @@ export class CoreTextUtilsProvider {
|
||||||
ucFirst(text: string): string {
|
ucFirst(text: string): string {
|
||||||
return text.charAt(0).toUpperCase() + text.slice(1);
|
return text.charAt(0).toUpperCase() + text.slice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unserialize Array from PHP.
|
||||||
|
* Taken from: https://github.com/kvz/locutus/blob/master/src/php/var/unserialize.js
|
||||||
|
*
|
||||||
|
* @param {string} data String to unserialize.
|
||||||
|
* @param {Function} [logErrorFn] An error to call with the exception to log the error. If not supplied, no error.
|
||||||
|
* @return {any} Unserialized data.
|
||||||
|
*/
|
||||||
|
unserialize (data: string, logErrorFn?: Function): any {
|
||||||
|
// Discuss at: http://locutus.io/php/unserialize/
|
||||||
|
// Original by: Arpad Ray (mailto:arpad@php.net)
|
||||||
|
// Improved by: Pedro Tainha (http://www.pedrotainha.com)
|
||||||
|
// Improved by: Kevin van Zonneveld (http://kvz.io)
|
||||||
|
// Improved by: Kevin van Zonneveld (http://kvz.io)
|
||||||
|
// Improved by: Chris
|
||||||
|
// Improved by: James
|
||||||
|
// Improved by: Le Torbi
|
||||||
|
// Improved by: Eli Skeggs
|
||||||
|
// Bugfixed by: dptr1988
|
||||||
|
// Bugfixed by: Kevin van Zonneveld (http://kvz.io)
|
||||||
|
// Bugfixed by: Brett Zamir (http://brett-zamir.me)
|
||||||
|
// Bugfixed by: philippsimon (https://github.com/philippsimon/)
|
||||||
|
// Revised by: d3x
|
||||||
|
// Input by: Brett Zamir (http://brett-zamir.me)
|
||||||
|
// Input by: Martin (http://www.erlenwiese.de/)
|
||||||
|
// Input by: kilops
|
||||||
|
// Input by: Jaroslaw Czarniak
|
||||||
|
// Input by: lovasoa (https://github.com/lovasoa/)
|
||||||
|
// Note 1: We feel the main purpose of this function should be
|
||||||
|
// Note 1: to ease the transport of data between php & js
|
||||||
|
// Note 1: Aiming for PHP-compatibility, we have to translate objects to arrays
|
||||||
|
// Example 1: unserialize('a:3:{i:0;s:5:"Kevin";i:1;s:3:"van";i:2;s:9:"Zonneveld";}')
|
||||||
|
// Returns 1: ['Kevin', 'van', 'Zonneveld']
|
||||||
|
// Example 2: unserialize('a:2:{s:9:"firstName";s:5:"Kevin";s:7:"midName";s:3:"van";}')
|
||||||
|
// Returns 2: {firstName: 'Kevin', midName: 'van'}
|
||||||
|
// Example 3: unserialize('a:3:{s:2:"ü";s:2:"ü";s:3:"四";s:3:"四";s:4:"𠜎";s:4:"𠜎";}')
|
||||||
|
// Returns 3: {'ü': 'ü', '四': '四', '𠜎': '𠜎'}
|
||||||
|
|
||||||
|
const utf8Overhead = (str: string): number => {
|
||||||
|
let s = str.length;
|
||||||
|
|
||||||
|
for (let i = str.length - 1; i >= 0; i--) {
|
||||||
|
const code = str.charCodeAt(i);
|
||||||
|
if (code > 0x7f && code <= 0x7ff) {
|
||||||
|
s++;
|
||||||
|
} else if (code > 0x7ff && code <= 0xffff) {
|
||||||
|
s += 2;
|
||||||
|
}
|
||||||
|
// Trail surrogate.
|
||||||
|
if (code >= 0xDC00 && code <= 0xDFFF) {
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s - 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const error = (type: string, msg: string): void => {
|
||||||
|
if (logErrorFn) {
|
||||||
|
logErrorFn(type + msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const readUntil = (data: string, offset: number, stopchr: string): Array<any> => {
|
||||||
|
let i = 2;
|
||||||
|
const buf = [];
|
||||||
|
let chr = data.slice(offset, offset + 1);
|
||||||
|
|
||||||
|
while (chr !== stopchr) {
|
||||||
|
if ((i + offset) > data.length) {
|
||||||
|
error('Error', 'Invalid');
|
||||||
|
}
|
||||||
|
buf.push(chr);
|
||||||
|
chr = data.slice(offset + (i - 1), offset + i);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [buf.length, buf.join('')];
|
||||||
|
};
|
||||||
|
|
||||||
|
const readChrs = (data: string, offset: number, length: number): Array<any> => {
|
||||||
|
let chr;
|
||||||
|
const buf = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
chr = data.slice(offset + (i - 1), offset + i);
|
||||||
|
buf.push(chr);
|
||||||
|
length -= utf8Overhead(chr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [buf.length, buf.join('')];
|
||||||
|
};
|
||||||
|
|
||||||
|
const _unserialize = (data: string, offset: number): any => {
|
||||||
|
let dtype,
|
||||||
|
dataoffset,
|
||||||
|
keyandchrs,
|
||||||
|
keys,
|
||||||
|
contig,
|
||||||
|
length,
|
||||||
|
array,
|
||||||
|
readdata,
|
||||||
|
readData,
|
||||||
|
ccount,
|
||||||
|
stringlength,
|
||||||
|
i,
|
||||||
|
key,
|
||||||
|
kprops,
|
||||||
|
kchrs,
|
||||||
|
vprops,
|
||||||
|
vchrs,
|
||||||
|
value,
|
||||||
|
chrs = 0,
|
||||||
|
typeconvert = (x: any): any => {
|
||||||
|
return x;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!offset) {
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
dtype = (data.slice(offset, offset + 1)).toLowerCase();
|
||||||
|
|
||||||
|
dataoffset = offset + 2;
|
||||||
|
|
||||||
|
switch (dtype) {
|
||||||
|
case 'i':
|
||||||
|
typeconvert = (x: any): number => {
|
||||||
|
return parseInt(x, 10);
|
||||||
|
};
|
||||||
|
readData = readUntil(data, dataoffset, ';');
|
||||||
|
chrs = readData[0];
|
||||||
|
readdata = readData[1];
|
||||||
|
dataoffset += chrs + 1;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
typeconvert = (x: any): boolean => {
|
||||||
|
return parseInt(x, 10) !== 0;
|
||||||
|
};
|
||||||
|
readData = readUntil(data, dataoffset, ';');
|
||||||
|
chrs = readData[0];
|
||||||
|
readdata = readData[1];
|
||||||
|
dataoffset += chrs + 1;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
typeconvert = (x: any): number => {
|
||||||
|
return parseFloat(x);
|
||||||
|
};
|
||||||
|
readData = readUntil(data, dataoffset, ';');
|
||||||
|
chrs = readData[0];
|
||||||
|
readdata = readData[1];
|
||||||
|
dataoffset += chrs + 1;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
readdata = null;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
ccount = readUntil(data, dataoffset, ':');
|
||||||
|
chrs = ccount[0];
|
||||||
|
stringlength = ccount[1];
|
||||||
|
dataoffset += chrs + 2;
|
||||||
|
|
||||||
|
readData = readChrs(data, dataoffset + 1, parseInt(stringlength, 10));
|
||||||
|
chrs = readData[0];
|
||||||
|
readdata = readData[1];
|
||||||
|
dataoffset += chrs + 2;
|
||||||
|
if (chrs !== parseInt(stringlength, 10) && chrs !== readdata.length) {
|
||||||
|
error('SyntaxError', 'String length mismatch');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
readdata = {};
|
||||||
|
|
||||||
|
keyandchrs = readUntil(data, dataoffset, ':');
|
||||||
|
chrs = keyandchrs[0];
|
||||||
|
keys = keyandchrs[1];
|
||||||
|
dataoffset += chrs + 2;
|
||||||
|
|
||||||
|
length = parseInt(keys, 10);
|
||||||
|
contig = true;
|
||||||
|
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
kprops = _unserialize(data, dataoffset);
|
||||||
|
kchrs = kprops[1];
|
||||||
|
key = kprops[2];
|
||||||
|
dataoffset += kchrs;
|
||||||
|
|
||||||
|
vprops = _unserialize(data, dataoffset);
|
||||||
|
vchrs = vprops[1];
|
||||||
|
value = vprops[2];
|
||||||
|
dataoffset += vchrs;
|
||||||
|
|
||||||
|
if (key !== i) {
|
||||||
|
contig = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
readdata[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contig) {
|
||||||
|
array = new Array(length);
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
array[i] = readdata[i];
|
||||||
|
}
|
||||||
|
readdata = array;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataoffset += 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error('SyntaxError', 'Unknown / Unhandled data type(s): ' + dtype);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [dtype, dataoffset - offset, typeconvert(readdata)];
|
||||||
|
};
|
||||||
|
|
||||||
|
return _unserialize((data + ''), 0)[2];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue