MOBILE-3640 database: Add fields components
parent
2991873dfe
commit
8febbe3ea7
|
@ -0,0 +1,116 @@
|
|||
// (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 { Input, Output, OnInit, OnChanges, SimpleChange, EventEmitter, Component } from '@angular/core';
|
||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||
import { CoreFormFields } from '@singletons/form';
|
||||
import { AddonModDataData, AddonModDataEntryField, AddonModDataField, AddonModDataTemplateMode } from '../services/data';
|
||||
|
||||
/**
|
||||
* Base class for component to render a field.
|
||||
*/
|
||||
@Component({
|
||||
template: '',
|
||||
})
|
||||
export abstract class AddonModDataFieldPluginComponent implements OnInit, OnChanges {
|
||||
|
||||
@Input() mode!: AddonModDataTemplateMode; // The render mode.
|
||||
@Input() field!: AddonModDataField; // The field to render.
|
||||
@Input() value?: Partial<AddonModDataEntryField>; // The value of the field.
|
||||
@Input() database?: AddonModDataData; // Database object.
|
||||
@Input() error?: string; // Error when editing.
|
||||
@Input() form?: FormGroup; // Form where to add the form control. Just required for edit and search modes.
|
||||
@Input() searchFields?: CoreFormFields; // The search value of all fields.
|
||||
@Output() gotoEntry: EventEmitter<number>; // Action to perform.
|
||||
|
||||
constructor(protected fb: FormBuilder) {
|
||||
this.gotoEntry = new EventEmitter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the form control for the search mode.
|
||||
*
|
||||
* @param fieldName Control field name.
|
||||
* @param value Initial set value.
|
||||
*/
|
||||
protected addControl(fieldName: string, value?: unknown): void {
|
||||
if (!this.form) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.searchMode) {
|
||||
this.form.addControl(fieldName, this.fb.control(this.searchFields?.[fieldName] || undefined));
|
||||
}
|
||||
|
||||
if (this.editMode) {
|
||||
this.form.addControl(fieldName, this.fb.control(value, this.field.required ? Validators.required : null));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize field.
|
||||
*/
|
||||
protected init(): void {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being changed.
|
||||
*/
|
||||
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
|
||||
if ((this.showMode || this.listMode) && changes.value) {
|
||||
this.updateValue(changes.value.currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update value being shown.
|
||||
*/
|
||||
protected updateValue(value?: Partial<AddonModDataEntryField>): void {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/** Magic mode getters */
|
||||
get listMode(): boolean {
|
||||
return this.mode == AddonModDataTemplateMode.LIST;
|
||||
}
|
||||
|
||||
get showMode(): boolean {
|
||||
return this.mode == AddonModDataTemplateMode.SHOW;
|
||||
}
|
||||
|
||||
get displayMode(): boolean {
|
||||
return this.listMode || this.showMode;
|
||||
}
|
||||
|
||||
get editMode(): boolean {
|
||||
return this.mode == AddonModDataTemplateMode.EDIT;
|
||||
}
|
||||
|
||||
get searchMode(): boolean {
|
||||
return this.mode == AddonModDataTemplateMode.SEARCH;
|
||||
}
|
||||
|
||||
get inputMode(): boolean {
|
||||
return this.searchMode || this.editMode;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<core-dynamic-component [component]="fieldComponent" [data]="pluginData">
|
||||
<!-- This content will be replaced by the component if found. -->
|
||||
<core-loading [hideUntil]="fieldLoaded">
|
||||
</core-loading>
|
||||
</core-dynamic-component>
|
|
@ -0,0 +1,103 @@
|
|||
// (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 { Component, OnInit, OnChanges, ViewChild, Input, Output, SimpleChange, Type, EventEmitter } from '@angular/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-component';
|
||||
import { CoreFormFields } from '@singletons/form';
|
||||
import { AddonModDataData, AddonModDataField, AddonModDataTemplateMode } from '../../services/data';
|
||||
import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate';
|
||||
|
||||
/**
|
||||
* Component that displays a database field plugin.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-data-field-plugin',
|
||||
templateUrl: 'addon-mod-data-field-plugin.html',
|
||||
})
|
||||
export class AddonModDataFieldPluginComponent implements OnInit, OnChanges {
|
||||
|
||||
@ViewChild(CoreDynamicComponent) dynamicComponent?: CoreDynamicComponent;
|
||||
|
||||
@Input() mode!: AddonModDataTemplateMode; // The render mode.
|
||||
@Input() field!: AddonModDataField; // The field to render.
|
||||
@Input() value?: unknown; // The value of the field.
|
||||
@Input() database?: AddonModDataData; // Database object.
|
||||
@Input() error?: string; // Error when editing.
|
||||
@Input() form?: FormGroup; // Form where to add the form control. Just required for edit and search modes.
|
||||
@Input() searchFields?: CoreFormFields; // The search value of all fields.
|
||||
@Output() gotoEntry = new EventEmitter(); // Action to perform.
|
||||
|
||||
fieldComponent?: Type<unknown>; // Component to render the plugin.
|
||||
pluginData?: AddonDataFieldPluginComponentData; // Data to pass to the component.
|
||||
fieldLoaded = false;
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
*/
|
||||
async ngOnInit(): Promise<void> {
|
||||
if (!this.field) {
|
||||
this.fieldLoaded = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
// Check if the plugin has defined its own component to render itself.
|
||||
this.fieldComponent = await AddonModDataFieldsDelegate.getComponentForField(this.field);
|
||||
|
||||
if (this.fieldComponent) {
|
||||
// Prepare the data to pass to the component.
|
||||
this.pluginData = {
|
||||
mode: this.mode,
|
||||
field: this.field,
|
||||
value: this.value,
|
||||
database: this.database,
|
||||
error: this.error,
|
||||
gotoEntry: this.gotoEntry,
|
||||
form: this.form,
|
||||
searchFields: this.searchFields,
|
||||
};
|
||||
}
|
||||
} finally {
|
||||
this.fieldLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being changed.
|
||||
*/
|
||||
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
|
||||
if (this.fieldLoaded && this.pluginData) {
|
||||
if (this.mode == AddonModDataTemplateMode.EDIT && changes.error) {
|
||||
this.pluginData.error = changes.error.currentValue;
|
||||
}
|
||||
if ((this.mode == AddonModDataTemplateMode.SHOW || this.mode == AddonModDataTemplateMode.LIST) && changes.value) {
|
||||
this.pluginData.value = changes.value.currentValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export type AddonDataFieldPluginComponentData = {
|
||||
mode: AddonModDataTemplateMode; // The render mode.
|
||||
field: AddonModDataField; // The field to render.
|
||||
value?: unknown; // The value of the field.
|
||||
database?: AddonModDataData; // Database object.
|
||||
error?: string; // Error when editing.
|
||||
form?: FormGroup; // Form where to add the form control. Just required for edit and search modes.
|
||||
searchFields?: CoreFormFields; // The search value of all fields.
|
||||
gotoEntry: EventEmitter<unknown>;
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
// (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 { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
import { AddonModDataFieldCheckboxComponent } from './component/checkbox';
|
||||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate';
|
||||
import { AddonModDataFieldCheckboxHandler } from './services/handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModDataFieldCheckboxComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
AddonModDataFieldsDelegate.registerHandler(AddonModDataFieldCheckboxHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
AddonModDataFieldCheckboxComponent,
|
||||
],
|
||||
})
|
||||
export class AddonModDataFieldCheckboxModule {}
|
|
@ -0,0 +1,16 @@
|
|||
<span *ngIf="inputMode && form" [formGroup]="form">
|
||||
<span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||
<ion-select [formControlName]="'f_'+field.id" multiple="true" [placeholder]="'addon.mod_data.menuchoose' | translate"
|
||||
[interfaceOptions]="{header: field.name}" interface="alert">
|
||||
<ion-select-option *ngFor="let option of options" [value]="option.value">{{option.key}}</ion-select-option>
|
||||
</ion-select>
|
||||
<core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||
|
||||
<ion-item *ngIf="searchMode">
|
||||
<ion-label>{{ 'addon.mod_data.selectedrequired' | translate }}</ion-label>
|
||||
<ion-checkbox slot="end" [formControlName]="'f_'+field.id+'_allreq'" [(ngModel)]="searchFields!['f_'+field.id+'_allreq']">
|
||||
</ion-checkbox>
|
||||
</ion-item>
|
||||
</span>
|
||||
|
||||
<core-format-text *ngIf="displayMode && value && value.content" [text]="value.content" [filter]="false"></core-format-text>
|
|
@ -0,0 +1,70 @@
|
|||
// (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 { AddonModDataEntryField } from '@addons/mod/data/services/data';
|
||||
import { Component } from '@angular/core';
|
||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||
|
||||
/**
|
||||
* Component to render data checkbox field.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-data-field-checkbox',
|
||||
templateUrl: 'addon-mod-data-field-checkbox.html',
|
||||
})
|
||||
export class AddonModDataFieldCheckboxComponent extends AddonModDataFieldPluginComponent {
|
||||
|
||||
options: {
|
||||
key: string;
|
||||
value: string;
|
||||
}[] = [];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected init(): void {
|
||||
if (this.displayMode) {
|
||||
this.updateValue(this.value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.options = this.field.param1.split(/\r?\n/).map((option) => ({ key: option, value: option }));
|
||||
|
||||
const values: string[] = [];
|
||||
if (this.editMode && this.value && this.value.content) {
|
||||
this.value.content.split('##').forEach((value) => {
|
||||
const x = this.options.findIndex((option) => value == option.key);
|
||||
if (x >= 0) {
|
||||
values.push(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (this.searchMode) {
|
||||
this.addControl('f_' + this.field.id + '_allreq');
|
||||
}
|
||||
|
||||
this.addControl('f_' + this.field.id, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected updateValue(value?: Partial<AddonModDataEntryField>): void {
|
||||
this.value = value || {};
|
||||
this.value.content = value?.content?.split('##').join('<br>');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
// (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 {
|
||||
AddonModDataEntryField,
|
||||
AddonModDataField,
|
||||
AddonModDataSearchEntriesAdvancedFieldFormatted,
|
||||
AddonModDataSubfieldData,
|
||||
} from '@addons/mod/data/services/data';
|
||||
import { AddonModDataFieldHandler } from '@addons/mod/data/services/data-fields-delegate';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreFormFields } from '@singletons/form';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { AddonModDataFieldCheckboxComponent } from '../component/checkbox';
|
||||
|
||||
/**
|
||||
* Handler for checkbox data field plugin.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonModDataFieldCheckboxHandlerService implements AddonModDataFieldHandler {
|
||||
|
||||
name = 'AddonModDataFieldCheckboxHandler';
|
||||
type = 'checkbox';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getComponent(): Type<unknown> {
|
||||
return AddonModDataFieldCheckboxComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldSearchData(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string[]>,
|
||||
): AddonModDataSearchEntriesAdvancedFieldFormatted[] {
|
||||
|
||||
const fieldName = 'f_' + field.id;
|
||||
const reqName = 'f_' + field.id + '_allreq';
|
||||
|
||||
if (inputData[fieldName]) {
|
||||
const values: AddonModDataSearchEntriesAdvancedFieldFormatted[] = [];
|
||||
|
||||
values.push({
|
||||
name: fieldName,
|
||||
value: inputData[fieldName],
|
||||
});
|
||||
|
||||
if (inputData[reqName]) {
|
||||
values.push({
|
||||
name: reqName,
|
||||
value: true,
|
||||
});
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldEditData(field: AddonModDataField, inputData: CoreFormFields<string[]>): AddonModDataSubfieldData[] {
|
||||
const fieldName = 'f_' + field.id;
|
||||
|
||||
return [{
|
||||
fieldid: field.id,
|
||||
value: inputData[fieldName] || [],
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
hasFieldDataChanged(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string[]>,
|
||||
originalFieldData: AddonModDataEntryField,
|
||||
): boolean {
|
||||
const fieldName = 'f_' + field.id;
|
||||
|
||||
const content = originalFieldData?.content || '';
|
||||
|
||||
return inputData[fieldName].join('##') != content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check and get field requeriments.
|
||||
*
|
||||
* @param field Defines the field to be rendered.
|
||||
* @param inputData Data entered in the edit form.
|
||||
* @return String with the notification or false.
|
||||
*/
|
||||
getFieldsNotifications(field: AddonModDataField, inputData: AddonModDataSubfieldData[]): string | undefined {
|
||||
if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
|
||||
return Translate.instant('addon.mod_data.errormustsupplyvalue');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
overrideData(originalContent: AddonModDataEntryField, offlineContent: CoreFormFields<string[]>): AddonModDataEntryField {
|
||||
originalContent.content = (offlineContent[''] && offlineContent[''].join('##')) || '';
|
||||
|
||||
return originalContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModDataFieldCheckboxHandler = makeSingleton(AddonModDataFieldCheckboxHandlerService);
|
|
@ -0,0 +1,16 @@
|
|||
<span *ngIf="inputMode && form" [formGroup]="form">
|
||||
<span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||
<ion-datetime [formControlName]="'f_'+field.id" [placeholder]="'core.date' | translate"
|
||||
[disabled]="searchMode && !searchFields!['f_'+field.id+'_z']" [displayFormat]="format"></ion-datetime>
|
||||
<core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||
|
||||
<ion-item *ngIf="searchMode">
|
||||
<ion-label>{{ 'addon.mod_data.usedate' | translate }}</ion-label>
|
||||
<ion-checkbox slot="end" [formControlName]="'f_'+field.id+'_z'" [(ngModel)]="searchFields!['f_'+field.id+'_z']">
|
||||
</ion-checkbox>
|
||||
</ion-item>
|
||||
</span>
|
||||
|
||||
<span *ngIf="displayMode && displayDate">
|
||||
{{ displayDate | coreFormatDate:'strftimedate' }}
|
||||
</span>
|
|
@ -0,0 +1,70 @@
|
|||
// (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 { Component } from '@angular/core';
|
||||
import { CoreTimeUtils } from '@services/utils/time';
|
||||
import { Translate } from '@singletons';
|
||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||
|
||||
/**
|
||||
* Component to render data date field.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-data-field-date',
|
||||
templateUrl: 'addon-mod-data-field-date.html',
|
||||
})
|
||||
export class AddonModDataFieldDateComponent extends AddonModDataFieldPluginComponent {
|
||||
|
||||
format!: string;
|
||||
displayDate?: number;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected init(): void {
|
||||
if (this.displayMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
let date: Date;
|
||||
|
||||
// Calculate format to use.
|
||||
this.format = CoreTimeUtils.fixFormatForDatetime(CoreTimeUtils.convertPHPToMoment(
|
||||
Translate.instant('core.strftimedate'),
|
||||
));
|
||||
|
||||
if (this.searchMode) {
|
||||
this.addControl('f_' + this.field.id + '_z');
|
||||
|
||||
date = this.searchFields!['f_' + this.field.id + '_y']
|
||||
? new Date(this.searchFields!['f_' + this.field.id + '_y'] + '-' +
|
||||
this.searchFields!['f_' + this.field.id + '_m'] + '-' + this.searchFields!['f_' + this.field.id + '_d'])
|
||||
: new Date();
|
||||
|
||||
this.searchFields!['f_' + this.field.id] = CoreTimeUtils.toDatetimeFormat(date.getTime());
|
||||
} else {
|
||||
date = this.value?.content
|
||||
? new Date(parseInt(this.value.content, 10) * 1000)
|
||||
: new Date();
|
||||
|
||||
this.displayDate = this.value?.content
|
||||
? parseInt(this.value.content, 10) * 1000
|
||||
: undefined;
|
||||
|
||||
}
|
||||
|
||||
this.addControl('f_' + this.field.id, CoreTimeUtils.toDatetimeFormat(date.getTime()));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// (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 { CoreSharedModule } from '@/core/shared.module';
|
||||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||
import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate';
|
||||
import { AddonModDataFieldDateComponent } from './component/date';
|
||||
import { AddonModDataFieldDateHandler } from './services/handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModDataFieldDateComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
AddonModDataFieldsDelegate.registerHandler(AddonModDataFieldDateHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
AddonModDataFieldDateComponent,
|
||||
],
|
||||
})
|
||||
export class AddonModDataFieldDateModule {}
|
|
@ -0,0 +1,165 @@
|
|||
// (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 {
|
||||
AddonModDataEntryField,
|
||||
AddonModDataField,
|
||||
AddonModDataSearchEntriesAdvancedFieldFormatted,
|
||||
AddonModDataSubfieldData,
|
||||
} from '@addons/mod/data/services/data';
|
||||
import { AddonModDataFieldHandler } from '@addons/mod/data/services/data-fields-delegate';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreFormFields } from '@singletons/form';
|
||||
import { CoreTimeUtils } from '@services/utils/time';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { AddonModDataFieldDateComponent } from '../component/date';
|
||||
|
||||
/**
|
||||
* Handler for date data field plugin.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonModDataFieldDateHandlerService implements AddonModDataFieldHandler {
|
||||
|
||||
name = 'AddonModDataFieldDateHandler';
|
||||
type = 'date';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getComponent(): Type<unknown>{
|
||||
return AddonModDataFieldDateComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldSearchData(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string>,
|
||||
): AddonModDataSearchEntriesAdvancedFieldFormatted[] {
|
||||
const fieldName = 'f_' + field.id;
|
||||
const enabledName = 'f_' + field.id + '_z';
|
||||
|
||||
if (inputData[enabledName] && typeof inputData[fieldName] == 'string') {
|
||||
const date = inputData[fieldName].substr(0, 10).split('-');
|
||||
|
||||
return [
|
||||
{
|
||||
name: fieldName + '_y',
|
||||
value: date[0],
|
||||
},
|
||||
{
|
||||
name: fieldName + '_m',
|
||||
value: date[1],
|
||||
},
|
||||
{
|
||||
name: fieldName + '_d',
|
||||
value: date[2],
|
||||
},
|
||||
{
|
||||
name: enabledName,
|
||||
value: 1,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldEditData(field: AddonModDataField, inputData: CoreFormFields<string>): AddonModDataSubfieldData[] {
|
||||
const fieldName = 'f_' + field.id;
|
||||
|
||||
if (typeof inputData[fieldName] != 'string') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const date = inputData[fieldName].substr(0, 10).split('-');
|
||||
|
||||
return [
|
||||
{
|
||||
fieldid: field.id,
|
||||
subfield: 'year',
|
||||
value: date[0],
|
||||
},
|
||||
{
|
||||
fieldid: field.id,
|
||||
subfield: 'month',
|
||||
value: date[1],
|
||||
},
|
||||
{
|
||||
fieldid: field.id,
|
||||
subfield: 'day',
|
||||
value: date[2],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
hasFieldDataChanged(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string>,
|
||||
originalFieldData: AddonModDataEntryField,
|
||||
): boolean {
|
||||
const fieldName = 'f_' + field.id;
|
||||
const input = inputData[fieldName] && inputData[fieldName].substr(0, 10) || '';
|
||||
|
||||
const content = (originalFieldData && originalFieldData?.content &&
|
||||
CoreTimeUtils.toDatetimeFormat(parseInt(originalFieldData.content, 10) * 1000).substr(0, 10)) || '';
|
||||
|
||||
return input != content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldsNotifications(field: AddonModDataField, inputData: AddonModDataSubfieldData[]): string | undefined {
|
||||
if (field.required &&
|
||||
(!inputData || inputData.length < 2 || !inputData[0].value || !inputData[1].value || !inputData[2].value)) {
|
||||
|
||||
return Translate.instant('addon.mod_data.errormustsupplyvalue');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
overrideData(originalContent: AddonModDataEntryField, offlineContent: CoreFormFields<string>): AddonModDataEntryField {
|
||||
if (offlineContent['day']) {
|
||||
let date = Date.UTC(
|
||||
parseInt(offlineContent['year'], 10),
|
||||
parseInt(offlineContent['month'], 10) - 1,
|
||||
parseInt(offlineContent['day'], 10),
|
||||
);
|
||||
date = Math.floor(date / 1000);
|
||||
|
||||
originalContent.content = String(date) || '';
|
||||
}
|
||||
|
||||
return originalContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModDataFieldDateHandler = makeSingleton(AddonModDataFieldDateHandlerService);
|
|
@ -0,0 +1,45 @@
|
|||
// (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 { NgModule } from '@angular/core';
|
||||
import { AddonModDataFieldCheckboxModule } from './checkbox/checkbox.module';
|
||||
import { AddonModDataFieldDateModule } from './date/date.module';
|
||||
import { AddonModDataFieldFileModule } from './file/file.module';
|
||||
import { AddonModDataFieldLatlongModule } from './latlong/latlong.module';
|
||||
import { AddonModDataFieldMenuModule } from './menu/menu.module';
|
||||
import { AddonModDataFieldMultimenuModule } from './multimenu/multimenu.module';
|
||||
import { AddonModDataFieldNumberModule } from './number/number.module';
|
||||
import { AddonModDataFieldPictureModule } from './picture/picture.module';
|
||||
import { AddonModDataFieldRadiobuttonModule } from './radiobutton/radiobutton.module';
|
||||
import { AddonModDataFieldTextModule } from './text/text.module';
|
||||
import { AddonModDataFieldTextareaModule } from './textarea/textarea.module';
|
||||
import { AddonModDataFieldUrlModule } from './url/url.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
AddonModDataFieldCheckboxModule,
|
||||
AddonModDataFieldDateModule,
|
||||
AddonModDataFieldFileModule,
|
||||
AddonModDataFieldLatlongModule,
|
||||
AddonModDataFieldMenuModule,
|
||||
AddonModDataFieldMultimenuModule,
|
||||
AddonModDataFieldNumberModule,
|
||||
AddonModDataFieldPictureModule,
|
||||
AddonModDataFieldRadiobuttonModule,
|
||||
AddonModDataFieldTextModule,
|
||||
AddonModDataFieldTextareaModule,
|
||||
AddonModDataFieldUrlModule,
|
||||
],
|
||||
})
|
||||
export class AddonModDataFieldModule { }
|
|
@ -0,0 +1,17 @@
|
|||
<span *ngIf="editMode && form">
|
||||
<span [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||
<core-attachments [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component"
|
||||
[componentId]="componentId" [allowOffline]="true">
|
||||
</core-attachments>
|
||||
<core-input-errors *ngIf="error" [errorText]="error"></core-input-errors>
|
||||
</span>
|
||||
|
||||
<span *ngIf="searchMode && form" [formGroup]="form">
|
||||
<ion-input type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input>
|
||||
</span>
|
||||
|
||||
<ng-container *ngIf="displayMode">
|
||||
<div lines="none">
|
||||
<core-files [files]="files" [component]="component" [componentId]="componentId" [alwaysDownload]="true"></core-files>
|
||||
</div>
|
||||
</ng-container>
|
|
@ -0,0 +1,81 @@
|
|||
// (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 { Component } from '@angular/core';
|
||||
import { AddonModDataEntryField, AddonModDataProvider } from '@addons/mod/data/services/data';
|
||||
import { AddonModDataFieldPluginComponent } from '@addons/mod/data/classes/field-plugin-component';
|
||||
import { CoreFileSession } from '@services/file-session';
|
||||
import { CoreWSExternalFile } from '@services/ws';
|
||||
import { FileEntry } from '@ionic-native/file';
|
||||
|
||||
/**
|
||||
* Component to render data file field.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-data-field-file',
|
||||
templateUrl: 'addon-mod-data-field-file.html',
|
||||
})
|
||||
export class AddonModDataFieldFileComponent extends AddonModDataFieldPluginComponent {
|
||||
|
||||
files: (CoreWSExternalFile | FileEntry)[] = [];
|
||||
component?: string;
|
||||
componentId?: number;
|
||||
maxSizeBytes?: number;
|
||||
|
||||
/**
|
||||
* Get the files from the input value.
|
||||
*
|
||||
* @param value Input value.
|
||||
* @return List of files.
|
||||
*/
|
||||
protected getFiles(value?: Partial<AddonModDataEntryField>): (CoreWSExternalFile | FileEntry)[] {
|
||||
let files = value?.files || [];
|
||||
|
||||
// Reduce to first element.
|
||||
if (files.length > 0) {
|
||||
files = [files[0]];
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected init(): void {
|
||||
if (this.searchMode) {
|
||||
this.addControl('f_' + this.field.id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.component = AddonModDataProvider.COMPONENT;
|
||||
this.componentId = this.database!.coursemodule;
|
||||
|
||||
this.updateValue(this.value);
|
||||
|
||||
if (this.editMode) {
|
||||
this.maxSizeBytes = parseInt(this.field.param3, 10);
|
||||
CoreFileSession.setFiles(this.component, this.database!.id + '_' + this.field.id, this.files);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected updateValue(value?: Partial<AddonModDataEntryField>): void {
|
||||
this.value = value;
|
||||
this.files = this.getFiles(value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// (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 { CoreSharedModule } from '@/core/shared.module';
|
||||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||
import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate';
|
||||
import { AddonModDataFieldFileComponent } from './component/file';
|
||||
import { AddonModDataFieldFileHandler } from './services/handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModDataFieldFileComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
AddonModDataFieldsDelegate.registerHandler(AddonModDataFieldFileHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
AddonModDataFieldFileComponent,
|
||||
],
|
||||
})
|
||||
export class AddonModDataFieldFileModule {}
|
|
@ -0,0 +1,136 @@
|
|||
// (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 {
|
||||
AddonModDataEntryField,
|
||||
AddonModDataField,
|
||||
AddonModDataProvider,
|
||||
AddonModDataSearchEntriesAdvancedFieldFormatted,
|
||||
AddonModDataSubfieldData,
|
||||
} from '@addons/mod/data/services/data';
|
||||
import { AddonModDataFieldHandler } from '@addons/mod/data/services/data-fields-delegate';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreFileUploader, CoreFileUploaderStoreFilesResult } from '@features/fileuploader/services/fileuploader';
|
||||
import { FileEntry } from '@ionic-native/file';
|
||||
import { CoreFileSession } from '@services/file-session';
|
||||
import { CoreFormFields } from '@singletons/form';
|
||||
import { CoreWSExternalFile } from '@services/ws';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { AddonModDataFieldFileComponent } from '../component/file';
|
||||
|
||||
/**
|
||||
* Handler for file data field plugin.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonModDataFieldFileHandlerService implements AddonModDataFieldHandler {
|
||||
|
||||
name = 'AddonModDataFieldFileHandler';
|
||||
type = 'file';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getComponent(): Type<unknown>{
|
||||
return AddonModDataFieldFileComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldSearchData(field: AddonModDataField, inputData: CoreFormFields): AddonModDataSearchEntriesAdvancedFieldFormatted[] {
|
||||
const fieldName = 'f_' + field.id;
|
||||
|
||||
if (inputData[fieldName]) {
|
||||
return [{
|
||||
name: fieldName,
|
||||
value: inputData[fieldName],
|
||||
}];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldEditData(field: AddonModDataField): AddonModDataSubfieldData[] {
|
||||
const files = this.getFieldEditFiles(field);
|
||||
|
||||
return [{
|
||||
fieldid: field.id,
|
||||
subfield: 'file',
|
||||
files: files,
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldEditFiles(field: AddonModDataField): (CoreWSExternalFile | FileEntry)[] {
|
||||
return CoreFileSession.getFiles(AddonModDataProvider.COMPONENT, field.dataid + '_' + field.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
hasFieldDataChanged(field: AddonModDataField, inputData: CoreFormFields, originalFieldData: AddonModDataEntryField): boolean {
|
||||
const files = CoreFileSession.getFiles(AddonModDataProvider.COMPONENT, field.dataid + '_' + field.id) || [];
|
||||
let originalFiles = (originalFieldData && originalFieldData.files) || [];
|
||||
|
||||
if (originalFiles.length) {
|
||||
originalFiles = [originalFiles[0]];
|
||||
}
|
||||
|
||||
return CoreFileUploader.areFileListDifferent(files, originalFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldsNotifications(field: AddonModDataField, inputData: AddonModDataSubfieldData[]): string | undefined {
|
||||
if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
|
||||
return Translate.instant('addon.mod_data.errormustsupplyvalue');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
overrideData(
|
||||
originalContent: AddonModDataEntryField,
|
||||
offlineContent: CoreFormFields,
|
||||
offlineFiles?: FileEntry[],
|
||||
): AddonModDataEntryField {
|
||||
const uploadedFilesResult: CoreFileUploaderStoreFilesResult = <CoreFileUploaderStoreFilesResult>offlineContent?.file;
|
||||
|
||||
if (uploadedFilesResult && uploadedFilesResult.offline > 0 && offlineFiles && offlineFiles?.length > 0) {
|
||||
originalContent.content = offlineFiles[0].name;
|
||||
originalContent.files = [offlineFiles[0]];
|
||||
} else if (uploadedFilesResult && uploadedFilesResult.online && uploadedFilesResult.online.length > 0) {
|
||||
originalContent.content = uploadedFilesResult.online[0].filename || '';
|
||||
originalContent.files = [uploadedFilesResult.online[0]];
|
||||
}
|
||||
|
||||
return originalContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModDataFieldFileHandler = makeSingleton(AddonModDataFieldFileHandlerService);
|
|
@ -0,0 +1,27 @@
|
|||
<span *ngIf="inputMode && form" [formGroup]="form">
|
||||
<ion-input *ngIf="searchMode" type="text" [placeholder]="field.name" [formControlName]="'f_'+field.id"></ion-input>
|
||||
|
||||
<ng-container *ngIf="editMode">
|
||||
<span [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||
<div class="addon-data-latlong">
|
||||
<ion-input type="text" [formControlName]="'f_'+field.id+'_0'" maxlength="10"></ion-input>
|
||||
<span class="placeholder-icon" item-right>°N</span>
|
||||
</div>
|
||||
<div class="addon-data-latlong">
|
||||
<ion-input type="text" [formControlName]="'f_'+field.id+'_1'" maxlength="10"></ion-input>
|
||||
<span class="placeholder-icon" item-right>°E</span>
|
||||
</div>
|
||||
<div class="addon-data-latlong">
|
||||
<ion-button (click)="getLocation($event)">
|
||||
<ion-icon name="fas-crosshairs" slot="start"></ion-icon>
|
||||
{{ 'addon.mod_data.mylocation' | translate }}
|
||||
</ion-button>
|
||||
</div>
|
||||
<core-input-errors *ngIf="error" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||
</ng-container>
|
||||
</span>
|
||||
|
||||
|
||||
<span *ngIf="displayMode && value">
|
||||
<a [href]="getLatLongLink(north, east)">{{ formatLatLong(north, east) }}</a>
|
||||
</span>
|
|
@ -0,0 +1,164 @@
|
|||
// (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 { AddonModDataFieldPluginComponent } from '@addons/mod/data/classes/field-plugin-component';
|
||||
import { AddonModDataEntryField } from '@addons/mod/data/services/data';
|
||||
import { Component } from '@angular/core';
|
||||
import { FormBuilder } from '@angular/forms';
|
||||
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
||||
import { CoreAnyError } from '@classes/errors/error';
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CoreGeolocation, CoreGeolocationError, CoreGeolocationErrorReason } from '@services/geolocation';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
|
||||
/**
|
||||
* Component to render data latlong field.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-data-field-latlong',
|
||||
templateUrl: 'addon-mod-data-field-latlong.html',
|
||||
})
|
||||
export class AddonModDataFieldLatlongComponent extends AddonModDataFieldPluginComponent {
|
||||
|
||||
north?: number;
|
||||
east?: number;
|
||||
|
||||
constructor(
|
||||
fb: FormBuilder,
|
||||
protected sanitizer: DomSanitizer,
|
||||
) {
|
||||
super(fb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format latitude and longitude in a simple text.
|
||||
*
|
||||
* @param north Degrees north.
|
||||
* @param east Degrees East.
|
||||
* @return Readable Latitude and logitude.
|
||||
*/
|
||||
formatLatLong(north?: number, east?: number): string {
|
||||
if (typeof north !== 'undefined' || typeof east !== 'undefined') {
|
||||
north = north || 0;
|
||||
east = east || 0;
|
||||
const northFixed = Math.abs(north).toFixed(4);
|
||||
const eastFixed = Math.abs(east).toFixed(4);
|
||||
|
||||
return northFixed + (north < 0 ? '°S' : '°N') + ' ' + eastFixed + (east < 0 ? '°W' : '°E');
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get link to maps from latitude and longitude.
|
||||
*
|
||||
* @param north Degrees north.
|
||||
* @param east Degrees East.
|
||||
* @return Link to maps depending on platform.
|
||||
*/
|
||||
getLatLongLink(north?: number, east?: number): SafeUrl {
|
||||
let url = '';
|
||||
if (typeof north !== 'undefined' || typeof east !== 'undefined') {
|
||||
const northFixed = north ? north.toFixed(4) : '0.0000';
|
||||
const eastFixed = east ? east.toFixed(4) : '0.0000';
|
||||
|
||||
if (CoreApp.isIOS()) {
|
||||
url = 'http://maps.apple.com/?ll=' + northFixed + ',' + eastFixed + '&near=' + northFixed + ',' + eastFixed;
|
||||
} else {
|
||||
url = 'geo:' + northFixed + ',' + eastFixed;
|
||||
}
|
||||
}
|
||||
|
||||
return this.sanitizer.bypassSecurityTrustUrl(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected init(): void {
|
||||
if (this.value) {
|
||||
this.updateValue(this.value);
|
||||
}
|
||||
|
||||
if (this.editMode) {
|
||||
this.addControl('f_' + this.field.id + '_0', this.north);
|
||||
this.addControl('f_' + this.field.id + '_1', this.east);
|
||||
} else if (this.searchMode) {
|
||||
this.addControl('f_' + this.field.id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected updateValue(value?: Partial<AddonModDataEntryField>): void {
|
||||
this.value = value;
|
||||
this.north = (value && parseFloat(value.content!)) || undefined;
|
||||
this.east = (value && parseFloat(value.content1!)) || undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user location.
|
||||
*
|
||||
* @param $event The event.
|
||||
*/
|
||||
async getLocation(event: Event): Promise<void> {
|
||||
event.preventDefault();
|
||||
|
||||
const modal = await CoreDomUtils.showModalLoading('addon.mod_data.gettinglocation', true);
|
||||
|
||||
try {
|
||||
const coordinates = await CoreGeolocation.getCoordinates();
|
||||
|
||||
this.form?.controls['f_' + this.field.id + '_0'].setValue(coordinates.latitude);
|
||||
this.form?.controls['f_' + this.field.id + '_1'].setValue(coordinates.longitude);
|
||||
} catch (error) {
|
||||
this.showLocationErrorModal(error);
|
||||
}
|
||||
|
||||
modal.dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the appropriate error modal for the given error getting the location.
|
||||
*
|
||||
* @param error Location error.
|
||||
*/
|
||||
protected showLocationErrorModal(error: CoreAnyError): void {
|
||||
if (error instanceof CoreGeolocationError) {
|
||||
CoreDomUtils.showErrorModal(this.getGeolocationErrorMessage(error), true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CoreDomUtils.showErrorModalDefault(error, 'Error getting location');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get error message from a geolocation error.
|
||||
*
|
||||
* @param error Geolocation error.
|
||||
*/
|
||||
protected getGeolocationErrorMessage(error: CoreGeolocationError): string {
|
||||
// tslint:disable-next-line: switch-default
|
||||
switch (error.reason) {
|
||||
case CoreGeolocationErrorReason.PermissionDenied:
|
||||
return 'addon.mod_data.locationpermissiondenied';
|
||||
case CoreGeolocationErrorReason.LocationNotEnabled:
|
||||
return 'addon.mod_data.locationnotenabled';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// (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 { CoreSharedModule } from '@/core/shared.module';
|
||||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||
import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate';
|
||||
import { AddonModDataFieldLatlongComponent } from './component/latlong';
|
||||
import { AddonModDataFieldLatlongHandler } from './services/handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModDataFieldLatlongComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
AddonModDataFieldsDelegate.registerHandler(AddonModDataFieldLatlongHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
AddonModDataFieldLatlongComponent,
|
||||
],
|
||||
})
|
||||
export class AddonModDataFieldLatlongModule {}
|
|
@ -0,0 +1,138 @@
|
|||
// (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 {
|
||||
AddonModDataEntryField,
|
||||
AddonModDataField,
|
||||
AddonModDataSearchEntriesAdvancedFieldFormatted,
|
||||
AddonModDataSubfieldData,
|
||||
} from '@addons/mod/data/services/data';
|
||||
import { AddonModDataFieldHandler } from '@addons/mod/data/services/data-fields-delegate';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreFormFields } from '@singletons/form';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { AddonModDataFieldLatlongComponent } from '../component/latlong';
|
||||
|
||||
/**
|
||||
* Handler for latlong data field plugin.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonModDataFieldLatlongHandlerService implements AddonModDataFieldHandler {
|
||||
|
||||
name = 'AddonModDataFieldLatlongHandler';
|
||||
type = 'latlong';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getComponent(): Type<unknown>{
|
||||
return AddonModDataFieldLatlongComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldSearchData(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string>,
|
||||
): AddonModDataSearchEntriesAdvancedFieldFormatted[] {
|
||||
const fieldName = 'f_' + field.id;
|
||||
|
||||
if (inputData[fieldName]) {
|
||||
return [{
|
||||
name: fieldName,
|
||||
value: inputData[fieldName],
|
||||
}];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldEditData(field: AddonModDataField, inputData: CoreFormFields<string>): AddonModDataSubfieldData[] {
|
||||
const fieldName = 'f_' + field.id;
|
||||
|
||||
return [
|
||||
{
|
||||
fieldid: field.id,
|
||||
subfield: '0',
|
||||
value: inputData[fieldName + '_0'] || '',
|
||||
},
|
||||
{
|
||||
fieldid: field.id,
|
||||
subfield: '1',
|
||||
value: inputData[fieldName + '_1'] || '',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
hasFieldDataChanged(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string>,
|
||||
originalFieldData: AddonModDataEntryField,
|
||||
): boolean {
|
||||
const fieldName = 'f_' + field.id;
|
||||
const lat = inputData[fieldName + '_0'] || '';
|
||||
const long = inputData[fieldName + '_1'] || '';
|
||||
const originalLat = (originalFieldData && originalFieldData.content) || '';
|
||||
const originalLong = (originalFieldData && originalFieldData.content1) || '';
|
||||
|
||||
return lat != originalLat || long != originalLong;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldsNotifications(field: AddonModDataField, inputData: AddonModDataSubfieldData[]): string | undefined {
|
||||
let valueCount = 0;
|
||||
|
||||
// The lat long class has two values that need to be checked.
|
||||
inputData.forEach((value) => {
|
||||
if (typeof value.value != 'undefined' && value.value != '') {
|
||||
valueCount++;
|
||||
}
|
||||
});
|
||||
|
||||
// If we get here then only one field has been filled in.
|
||||
if (valueCount == 1) {
|
||||
return Translate.instant('addon.mod_data.latlongboth');
|
||||
} else if (field.required && valueCount == 0) {
|
||||
return Translate.instant('addon.mod_data.errormustsupplyvalue');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
overrideData(originalContent: AddonModDataEntryField, offlineContent: CoreFormFields<string>): AddonModDataEntryField {
|
||||
originalContent.content = offlineContent[0] || '';
|
||||
originalContent.content1 = offlineContent[1] || '';
|
||||
|
||||
return originalContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModDataFieldLatlongHandler = makeSingleton(AddonModDataFieldLatlongHandlerService);
|
|
@ -0,0 +1,11 @@
|
|||
<span *ngIf="inputMode && form" [formGroup]="form">
|
||||
<span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||
<ion-select [formControlName]="'f_'+field.id" [placeholder]="'addon.mod_data.menuchoose' | translate"
|
||||
[interfaceOptions]="{header: field.name}" interface="action-sheet">
|
||||
<ion-select-option value="">{{ 'addon.mod_data.menuchoose' | translate }}</ion-select-option>
|
||||
<ion-select-option *ngFor="let option of options" [value]="option">{{option}}</ion-select-option>
|
||||
</ion-select>
|
||||
<core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||
</span>
|
||||
|
||||
<span *ngIf="displayMode && value && value.content">{{ value.content }}</span>
|
|
@ -0,0 +1,47 @@
|
|||
// (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 { Component } from '@angular/core';
|
||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||
|
||||
/**
|
||||
* Component to render data menu field.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-data-field-menu',
|
||||
templateUrl: 'addon-mod-data-field-menu.html',
|
||||
})
|
||||
export class AddonModDataFieldMenuComponent extends AddonModDataFieldPluginComponent {
|
||||
|
||||
options: string[] = [];
|
||||
|
||||
/**
|
||||
* Initialize field.
|
||||
*/
|
||||
protected init(): void {
|
||||
if (this.displayMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.options = this.field.param1.split('\n');
|
||||
|
||||
let val: string | undefined;
|
||||
if (this.editMode && this.value) {
|
||||
val = this.value.content;
|
||||
}
|
||||
|
||||
this.addControl('f_' + this.field.id, val);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// (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 { CoreSharedModule } from '@/core/shared.module';
|
||||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||
import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate';
|
||||
import { AddonModDataFieldMenuComponent } from './component/menu';
|
||||
import { AddonModDataFieldMenuHandler } from './services/handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModDataFieldMenuComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
AddonModDataFieldsDelegate.registerHandler(AddonModDataFieldMenuHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
AddonModDataFieldMenuComponent,
|
||||
],
|
||||
})
|
||||
export class AddonModDataFieldMenuModule {}
|
|
@ -0,0 +1,116 @@
|
|||
// (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 {
|
||||
AddonModDataEntryField,
|
||||
AddonModDataField,
|
||||
AddonModDataSearchEntriesAdvancedFieldFormatted,
|
||||
AddonModDataSubfieldData,
|
||||
} from '@addons/mod/data/services/data';
|
||||
import { AddonModDataFieldHandler } from '@addons/mod/data/services/data-fields-delegate';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreFormFields } from '@singletons/form';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { AddonModDataFieldMenuComponent } from '../component/menu';
|
||||
|
||||
/**
|
||||
* Handler for menu data field plugin.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonModDataFieldMenuHandlerService implements AddonModDataFieldHandler {
|
||||
|
||||
name = 'AddonModDataFieldMenuHandler';
|
||||
type = 'menu';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getComponent(): Type<unknown>{
|
||||
return AddonModDataFieldMenuComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldSearchData(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string>,
|
||||
): AddonModDataSearchEntriesAdvancedFieldFormatted[] {
|
||||
const fieldName = 'f_' + field.id;
|
||||
if (inputData[fieldName]) {
|
||||
return [{
|
||||
name: fieldName,
|
||||
value: inputData[fieldName],
|
||||
}];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldEditData(field: AddonModDataField, inputData: CoreFormFields<string>): AddonModDataSubfieldData[] {
|
||||
|
||||
const fieldName = 'f_' + field.id;
|
||||
|
||||
if (inputData[fieldName]) {
|
||||
return [{
|
||||
fieldid: field.id,
|
||||
value: inputData[fieldName],
|
||||
}];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
hasFieldDataChanged(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string>,
|
||||
originalFieldData: AddonModDataEntryField,
|
||||
): boolean {
|
||||
const fieldName = 'f_' + field.id;
|
||||
const input = inputData[fieldName] || '';
|
||||
const content = originalFieldData?.content || '';
|
||||
|
||||
return input != content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldsNotifications(field: AddonModDataField, inputData: AddonModDataSubfieldData[]): string | undefined {
|
||||
if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
|
||||
return Translate.instant('addon.mod_data.errormustsupplyvalue');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
overrideData(originalContent: AddonModDataEntryField, offlineContent: CoreFormFields<string>): AddonModDataEntryField {
|
||||
originalContent.content = offlineContent[''] || '';
|
||||
|
||||
return originalContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModDataFieldMenuHandler = makeSingleton(AddonModDataFieldMenuHandlerService);
|
|
@ -0,0 +1,17 @@
|
|||
<span *ngIf="inputMode && form" [formGroup]="form">
|
||||
<span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||
<ion-select [formControlName]="'f_'+field.id" multiple="true" [placeholder]="'addon.mod_data.menuchoose' | translate"
|
||||
[interfaceOptions]="{header: field.name}" interface="alert">
|
||||
<ion-select-option *ngFor="let option of options" [value]="option.value">{{option.key}}</ion-select-option>
|
||||
</ion-select>
|
||||
<core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||
|
||||
|
||||
<ion-item *ngIf="searchMode">
|
||||
<ion-label>{{ 'addon.mod_data.selectedrequired' | translate }}</ion-label>
|
||||
<ion-checkbox slot="end" [formControlName]="'f_'+field.id+'_allreq'" [(ngModel)]="searchFields!['f_'+field.id+'_allreq']">
|
||||
</ion-checkbox>
|
||||
</ion-item>
|
||||
</span>
|
||||
|
||||
<core-format-text *ngIf="displayMode && value && value.content" [text]="value.content" [filter]="false"></core-format-text>
|
|
@ -0,0 +1,70 @@
|
|||
// (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 { AddonModDataEntryField } from '@addons/mod/data/services/data';
|
||||
import { Component } from '@angular/core';
|
||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||
|
||||
/**
|
||||
* Component to render data multimenu field.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-data-field-multimenu',
|
||||
templateUrl: 'addon-mod-data-field-multimenu.html',
|
||||
})
|
||||
export class AddonModDataFieldMultimenuComponent extends AddonModDataFieldPluginComponent {
|
||||
|
||||
options: {
|
||||
key: string;
|
||||
value: string;
|
||||
}[] = [];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected init(): void {
|
||||
if (this.displayMode) {
|
||||
this.updateValue(this.value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.options = this.field.param1.split(/\r?\n/).map((option) => ({ key: option, value: option }));
|
||||
|
||||
const values: string[] = [];
|
||||
if (this.editMode && this.value?.content) {
|
||||
this.value.content.split('##').forEach((value) => {
|
||||
const x = this.options.findIndex((option) => value == option.key);
|
||||
if (x >= 0) {
|
||||
values.push(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (this.searchMode) {
|
||||
this.addControl('f_' + this.field.id + '_allreq');
|
||||
}
|
||||
|
||||
this.addControl('f_' + this.field.id, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected updateValue(value?: Partial<AddonModDataEntryField>): void {
|
||||
this.value = value || {};
|
||||
this.value.content = value?.content && value.content.split('##').join('<br>');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// (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 { CoreSharedModule } from '@/core/shared.module';
|
||||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||
import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate';
|
||||
import { AddonModDataFieldMultimenuComponent } from './component/multimenu';
|
||||
import { AddonModDataFieldMultimenuHandler } from './services/handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModDataFieldMultimenuComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
AddonModDataFieldsDelegate.registerHandler(AddonModDataFieldMultimenuHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
AddonModDataFieldMultimenuComponent,
|
||||
],
|
||||
})
|
||||
export class AddonModDataFieldMultimenuModule {}
|
|
@ -0,0 +1,127 @@
|
|||
// (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 {
|
||||
AddonModDataEntryField,
|
||||
AddonModDataField,
|
||||
AddonModDataSearchEntriesAdvancedFieldFormatted,
|
||||
AddonModDataSubfieldData,
|
||||
} from '@addons/mod/data/services/data';
|
||||
import { AddonModDataFieldHandler } from '@addons/mod/data/services/data-fields-delegate';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreFormFields } from '@singletons/form';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { AddonModDataFieldMultimenuComponent } from '../component/multimenu';
|
||||
|
||||
/**
|
||||
* Handler for multimenu data field plugin.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonModDataFieldMultimenuHandlerService implements AddonModDataFieldHandler {
|
||||
|
||||
name = 'AddonModDataFieldMultimenuHandler';
|
||||
type = 'multimenu';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getComponent(): Type<unknown>{
|
||||
return AddonModDataFieldMultimenuComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldSearchData(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string[]>,
|
||||
): AddonModDataSearchEntriesAdvancedFieldFormatted[] {
|
||||
const fieldName = 'f_' + field.id;
|
||||
const reqName = 'f_' + field.id + '_allreq';
|
||||
|
||||
if (inputData[fieldName]) {
|
||||
|
||||
const values: AddonModDataSearchEntriesAdvancedFieldFormatted[] = [];
|
||||
values.push({
|
||||
name: fieldName,
|
||||
value: inputData[fieldName],
|
||||
});
|
||||
|
||||
if (inputData[reqName]) {
|
||||
values.push({
|
||||
name: reqName,
|
||||
value: true,
|
||||
});
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldEditData(field: AddonModDataField, inputData: CoreFormFields<string[]>): AddonModDataSubfieldData[] {
|
||||
|
||||
const fieldName = 'f_' + field.id;
|
||||
|
||||
return [{
|
||||
fieldid: field.id,
|
||||
value: inputData[fieldName] || [],
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
hasFieldDataChanged(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string[]>,
|
||||
originalFieldData: AddonModDataEntryField,
|
||||
): boolean {
|
||||
const fieldName = 'f_' + field.id;
|
||||
const content = originalFieldData?.content || '';
|
||||
|
||||
return inputData[fieldName].join('##') != content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldsNotifications(field: AddonModDataField, inputData: AddonModDataSubfieldData[]): string | undefined {
|
||||
if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
|
||||
return Translate.instant('addon.mod_data.errormustsupplyvalue');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
overrideData(originalContent: AddonModDataEntryField, offlineContent: CoreFormFields<string[]>): AddonModDataEntryField {
|
||||
originalContent.content = (offlineContent[''] && offlineContent[''].join('##')) || '';
|
||||
|
||||
return originalContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModDataFieldMultimenuHandler = makeSingleton(AddonModDataFieldMultimenuHandlerService);
|
|
@ -0,0 +1,7 @@
|
|||
<span *ngIf="inputMode && form" [formGroup]="form">
|
||||
<span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||
<ion-input type="number" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input>
|
||||
<core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||
</span>
|
||||
|
||||
<span *ngIf="displayMode && value && value.content">{{ value.content }}</span>
|
|
@ -0,0 +1,44 @@
|
|||
// (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 { Component } from '@angular/core';
|
||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||
|
||||
/**
|
||||
* Component to render data number field.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-data-field-number',
|
||||
templateUrl: 'addon-mod-data-field-number.html',
|
||||
})
|
||||
export class AddonModDataFieldNumberComponent extends AddonModDataFieldPluginComponent{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected init(): void {
|
||||
if (this.displayMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
let value: number | string | undefined;
|
||||
if (this.editMode && this.value) {
|
||||
const v = parseFloat(this.value.content || '');
|
||||
value = isNaN(v) ? '' : v;
|
||||
}
|
||||
|
||||
this.addControl('f_' + this.field.id, value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// (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 { CoreSharedModule } from '@/core/shared.module';
|
||||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||
import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate';
|
||||
import { AddonModDataFieldNumberComponent } from './component/number';
|
||||
import { AddonModDataFieldNumberHandler } from './services/handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModDataFieldNumberComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
AddonModDataFieldsDelegate.registerHandler(AddonModDataFieldNumberHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
AddonModDataFieldNumberComponent,
|
||||
],
|
||||
})
|
||||
export class AddonModDataFieldNumberModule {}
|
|
@ -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 { AddonModDataEntryField, AddonModDataField, AddonModDataSubfieldData } from '@addons/mod/data/services/data';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreFormFields } from '@singletons/form';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { AddonModDataFieldTextHandlerService } from '../../text/services/handler';
|
||||
import { AddonModDataFieldNumberComponent } from '../component/number';
|
||||
|
||||
/**
|
||||
* Handler for number data field plugin.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonModDataFieldNumberHandlerService extends AddonModDataFieldTextHandlerService {
|
||||
|
||||
name = 'AddonModDataFieldNumberHandler';
|
||||
type = 'number';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getComponent(): Type<unknown>{
|
||||
return AddonModDataFieldNumberComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
hasFieldDataChanged(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields,
|
||||
originalFieldData: AddonModDataEntryField,
|
||||
): boolean {
|
||||
const fieldName = 'f_' + field.id;
|
||||
const input = inputData[fieldName] || '';
|
||||
const content = originalFieldData?.content || '';
|
||||
|
||||
return input != content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldsNotifications(field: AddonModDataField, inputData: AddonModDataSubfieldData[]): string | undefined {
|
||||
if (field.required && (!inputData || !inputData.length || inputData[0].value == '')) {
|
||||
return Translate.instant('addon.mod_data.errormustsupplyvalue');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModDataFieldNumberHandler = makeSingleton(AddonModDataFieldNumberHandlerService);
|
|
@ -0,0 +1,22 @@
|
|||
<span *ngIf="editMode && form" [formGroup]="form">
|
||||
<span [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||
<core-attachments [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component"
|
||||
[componentId]="componentId" [allowOffline]="true" acceptedTypes="image">
|
||||
</core-attachments>
|
||||
<core-input-errors *ngIf="error" [errorText]="error"></core-input-errors>
|
||||
|
||||
<ion-label position="stacked">{{ 'addon.mod_data.alttext' | translate }}</ion-label>
|
||||
<ion-input type="text" [formControlName]="'f_'+field.id+'_alttext'" [placeholder]=" 'addon.mod_data.alttext' | translate" >
|
||||
</ion-input>
|
||||
</span>
|
||||
|
||||
<span *ngIf="searchMode && form" [formGroup]="form">
|
||||
<ion-input type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input>
|
||||
</span>
|
||||
|
||||
<span *ngIf="listMode && imageUrl" (click)="gotoEntry.emit(entryId)">
|
||||
<img [src]="imageUrl" [alt]="title" class="core-media-adapt-width listMode_picture" core-external-content/>
|
||||
</span>
|
||||
|
||||
<img *ngIf="showMode && imageUrl" [src]="imageUrl" [alt]="title" class="core-media-adapt-width listMode_picture"
|
||||
[attr.width]="width" [attr.height]="height" core-external-content/>
|
|
@ -0,0 +1,142 @@
|
|||
// (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 { AddonModDataEntryField, AddonModDataProvider } from '@addons/mod/data/services/data';
|
||||
import { Component } from '@angular/core';
|
||||
import { FileEntry } from '@ionic-native/file';
|
||||
import { CoreFileSession } from '@services/file-session';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreWSExternalFile } from '@services/ws';
|
||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||
|
||||
/**
|
||||
* Component to render data picture field.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-data-field-picture',
|
||||
templateUrl: 'addon-mod-data-field-picture.html',
|
||||
})
|
||||
export class AddonModDataFieldPictureComponent extends AddonModDataFieldPluginComponent {
|
||||
|
||||
files: (CoreWSExternalFile | FileEntry)[] = [];
|
||||
component?: string;
|
||||
componentId?: number;
|
||||
maxSizeBytes?: number;
|
||||
|
||||
image?: CoreWSExternalFile | FileEntry;
|
||||
entryId?: number;
|
||||
imageUrl?: string;
|
||||
title?: string;
|
||||
width?: string;
|
||||
height?: string;
|
||||
|
||||
/**
|
||||
* Get the files from the input value.
|
||||
*
|
||||
* @param value Input value.
|
||||
* @return List of files.
|
||||
*/
|
||||
protected getFiles(value?: Partial<AddonModDataEntryField>): (CoreWSExternalFile | FileEntry)[] {
|
||||
let files = value?.files || [];
|
||||
|
||||
// Reduce to first element.
|
||||
if (files.length > 0) {
|
||||
files = [files[0]];
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find file in a list.
|
||||
*
|
||||
* @param files File list where to search.
|
||||
* @param filenameSeek Filename to search.
|
||||
* @return File found or false.
|
||||
*/
|
||||
protected findFile(
|
||||
files: (CoreWSExternalFile | FileEntry)[],
|
||||
filenameSeek: string,
|
||||
): CoreWSExternalFile | FileEntry | undefined {
|
||||
return files.find((file) => ('name' in file ? file.name : file.filename) == filenameSeek) || undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected init(): void {
|
||||
if (this.searchMode) {
|
||||
this.addControl('f_' + this.field.id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.component = AddonModDataProvider.COMPONENT;
|
||||
this.componentId = this.database!.coursemodule;
|
||||
|
||||
this.updateValue(this.value);
|
||||
|
||||
if (this.editMode) {
|
||||
this.maxSizeBytes = parseInt(this.field.param3, 10);
|
||||
CoreFileSession.setFiles(this.component, this.database!.id + '_' + this.field.id, this.files);
|
||||
|
||||
const alttext = (this.value && this.value.content1) || '';
|
||||
this.addControl('f_' + this.field.id + '_alttext', alttext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected updateValue(value?: Partial<AddonModDataEntryField>): void {
|
||||
|
||||
// Edit mode, the list shouldn't change so there is no need to watch it.
|
||||
const files = value?.files || [];
|
||||
|
||||
// Get image or thumb.
|
||||
if (files.length > 0) {
|
||||
const filenameSeek = this.listMode
|
||||
? 'thumb_' + value?.content
|
||||
: value?.content;
|
||||
this.image = this.findFile(files, filenameSeek || '');
|
||||
|
||||
if (!this.image && this.listMode) {
|
||||
this.image = this.findFile(files, value?.content || '');
|
||||
}
|
||||
|
||||
if (this.image) {
|
||||
this.files = [this.image];
|
||||
}
|
||||
} else {
|
||||
this.image = undefined;
|
||||
this.files = [];
|
||||
}
|
||||
|
||||
if (!this.editMode) {
|
||||
this.entryId = (value && value.recordid) || undefined;
|
||||
this.title = (value && value.content1) || '';
|
||||
this.imageUrl = undefined;
|
||||
setTimeout(() => {
|
||||
if (this.image) {
|
||||
this.imageUrl = 'name' in this.image
|
||||
? this.image.toURL() // Is Offline.
|
||||
: this.image.fileurl;
|
||||
}
|
||||
}, 1);
|
||||
|
||||
this.width = CoreDomUtils.formatPixelsSize(this.field.param1);
|
||||
this.height = CoreDomUtils.formatPixelsSize(this.field.param2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// (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 { CoreSharedModule } from '@/core/shared.module';
|
||||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||
import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate';
|
||||
import { AddonModDataFieldPictureComponent } from './component/picture';
|
||||
import { AddonModDataFieldPictureHandler } from './services/handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModDataFieldPictureComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
AddonModDataFieldsDelegate.registerHandler(AddonModDataFieldPictureHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
AddonModDataFieldPictureComponent,
|
||||
],
|
||||
})
|
||||
export class AddonModDataFieldPictureModule {}
|
|
@ -0,0 +1,181 @@
|
|||
// (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 {
|
||||
AddonModDataEntryField,
|
||||
AddonModDataField,
|
||||
AddonModDataProvider,
|
||||
AddonModDataSearchEntriesAdvancedFieldFormatted,
|
||||
AddonModDataSubfieldData,
|
||||
} from '@addons/mod/data/services/data';
|
||||
import { AddonModDataFieldHandler } from '@addons/mod/data/services/data-fields-delegate';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreFileUploader, CoreFileUploaderStoreFilesResult } from '@features/fileuploader/services/fileuploader';
|
||||
import { FileEntry } from '@ionic-native/file';
|
||||
import { CoreFileSession } from '@services/file-session';
|
||||
import { CoreFormFields } from '@singletons/form';
|
||||
import { CoreWSExternalFile } from '@services/ws';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { AddonModDataFieldPictureComponent } from '../component/picture';
|
||||
|
||||
/**
|
||||
* Handler for picture data field plugin.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonModDataFieldPictureHandlerService implements AddonModDataFieldHandler {
|
||||
|
||||
name = 'AddonModDataFieldPictureHandler';
|
||||
type = 'picture';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getComponent(): Type<unknown>{
|
||||
return AddonModDataFieldPictureComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldSearchData(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string>,
|
||||
): AddonModDataSearchEntriesAdvancedFieldFormatted[] {
|
||||
const fieldName = 'f_' + field.id;
|
||||
|
||||
if (inputData[fieldName]) {
|
||||
return [{
|
||||
name: fieldName,
|
||||
value: inputData[fieldName],
|
||||
}];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldEditData(field: AddonModDataField, inputData: CoreFormFields<string>): AddonModDataSubfieldData[] {
|
||||
const files = this.getFieldEditFiles(field);
|
||||
const fieldName = 'f_' + field.id + '_alttext';
|
||||
|
||||
return [
|
||||
{
|
||||
fieldid: field.id,
|
||||
subfield: 'file',
|
||||
files: files,
|
||||
},
|
||||
{
|
||||
fieldid: field.id,
|
||||
subfield: 'alttext',
|
||||
value: inputData[fieldName],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldEditFiles(field: AddonModDataField): (CoreWSExternalFile | FileEntry)[] {
|
||||
return CoreFileSession.getFiles(AddonModDataProvider.COMPONENT, field.dataid + '_' + field.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
hasFieldDataChanged(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string>,
|
||||
originalFieldData: AddonModDataEntryField,
|
||||
): boolean {
|
||||
const fieldName = 'f_' + field.id + '_alttext';
|
||||
const altText = inputData[fieldName] || '';
|
||||
const originalAltText = originalFieldData?.content1 || '';
|
||||
if (altText != originalAltText) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const files = this.getFieldEditFiles(field) || [];
|
||||
let originalFiles = originalFieldData?.files || [];
|
||||
|
||||
// Get image.
|
||||
if (originalFiles.length > 0) {
|
||||
const filenameSeek = originalFieldData?.content || '';
|
||||
const file = originalFiles.find((file) => ('name' in file ? file.name : file.filename) == filenameSeek);
|
||||
if (file) {
|
||||
originalFiles = [file];
|
||||
}
|
||||
}
|
||||
|
||||
return CoreFileUploader.areFileListDifferent(files, originalFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldsNotifications(field: AddonModDataField, inputData: AddonModDataSubfieldData[]): string | undefined {
|
||||
if (!field.required) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inputData || !inputData.length) {
|
||||
return Translate.instant('addon.mod_data.errormustsupplyvalue');
|
||||
}
|
||||
|
||||
const found = inputData.some((input) => {
|
||||
if (typeof input.subfield != 'undefined' && input.subfield == 'file') {
|
||||
return !!input.value;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
return Translate.instant('addon.mod_data.errormustsupplyvalue');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
overrideData(
|
||||
originalContent: AddonModDataEntryField,
|
||||
offlineContent: CoreFormFields,
|
||||
offlineFiles?: FileEntry[],
|
||||
): AddonModDataEntryField {
|
||||
const uploadedFilesResult: CoreFileUploaderStoreFilesResult = <CoreFileUploaderStoreFilesResult>offlineContent?.file;
|
||||
|
||||
if (uploadedFilesResult && uploadedFilesResult.offline > 0 && offlineFiles && offlineFiles?.length > 0) {
|
||||
originalContent.content = offlineFiles[0].name;
|
||||
originalContent.files = [offlineFiles[0]];
|
||||
} else if (uploadedFilesResult && uploadedFilesResult.online && uploadedFilesResult.online.length > 0) {
|
||||
originalContent.content = uploadedFilesResult.online[0].filename || '';
|
||||
originalContent.files = [uploadedFilesResult.online[0]];
|
||||
}
|
||||
|
||||
originalContent.content1 = <string>offlineContent.alttext || '';
|
||||
|
||||
return originalContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModDataFieldPictureHandler = makeSingleton(AddonModDataFieldPictureHandlerService);
|
|
@ -0,0 +1,11 @@
|
|||
<span *ngIf="inputMode && form" [formGroup]="form">
|
||||
<span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||
<ion-select [formControlName]="'f_'+field.id" [placeholder]="'addon.mod_data.menuchoose' | translate"
|
||||
[interfaceOptions]="{header: field.name}" interface="alert">
|
||||
<ion-select-option value="">{{ 'addon.mod_data.menuchoose' | translate }}</ion-select-option>
|
||||
<ion-select-option *ngFor="let option of options" [value]="option">{{option}}</ion-select-option>
|
||||
</ion-select>
|
||||
<core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||
</span>
|
||||
|
||||
<span *ngIf="displayMode && value && value.content">{{ value.content }}</span>
|
|
@ -0,0 +1,46 @@
|
|||
// (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 { Component } from '@angular/core';
|
||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||
|
||||
/**
|
||||
* Component to render data radiobutton field.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-data-field-radiobutton',
|
||||
templateUrl: 'addon-mod-data-field-radiobutton.html',
|
||||
})
|
||||
export class AddonModDataFieldRadiobuttonComponent extends AddonModDataFieldPluginComponent {
|
||||
|
||||
options: string[] = [];
|
||||
|
||||
/**
|
||||
* Initialize field.
|
||||
*/
|
||||
protected init(): void {
|
||||
if (this.displayMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.options = this.field.param1.split('\n');
|
||||
|
||||
let val: string | undefined;
|
||||
if (this.editMode && this.value) {
|
||||
val = this.value.content;
|
||||
}
|
||||
|
||||
this.addControl('f_' + this.field.id, val);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// (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 { CoreSharedModule } from '@/core/shared.module';
|
||||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||
import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate';
|
||||
import { AddonModDataFieldRadiobuttonComponent } from './component/radiobutton';
|
||||
import { AddonModDataFieldRadiobuttonHandler } from './services/handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModDataFieldRadiobuttonComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
AddonModDataFieldsDelegate.registerHandler(AddonModDataFieldRadiobuttonHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
AddonModDataFieldRadiobuttonComponent,
|
||||
],
|
||||
})
|
||||
export class AddonModDataFieldRadiobuttonModule {}
|
|
@ -0,0 +1,114 @@
|
|||
// (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 {
|
||||
AddonModDataEntryField,
|
||||
AddonModDataField,
|
||||
AddonModDataSearchEntriesAdvancedFieldFormatted,
|
||||
AddonModDataSubfieldData,
|
||||
} from '@addons/mod/data/services/data';
|
||||
import { AddonModDataFieldHandler } from '@addons/mod/data/services/data-fields-delegate';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreFormFields } from '@singletons/form';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { AddonModDataFieldRadiobuttonComponent } from '../component/radiobutton';
|
||||
|
||||
/**
|
||||
* Handler for checkbox data field plugin.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonModDataFieldRadiobuttonHandlerService implements AddonModDataFieldHandler {
|
||||
|
||||
name = 'AddonModDataFieldRadiobuttonHandler';
|
||||
type = 'radiobutton';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getComponent(): Type<unknown>{
|
||||
return AddonModDataFieldRadiobuttonComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldSearchData(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string>,
|
||||
): AddonModDataSearchEntriesAdvancedFieldFormatted[] {
|
||||
const fieldName = 'f_' + field.id;
|
||||
if (inputData[fieldName]) {
|
||||
return [{
|
||||
name: fieldName,
|
||||
value: inputData[fieldName],
|
||||
}];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldEditData(field: AddonModDataField, inputData: CoreFormFields<string>): AddonModDataSubfieldData[] {
|
||||
const fieldName = 'f_' + field.id;
|
||||
|
||||
return [{
|
||||
fieldid: field.id,
|
||||
value: inputData[fieldName] || '',
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
hasFieldDataChanged(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string>,
|
||||
originalFieldData: AddonModDataEntryField,
|
||||
): boolean {
|
||||
const fieldName = 'f_' + field.id;
|
||||
const input = inputData[fieldName] || '';
|
||||
const content = originalFieldData?.content || '';
|
||||
|
||||
return input != content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldsNotifications(field: AddonModDataField, inputData: AddonModDataSubfieldData[]): string | undefined {
|
||||
if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
|
||||
return Translate.instant('addon.mod_data.errormustsupplyvalue');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
overrideData(originalContent: AddonModDataEntryField, offlineContent: CoreFormFields<string>): AddonModDataEntryField {
|
||||
originalContent.content = offlineContent[''] || '';
|
||||
|
||||
return originalContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModDataFieldRadiobuttonHandler = makeSingleton(AddonModDataFieldRadiobuttonHandlerService);
|
|
@ -0,0 +1,7 @@
|
|||
<span *ngIf="inputMode && form" [formGroup]="form">
|
||||
<span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||
<ion-input type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input>
|
||||
<core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||
</span>
|
||||
|
||||
<span *ngIf="displayMode && value && value.content">{{ value.content }}</span>
|
|
@ -0,0 +1,43 @@
|
|||
// (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 { Component } from '@angular/core';
|
||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||
|
||||
/**
|
||||
* Component to render data text field.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-data-field-text',
|
||||
templateUrl: 'addon-mod-data-field-text.html',
|
||||
})
|
||||
export class AddonModDataFieldTextComponent extends AddonModDataFieldPluginComponent {
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected init(): void {
|
||||
if (this.displayMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
let value: string | undefined;
|
||||
if (this.editMode && this.value) {
|
||||
value = this.value.content;
|
||||
}
|
||||
|
||||
this.addControl('f_' + this.field.id, value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
// (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 {
|
||||
AddonModDataEntryField,
|
||||
AddonModDataField,
|
||||
AddonModDataSearchEntriesAdvancedFieldFormatted,
|
||||
AddonModDataSubfieldData,
|
||||
} from '@addons/mod/data/services/data';
|
||||
import { AddonModDataFieldHandler } from '@addons/mod/data/services/data-fields-delegate';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreFormFields } from '@singletons/form';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { AddonModDataFieldTextComponent } from '../component/text';
|
||||
|
||||
/**
|
||||
* Handler for number data field plugin.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonModDataFieldTextHandlerService implements AddonModDataFieldHandler {
|
||||
|
||||
name = 'AddonModDataFieldTextHandler';
|
||||
type = 'text';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getComponent(): Type<unknown>{
|
||||
return AddonModDataFieldTextComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldSearchData(field: AddonModDataField, inputData: CoreFormFields): AddonModDataSearchEntriesAdvancedFieldFormatted[] {
|
||||
const fieldName = 'f_' + field.id;
|
||||
|
||||
if (inputData[fieldName]) {
|
||||
return [{
|
||||
name: fieldName,
|
||||
value: inputData[fieldName],
|
||||
}];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldEditData(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string>,
|
||||
originalFieldData: AddonModDataEntryField, // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
): AddonModDataSubfieldData[] {
|
||||
|
||||
const fieldName = 'f_' + field.id;
|
||||
|
||||
return [{
|
||||
fieldid: field.id,
|
||||
value: inputData[fieldName] || '',
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
hasFieldDataChanged(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string>,
|
||||
originalFieldData: AddonModDataEntryField,
|
||||
): boolean {
|
||||
const fieldName = 'f_' + field.id;
|
||||
const input = inputData[fieldName] || '';
|
||||
const content = originalFieldData?.content || '';
|
||||
|
||||
return input != content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldsNotifications(field: AddonModDataField, inputData: AddonModDataSubfieldData[]): string | undefined {
|
||||
if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
|
||||
return Translate.instant('addon.mod_data.errormustsupplyvalue');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
overrideData(originalContent: AddonModDataEntryField, offlineContent: CoreFormFields<string>): AddonModDataEntryField {
|
||||
originalContent.content = offlineContent[''] || '';
|
||||
|
||||
return originalContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModDataFieldTextHandler = makeSingleton(AddonModDataFieldTextHandlerService);
|
|
@ -0,0 +1,42 @@
|
|||
// (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 { CoreSharedModule } from '@/core/shared.module';
|
||||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||
import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate';
|
||||
import { AddonModDataFieldTextComponent } from './component/text';
|
||||
import { AddonModDataFieldTextHandler } from './services/handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModDataFieldTextComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
AddonModDataFieldsDelegate.registerHandler(AddonModDataFieldTextHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
AddonModDataFieldTextComponent,
|
||||
],
|
||||
})
|
||||
export class AddonModDataFieldTextModule {}
|
|
@ -0,0 +1,14 @@
|
|||
<span *ngIf="inputMode && form" [formGroup]="form">
|
||||
<ion-input *ngIf="searchMode" type="text" [placeholder]="field.name" [formControlName]="'f_'+field.id"></ion-input>
|
||||
|
||||
<span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||
<core-rich-text-editor *ngIf="editMode" item-content [control]="form.controls['f_'+field.id]" [placeholder]="field.name"
|
||||
[formControlName]="'f_'+field.id" [component]="component" [componentId]="componentId" [autoSave]="true"
|
||||
contextLevel="module" [contextInstanceId]="componentId" [elementId]="'field_'+field.id" ngDefaultControl>
|
||||
</core-rich-text-editor>
|
||||
<core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||
</span>
|
||||
|
||||
<core-format-text *ngIf="displayMode && value" [text]="format(value)" [component]="component" [componentId]="componentId"
|
||||
contextLevel="module" [contextInstanceId]="componentId" [courseId]="database!.course">
|
||||
</core-format-text>
|
|
@ -0,0 +1,65 @@
|
|||
// (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 { Component } from '@angular/core';
|
||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||
import { AddonModDataEntryField, AddonModDataProvider } from '@addons/mod/data/services/data';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreWSExternalFile } from '@services/ws';
|
||||
|
||||
/**
|
||||
* Component to render data number field.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-data-field-textarea',
|
||||
templateUrl: 'addon-mod-data-field-textarea.html',
|
||||
})
|
||||
export class AddonModDataFieldTextareaComponent extends AddonModDataFieldPluginComponent {
|
||||
|
||||
component?: string;
|
||||
componentId?: number;
|
||||
|
||||
/**
|
||||
* Format value to be shown. Replacing plugin file Urls.
|
||||
*
|
||||
* @param value Value to replace.
|
||||
* @return Replaced string to be rendered.
|
||||
*/
|
||||
format(value?: Partial<AddonModDataEntryField>): string {
|
||||
const files: CoreWSExternalFile[] = (value && <CoreWSExternalFile[]>value.files) || [];
|
||||
|
||||
return value ? CoreTextUtils.replacePluginfileUrls(value.content || '', files) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize field.
|
||||
*/
|
||||
protected init(): void {
|
||||
this.component = AddonModDataProvider.COMPONENT;
|
||||
this.componentId = this.database?.coursemodule;
|
||||
|
||||
if (this.displayMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
let text: string | undefined;
|
||||
// Check if rich text editor is enabled.
|
||||
if (this.editMode) {
|
||||
text = this.format(this.value);
|
||||
}
|
||||
|
||||
this.addControl('f_' + this.field.id, text);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
// (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 { AddonModDataEntryField, AddonModDataField, AddonModDataSubfieldData } from '@addons/mod/data/services/data';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { FileEntry } from '@ionic-native/file';
|
||||
import { CoreFormFields } from '@singletons/form';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreWSExternalFile } from '@services/ws';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { AddonModDataFieldTextHandlerService } from '../../text/services/handler';
|
||||
import { AddonModDataFieldTextareaComponent } from '../component/textarea';
|
||||
|
||||
/**
|
||||
* Handler for textarea data field plugin.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonModDataFieldTextareaHandlerService extends AddonModDataFieldTextHandlerService {
|
||||
|
||||
name = 'AddonModDataFieldTextareaHandler';
|
||||
type = 'textarea';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getComponent(): Type<unknown>{
|
||||
return AddonModDataFieldTextareaComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldEditData(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields<string>,
|
||||
originalFieldData: AddonModDataEntryField,
|
||||
): AddonModDataSubfieldData[] {
|
||||
const fieldName = 'f_' + field.id;
|
||||
const files = this.getFieldEditFiles(field, inputData, originalFieldData);
|
||||
|
||||
let text = CoreTextUtils.restorePluginfileUrls(inputData[fieldName] || '', <CoreWSExternalFile[]>files);
|
||||
// Add some HTML to the text if needed.
|
||||
text = CoreTextUtils.formatHtmlLines(text);
|
||||
|
||||
// WS does not properly check if HTML content is blank when the field is required.
|
||||
if (CoreTextUtils.htmlIsBlank(text)) {
|
||||
text = '';
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
fieldid: field.id,
|
||||
value: text,
|
||||
},
|
||||
{
|
||||
fieldid: field.id,
|
||||
subfield: 'content1',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
fieldid: field.id,
|
||||
subfield: 'itemid',
|
||||
files: files,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldEditFiles(
|
||||
field: AddonModDataField,
|
||||
inputData: CoreFormFields,
|
||||
originalFieldData: AddonModDataEntryField,
|
||||
): (CoreWSExternalFile | FileEntry)[] {
|
||||
return (originalFieldData && originalFieldData.files) || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldsNotifications(field: AddonModDataField, inputData: AddonModDataSubfieldData[]): string | undefined {
|
||||
if (!field.required) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inputData || !inputData.length) {
|
||||
return Translate.instant('addon.mod_data.errormustsupplyvalue');
|
||||
}
|
||||
|
||||
const value = inputData.find((value) => value.subfield == '');
|
||||
|
||||
if (!value || CoreTextUtils.htmlIsBlank(<string>value.value || '')) {
|
||||
return Translate.instant('addon.mod_data.errormustsupplyvalue');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
overrideData(originalContent: AddonModDataEntryField, offlineContent: CoreFormFields<string>): AddonModDataEntryField {
|
||||
originalContent.content = offlineContent[''] || '';
|
||||
if (originalContent.content.length > 0 && originalContent.files && originalContent.files.length > 0) {
|
||||
// Take the original files since we cannot edit them on the app.
|
||||
originalContent.content = CoreTextUtils.replacePluginfileUrls(
|
||||
originalContent.content,
|
||||
<CoreWSExternalFile[]>originalContent.files,
|
||||
);
|
||||
}
|
||||
|
||||
return originalContent;
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModDataFieldTextareaHandler = makeSingleton(AddonModDataFieldTextareaHandlerService);
|
|
@ -0,0 +1,44 @@
|
|||
// (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 { CoreSharedModule } from '@/core/shared.module';
|
||||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||
import { CoreEditorComponentsModule } from '@features/editor/components/components.module';
|
||||
import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate';
|
||||
import { AddonModDataFieldTextareaComponent } from './component/textarea';
|
||||
import { AddonModDataFieldTextareaHandler } from './services/handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModDataFieldTextareaComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
CoreEditorComponentsModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
AddonModDataFieldsDelegate.registerHandler(AddonModDataFieldTextareaHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
AddonModDataFieldTextareaComponent,
|
||||
],
|
||||
})
|
||||
export class AddonModDataFieldTextareaModule {}
|
|
@ -0,0 +1,10 @@
|
|||
<span *ngIf="inputMode && form" [formGroup]="form">
|
||||
<span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||
<ion-input type="url" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input>
|
||||
<core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||
</span>
|
||||
|
||||
<ng-container *ngIf="displayMode && value && value.content">
|
||||
<a *ngIf="autoLink" [href]="value.content" core-link capture="true">{{ displayValue }}</a>
|
||||
<span *ngIf="!autoLink">{{ displayValue }}</span>
|
||||
</ng-container>
|
|
@ -0,0 +1,78 @@
|
|||
// (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 { AddonModDataEntryField } from '@addons/mod/data/services/data';
|
||||
import { Component } from '@angular/core';
|
||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||
|
||||
/**
|
||||
* Component to render data url field.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-data-field-url',
|
||||
templateUrl: 'addon-mod-data-field-url.html',
|
||||
})
|
||||
export class AddonModDataFieldUrlComponent extends AddonModDataFieldPluginComponent {
|
||||
|
||||
autoLink = false;
|
||||
displayValue = '';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected init(): void {
|
||||
if (this.displayMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
let value: string | undefined;
|
||||
if (this.editMode && this.value) {
|
||||
value = this.value.content;
|
||||
}
|
||||
|
||||
this.addControl('f_' + this.field.id, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate data for show or list mode.
|
||||
*/
|
||||
protected calculateShowListData(): void {
|
||||
if (!this.value || !this.value.content) {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = this.value.content;
|
||||
const text = this.field.param2 || this.value.content1; // Param2 forces the text to display.
|
||||
|
||||
this.autoLink = parseInt(this.field.param1, 10) === 1;
|
||||
|
||||
if (this.autoLink) {
|
||||
this.displayValue = text || url;
|
||||
} else {
|
||||
// No auto link, always display the URL.
|
||||
this.displayValue = url;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected updateValue(value?: Partial<AddonModDataEntryField>): void {
|
||||
super.updateValue(value);
|
||||
|
||||
if (this.displayMode) {
|
||||
this.calculateShowListData();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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 { AddonModDataField, AddonModDataSubfieldData } from '@addons/mod/data/services/data';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreFormFields } from '@singletons/form';
|
||||
import { Translate, makeSingleton } from '@singletons';
|
||||
import { AddonModDataFieldTextHandlerService } from '../../text/services/handler';
|
||||
import { AddonModDataFieldUrlComponent } from '../component/url';
|
||||
|
||||
/**
|
||||
* Handler for url data field plugin.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AddonModDataFieldUrlHandlerService extends AddonModDataFieldTextHandlerService {
|
||||
|
||||
name = 'AddonModDataFieldUrlHandler';
|
||||
type = 'url';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getComponent(): Type<unknown>{
|
||||
return AddonModDataFieldUrlComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldEditData(field: AddonModDataField, inputData: CoreFormFields<string>): AddonModDataSubfieldData[] {
|
||||
const fieldName = 'f_' + field.id;
|
||||
|
||||
return [
|
||||
{
|
||||
fieldid: field.id,
|
||||
subfield: '0',
|
||||
value: (inputData[fieldName] && inputData[fieldName].trim()) || '',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
getFieldsNotifications(field: AddonModDataField, inputData: AddonModDataSubfieldData[]): string | undefined {
|
||||
if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
|
||||
return Translate.instant('addon.mod_data.errormustsupplyvalue');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModDataFieldUrlHandler = makeSingleton(AddonModDataFieldUrlHandlerService);
|
|
@ -0,0 +1,42 @@
|
|||
// (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 { CoreSharedModule } from '@/core/shared.module';
|
||||
import { NgModule, APP_INITIALIZER } from '@angular/core';
|
||||
import { AddonModDataFieldsDelegate } from '../../services/data-fields-delegate';
|
||||
import { AddonModDataFieldUrlComponent } from './component/url';
|
||||
import { AddonModDataFieldUrlHandler } from './services/handler';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModDataFieldUrlComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
AddonModDataFieldsDelegate.registerHandler(AddonModDataFieldUrlHandler.instance);
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [
|
||||
AddonModDataFieldUrlComponent,
|
||||
],
|
||||
})
|
||||
export class AddonModDataFieldUrlModule {}
|
Loading…
Reference in New Issue