MOBILE-2338 data: Add field plugins

main
Pau Ferrer Ocaña 2018-05-02 10:44:28 +02:00
parent bbc6fcdff5
commit 661dbe2260
56 changed files with 3028 additions and 29 deletions

View File

@ -13,6 +13,10 @@
<allow-navigation href="data:*" />
<allow-navigation href="*" />
<allow-intent href="*" />
<allow-intent href="tel:*" />
<allow-intent href="sms:*" />
<allow-intent href="mailto:*" />
<allow-intent href="geo:*" />
<preference name="orientation" value="default" />
<preference name="target-device" value="universal" />
<preference name="fullscreen" value="false" />

View File

@ -38,13 +38,13 @@ export class AddonModDataFieldPluginComponent implements OnInit {
fieldLoaded: boolean;
constructor(protected injector: Injector, protected dataDelegate: AddonModDataFieldsDelegate,
protected dataProvider: AddonModDataProvider) { }
protected dataProvider: AddonModDataProvider) {
}
/**
* Component being initialized.
*/
ngOnInit(): void {
console.error('HERE');
if (!this.field) {
this.fieldLoaded = true;
@ -65,6 +65,7 @@ export class AddonModDataFieldPluginComponent implements OnInit {
error: this.error,
viewAction: this.viewAction
};
} else {
this.fieldLoaded = true;
}

View File

@ -63,7 +63,7 @@
{{ cssTemplate }}
</style>
<core-compile-html [text]="entriesRendered"></core-compile-html>
<core-compile-html [text]="entriesRendered" [jsData]="jsData" [extraImports]="extraImports"></core-compile-html>
</div>
<ion-grid *ngIf="search.page > 0 || hasNextPage">

View File

@ -1,3 +1,28 @@
addon-mod-data-index {
.core-data-contents {
overflow: visible;
white-space: normal;
word-break: break-word;
padding: $content-padding;
background-color: white;
border-top-width: 1px;
border-bottom-width: 1px;
border-right-width: 0;
border-left-width: 0;
border-style: solid;
border-color: $list-border-color;
table, tbody {
display: block;
}
tr {
@extend .row;
padding: 0;
}
td, th {
@extend .col;
}
}
}

View File

@ -23,6 +23,7 @@ import { AddonModDataProvider } from '../../providers/data';
import { AddonModDataHelperProvider } from '../../providers/helper';
import { AddonModDataOfflineProvider } from '../../providers/offline';
import { AddonModDataSyncProvider } from '../../providers/sync';
import { AddonModDataComponentsModule } from '../components.module';
import * as moment from 'moment';
/**
@ -33,6 +34,7 @@ import * as moment from 'moment';
templateUrl: 'index.html',
})
export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComponent {
component = AddonModDataProvider.COMPONENT;
moduleName = 'data';
@ -65,13 +67,16 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
offlineEntries: any;
entriesRendered = '';
cssTemplate = '';
extraImports = [AddonModDataComponentsModule];
jsData;
protected syncEventName = AddonModDataSyncProvider.AUTO_SYNCED;
protected entryChangedObserver: any;
protected hasComments = false;
protected fieldsArray: any;
constructor(injector: Injector, private dataProvider: AddonModDataProvider, private dataHelper: AddonModDataHelperProvider,
private dataOffline: AddonModDataOfflineProvider, @Optional() private content: Content,
private dataOffline: AddonModDataOfflineProvider, @Optional() @Optional() content: Content,
private dataSync: AddonModDataSyncProvider, private timeUtils: CoreTimeUtilsProvider,
private groupsProvider: CoreGroupsProvider, private commentsProvider: CoreCommentsProvider,
private modalCtrl: ModalController, private utils: CoreUtilsProvider) {
@ -216,8 +221,8 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
fields.forEach((field) => {
this.fields[field.id] = field;
});
this.fields = this.utils.objectToArray(this.fields);
this.advancedSearch = this.dataHelper.displayAdvancedSearchFields(this.data.asearchtemplate, this.fields);
this.fieldsArray = this.utils.objectToArray(this.fields);
this.advancedSearch = this.dataHelper.displayAdvancedSearchFields(this.data.asearchtemplate, this.fieldsArray);
return this.fetchEntriesData();
});
@ -283,7 +288,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
};
if (offlineActions.length > 0) {
promises.push(this.dataHelper.applyOfflineActions(entry, offlineActions, this.fields));
promises.push(this.dataHelper.applyOfflineActions(entry, offlineActions, this.fieldsArray));
} else {
promises.push(Promise.resolve(entry));
}
@ -299,7 +304,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
entry.contents = contents;
if (typeof this.offlineActions[entry.id] != 'undefined') {
promises.push(this.dataHelper.applyOfflineActions(entry, this.offlineActions[entry.id], this.fields));
promises.push(this.dataHelper.applyOfflineActions(entry, this.offlineActions[entry.id], this.fieldsArray));
} else {
promises.push(Promise.resolve(entry));
}
@ -318,12 +323,19 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
const actions = this.dataHelper.getActions(this.data, this.access, entry);
entriesHTML += this.dataHelper.displayShowFields(this.data.listtemplate, this.fields, entry, 'list',
entriesHTML += this.dataHelper.displayShowFields(this.data.listtemplate, this.fieldsArray, entry, 'list',
actions);
});
entriesHTML += this.data.listtemplatefooter || '';
this.entriesRendered = entriesHTML;
// Pass the input data to the component.
this.jsData = {
fields: this.fields,
entries: this.entries,
data: this.data
};
});
} else if (!this.search.searching) {
// Empty and no searching.
@ -356,7 +368,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
if (this.search.searchingAdvanced) {
this.search.advanced = this.dataHelper.getSearchDataFromForm(document.forms['addon-mod_data-advanced-search-form'],
this.fields);
this.fieldsArray);
this.search.searching = this.search.advanced.length > 0;
} else {
this.search.searching = this.search.text.length > 0;

View File

@ -32,7 +32,6 @@ export class AddonModDataFieldCheckboxComponent extends AddonModDataFieldPluginC
constructor(protected fb: FormBuilder, protected domUtils: CoreDomUtilsProvider, protected textUtils: CoreTextUtilsProvider,
element: ElementRef) {
super();
}
@ -46,7 +45,7 @@ export class AddonModDataFieldCheckboxComponent extends AddonModDataFieldPluginC
protected render(): void {
if (this.mode == 'show') {
this.value.content.split('##').join('<br>');
this.value.content = this.value.content.split('##').join('<br>');
return;
}

View File

@ -35,7 +35,6 @@ export class AddonModDataFieldCheckboxHandler implements AddonModDataFieldHandle
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(injector: Injector, plugin: any): any | Promise<any> {
console.error(AddonModDataFieldCheckboxComponent);
return AddonModDataFieldCheckboxComponent;
}

View File

@ -0,0 +1,12 @@
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
<ion-datetime *ngIf="mode != 'show'" [formControlName]="'f_'+field.id" [placeholder]="'core.date' | translate" [disabled]="!enable && mode == 'search'"></ion-datetime>
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="errors"></core-input-errors>
<ion-item *ngIf="mode == 'search'" [formGroup]="form">
<ion-label>{{ 'addon.mod_data.usedate' | translate }}</ion-label>
<ion-checkbox item-end [formControlName]="'f_'+field.id+'_z'" [(ngModel)]="values['f_'+field.id+'_z']">
</ion-checkbox>
</ion-item>
<core-format-text *ngIf="mode == 'show' && value && value.content" [text]="value.content * 1000 | coreFormatDate:'dfdaymonthyear'"></core-format-text>

View File

@ -0,0 +1,63 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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, ElementRef } from '@angular/core';
import { FormBuilder, FormControl } from '@angular/forms';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
/**
* Component to render data date field.
*/
@Component({
selector: 'addon-mod-data-field-date',
templateUrl: 'date.html'
})
export class AddonModDataFieldDateComponent extends AddonModDataFieldPluginComponent implements OnInit {
control: FormControl;
values = {};
enable: boolean;
val: any;
constructor(protected fb: FormBuilder, protected domUtils: CoreDomUtilsProvider, protected textUtils: CoreTextUtilsProvider,
element: ElementRef) {
super();
}
/**
* Component being initialized.
*/
ngOnInit(): void {
this.mode = this.mode == 'list' ? 'show' : this.mode;
this.render();
}
protected render(): void {
if (this.mode == 'show') {
return;
}
if (this.mode == 'edit' && this.value) {
this.enable = true;
} else {
this.value = {
content: Math.floor(Date.now() / 1000)
};
this.enable = false;
}
this.val = new Date(this.value.content * 1000);
}
}

View File

@ -0,0 +1,51 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonModDataFieldDateHandler } from './providers/handler';
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
import { AddonModDataFieldDateComponent } from './component/date';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
@NgModule({
declarations: [
AddonModDataFieldDateComponent
],
imports: [
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule,
CorePipesModule
],
providers: [
AddonModDataFieldDateHandler
],
exports: [
AddonModDataFieldDateComponent
],
entryComponents: [
AddonModDataFieldDateComponent
]
})
export class AddonModDataFieldDateModule {
constructor(fieldDelegate: AddonModDataFieldsDelegate, handler: AddonModDataFieldDateHandler) {
fieldDelegate.registerHandler(handler);
}
}

View File

@ -0,0 +1,180 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Injector, Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { AddonModDataFieldHandler } from '../../../providers/fields-delegate';
import { AddonModDataFieldDateComponent } from '../component/date';
/**
* Handler for date data field plugin.
*/
@Injectable()
export class AddonModDataFieldDateHandler implements AddonModDataFieldHandler {
name = 'AddonModDataFieldDateHandler';
type = 'date';
constructor(private translate: TranslateService) { }
/**
* Return the Component to use to display the plugin data.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} field The field object.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(injector: Injector, plugin: any): any | Promise<any> {
return AddonModDataFieldDateComponent;
}
/**
* Get field search data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the search form.
* @return {any} With name and value of the data to be sent.
*/
getFieldSearchData(field: any, inputData: any): any {
const fieldName = 'f_' + field.id,
enabledName = 'f_' + field.id + '_z';
if (inputData[enabledName]['1']) {
const values = [],
date = inputData[fieldName].split('-'),
year = date[0],
month = date[1],
day = date[2];
values.push({
name: fieldName + '_y',
value: year
});
values.push({
name: fieldName + '_m',
value: month
});
values.push({
name: fieldName + '_d',
value: day
});
values.push({
name: enabledName,
value: 1
});
return values;
}
return false;
}
/**
* Get field edit data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {any} With name and value of the data to be sent.
*/
getFieldEditData(field: any, inputData: any, originalFieldData: any): any {
const fieldName = 'f_' + field.id;
if (inputData[fieldName]) {
const values = [],
date = inputData[fieldName].split('-'),
year = date[0],
month = date[1],
day = date[2];
values.push({
fieldid: field.id,
subfield: 'year',
value: year
});
values.push({
fieldid: field.id,
subfield: 'month',
value: month
});
values.push({
fieldid: field.id,
subfield: 'day',
value: day
});
return values;
}
return false;
}
/**
* Get field data in changed.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @param {any} originalFieldData Original field entered data.
* @return {Promise<boolean> | boolean} If the field has changes.
*/
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | boolean {
const fieldName = 'f_' + field.id,
input = inputData[fieldName] || '';
originalFieldData = (originalFieldData && originalFieldData.content &&
new Date(originalFieldData.content * 1000).toISOString().substr(0, 10)) || '';
return input != originalFieldData;
}
/**
* Check and get field requeriments.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {string | false} String with the notification or false.
*/
getFieldsNotifications(field: any, inputData: any): string | false {
if (field.required &&
(!inputData || inputData.length < 2 || !inputData[0].value || !inputData[1].value || !inputData[2].value)) {
return this.translate.instant('addon.mod_data.errormustsupplyvalue');
}
return false;
}
/**
* Override field content data with offline submission.
*
* @param {any} originalContent Original data to be overriden.
* @param {any} offlineContent Array with all the offline data to override.
* @param {any} [offlineFiles] Array with all the offline files in the field.
* @return {any} Data overriden
*/
overrideData(originalContent: any, offlineContent: any, offlineFiles?: any): any {
let date = Date.UTC(offlineContent['year'] || '', offlineContent['month'] ? offlineContent['month'] - 1 : null,
offlineContent['day'] || null);
date = Math.floor(date / 1000);
originalContent.content = date || '';
return originalContent;
}
/**
* Whether or not the handler is enabled on a site level.
*
* @return {boolean|Promise<boolean>} True or promise resolved with true if enabled.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
}

View File

@ -14,11 +14,33 @@
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({
declarations: [],
imports: [
AddonModDataFieldCheckboxModule
AddonModDataFieldCheckboxModule,
AddonModDataFieldDateModule,
AddonModDataFieldFileModule,
AddonModDataFieldLatlongModule,
AddonModDataFieldMenuModule,
AddonModDataFieldMultimenuModule,
AddonModDataFieldNumberModule,
AddonModDataFieldPictureModule,
AddonModDataFieldRadiobuttonModule,
AddonModDataFieldTextModule,
AddonModDataFieldTextareaModule,
AddonModDataFieldUrlModule
],
providers: [
],

View File

@ -0,0 +1,14 @@
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
<core-input-errors *ngIf="error && mode == 'edit'" [errorMessages]="error"></core-input-errors>
<input *ngIf="mode == 'search'" type="text" [placeholder]="field.name" [name]="'f_'+field.id">
<core-attachments *ngIf="mode == 'edit'" [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component" [componentId]="componentId" [allowOffline]="true"></core-attachments>
<ng-container *ngIf="mode == 'show'">
<div *ngFor="let file of files" no-lines>
<!-- Files already attached to the submission. -->
<core-file *ngIf="!file.name" [file]="file" [component]="component" [componentId]="componentId" [alwaysDownload]="true"></core-file>
<!-- Files stored in offline to be sent later. -->
<core-local-file *ngIf="file.name" [file]="file"></core-local-file>
</div>
</ng-container>

View File

@ -0,0 +1,81 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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, ElementRef } from '@angular/core';
import { FormBuilder, FormControl } from '@angular/forms';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
import { CoreFileSessionProvider } from '@providers/file-session';
import { AddonModDataProvider } from '../../../providers/data';
/**
* Component to render data file field.
*/
@Component({
selector: 'addon-mod-data-field-file',
templateUrl: 'file.html'
})
export class AddonModDataFieldFileComponent extends AddonModDataFieldPluginComponent implements OnInit {
control: FormControl;
files = [];
component: string;
componentId: number;
maxSizeBytes: number;
constructor(protected fb: FormBuilder, protected domUtils: CoreDomUtilsProvider, protected textUtils: CoreTextUtilsProvider,
element: ElementRef, private fileSessionprovider: CoreFileSessionProvider) {
super();
}
/**
* Component being initialized.
*/
ngOnInit(): void {
this.mode = this.mode == 'list' ? 'show' : this.mode;
this.render();
}
/**
* Get the files from the input value.
*
* @param {any} value Input value.
* @return {any} List of files.
*/
protected getFiles(value: any): any {
let files = (value && value.files) || [];
// Reduce to first element.
if (files.length > 0) {
files = [files[0]];
}
return files;
}
protected render(): void {
if (this.mode == 'show' || this.mode == 'edit') {
this.component = AddonModDataProvider.COMPONENT;
this.componentId = this.database.coursemodule;
this.files = this.getFiles(this.value);
if (this.mode != 'show') {
// Edit mode, the list shouldn't change so there is no need to watch it.
this.maxSizeBytes = parseInt(this.field.param3, 10);
this.fileSessionprovider.setFiles(this.component, this.database.id + '_' + this.field.id, this.files);
}
}
}
}

View File

@ -0,0 +1,49 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonModDataFieldFileHandler } from './providers/handler';
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
import { AddonModDataFieldFileComponent } from './component/file';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [
AddonModDataFieldFileComponent
],
imports: [
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule,
],
providers: [
AddonModDataFieldFileHandler
],
exports: [
AddonModDataFieldFileComponent
],
entryComponents: [
AddonModDataFieldFileComponent
]
})
export class AddonModDataFieldFileModule {
constructor(fieldDelegate: AddonModDataFieldsDelegate, handler: AddonModDataFieldFileHandler) {
fieldDelegate.registerHandler(handler);
}
}

View File

@ -0,0 +1,158 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Injector, Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreFileSessionProvider } from '@providers/file-session';
import { AddonModDataFieldHandler } from '../../../providers/fields-delegate';
import { AddonModDataProvider } from '../../../providers/data';
import { AddonModDataFieldFileComponent } from '../component/file';
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
/**
* Handler for file data field plugin.
*/
@Injectable()
export class AddonModDataFieldFileHandler implements AddonModDataFieldHandler {
name = 'AddonModDataFieldFileHandler';
type = 'file';
constructor(private translate: TranslateService, private fileSessionprovider: CoreFileSessionProvider,
private fileUploaderProvider: CoreFileUploaderProvider) { }
/**
* Return the Component to use to display the plugin data.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} field The field object.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(injector: Injector, plugin: any): any | Promise<any> {
return AddonModDataFieldFileComponent;
}
/**
* Get field search data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the search form.
* @return {any} With name and value of the data to be sent.
*/
getFieldSearchData(field: any, inputData: any): any {
const fieldName = 'f_' + field.id;
if (inputData[fieldName]) {
return [{
name: fieldName,
value: inputData[fieldName]
}];
}
return false;
}
/**
* Get field edit data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {any} With name and value of the data to be sent.
*/
getFieldEditData(field: any, inputData: any, originalFieldData: any): any {
const files = this.getFieldEditFiles(field);
if (files.length) {
return [{
fieldid: field.id,
subfield: 'file',
files: files
}];
}
return false;
}
/**
* Get field edit files in the input data.
*
* @param {any} field Defines the field..
* @return {any} With name and value of the data to be sent.
*/
getFieldEditFiles(field: any): any {
return this.fileSessionprovider.getFiles(AddonModDataProvider.COMPONENT, field.dataid + '_' + field.id);
}
/**
* Get field data in changed.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @param {any} originalFieldData Original field entered data.
* @return {Promise<boolean> | boolean} If the field has changes.
*/
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | boolean {
const files = this.fileSessionprovider.getFiles(AddonModDataProvider.COMPONENT, field.dataid + '_' + field.id) || [];
let originalFiles = (originalFieldData && originalFieldData.files) || [];
if (originalFiles.length) {
originalFiles = [originalFiles[0]];
}
return this.fileUploaderProvider.areFileListDifferent(files, originalFiles);
}
/**
* Check and get field requeriments.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {string | false} String with the notification or false.
*/
getFieldsNotifications(field: any, inputData: any): string | false {
if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
return this.translate.instant('addon.mod_data.errormustsupplyvalue');
}
return false;
}
/**
* Override field content data with offline submission.
*
* @param {any} originalContent Original data to be overriden.
* @param {any} offlineContent Array with all the offline data to override.
* @param {any} [offlineFiles] Array with all the offline files in the field.
* @return {any} Data overriden
*/
overrideData(originalContent: any, offlineContent: any, offlineFiles?: any): any {
if (offlineContent && offlineContent.file && offlineContent.file.offline > 0 && offlineFiles && offlineFiles.length > 0) {
originalContent.content = offlineFiles[0].filename;
originalContent.files = [offlineFiles[0]];
} else if (offlineContent && offlineContent.file && offlineContent.file.online && offlineContent.file.online.length > 0) {
originalContent.content = offlineContent.file.online[0].filename;
originalContent.files = [offlineContent.file.online[0]];
}
return originalContent;
}
/**
* Whether or not the handler is enabled on a site level.
*
* @return {boolean|Promise<boolean>} True or promise resolved with true if enabled.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
}

View File

@ -0,0 +1,19 @@
<ion-input *ngIf="mode == 'search'" type="text" [placeholder]="field.name" [formControlName]="'f_'+field.id"></ion-input>
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="errors"></core-input-errors>
<ion-item *ngIf="mode == 'edit'" [formGroup]="form">
<ion-input type="text" [formControlName]="'f_'+field.id+'_0'" [(ngModel)]="north" maxlength="10" core-input-errors></ion-input>
<span class="placeholder-icon" item-right>°N</span>
</ion-item>
<ion-item *ngIf="mode == 'edit'" [formGroup]="form">
<ion-input type="text" [formControlName]="'f_'+field.id+'_1'" [(ngModel)]="east" maxlength="10" core-input-errors></ion-input>
<span class="placeholder-icon" item-right>°E</span>
</ion-item>
<span *ngIf="mode == 'show' && value">
<a [href]="getLatLongLink(north, east)">{{ formatLatLong(north, east) }}</a>
</span>

View File

@ -0,0 +1,90 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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, ElementRef } from '@angular/core';
import { FormBuilder, FormControl } from '@angular/forms';
import { Platform } from 'ionic-angular';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
/**
* Component to render data latlong field.
*/
@Component({
selector: 'addon-mod-data-field-latlong',
templateUrl: 'latlong.html'
})
export class AddonModDataFieldLatlongComponent extends AddonModDataFieldPluginComponent implements OnInit {
control: FormControl;
values = {};
north: number;
east: number;
constructor(protected fb: FormBuilder, protected domUtils: CoreDomUtilsProvider, protected textUtils: CoreTextUtilsProvider,
element: ElementRef, private platform: Platform) {
super();
}
/**
* Format latitude and longitude in a simple text.
*
* @param {number} north Degrees north.
* @param {number} east Degrees East.
* @return {string} Readable Latitude and logitude.
*/
formatLatLong(north: number, east: number): string {
if (north !== null || east !== null) {
const northFixed = north ? Math.abs(north).toFixed(4) : '0.0000',
eastFixed = east ? Math.abs(east).toFixed(4) : '0.0000';
return northFixed + (north < 0 ? '°S' : '°N') + ' ' + eastFixed + (east < 0 ? '°W' : '°E');
}
}
/**
* Get link to maps from latitude and longitude.
*
* @param {number} north Degrees north.
* @param {number} east Degrees East.
* @return {string} Link to maps depending on platform.
*/
getLatLongLink(north: number, east: number): string {
if (north !== null || east !== null) {
const northFixed = north ? north.toFixed(4) : '0.0000',
eastFixed = east ? east.toFixed(4) : '0.0000';
if (this.platform.is('ios')) {
return 'http://maps.apple.com/?ll=' + northFixed + ',' + eastFixed + '&near=' + northFixed + ',' + eastFixed;
}
return 'geo:' + northFixed + ',' + eastFixed;
}
}
/**
* Component being initialized.
*/
ngOnInit(): void {
this.mode = this.mode == 'list' ? 'show' : this.mode;
this.render();
}
protected render(): void {
if (this.value) {
this.north = (this.value && parseFloat(this.value.content)) || null;
this.east = (this.value && parseFloat(this.value.content1)) || null;
}
}
}

View File

@ -0,0 +1,49 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonModDataFieldLatlongHandler } from './providers/handler';
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
import { AddonModDataFieldLatlongComponent } from './component/latlong';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [
AddonModDataFieldLatlongComponent
],
imports: [
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule
],
providers: [
AddonModDataFieldLatlongHandler
],
exports: [
AddonModDataFieldLatlongComponent
],
entryComponents: [
AddonModDataFieldLatlongComponent
]
})
export class AddonModDataFieldLatlongModule {
constructor(fieldDelegate: AddonModDataFieldsDelegate, handler: AddonModDataFieldLatlongHandler) {
fieldDelegate.registerHandler(handler);
}
}

View File

@ -0,0 +1,159 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Injector, Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { AddonModDataFieldHandler } from '../../../providers/fields-delegate';
import { AddonModDataFieldLatlongComponent } from '../component/latlong';
/**
* Handler for latlong data field plugin.
*/
@Injectable()
export class AddonModDataFieldLatlongHandler implements AddonModDataFieldHandler {
name = 'AddonModDataFieldLatlongHandler';
type = 'latlong';
constructor(private translate: TranslateService) { }
/**
* Return the Component to use to display the plugin data.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} field The field object.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(injector: Injector, plugin: any): any | Promise<any> {
return AddonModDataFieldLatlongComponent;
}
/**
* Get field search data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the search form.
* @return {any} With name and value of the data to be sent.
*/
getFieldSearchData(field: any, inputData: any): any {
const fieldName = 'f_' + field.id;
if (inputData[fieldName]) {
return [{
name: fieldName,
value: inputData[fieldName]
}];
}
return false;
}
/**
* Get field edit data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {any} With name and value of the data to be sent.
*/
getFieldEditData(field: any, inputData: any, originalFieldData: any): any {
const fieldName = 'f_' + field.id,
values = [];
if (inputData[fieldName + '_0']) {
values.push({
fieldid: field.id,
subfield: '0',
value: inputData[fieldName + '_0']
});
}
if (inputData[fieldName + '_1']) {
values.push({
fieldid: field.id,
subfield: '1',
value: inputData[fieldName + '_1']
});
}
return values;
}
/**
* Get field data in changed.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @param {any} originalFieldData Original field entered data.
* @return {Promise<boolean> | boolean} If the field has changes.
*/
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | boolean {
const fieldName = 'f_' + field.id,
lat = inputData[fieldName + '_0'] || '',
long = inputData[fieldName + '_1'] || '',
originalLat = (originalFieldData && originalFieldData.content) || '',
originalLong = (originalFieldData && originalFieldData.content1) || '';
return lat != originalLat || long != originalLong;
}
/**
* Check and get field requeriments.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {string | false} String with the notification or false.
*/
getFieldsNotifications(field: any, inputData: any): string | false {
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 this.translate.instant('addon.mod_data.latlongboth');
} else if (field.required && valueCount == 0) {
return this.translate.instant('addon.mod_data.errormustsupplyvalue');
}
return false;
}
/**
* Override field content data with offline submission.
*
* @param {any} originalContent Original data to be overriden.
* @param {any} offlineContent Array with all the offline data to override.
* @param {any} [offlineFiles] Array with all the offline files in the field.
* @return {any} Data overriden
*/
overrideData(originalContent: any, offlineContent: any, offlineFiles?: any): any {
originalContent.content = offlineContent[0] || '';
originalContent.content1 = offlineContent[1] || '';
return originalContent;
}
/**
* Whether or not the handler is enabled on a site level.
*
* @return {boolean|Promise<boolean>} True or promise resolved with true if enabled.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
}

View File

@ -0,0 +1,9 @@
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="error"></core-input-errors>
<ion-select *ngIf="mode != 'show'" [formControlName]="'f_'+field.id" [placeholder]="'addon.mod_data.menuchoose' | translate" core-input-errors [(ngModel)]="val">
<ion-option value="">{{ 'addon.mod_data.menuchoose' | translate }}</ion-option>
<ion-option *ngFor="let option of options" [value]="option">{{option}}</ion-option>
</ion-select>
<core-format-text *ngIf="mode == 'show' && value && value.content" [text]="value.content"></core-format-text>

View File

@ -0,0 +1,57 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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, ElementRef } from '@angular/core';
import { FormBuilder, FormControl } from '@angular/forms';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
/**
* Component to render data menu field.
*/
@Component({
selector: 'addon-mod-data-field-menu',
templateUrl: 'menu.html'
})
export class AddonModDataFieldMenuComponent extends AddonModDataFieldPluginComponent implements OnInit {
control: FormControl;
val: string;
options = [];
constructor(protected fb: FormBuilder, protected domUtils: CoreDomUtilsProvider, protected textUtils: CoreTextUtilsProvider,
element: ElementRef) {
super();
}
/**
* Component being initialized.
*/
ngOnInit(): void {
this.mode = this.mode == 'list' ? 'show' : this.mode;
this.render();
}
protected render(): void {
if (this.mode == 'show') {
return;
}
this.options = this.field.param1.split('\n');
if (this.mode == 'edit' && this.value) {
this.val = this.value.content;
}
}
}

View File

@ -0,0 +1,49 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonModDataFieldMenuHandler } from './providers/handler';
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
import { AddonModDataFieldMenuComponent } from './component/menu';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [
AddonModDataFieldMenuComponent
],
imports: [
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule
],
providers: [
AddonModDataFieldMenuHandler
],
exports: [
AddonModDataFieldMenuComponent
],
entryComponents: [
AddonModDataFieldMenuComponent
]
})
export class AddonModDataFieldMenuModule {
constructor(fieldDelegate: AddonModDataFieldsDelegate, handler: AddonModDataFieldMenuHandler) {
fieldDelegate.registerHandler(handler);
}
}

View File

@ -0,0 +1,134 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Injector, Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { AddonModDataFieldHandler } from '../../../providers/fields-delegate';
import { AddonModDataFieldMenuComponent } from '../component/menu';
/**
* Handler for menu data field plugin.
*/
@Injectable()
export class AddonModDataFieldMenuHandler implements AddonModDataFieldHandler {
name = 'AddonModDataFieldMenuHandler';
type = 'menu';
constructor(private translate: TranslateService) { }
/**
* Return the Component to use to display the plugin data.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} field The field object.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(injector: Injector, plugin: any): any | Promise<any> {
return AddonModDataFieldMenuComponent;
}
/**
* Get field search data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the search form.
* @return {any} With name and value of the data to be sent.
*/
getFieldSearchData(field: any, inputData: any): any {
const fieldName = 'f_' + field.id;
if (inputData[fieldName]) {
return [{
name: fieldName,
value: inputData[fieldName]
}];
}
return false;
}
/**
* Get field edit data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {any} With name and value of the data to be sent.
*/
getFieldEditData(field: any, inputData: any, originalFieldData: any): any {
const fieldName = 'f_' + field.id;
if (inputData[fieldName]) {
return [{
fieldid: field.id,
value: inputData[fieldName]
}];
}
return false;
}
/**
* Get field data in changed.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @param {any} originalFieldData Original field entered data.
* @return {Promise<boolean> | boolean} If the field has changes.
*/
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | boolean {
const fieldName = 'f_' + field.id,
input = inputData[fieldName] || '';
originalFieldData = (originalFieldData && originalFieldData.content) || '';
return input != originalFieldData;
}
/**
* Check and get field requeriments.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {string | false} String with the notification or false.
*/
getFieldsNotifications(field: any, inputData: any): string | false {
if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
return this.translate.instant('addon.mod_data.errormustsupplyvalue');
}
return false;
}
/**
* Override field content data with offline submission.
*
* @param {any} originalContent Original data to be overriden.
* @param {any} offlineContent Array with all the offline data to override.
* @param {any} [offlineFiles] Array with all the offline files in the field.
* @return {any} Data overriden
*/
overrideData(originalContent: any, offlineContent: any, offlineFiles?: any): any {
originalContent.content = offlineContent[''] || '';
return originalContent;
}
/**
* Whether or not the handler is enabled on a site level.
*
* @return {boolean|Promise<boolean>} True or promise resolved with true if enabled.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
}

View File

@ -0,0 +1,8 @@
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="error"></core-input-errors>
<!--<mm-multiple-select *ngIf="mode != 'show'" title="{{field.name}}" name="f_{{field.id}}" options="options"></mm-multiple-select>
<ion-checkbox *ngIf="mode == 'search'" name="f_{{field.id}}_allreq" ng-value="1">{{ 'addon.mod_data.selectedrequired' | translate }}</ion-checkbox>-->
<core-format-text *ngIf="mode == 'show' && value && value.content" [text]="value.content.split('##').join('<br>')"></core-format-text>

View File

@ -0,0 +1,63 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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, ElementRef } from '@angular/core';
import { FormBuilder, FormControl } from '@angular/forms';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
/**
* Component to render data multimenu field.
*/
@Component({
selector: 'addon-mod-data-field-multimenu',
templateUrl: 'multimenu.html'
})
export class AddonModDataFieldMultimenuComponent extends AddonModDataFieldPluginComponent implements OnInit {
control: FormControl;
options = [];
constructor(protected fb: FormBuilder, protected domUtils: CoreDomUtilsProvider, protected textUtils: CoreTextUtilsProvider,
element: ElementRef) {
super();
}
/**
* Component being initialized.
*/
ngOnInit(): void {
this.mode = this.mode == 'list' ? 'show' : this.mode;
this.render();
}
protected render(): void {
if (this.mode == 'show') {
return;
}
this.options = this.field.param1.split('\n').map((option) => {
return { key: option, value: option };
});
if (this.mode == 'edit' && this.value && this.value.content) {
this.value.content.split('##').forEach((value) => {
const x = this.options.findIndex((option) => value == option.key);
if (x >= 0) {
this.options[x].selected = true;
}
});
}
}
}

View File

@ -0,0 +1,49 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonModDataFieldMultimenuHandler } from './providers/handler';
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
import { AddonModDataFieldMultimenuComponent } from './component/multimenu';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [
AddonModDataFieldMultimenuComponent
],
imports: [
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule
],
providers: [
AddonModDataFieldMultimenuHandler
],
exports: [
AddonModDataFieldMultimenuComponent
],
entryComponents: [
AddonModDataFieldMultimenuComponent
]
})
export class AddonModDataFieldMultimenuModule {
constructor(fieldDelegate: AddonModDataFieldsDelegate, handler: AddonModDataFieldMultimenuHandler) {
fieldDelegate.registerHandler(handler);
}
}

View File

@ -0,0 +1,152 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Injector, Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { AddonModDataFieldHandler } from '../../../providers/fields-delegate';
import { AddonModDataFieldMultimenuComponent } from '../component/multimenu';
/**
* Handler for multimenu data field plugin.
*/
@Injectable()
export class AddonModDataFieldMultimenuHandler implements AddonModDataFieldHandler {
name = 'AddonModDataFieldMultimenuHandler';
type = 'multimenu';
constructor(private translate: TranslateService) { }
/**
* Return the Component to use to display the plugin data.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} field The field object.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(injector: Injector, plugin: any): any | Promise<any> {
return AddonModDataFieldMultimenuComponent;
}
/**
* Get field search data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the search form.
* @return {any} With name and value of the data to be sent.
*/
getFieldSearchData(field: any, inputData: any): any {
const fieldName = 'f_' + field.id,
reqName = 'f_' + field.id + '_allreq';
if (inputData[fieldName].length > 0) {
const options = inputData[fieldName].split('###'),
values = [];
if (options.length > 0) {
values.push({
name: fieldName,
value: options
});
if (inputData[reqName]['1']) {
values.push({
name: reqName,
value: true
});
}
return values;
}
}
return false;
}
/**
* Get field edit data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {any} With name and value of the data to be sent.
*/
getFieldEditData(field: any, inputData: any, originalFieldData: any): any {
const fieldName = 'f_' + field.id;
if (inputData[fieldName] && inputData[fieldName].length > 0) {
const options = inputData[fieldName].split('###');
if (options.length > 0) {
return [{
fieldid: field.id,
value: options
}];
}
}
return false;
}
/**
* Get field data in changed.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @param {any} originalFieldData Original field entered data.
* @return {Promise<boolean> | boolean} If the field has changes.
*/
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | boolean {
const fieldName = 'f_' + field.id,
input = inputData[fieldName] || '';
originalFieldData = (originalFieldData && originalFieldData.content) || '';
return input != originalFieldData;
}
/**
* Check and get field requeriments.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {string | false} String with the notification or false.
*/
getFieldsNotifications(field: any, inputData: any): string | false {
if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
return this.translate.instant('addon.mod_data.errormustsupplyvalue');
}
return false;
}
/**
* Override field content data with offline submission.
*
* @param {any} originalContent Original data to be overriden.
* @param {any} offlineContent Array with all the offline data to override.
* @param {any} [offlineFiles] Array with all the offline files in the field.
* @return {any} Data overriden
*/
overrideData(originalContent: any, offlineContent: any, offlineFiles?: any): any {
originalContent.content = (offlineContent[''] && offlineContent[''].join('###')) || '';
return originalContent;
}
/**
* Whether or not the handler is enabled on a site level.
*
* @return {boolean|Promise<boolean>} True or promise resolved with true if enabled.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
}

View File

@ -0,0 +1,7 @@
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="error"></core-input-errors>
<ion-input *ngIf="mode != 'show'" type="number" [formControlName]="'f_'+field.id" [placeholder]="field.name" [(ngModel)]="val"></ion-input>
<core-format-text *ngIf="mode == 'show' && value && value.content" [text]="value.content"></core-format-text>

View File

@ -0,0 +1,54 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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, ElementRef } from '@angular/core';
import { FormBuilder, FormControl } from '@angular/forms';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
/**
* Component to render data number field.
*/
@Component({
selector: 'addon-mod-data-field-number',
templateUrl: 'number.html'
})
export class AddonModDataFieldNumberComponent extends AddonModDataFieldPluginComponent implements OnInit {
control: FormControl;
val: number;
constructor(protected fb: FormBuilder, protected domUtils: CoreDomUtilsProvider, protected textUtils: CoreTextUtilsProvider,
element: ElementRef) {
super();
}
/**
* Component being initialized.
*/
ngOnInit(): void {
this.mode = this.mode == 'list' ? 'show' : this.mode;
this.render();
}
protected render(): void {
if (this.mode == 'show') {
return;
}
if (this.mode == 'edit' && this.value) {
this.val = this.value && parseFloat(this.value.content);
}
}
}

View File

@ -0,0 +1,49 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonModDataFieldNumberHandler } from './providers/handler';
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
import { AddonModDataFieldNumberComponent } from './component/number';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [
AddonModDataFieldNumberComponent
],
imports: [
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule
],
providers: [
AddonModDataFieldNumberHandler
],
exports: [
AddonModDataFieldNumberComponent
],
entryComponents: [
AddonModDataFieldNumberComponent
]
})
export class AddonModDataFieldNumberModule {
constructor(fieldDelegate: AddonModDataFieldsDelegate, handler: AddonModDataFieldNumberHandler) {
fieldDelegate.registerHandler(handler);
}
}

View File

@ -0,0 +1,57 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Injector, Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { AddonModDataFieldTextHandler } from '../../text/providers/handler';
import { AddonModDataFieldNumberComponent } from '../component/number';
/**
* Handler for number data field plugin.
*/
@Injectable()
export class AddonModDataFieldNumberHandler extends AddonModDataFieldTextHandler {
name = 'AddonModDataFieldNumberHandler';
type = 'number';
constructor(protected translate: TranslateService) {
super(translate);
}
/**
* Return the Component to use to display the plugin data.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} field The field object.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(injector: Injector, plugin: any): any | Promise<any> {
return AddonModDataFieldNumberComponent;
}
/**
* Check and get field requeriments.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {string | false} String with the notification or false.
*/
getFieldsNotifications(field: any, inputData: any): string | false {
if (field.required && (!inputData || !inputData.length || inputData[0].value == '')) {
return this.translate.instant('addon.mod_data.errormustsupplyvalue');
}
return false;
}
}

View File

@ -0,0 +1,17 @@
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
<core-input-errors *ngIf="error && mode == 'edit'" [errorMessages]="error"></core-input-errors>
<input *ngIf="mode == 'search'" type="text" [placeholder]="field.name" [name]="'f_'+field.id">
<core-attachments *ngIf="mode == 'edit'" [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component" [componentId]="componentId" [allowOffline]="true"></core-attachments>
<ion-item *ngIf="mode == 'edit'" [formGroup]="form">
<ion-label>{{ 'addon.mod_data.alttext' | translate }}</ion-label>
<ion-input type="text" [formControlName]="'f_'+field.id+'_alttext'" [(ngModel)]="alttext" [placeholder]=" 'addon.mod_data.alttext' | translate" ></ion-input>
<span class="placeholder-icon" item-right>°N</span>
</ion-item>
<span *ngIf="mode == 'list' && imageUrl" (click)="viewAction()"><img [src]="imageUrl" [alt]="title" [title]="title" class="core-media-adapt-width list_picture" core-external-content/></span>
<img *ngIf="mode == 'show' && imageUrl" [src]="imageUrl" [alt]="title" [title]="title" class="core-media-adapt-width list_picture" [width]="width" [height]="height" core-external-content/>

View File

@ -0,0 +1,128 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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, ElementRef } from '@angular/core';
import { FormBuilder, FormControl } from '@angular/forms';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
import { CoreFileSessionProvider } from '@providers/file-session';
import { AddonModDataProvider } from '../../../providers/data';
/**
* Component to render data picture field.
*/
@Component({
selector: 'addon-mod-data-field-picture',
templateUrl: 'picture.html'
})
export class AddonModDataFieldPictureComponent extends AddonModDataFieldPluginComponent implements OnInit {
control: FormControl;
files = [];
component: string;
componentId: number;
maxSizeBytes: number;
image: any;
entryId: number;
imageUrl: string;
title: string;
alttext: string;
width: string;
height: string;
constructor(protected fb: FormBuilder, protected domUtils: CoreDomUtilsProvider, protected textUtils: CoreTextUtilsProvider,
element: ElementRef, private fileSessionprovider: CoreFileSessionProvider) {
super();
}
/**
* Component being initialized.
*/
ngOnInit(): void {
this.render();
}
/**
* Get the files from the input value.
*
* @param {any} value Input value.
* @return {any} List of files.
*/
protected getFiles(value: any): any {
let files = (value && value.files) || [];
// Reduce to first element.
if (files.length > 0) {
files = [files[0]];
}
return files;
}
/**
* Find file in a list.
*
* @param {any[]} files File list where to search.
* @param {string} filenameSeek Filename to search.
* @return {any} File found or false.
*/
protected findFile(files: any[], filenameSeek: string): any {
return files.find((file) => file.filename == filenameSeek) || false;
}
protected render(): void {
if (this.mode != 'search') {
this.component = AddonModDataProvider.COMPONENT;
this.componentId = this.database.coursemodule;
// Edit mode, the list shouldn't change so there is no need to watch it.
const files = this.value && this.value.files || [];
// Get image or thumb.
if (files.length > 0) {
const filenameSeek = this.mode == 'list' ? 'thumb_' + this.value.content : this.value.content;
this.image = this.findFile(files, filenameSeek);
if (!this.image && this.mode == 'list') {
this.image = this.findFile(files, this.value.content);
}
this.files = [this.image];
} else {
this.image = false;
this.files = [];
}
if (this.mode == 'edit') {
this.maxSizeBytes = parseInt(this.field.param3, 10);
this.fileSessionprovider.setFiles(this.component, this.database.id + '_' + this.field.id, this.files);
this.alttext = (this.value && this.value.content1) || '';
} else {
this.entryId = (this.value && this.value.recordid) || null;
this.title = (this.value && this.value.content1) || '';
this.imageUrl = null;
if (this.image) {
if (this.image.offline) {
this.imageUrl = (this.image && this.image.toURL()) || null;
} else {
this.imageUrl = (this.image && this.image.fileurl) || null;
}
}
this.width = this.field.param1 || '';
this.height = this.field.param2 || '';
}
}
}
}

View File

@ -0,0 +1,49 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonModDataFieldPictureHandler } from './providers/handler';
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
import { AddonModDataFieldPictureComponent } from './component/picture';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [
AddonModDataFieldPictureComponent
],
imports: [
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule,
],
providers: [
AddonModDataFieldPictureHandler
],
exports: [
AddonModDataFieldPictureComponent
],
entryComponents: [
AddonModDataFieldPictureComponent
]
})
export class AddonModDataFieldPictureModule {
constructor(fieldDelegate: AddonModDataFieldsDelegate, handler: AddonModDataFieldPictureHandler) {
fieldDelegate.registerHandler(handler);
}
}

View File

@ -0,0 +1,194 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Injector, Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { CoreFileSessionProvider } from '@providers/file-session';
import { AddonModDataFieldHandler } from '../../../providers/fields-delegate';
import { AddonModDataProvider } from '../../../providers/data';
import { AddonModDataFieldPictureComponent } from '../component/picture';
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
/**
* Handler for picture data field plugin.
*/
@Injectable()
export class AddonModDataFieldPictureHandler implements AddonModDataFieldHandler {
name = 'AddonModDataFieldPictureHandler';
type = 'picture';
constructor(private translate: TranslateService, private fileSessionprovider: CoreFileSessionProvider,
private fileUploaderProvider: CoreFileUploaderProvider) { }
/**
* Return the Component to use to display the plugin data.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} field The field object.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(injector: Injector, plugin: any): any | Promise<any> {
return AddonModDataFieldPictureComponent;
}
/**
* Get field search data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the search form.
* @return {any} With name and value of the data to be sent.
*/
getFieldSearchData(field: any, inputData: any): any {
const fieldName = 'f_' + field.id;
if (inputData[fieldName]) {
return [{
name: fieldName,
value: inputData[fieldName]
}];
}
return false;
}
/**
* Get field edit data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {any} With name and value of the data to be sent.
*/
getFieldEditData(field: any, inputData: any, originalFieldData: any): any {
const files = this.getFieldEditFiles(field),
values = [],
fieldName = 'f_' + field.id + '_alttext';
if (files.length) {
values.push({
fieldid: field.id,
subfield: 'file',
files: files
});
}
if (inputData[fieldName]) {
values.push({
fieldid: field.id,
subfield: 'alttext',
value: inputData[fieldName]
});
}
return values;
}
/**
* Get field edit files in the input data.
*
* @param {any} field Defines the field..
* @return {any} With name and value of the data to be sent.
*/
getFieldEditFiles(field: any): any {
return this.fileSessionprovider.getFiles(AddonModDataProvider.COMPONENT, field.dataid + '_' + field.id);
}
/**
* Get field data in changed.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @param {any} originalFieldData Original field entered data.
* @return {Promise<boolean> | boolean} If the field has changes.
*/
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | boolean {
const fieldName = 'f_' + field.id + '_alttext',
altText = inputData[fieldName] || '',
originalAltText = (originalFieldData && originalFieldData.content1) || '',
files = this.getFieldEditFiles(field) || [];
let originalFiles = (originalFieldData && originalFieldData.files) || [];
// Get image.
if (originalFiles.length > 0) {
const filenameSeek = (originalFieldData && originalFieldData.content) || '',
file = originalFiles.find((file) => file.filename == filenameSeek);
if (file) {
originalFiles = [file];
}
} else {
originalFiles = [];
}
return altText != originalAltText || this.fileUploaderProvider.areFileListDifferent(files, originalFiles);
}
/**
* Check and get field requeriments.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {string | false} String with the notification or false.
*/
getFieldsNotifications(field: any, inputData: any): string | false {
if (field.required) {
if (!inputData || !inputData.length) {
return this.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 this.translate.instant('addon.mod_data.errormustsupplyvalue');
}
}
return false;
}
/**
* Override field content data with offline submission.
*
* @param {any} originalContent Original data to be overriden.
* @param {any} offlineContent Array with all the offline data to override.
* @param {any} [offlineFiles] Array with all the offline files in the field.
* @return {any} Data overriden
*/
overrideData(originalContent: any, offlineContent: any, offlineFiles?: any): any {
if (offlineContent && offlineContent.file && offlineContent.file.offline > 0 && offlineFiles && offlineFiles.length > 0) {
originalContent.content = offlineFiles[0].filename;
originalContent.files = [offlineFiles[0]];
} else if (offlineContent && offlineContent.file && offlineContent.file.online && offlineContent.file.online.length > 0) {
originalContent.content = offlineContent.file.online[0].filename;
originalContent.files = [offlineContent.file.online[0]];
}
originalContent.content1 = offlineContent.alttext || '';
return originalContent;
}
/**
* Whether or not the handler is enabled on a site level.
*
* @return {boolean|Promise<boolean>} True or promise resolved with true if enabled.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
}

View File

@ -0,0 +1,9 @@
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="error"></core-input-errors>
<ion-select *ngIf="mode != 'show'" [formControlName]="'f_'+field.id" [placeholder]="'addon.mod_data.menuchoose' | translate" core-input-errors [(ngModel)]="val">
<ion-option value="">{{ 'addon.mod_data.menuchoose' | translate }}</ion-option>
<ion-option *ngFor="let option of options" [value]="option">{{option}}</ion-option>
</ion-select>
<core-format-text *ngIf="mode == 'show' && value && value.content" [text]="value.content"></core-format-text>

View File

@ -0,0 +1,57 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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, ElementRef } from '@angular/core';
import { FormBuilder, FormControl } from '@angular/forms';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
/**
* Component to render data radiobutton field.
*/
@Component({
selector: 'addon-mod-data-field-radiobutton',
templateUrl: 'radiobutton.html'
})
export class AddonModDataFieldRadiobuttonComponent extends AddonModDataFieldPluginComponent implements OnInit {
control: FormControl;
options: number;
val: number;
constructor(protected fb: FormBuilder, protected domUtils: CoreDomUtilsProvider, protected textUtils: CoreTextUtilsProvider,
element: ElementRef) {
super();
}
/**
* Component being initialized.
*/
ngOnInit(): void {
this.mode = this.mode == 'list' ? 'show' : this.mode;
this.render();
}
protected render(): void {
if (this.mode == 'show') {
return;
}
this.options = this.field.param1.split('\n');
if (this.mode == 'edit' && this.value) {
this.val = this.value.content;
}
}
}

View File

@ -0,0 +1,133 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Injector, Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { AddonModDataFieldHandler } from '../../../providers/fields-delegate';
import { AddonModDataFieldRadiobuttonComponent } from '../component/radiobutton';
/**
* Handler for checkbox data field plugin.
*/
@Injectable()
export class AddonModDataFieldRadiobuttonHandler implements AddonModDataFieldHandler {
name = 'AddonModDataFieldRadiobuttonHandler';
type = 'radiobutton';
constructor(private translate: TranslateService) { }
/**
* Return the Component to use to display the plugin data.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} field The field object.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(injector: Injector, plugin: any): any | Promise<any> {
return AddonModDataFieldRadiobuttonComponent;
}
/**
* Get field search data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the search form.
* @return {any} With name and value of the data to be sent.
*/
getFieldSearchData(field: any, inputData: any): any {
const fieldName = 'f_' + field.id;
if (inputData[fieldName]) {
return [{
name: fieldName,
value: inputData[fieldName]
}];
}
return false;
}
/**
* Get field edit data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {any} With name and value of the data to be sent.
*/
getFieldEditData(field: any, inputData: any, originalFieldData: any): any {
const fieldName = 'f_' + field.id;
if (inputData[fieldName]) {
return [{
fieldid: field.id,
value: inputData[fieldName]
}];
}
return false;
}
/**
* Get field data in changed.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @param {any} originalFieldData Original field entered data.
* @return {Promise<boolean> | boolean} If the field has changes.
*/
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | boolean {
const fieldName = 'f_' + field.id,
input = inputData[fieldName] || '';
originalFieldData = (originalFieldData && originalFieldData.content) || '';
return input != originalFieldData;
}
/**
* Check and get field requeriments.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {string | false} String with the notification or false.
*/
getFieldsNotifications(field: any, inputData: any): string | false {
if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
return this.translate.instant('addon.mod_data.errormustsupplyvalue');
}
return false;
}
/**
* Override field content data with offline submission.
*
* @param {any} originalContent Original data to be overriden.
* @param {any} offlineContent Array with all the offline data to override.
* @param {any} [offlineFiles] Array with all the offline files in the field.
* @return {any} Data overriden
*/
overrideData(originalContent: any, offlineContent: any, offlineFiles?: any): any {
originalContent.content = offlineContent[''] || '';
return originalContent;
}
/**
* Whether or not the handler is enabled on a site level.
*
* @return {boolean|Promise<boolean>} True or promise resolved with true if enabled.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
}

View File

@ -0,0 +1,49 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonModDataFieldRadiobuttonHandler } from './providers/handler';
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
import { AddonModDataFieldRadiobuttonComponent } from './component/radiobutton';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [
AddonModDataFieldRadiobuttonComponent
],
imports: [
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule
],
providers: [
AddonModDataFieldRadiobuttonHandler
],
exports: [
AddonModDataFieldRadiobuttonComponent
],
entryComponents: [
AddonModDataFieldRadiobuttonComponent
]
})
export class AddonModDataFieldRadiobuttonModule {
constructor(fieldDelegate: AddonModDataFieldsDelegate, handler: AddonModDataFieldRadiobuttonHandler) {
fieldDelegate.registerHandler(handler);
}
}

View File

@ -0,0 +1,7 @@
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="error"></core-input-errors>
<ion-input *ngIf="mode != 'show'" type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name" [(ngModel)]="val"></ion-input>
<core-format-text *ngIf="mode == 'show' && value && value.content" [text]="value.content"></core-format-text>

View File

@ -0,0 +1,54 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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, ElementRef } from '@angular/core';
import { FormBuilder, FormControl } from '@angular/forms';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
/**
* Component to render data text field.
*/
@Component({
selector: 'addon-mod-data-field-text',
templateUrl: 'text.html'
})
export class AddonModDataFieldTextComponent extends AddonModDataFieldPluginComponent implements OnInit {
control: FormControl;
val: number;
constructor(protected fb: FormBuilder, protected domUtils: CoreDomUtilsProvider, protected textUtils: CoreTextUtilsProvider,
element: ElementRef) {
super();
}
/**
* Component being initialized.
*/
ngOnInit(): void {
this.mode = this.mode == 'list' ? 'show' : this.mode;
this.render();
}
protected render(): void {
if (this.mode == 'show') {
return;
}
if (this.mode == 'edit' && this.value) {
this.val = this.value.content;
}
}
}

View File

@ -0,0 +1,134 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Injector, Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { AddonModDataFieldHandler } from '../../../providers/fields-delegate';
import { AddonModDataFieldTextComponent } from '../component/text';
/**
* Handler for number data field plugin.
*/
@Injectable()
export class AddonModDataFieldTextHandler implements AddonModDataFieldHandler {
name = 'AddonModDataFieldTextHandler';
type = 'text';
constructor(protected translate: TranslateService) { }
/**
* Return the Component to use to display the plugin data.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} field The field object.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(injector: Injector, plugin: any): any | Promise<any> {
return AddonModDataFieldTextComponent;
}
/**
* Get field search data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the search form.
* @return {any} With name and value of the data to be sent.
*/
getFieldSearchData(field: any, inputData: any): any {
const fieldName = 'f_' + field.id;
if (inputData[fieldName]) {
return [{
name: fieldName,
value: inputData[fieldName]
}];
}
return false;
}
/**
* Get field edit data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {any} With name and value of the data to be sent.
*/
getFieldEditData(field: any, inputData: any, originalFieldData: any): any {
const fieldName = 'f_' + field.id;
if (inputData[fieldName]) {
return [{
fieldid: field.id,
value: inputData[fieldName]
}];
}
return false;
}
/**
* Get field data in changed.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @param {any} originalFieldData Original field entered data.
* @return {Promise<boolean> | boolean} If the field has changes.
*/
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | boolean {
const fieldName = 'f_' + field.id,
input = inputData[fieldName] || '';
originalFieldData = (originalFieldData && originalFieldData.content) || '';
return input != originalFieldData;
}
/**
* Check and get field requeriments.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {string | false} String with the notification or false.
*/
getFieldsNotifications(field: any, inputData: any): string | false {
if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
return this.translate.instant('addon.mod_data.errormustsupplyvalue');
}
return false;
}
/**
* Override field content data with offline submission.
*
* @param {any} originalContent Original data to be overriden.
* @param {any} offlineContent Array with all the offline data to override.
* @param {any} [offlineFiles] Array with all the offline files in the field.
* @return {any} Data overriden
*/
overrideData(originalContent: any, offlineContent: any, offlineFiles?: any): any {
originalContent.content = offlineContent[''] || '';
return originalContent;
}
/**
* Whether or not the handler is enabled on a site level.
*
* @return {boolean|Promise<boolean>} True or promise resolved with true if enabled.
*/
isEnabled(): boolean | Promise<boolean> {
return true;
}
}

View File

@ -0,0 +1,49 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonModDataFieldTextHandler } from './providers/handler';
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
import { AddonModDataFieldTextComponent } from './component/text';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [
AddonModDataFieldTextComponent
],
imports: [
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule
],
providers: [
AddonModDataFieldTextHandler
],
exports: [
AddonModDataFieldTextComponent
],
entryComponents: [
AddonModDataFieldTextComponent
]
})
export class AddonModDataFieldTextModule {
constructor(fieldDelegate: AddonModDataFieldsDelegate, handler: AddonModDataFieldTextHandler) {
fieldDelegate.registerHandler(handler);
}
}

View File

@ -0,0 +1,10 @@
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="error"></core-input-errors>
<input *ngIf="mode == 'search'" type="text" [placeholder]="field.name" [name]="'f_'+field.id">
<core-rich-text-editor *ngIf="mode == 'edit'" item-content [control]="form.controls['f_'+field.id]" [placeholder]="field.name" [formControlName]="'f_'+field.id"></core-rich-text-editor>
<!-- @todo: [component]="component" [componentId]="componentId" -->
<core-format-text *ngIf="mode == 'show' && value" [text]="value.content" [component]="component" [componentId]="componentId"></core-format-text>

View File

@ -0,0 +1,69 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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, ElementRef } from '@angular/core';
import { FormBuilder, FormControl } from '@angular/forms';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { AddonModDataProvider } from '../../../providers/data';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
/**
* Component to render data number field.
*/
@Component({
selector: 'addon-mod-data-field-textarea',
templateUrl: 'textarea.html'
})
export class AddonModDataFieldTextareaComponent extends AddonModDataFieldPluginComponent implements OnInit {
control: FormControl;
component: string;
componentId: number;
constructor(protected fb: FormBuilder, protected domUtils: CoreDomUtilsProvider, protected textUtils: CoreTextUtilsProvider,
element: ElementRef) {
super();
}
format(value: any): string {
const files = (value && value.files) || [];
return value ? this.textUtils.replacePluginfileUrls(value.content, files) : '';
}
/**
* Component being initialized.
*/
ngOnInit(): void {
this.mode = this.mode == 'list' ? 'show' : this.mode;
this.render();
}
protected render(): void {
if (this.mode == 'show') {
this.component = AddonModDataProvider.COMPONENT;
this.componentId = this.database.coursemodule;
return;
}
// Check if rich text editor is enabled.
if (this.mode == 'edit') {
const files = (this.value && this.value.files) || [],
text = this.value ? this.textUtils.replacePluginfileUrls(this.value.content, files) : '';
this.control = this.fb.control(text);
}
}
}

View File

@ -0,0 +1,145 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Injector, Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { AddonModDataFieldTextHandler } from '../../text/providers/handler';
import { AddonModDataFieldTextareaComponent } from '../component/textarea';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
/**
* Handler for textarea data field plugin.
*/
@Injectable()
export class AddonModDataFieldTextareaHandler extends AddonModDataFieldTextHandler {
name = 'AddonModDataFieldTextareaHandler';
type = 'textarea';
constructor(protected translate: TranslateService, private textUtils: CoreTextUtilsProvider,
private domUtils: CoreDomUtilsProvider) {
super(translate);
}
/**
* Return the Component to use to display the plugin data.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} field The field object.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(injector: Injector, plugin: any): any | Promise<any> {
return AddonModDataFieldTextareaComponent;
}
/**
* Get field edit data in the input data.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {any} With name and value of the data to be sent.
*/
getFieldEditData(field: any, inputData: any, originalFieldData: any): any {
const fieldName = 'f_' + field.id;
if (inputData[fieldName]) {
return this.domUtils.isRichTextEditorEnabled().then((enabled) => {
const files = this.getFieldEditFiles(field, inputData, originalFieldData);
let text = this.textUtils.restorePluginfileUrls(inputData[fieldName], files);
if (!enabled) {
// Rich text editor not enabled, add some HTML to the text if needed.
text = this.textUtils.formatHtmlLines(text);
}
return [{
fieldid: field.id,
value: text
},
{
fieldid: field.id,
subfield: 'content1',
value: 1
},
{
fieldid: field.id,
subfield: 'itemid',
files: files
}
];
});
}
return false;
}
/**
* Get field edit files in the input data.
*
* @param {any} field Defines the field..
* @param {any} inputData Data entered in the edit form.
* @param {any} originalFieldData Original field entered data.
* @return {any} With name and value of the data to be sent.
*/
getFieldEditFiles(field: any, inputData: any, originalFieldData: any): any {
return (originalFieldData && originalFieldData.files) || [];
}
/**
* Check and get field requeriments.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {string | false} String with the notification or false.
*/
getFieldsNotifications(field: any, inputData: any): string | false {
if (field.required) {
if (!inputData || !inputData.length) {
return this.translate.instant('addon.mod_data.errormustsupplyvalue');
}
const found = inputData.some((input) => {
if (!input.subfield) {
return !!input.value;
}
return false;
});
if (!found) {
return this.translate.instant('addon.mod_data.errormustsupplyvalue');
}
}
return false;
}
/**
* Override field content data with offline submission.
*
* @param {any} originalContent Original data to be overriden.
* @param {any} offlineContent Array with all the offline data to override.
* @param {any} [offlineFiles] Array with all the offline files in the field.
* @return {any} Data overriden
*/
overrideData(originalContent: any, offlineContent: any, offlineFiles?: any): any {
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 = this.textUtils.replacePluginfileUrls(originalContent.content, originalContent.files);
}
return originalContent;
}
}

View File

@ -0,0 +1,49 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonModDataFieldTextareaHandler } from './providers/handler';
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
import { AddonModDataFieldTextareaComponent } from './component/textarea';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [
AddonModDataFieldTextareaComponent
],
imports: [
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule
],
providers: [
AddonModDataFieldTextareaHandler
],
exports: [
AddonModDataFieldTextareaComponent
],
entryComponents: [
AddonModDataFieldTextareaComponent
]
})
export class AddonModDataFieldTextareaModule {
constructor(fieldDelegate: AddonModDataFieldsDelegate, handler: AddonModDataFieldTextareaHandler) {
fieldDelegate.registerHandler(handler);
}
}

View File

@ -0,0 +1,7 @@
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="error"></core-input-errors>
<ion-input *ngIf="mode != 'show'" type="url" [formControlName]="'f_'+field.id" [placeholder]="field.name" [(ngModel)]="val"></ion-input>
<a *ngIf="mode == 'show' && value && value.content" [href]="value.content" core-link capture-link="true">{{field.name}}</a>

View File

@ -0,0 +1,54 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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, ElementRef } from '@angular/core';
import { FormBuilder, FormControl } from '@angular/forms';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text';
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
/**
* Component to render data url field.
*/
@Component({
selector: 'addon-mod-data-field-url',
templateUrl: 'url.html'
})
export class AddonModDataFieldUrlComponent extends AddonModDataFieldPluginComponent implements OnInit {
control: FormControl;
val: number;
constructor(protected fb: FormBuilder, protected domUtils: CoreDomUtilsProvider, protected textUtils: CoreTextUtilsProvider,
element: ElementRef) {
super();
}
/**
* Component being initialized.
*/
ngOnInit(): void {
this.mode = this.mode == 'list' ? 'show' : this.mode;
this.render();
}
protected render(): void {
if (this.mode == 'show') {
return;
}
if (this.mode == 'edit' && this.value) {
this.val = this.value.content;
}
}
}

View File

@ -0,0 +1,57 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Injector, Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { AddonModDataFieldTextHandler } from '../../text/providers/handler';
import { AddonModDataFieldUrlComponent } from '../component/url';
/**
* Handler for url data field plugin.
*/
@Injectable()
export class AddonModDataFieldUrlHandler extends AddonModDataFieldTextHandler {
name = 'AddonModDataFieldUrlHandler';
type = 'url';
constructor(protected translate: TranslateService) {
super(translate);
}
/**
* Return the Component to use to display the plugin data.
* It's recommended to return the class of the component, but you can also return an instance of the component.
*
* @param {Injector} injector Injector.
* @param {any} field The field object.
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/
getComponent(injector: Injector, plugin: any): any | Promise<any> {
return AddonModDataFieldUrlComponent;
}
/**
* Check and get field requeriments.
*
* @param {any} field Defines the field to be rendered.
* @param {any} inputData Data entered in the edit form.
* @return {string | false} String with the notification or false.
*/
getFieldsNotifications(field: any, inputData: any): string | false {
if (field.required && (!inputData || !inputData.length || !inputData[0].value)) {
return this.translate.instant('addon.mod_data.errormustsupplyvalue');
}
return false;
}
}

View File

@ -0,0 +1,49 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { CommonModule } from '@angular/common';
import { IonicModule } from 'ionic-angular';
import { TranslateModule } from '@ngx-translate/core';
import { AddonModDataFieldUrlHandler } from './providers/handler';
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
import { AddonModDataFieldUrlComponent } from './component/url';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
@NgModule({
declarations: [
AddonModDataFieldUrlComponent
],
imports: [
CommonModule,
IonicModule,
TranslateModule.forChild(),
CoreComponentsModule,
CoreDirectivesModule
],
providers: [
AddonModDataFieldUrlHandler
],
exports: [
AddonModDataFieldUrlComponent
],
entryComponents: [
AddonModDataFieldUrlComponent
]
})
export class AddonModDataFieldUrlModule {
constructor(fieldDelegate: AddonModDataFieldsDelegate, handler: AddonModDataFieldUrlHandler) {
fieldDelegate.registerHandler(handler);
}
}

View File

@ -113,7 +113,7 @@ export class AddonModDataHelperProvider {
replace = new RegExp(replace, 'gi');
// Replace field by a generic directive.
const render = '<addon-mod-data-field-plugin mode="search" field="fields[' + field.id +
const render = '<addon-mod-data-field-plugin mode="search" [field]="fields[' + field.id +
']"></addon-mod-data-field-plugin>';
template = template.replace(replace, render);
});
@ -156,13 +156,13 @@ export class AddonModDataHelperProvider {
replace = new RegExp(replace, 'gi');
// Replace field by a generic directive.
render = '<addon-mod-data-field-plugin field="fields[' + field.id + ']" value="entries[' + entry.id + '].contents[' +
field.id + ']" mode="' + mode + '" database="data" (viewAction)="gotoEntry(' + entry.id +
render = '<addon-mod-data-field-plugin [field]="fields[' + field.id + ']" [value]="entries[' + entry.id +
'].contents[' + field.id + ']" mode="' + mode + '" [database]="data" (viewAction)="gotoEntry(' + entry.id +
')"></addon-mod-data-field-plugin>';
template = template.replace(replace, render);
});
for (const action in actions) {
/*for (const action in actions) {
replace = new RegExp('##' + action + '##', 'gi');
// Is enabled?
if (actions[action]) {
@ -179,7 +179,7 @@ export class AddonModDataHelperProvider {
} else {
template = template.replace(replace, '');
}
}
}*/
return template;
}

View File

@ -47,7 +47,6 @@ export class AddonModFeedbackHelperProvider {
protected getActivityHistoryBackCounter(pageName: string, instance: number, paramName: string, prefix: string,
navCtrl: NavController): number {
let historyInstance, params,
backTimes = 0,
view = navCtrl.getActive();
while (!view.isFirst()) {
@ -60,9 +59,7 @@ export class AddonModFeedbackHelperProvider {
historyInstance = params.get(paramName) ? params.get(paramName) : params.get('module').instance;
// Check we are not changing to another activity.
if (historyInstance && historyInstance == instance) {
backTimes++;
} else {
if (!historyInstance || historyInstance != instance) {
break;
}

View File

@ -42,6 +42,8 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy {
@Input() text: string; // The HTML text to display.
@Input() javascript: string; // The Javascript to execute in the component.
@Input() jsData: any; // Data to pass to the fake component.
@Input() extraImports: any[] = []; // Extra import modules.
@Input() extraProviders: any[] = []; // Extra providers.
@Output() created: EventEmitter<any> = new EventEmitter(); // Will emit an event when the component is instantiated.
// Get the container where to put the content.
@ -61,7 +63,8 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy {
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
if ((changes.text || changes.javascript) && this.text) {
// Create a new component and a new module.
this.compileProvider.createAndCompileComponent(this.text, this.getComponentClass()).then((factory) => {
this.compileProvider.createAndCompileComponent(this.text, this.getComponentClass(), this.extraImports)
.then((factory) => {
// Destroy previous components.
this.componentRef && this.componentRef.destroy();
@ -95,7 +98,7 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy {
constructor() {
// If there is some javascript to run, prepare the instance.
if (compileInstance.javascript) {
compileInstance.compileProvider.injectLibraries(this);
compileInstance.compileProvider.injectLibraries(this, compileInstance.extraProviders);
}
// Always add these elements, they could be needed on component init (componentObservable).

View File

@ -112,17 +112,20 @@ export class CoreCompileProvider {
*
* @param {string} template The template of the component.
* @param {any} componentClass The JS class of the component.
* @param {any[]} [extraImports] Extra imported modules if needed and not imported by this class.
* @return {Promise<ComponentFactory<any>>} Promise resolved with the factory to instantiate the component.
*/
createAndCompileComponent(template: string, componentClass: any): Promise<ComponentFactory<any>> {
createAndCompileComponent(template: string, componentClass: any, extraImports: any[] = []): Promise<ComponentFactory<any>> {
// Create the component using the template and the class.
const component = Component({
template: template
})
(componentClass);
const imports = this.IMPORTS.concat(extraImports);
// Now create the module containing the component.
const module = NgModule({imports: this.IMPORTS, declarations: [component]})(class {});
const module = NgModule({imports: imports, declarations: [component]})(class {});
// Compile the module and the component.
return this.compiler.compileModuleAndAllComponentsAsync(module).then((factories) => {
@ -166,13 +169,14 @@ export class CoreCompileProvider {
* Inject all the core libraries in a certain object.
*
* @param {any} instance The instance where to inject the libraries.
* @param {any[]} [extraProviders] Extra imported providers if needed and not imported by this class.
*/
injectLibraries(instance: any): void {
injectLibraries(instance: any, extraProviders: any[] = []): void {
const providers = (<any[]> CORE_PROVIDERS).concat(CORE_CONTENTLINKS_PROVIDERS).concat(CORE_COURSE_PROVIDERS)
.concat(CORE_COURSES_PROVIDERS).concat(CORE_FILEUPLOADER_PROVIDERS).concat(CORE_GRADES_PROVIDERS)
.concat(CORE_LOGIN_PROVIDERS).concat(CORE_MAINMENU_PROVIDERS).concat(CORE_SHAREDFILES_PROVIDERS)
.concat(CORE_SITEHOME_PROVIDERS).concat([CoreSitePluginsProvider]).concat(CORE_USER_PROVIDERS)
.concat(CORE_QUESTION_PROVIDERS).concat(IONIC_NATIVE_PROVIDERS).concat(this.OTHER_PROVIDERS);
.concat(CORE_QUESTION_PROVIDERS).concat(IONIC_NATIVE_PROVIDERS).concat(this.OTHER_PROVIDERS).concat(extraProviders);
// We cannot inject anything to this constructor. Use the Injector to inject all the providers into the instance.
for (const i in providers) {