Merge pull request #2841 from dpalou/MOBILE-3320

Mobile 3320
main
Pau Ferrer Ocaña 2021-06-21 12:14:33 +02:00 committed by GitHub
commit 7cce817d12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 113 additions and 17 deletions

View File

@ -71,7 +71,7 @@ export class AddonModDataSearchComponent implements OnInit {
this.search.advanced?.forEach((field) => {
if (typeof field != 'undefined') {
this.advancedIndexed[field.name] = field.value
? CoreTextUtils.parseJSON(field.value)
? CoreTextUtils.parseJSON(field.value, '')
: '';
}
});

View File

@ -112,7 +112,8 @@ export class AddonModDataFieldFileHandlerService implements AddonModDataFieldHan
offlineContent: CoreFormFields,
offlineFiles?: FileEntry[],
): AddonModDataEntryField {
const uploadedFilesResult: CoreFileUploaderStoreFilesResult = <CoreFileUploaderStoreFilesResult>offlineContent?.file;
const uploadedFilesResult: CoreFileUploaderStoreFilesResult | undefined =
<CoreFileUploaderStoreFilesResult | undefined> offlineContent?.file;
if (uploadedFilesResult && uploadedFilesResult.offline > 0 && offlineFiles && offlineFiles?.length > 0) {
originalContent.content = offlineFiles[0].name;

View File

@ -121,8 +121,8 @@ export class AddonModDataFieldLatlongHandlerService implements AddonModDataField
* @inheritdoc
*/
overrideData(originalContent: AddonModDataEntryField, offlineContent: CoreFormFields<string>): AddonModDataEntryField {
originalContent.content = offlineContent[0] || '';
originalContent.content1 = offlineContent[1] || '';
originalContent.content = offlineContent['0'] || '';
originalContent.content1 = offlineContent['1'] || '';
return originalContent;
}

View File

@ -155,7 +155,8 @@ export class AddonModDataFieldPictureHandlerService implements AddonModDataField
offlineContent: CoreFormFields,
offlineFiles?: FileEntry[],
): AddonModDataEntryField {
const uploadedFilesResult: CoreFileUploaderStoreFilesResult = <CoreFileUploaderStoreFilesResult>offlineContent?.file;
const uploadedFilesResult: CoreFileUploaderStoreFilesResult | undefined =
<CoreFileUploaderStoreFilesResult | undefined> offlineContent?.file;
if (uploadedFilesResult && uploadedFilesResult.offline > 0 && offlineFiles && offlineFiles?.length > 0) {
originalContent.content = offlineFiles[0].name;
@ -165,7 +166,7 @@ export class AddonModDataFieldPictureHandlerService implements AddonModDataField
originalContent.files = [uploadedFilesResult.online[0]];
}
originalContent.content1 = <string>offlineContent.alttext || '';
originalContent.content1 = <string> offlineContent.alttext || '';
return originalContent;
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { AddonModDataField, AddonModDataSubfieldData } from '@addons/mod/data/services/data';
import { AddonModDataEntryField, AddonModDataField, AddonModDataSubfieldData } from '@addons/mod/data/services/data';
import { Injectable, Type } from '@angular/core';
import { CoreFormFields } from '@singletons/form';
import { Translate, makeSingleton } from '@singletons';
@ -59,5 +59,14 @@ export class AddonModDataFieldUrlHandlerService extends AddonModDataFieldTextHan
}
}
/**
* @inheritdoc
*/
overrideData(originalContent: AddonModDataEntryField, offlineContent: CoreFormFields<string>): AddonModDataEntryField {
originalContent.content = offlineContent['0'] || '';
return originalContent;
}
}
export const AddonModDataFieldUrlHandler = makeSingleton(AddonModDataFieldUrlHandlerService);

View File

@ -92,9 +92,9 @@ export class AddonModDataHelperProvider {
if (offlineContent.subfield) {
offlineContents[offlineContent.fieldid][offlineContent.subfield] =
CoreTextUtils.parseJSON(offlineContent.value);
CoreTextUtils.parseJSON(offlineContent.value, '');
} else {
offlineContents[offlineContent.fieldid][''] = CoreTextUtils.parseJSON(offlineContent.value);
offlineContents[offlineContent.fieldid][''] = CoreTextUtils.parseJSON(offlineContent.value, '');
}
});
@ -632,7 +632,7 @@ export class AddonModDataHelperProvider {
const folderPath = await AddonModDataOffline.getEntryFieldFolder(dataId, entryId, fieldId, siteId);
try {
return CoreFileUploader.getStoredFiles(folderPath);
return await CoreFileUploader.getStoredFiles(folderPath);
} catch {
// Ignore not found files.
return [];

View File

@ -88,9 +88,9 @@ export class AddonModDataOfflineProvider {
const promises: Promise<void>[] = [];
entry.fields.forEach((field) => {
const value = CoreTextUtils.parseJSON<CoreFileUploaderStoreFilesResult>(field.value);
const value = CoreTextUtils.parseJSON<CoreFileUploaderStoreFilesResult | null>(field.value, null);
if (!value.offline) {
if (!value || !value.offline) {
return;
}

View File

@ -345,8 +345,8 @@ export class AddonModDataSyncProvider extends CoreCourseActivitySyncBaseProvider
try {
await Promise.all(editAction.fields.map(async (field) => {
// Upload Files if asked.
const value = CoreTextUtils.parseJSON<CoreFileUploaderStoreFilesResult>(field.value || '');
if (value.online || value.offline) {
const value = CoreTextUtils.parseJSON<CoreFileUploaderStoreFilesResult | null>(field.value || '', null);
if (value && (value.online || value.offline)) {
let files: CoreFileEntry[] = value.online || [];
const offlineFiles = value.offline

View File

@ -155,7 +155,7 @@
</ion-item>
</ion-card>
<ion-card *ngIf="completed">
<ion-card *ngIf="completed && (access!.canviewanalysis || hasNextPage)">
<ion-grid>
<ion-row class="ion-align-items-center">
<ion-col *ngIf="access!.canviewanalysis">

View File

@ -98,7 +98,8 @@
</ng-container>
</ion-list>
<core-empty-box *ngIf="entries.empty" icon="fas-list" [message]="'addon.mod_glossary.noentriesfound' | translate">
<core-empty-box *ngIf="entries.empty && (!isSearch || hasSearched)" icon="fas-list"
[message]="'addon.mod_glossary.noentriesfound' | translate">
</core-empty-box>
<core-infinite-loading [enabled]="!entries.completed" [error]="loadMoreError" (action)="loadMoreEntries($event)">

View File

@ -64,6 +64,7 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
moduleName = 'glossary';
isSearch = false;
hasSearched = false;
canAdd = false;
loadMoreError = false;
loadingMessage?: string;
@ -429,6 +430,7 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
toggleSearch(): void {
if (this.isSearch) {
this.isSearch = false;
this.hasSearched = false;
this.entries.setOnlineEntries(this.fetchedEntries, this.fetchedEntriesCanLoadMore);
this.switchMode(this.fetchMode!);
} else {
@ -488,6 +490,7 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
'ASC',
);
this.loaded = false;
this.hasSearched = true;
this.loadContent();
}

View File

@ -26,6 +26,7 @@ import { CoreSupressEventsDirective } from './supress-events';
import { CoreUserLinkDirective } from './user-link';
import { CoreAriaButtonClickDirective } from './aria-button';
import { CoreOnResizeDirective } from './on-resize';
import { CoreDownloadFileDirective } from './download-file';
@NgModule({
declarations: [
@ -41,6 +42,7 @@ import { CoreOnResizeDirective } from './on-resize';
CoreUserLinkDirective,
CoreAriaButtonClickDirective,
CoreOnResizeDirective,
CoreDownloadFileDirective,
],
exports: [
CoreAutoFocusDirective,
@ -55,6 +57,7 @@ import { CoreOnResizeDirective } from './on-resize';
CoreUserLinkDirective,
CoreAriaButtonClickDirective,
CoreOnResizeDirective,
CoreDownloadFileDirective,
],
})
export class CoreDirectivesModule {}

View File

@ -0,0 +1,63 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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 { Directive, Input, OnInit, ElementRef } from '@angular/core';
import { CoreFileHelper } from '@services/file-helper';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreWSFile } from '@services/ws';
/**
* Directive to allow downloading and open a file. When the item with this directive is clicked, the file will be
* downloaded (if needed) and opened.
*/
@Directive({
selector: '[core-download-file]',
})
export class CoreDownloadFileDirective implements OnInit {
@Input('core-download-file') file?: CoreWSFile; // The file to download.
@Input() component?: string; // Component to link the file to.
@Input() componentId?: string | number; // Component ID to use in conjunction with the component.
protected element: HTMLElement;
constructor(element: ElementRef) {
this.element = element.nativeElement;
}
/**
* Component being initialized.
*/
ngOnInit(): void {
this.element.addEventListener('click', async (ev: Event) => {
if (!this.file) {
return;
}
ev.preventDefault();
ev.stopPropagation();
const modal = await CoreDomUtils.showModalLoading();
try {
await CoreFileHelper.downloadAndOpenFile(this.file, this.component, this.componentId);
} catch (error) {
CoreDomUtils.showErrorModalDefault(error, 'core.errordownloading', true);
} finally {
modal.dismiss();
}
});
}
}

View File

@ -277,7 +277,10 @@ export class CoreUtilsProvider {
return source;
}
if (Array.isArray(source)) {
if (this.valueIsFileEntry(source)) {
// Don't clone FileEntry. It has a lot of depth and they shouldn't be modified.
return source;
} else if (Array.isArray(source)) {
// Clone the array and all the entries.
const newArray = [] as unknown as T;
for (let i = 0; i < source.length; i++) {
@ -750,6 +753,18 @@ export class CoreUtilsProvider {
return 'isFile' in file;
}
/**
* Check if an unknown value is a FileEntry.
*
* @param value Value to check.
* @return Type guard indicating if the file is a FileEntry.
*/
valueIsFileEntry(file: unknown): file is FileEntry {
// We cannot use instanceof because FileEntry is a type. Check some of the properties.
return !!(file && typeof file == 'object' && 'isFile' in file && 'filesystem' in file &&
'toInternalURL' in file && 'copyTo' in file);
}
/**
* Check if a value is an object.
*