forked from EVOgeek/Vmeda.Online
		
	MOBILE-3640 database: Add fields components
This commit is contained in:
		
							parent
							
								
									2991873dfe
								
							
						
					
					
						commit
						8febbe3ea7
					
				
							
								
								
									
										116
									
								
								src/addons/mod/data/classes/field-plugin-component.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								src/addons/mod/data/classes/field-plugin-component.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										103
									
								
								src/addons/mod/data/components/field-plugin/field-plugin.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/addons/mod/data/components/field-plugin/field-plugin.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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>; | ||||
| }; | ||||
							
								
								
									
										42
									
								
								src/addons/mod/data/fields/checkbox/checkbox.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/addons/mod/data/fields/checkbox/checkbox.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										70
									
								
								src/addons/mod/data/fields/checkbox/component/checkbox.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/addons/mod/data/fields/checkbox/component/checkbox.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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>'); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										131
									
								
								src/addons/mod/data/fields/checkbox/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								src/addons/mod/data/fields/checkbox/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										70
									
								
								src/addons/mod/data/fields/date/component/date.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/addons/mod/data/fields/date/component/date.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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())); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/addons/mod/data/fields/date/date.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/addons/mod/data/fields/date/date.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 {} | ||||
							
								
								
									
										165
									
								
								src/addons/mod/data/fields/date/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								src/addons/mod/data/fields/date/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
							
								
								
									
										45
									
								
								src/addons/mod/data/fields/field.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/addons/mod/data/fields/field.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										81
									
								
								src/addons/mod/data/fields/file/component/file.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/addons/mod/data/fields/file/component/file.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/addons/mod/data/fields/file/file.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/addons/mod/data/fields/file/file.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 {} | ||||
							
								
								
									
										136
									
								
								src/addons/mod/data/fields/file/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								src/addons/mod/data/fields/file/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										164
									
								
								src/addons/mod/data/fields/latlong/component/latlong.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								src/addons/mod/data/fields/latlong/component/latlong.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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'; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/addons/mod/data/fields/latlong/latlong.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/addons/mod/data/fields/latlong/latlong.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 {} | ||||
							
								
								
									
										138
									
								
								src/addons/mod/data/fields/latlong/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								src/addons/mod/data/fields/latlong/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										47
									
								
								src/addons/mod/data/fields/menu/component/menu.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/addons/mod/data/fields/menu/component/menu.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/addons/mod/data/fields/menu/menu.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/addons/mod/data/fields/menu/menu.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 {} | ||||
							
								
								
									
										116
									
								
								src/addons/mod/data/fields/menu/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								src/addons/mod/data/fields/menu/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										70
									
								
								src/addons/mod/data/fields/multimenu/component/multimenu.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/addons/mod/data/fields/multimenu/component/multimenu.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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>'); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/addons/mod/data/fields/multimenu/multimenu.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/addons/mod/data/fields/multimenu/multimenu.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 {} | ||||
							
								
								
									
										127
									
								
								src/addons/mod/data/fields/multimenu/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								src/addons/mod/data/fields/multimenu/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										44
									
								
								src/addons/mod/data/fields/number/component/number.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/addons/mod/data/fields/number/component/number.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/addons/mod/data/fields/number/number.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/addons/mod/data/fields/number/number.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 {} | ||||
							
								
								
									
										63
									
								
								src/addons/mod/data/fields/number/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/addons/mod/data/fields/number/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { 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/> | ||||
							
								
								
									
										142
									
								
								src/addons/mod/data/fields/picture/component/picture.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								src/addons/mod/data/fields/picture/component/picture.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/addons/mod/data/fields/picture/picture.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/addons/mod/data/fields/picture/picture.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 {} | ||||
							
								
								
									
										181
									
								
								src/addons/mod/data/fields/picture/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								src/addons/mod/data/fields/picture/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										42
									
								
								src/addons/mod/data/fields/radiobutton/radiobutton.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/addons/mod/data/fields/radiobutton/radiobutton.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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 {} | ||||
							
								
								
									
										114
									
								
								src/addons/mod/data/fields/radiobutton/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/addons/mod/data/fields/radiobutton/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										43
									
								
								src/addons/mod/data/fields/text/component/text.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/addons/mod/data/fields/text/component/text.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										117
									
								
								src/addons/mod/data/fields/text/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/addons/mod/data/fields/text/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
							
								
								
									
										42
									
								
								src/addons/mod/data/fields/text/text.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/addons/mod/data/fields/text/text.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										65
									
								
								src/addons/mod/data/fields/textarea/component/textarea.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/addons/mod/data/fields/textarea/component/textarea.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										127
									
								
								src/addons/mod/data/fields/textarea/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								src/addons/mod/data/fields/textarea/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
							
								
								
									
										44
									
								
								src/addons/mod/data/fields/textarea/textarea.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/addons/mod/data/fields/textarea/textarea.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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> | ||||
							
								
								
									
										78
									
								
								src/addons/mod/data/fields/url/component/url.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/addons/mod/data/fields/url/component/url.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										63
									
								
								src/addons/mod/data/fields/url/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/addons/mod/data/fields/url/services/handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { 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); | ||||
							
								
								
									
										42
									
								
								src/addons/mod/data/fields/url/url.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/addons/mod/data/fields/url/url.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user