forked from EVOgeek/Vmeda.Online
MOBILE-2338 data: Edit page
parent
d53a7acda5
commit
1bcc3c35b7
|
@ -153,7 +153,7 @@
|
||||||
<!-- Numeric grade. -->
|
<!-- Numeric grade. -->
|
||||||
<ion-item text-wrap *ngIf="grade.method == 'simple' && !grade.scale">
|
<ion-item text-wrap *ngIf="grade.method == 'simple' && !grade.scale">
|
||||||
<ion-label stacked>{{ 'addon.mod_assign.gradeoutof' | translate: {$a: gradeInfo.grade} }}</ion-label>
|
<ion-label stacked>{{ 'addon.mod_assign.gradeoutof' | translate: {$a: gradeInfo.grade} }}</ion-label>
|
||||||
<ion-input type="number" [(ngModel)]="grade.grade" min="0" [max]="gradeInfo.grade" [lang]="grade.lang" core-input-errors></ion-input>
|
<ion-input type="number" [(ngModel)]="grade.grade" min="0" [max]="gradeInfo.grade" [lang]="grade.lang"></ion-input>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<!-- Grade using a scale. -->
|
<!-- Grade using a scale. -->
|
||||||
|
|
|
@ -11,13 +11,13 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Input } from '@angular/core';
|
import { Input, OnInit, OnChanges, SimpleChange } from '@angular/core';
|
||||||
import { FormGroup, FormBuilder } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for component to render a field.
|
* Base class for component to render a field.
|
||||||
*/
|
*/
|
||||||
export class AddonModDataFieldPluginComponent {
|
export class AddonModDataFieldPluginComponent implements OnInit, OnChanges {
|
||||||
@Input() mode: string; // The render mode.
|
@Input() mode: string; // The render mode.
|
||||||
@Input() field: any; // The field to render.
|
@Input() field: any; // The field to render.
|
||||||
@Input() value?: any; // The value of the field.
|
@Input() value?: any; // The value of the field.
|
||||||
|
@ -45,7 +45,46 @@ export class AddonModDataFieldPluginComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.mode == 'edit') {
|
if (this.mode == 'edit') {
|
||||||
this.form.addControl(fieldName, this.fb.control(value || null));
|
this.form.addControl(fieldName, this.fb.control(value, this.field.required ? Validators.required : null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component being initialized.
|
||||||
|
*/
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize field.
|
||||||
|
*/
|
||||||
|
protected init(): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return if is shown or list mode.
|
||||||
|
*
|
||||||
|
* @return {boolean} True if mode is show or list.
|
||||||
|
*/
|
||||||
|
isShowOrListMode(): boolean {
|
||||||
|
return this.mode == 'list' || this.mode == 'show';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component being changed.
|
||||||
|
*/
|
||||||
|
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
|
||||||
|
if (this.isShowOrListMode() && changes.value) {
|
||||||
|
this.updateValue(changes.value.currentValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update value being shown.
|
||||||
|
*/
|
||||||
|
protected updateValue(value: any): void {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component, Input, OnInit, Injector, ViewChild } from '@angular/core';
|
import { Component, Input, OnInit, Injector, ViewChild, OnChanges, SimpleChange } from '@angular/core';
|
||||||
import { FormGroup } from '@angular/forms';
|
import { FormGroup } from '@angular/forms';
|
||||||
import { AddonModDataProvider } from '../../providers/data';
|
import { AddonModDataProvider } from '../../providers/data';
|
||||||
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
|
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
|
||||||
|
@ -24,7 +24,7 @@ import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-comp
|
||||||
selector: 'addon-mod-data-field-plugin',
|
selector: 'addon-mod-data-field-plugin',
|
||||||
templateUrl: 'field-plugin.html',
|
templateUrl: 'field-plugin.html',
|
||||||
})
|
})
|
||||||
export class AddonModDataFieldPluginComponent implements OnInit {
|
export class AddonModDataFieldPluginComponent implements OnInit, OnChanges {
|
||||||
@ViewChild(CoreDynamicComponent) dynamicComponent: CoreDynamicComponent;
|
@ViewChild(CoreDynamicComponent) dynamicComponent: CoreDynamicComponent;
|
||||||
|
|
||||||
@Input() mode: string; // The render mode.
|
@Input() mode: string; // The render mode.
|
||||||
|
@ -70,10 +70,23 @@ export class AddonModDataFieldPluginComponent implements OnInit {
|
||||||
form: this.form,
|
form: this.form,
|
||||||
search: this.search
|
search: this.search
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.fieldLoaded = true;
|
this.fieldLoaded = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component being changed.
|
||||||
|
*/
|
||||||
|
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
|
||||||
|
if (this.fieldLoaded && this.data) {
|
||||||
|
if (this.mode == 'edit' && changes.error) {
|
||||||
|
this.data.error = changes.error.currentValue;
|
||||||
|
}
|
||||||
|
if ((this.mode == 'show' || this.mode == 'list') && changes.value) {
|
||||||
|
this.data.value = changes.value.currentValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,3 +24,78 @@
|
||||||
@extend .col;
|
@extend .col;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
page-addon-mod-data-search,
|
||||||
|
page-addon-mod-data-edit {
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item.item-input.item-block .item-inner ion-input,
|
||||||
|
.item.item-input.item-input-has-focus .item-inner ion-input,
|
||||||
|
.item.item-input.input-has-focus .item-inner ion-input {
|
||||||
|
border: 0 !important;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addon-data-lantlong {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
form, .addon-data-advanced-search {
|
||||||
|
background-color: $list-background-color;
|
||||||
|
|
||||||
|
.core-mark-required {
|
||||||
|
float: right;
|
||||||
|
|
||||||
|
+ ion-input,
|
||||||
|
+ ion-select {
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@if ($text-input-md-show-focus-highlight) {
|
||||||
|
.input-md input:focus {
|
||||||
|
@include md-input-highlight($text-input-md-highlight-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-md input {
|
||||||
|
@include padding-horizontal(null, ($item-md-padding-end / 2));
|
||||||
|
border-bottom: 1px solid $list-md-border-color;
|
||||||
|
&:focus {
|
||||||
|
@include md-input-highlight($text-input-md-highlight-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-ios input {
|
||||||
|
@include padding-horizontal(null, $item-ios-padding-end / 2);
|
||||||
|
@include safe-area-padding-horizontal(null, $item-ios-padding-end / 2);
|
||||||
|
border-bottom: $hairlines-width solid $list-ios-border-color;
|
||||||
|
&:focus {
|
||||||
|
@include ios-input-highlight($text-input-ios-highlight-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-wp input {
|
||||||
|
@include padding-horizontal(null, ($item-wp-padding-end / 2));
|
||||||
|
border-bottom: 1px solid $list-wp-border-color;
|
||||||
|
&:focus {
|
||||||
|
border-color: $text-input-wp-highlight-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-select {
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.core-item-has-rich-text-editor {
|
||||||
|
margin-right: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,9 @@
|
||||||
<span *ngIf="mode != 'show'" [formGroup]="form">
|
<span *ngIf="!isShowOrListMode()" [formGroup]="form">
|
||||||
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
|
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||||
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="error"></core-input-errors>
|
<ion-select [formControlName]="'f_'+field.id" multiple="true" [placeholder]="'addon.mod_data.menuchoose' | translate" [selectOptions]="{title: field.name}" interface="popover">
|
||||||
|
|
||||||
<ion-select [formControlName]="'f_'+field.id" multiple="true" [placeholder]="'addon.mod_data.menuchoose' | translate" core-input-errors [selectOptions]="{title: field.name}">
|
|
||||||
<ion-option *ngFor="let option of options" [value]="option.value">{{option.key}}</ion-option>
|
<ion-option *ngFor="let option of options" [value]="option.value">{{option.key}}</ion-option>
|
||||||
</ion-select>
|
</ion-select>
|
||||||
|
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||||
|
|
||||||
<ion-item *ngIf="mode == 'search'">
|
<ion-item *ngIf="mode == 'search'">
|
||||||
<ion-label>{{ 'addon.mod_data.selectedrequired' | translate }}</ion-label>
|
<ion-label>{{ 'addon.mod_data.selectedrequired' | translate }}</ion-label>
|
||||||
|
@ -14,4 +12,4 @@
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<core-format-text *ngIf="mode == 'show' && value && value.content" [text]="value.content"></core-format-text>
|
<core-format-text *ngIf="isShowOrListMode() && value && value.content" [text]="value.content"></core-format-text>
|
|
@ -11,7 +11,7 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
|
||||||
selector: 'addon-mod-data-field-checkbox',
|
selector: 'addon-mod-data-field-checkbox',
|
||||||
templateUrl: 'checkbox.html'
|
templateUrl: 'checkbox.html'
|
||||||
})
|
})
|
||||||
export class AddonModDataFieldCheckboxComponent extends AddonModDataFieldPluginComponent implements OnInit {
|
export class AddonModDataFieldCheckboxComponent extends AddonModDataFieldPluginComponent {
|
||||||
|
|
||||||
options = [];
|
options = [];
|
||||||
|
|
||||||
|
@ -31,16 +31,11 @@ export class AddonModDataFieldCheckboxComponent extends AddonModDataFieldPluginC
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being initialized.
|
* Initialize field.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
protected init(): void {
|
||||||
this.mode = this.mode == 'list' ? 'show' : this.mode;
|
if (this.isShowOrListMode()) {
|
||||||
this.render();
|
this.updateValue(this.value);
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): void {
|
|
||||||
if (this.mode == 'show') {
|
|
||||||
this.value.content = this.value && this.value.content && this.value.content.split('##').join('<br>');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -49,11 +44,12 @@ export class AddonModDataFieldCheckboxComponent extends AddonModDataFieldPluginC
|
||||||
return { key: option, value: option };
|
return { key: option, value: option };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const values = [];
|
||||||
if (this.mode == 'edit' && this.value && this.value.content) {
|
if (this.mode == 'edit' && this.value && this.value.content) {
|
||||||
this.value.content.split('##').forEach((value) => {
|
this.value.content.split('##').forEach((value) => {
|
||||||
const x = this.options.findIndex((option) => value == option.key);
|
const x = this.options.findIndex((option) => value == option.key);
|
||||||
if (x >= 0) {
|
if (x >= 0) {
|
||||||
this.options[x].selected = true;
|
values.push(value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -62,6 +58,16 @@ export class AddonModDataFieldCheckboxComponent extends AddonModDataFieldPluginC
|
||||||
this.addControl('f_' + this.field.id + '_allreq');
|
this.addControl('f_' + this.field.id + '_allreq');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addControl('f_' + this.field.id);
|
this.addControl('f_' + this.field.id, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update value being shown.
|
||||||
|
*
|
||||||
|
* @param {any} value New value to be set.
|
||||||
|
*/
|
||||||
|
protected updateValue(value: any): void {
|
||||||
|
this.value = value;
|
||||||
|
this.value.content = value && value.content && value.content.split('##').join('<br>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,19 +49,12 @@ export class AddonModDataFieldCheckboxHandler implements AddonModDataFieldHandle
|
||||||
const fieldName = 'f_' + field.id,
|
const fieldName = 'f_' + field.id,
|
||||||
reqName = 'f_' + field.id + '_allreq';
|
reqName = 'f_' + field.id + '_allreq';
|
||||||
|
|
||||||
const options = field.param1.split('\n'),
|
const values = [];
|
||||||
checkboxes = [],
|
|
||||||
values = [];
|
|
||||||
options.forEach((option) => {
|
|
||||||
if (inputData[fieldName + '_' + option]) {
|
|
||||||
checkboxes.push(option);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (checkboxes.length > 0) {
|
if (inputData[fieldName] && inputData[fieldName].length > 0) {
|
||||||
values.push({
|
values.push({
|
||||||
name: fieldName,
|
name: fieldName,
|
||||||
value: checkboxes
|
value: inputData[fieldName]
|
||||||
});
|
});
|
||||||
|
|
||||||
if (inputData[reqName]) {
|
if (inputData[reqName]) {
|
||||||
|
@ -87,17 +80,10 @@ export class AddonModDataFieldCheckboxHandler implements AddonModDataFieldHandle
|
||||||
getFieldEditData(field: any, inputData: any, originalFieldData: any): any {
|
getFieldEditData(field: any, inputData: any, originalFieldData: any): any {
|
||||||
const fieldName = 'f_' + field.id;
|
const fieldName = 'f_' + field.id;
|
||||||
|
|
||||||
const options = field.param1.split('\n'),
|
if (inputData[fieldName] && inputData[fieldName].length > 0) {
|
||||||
checkboxes = [];
|
|
||||||
options.forEach((option) => {
|
|
||||||
if (inputData[fieldName + '_' + option]) {
|
|
||||||
checkboxes.push(option);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (checkboxes.length > 0) {
|
|
||||||
return [{
|
return [{
|
||||||
fieldid: field.id,
|
fieldid: field.id,
|
||||||
value: checkboxes
|
value: inputData[fieldName]
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,18 +99,11 @@ export class AddonModDataFieldCheckboxHandler implements AddonModDataFieldHandle
|
||||||
* @return {Promise<boolean> | boolean} If the field has changes.
|
* @return {Promise<boolean> | boolean} If the field has changes.
|
||||||
*/
|
*/
|
||||||
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | boolean {
|
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | boolean {
|
||||||
const fieldName = 'f_' + field.id,
|
const fieldName = 'f_' + field.id;
|
||||||
checkboxes = [];
|
|
||||||
|
|
||||||
inputData[fieldName].forEach((value, option) => {
|
|
||||||
if (value) {
|
|
||||||
checkboxes.push(option);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
originalFieldData = (originalFieldData && originalFieldData.content) || '';
|
originalFieldData = (originalFieldData && originalFieldData.content) || '';
|
||||||
|
|
||||||
return checkboxes.join('##') != originalFieldData;
|
return inputData[fieldName].join('##') != originalFieldData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<span *ngIf="mode != 'show'" [formGroup]="form">
|
<span *ngIf="!isShowOrListMode()" [formGroup]="form">
|
||||||
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
|
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||||
<ion-datetime [formControlName]="'f_'+field.id" [placeholder]="'core.date' | translate" [disabled]="mode == 'search' && !search['f_'+field.id+'_z']" [displayFormat]="format"></ion-datetime>
|
<ion-datetime [formControlName]="'f_'+field.id" [placeholder]="'core.date' | translate" [disabled]="mode == 'search' && !search['f_'+field.id+'_z']" [displayFormat]="format"></ion-datetime>
|
||||||
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="errors"></core-input-errors>
|
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||||
|
|
||||||
<ion-item *ngIf="mode == 'search'">
|
<ion-item *ngIf="mode == 'search'">
|
||||||
<ion-label>{{ 'addon.mod_data.usedate' | translate }}</ion-label>
|
<ion-label>{{ 'addon.mod_data.usedate' | translate }}</ion-label>
|
||||||
|
@ -10,5 +10,5 @@
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<core-format-text *ngIf="mode == 'show' && value && value.content" [text]="value.content * 1000 | coreFormatDate:'dfdaymonthyear'"></core-format-text>
|
<core-format-text *ngIf="isShowOrListMode() && value && value.content" [text]="value.content * 1000 | coreFormatDate:'LL'"></core-format-text>
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||||
|
@ -23,11 +23,8 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
|
||||||
selector: 'addon-mod-data-field-date',
|
selector: 'addon-mod-data-field-date',
|
||||||
templateUrl: 'date.html'
|
templateUrl: 'date.html'
|
||||||
})
|
})
|
||||||
export class AddonModDataFieldDateComponent extends AddonModDataFieldPluginComponent implements OnInit {
|
export class AddonModDataFieldDateComponent extends AddonModDataFieldPluginComponent {
|
||||||
|
|
||||||
values = {};
|
|
||||||
enable: boolean;
|
|
||||||
val: any;
|
|
||||||
format: string;
|
format: string;
|
||||||
|
|
||||||
constructor(protected fb: FormBuilder, protected timeUtils: CoreTimeUtilsProvider) {
|
constructor(protected fb: FormBuilder, protected timeUtils: CoreTimeUtilsProvider) {
|
||||||
|
@ -35,35 +32,27 @@ export class AddonModDataFieldDateComponent extends AddonModDataFieldPluginCompo
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being initialized.
|
* Initialize field.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
protected init(): void {
|
||||||
this.mode = this.mode == 'list' ? 'show' : this.mode;
|
if (this.isShowOrListMode()) {
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): void {
|
|
||||||
if (this.mode == 'show') {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.value) {
|
let val;
|
||||||
this.value = {
|
|
||||||
content: Math.floor(Date.now() / 1000)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
this.val = new Date(this.value.content * 1000);
|
|
||||||
|
|
||||||
this.format = this.timeUtils.getLocalizedDateFormat('LL');
|
this.format = this.timeUtils.getLocalizedDateFormat('LL');
|
||||||
|
|
||||||
if (this.mode == 'search') {
|
if (this.mode == 'search') {
|
||||||
this.addControl('f_' + this.field.id + '_z');
|
this.addControl('f_' + this.field.id + '_z');
|
||||||
this.search['f_' + this.field.id] = this.search['f_' + this.field.id + '_y'] ? new Date(
|
val = this.search['f_' + this.field.id + '_y'] ? new Date(this.search['f_' + this.field.id + '_y'] + '-' +
|
||||||
this.search['f_' + this.field.id + '_y'] + '-' + this.search['f_' + this.field.id + '_m'] + '-' +
|
this.search['f_' + this.field.id + '_m'] + '-' + this.search['f_' + this.field.id + '_d']) : new Date();
|
||||||
this.search['f_' + this.field.id + '_d']) : this.val;
|
|
||||||
|
this.search['f_' + this.field.id] = val.toISOString();
|
||||||
|
} else {
|
||||||
|
val = this.value && this.value.content ? new Date(parseInt(this.value.content, 10) * 1000) : new Date();
|
||||||
|
val = val.toISOString();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addControl('f_' + this.field.id, this.val);
|
this.addControl('f_' + this.field.id, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ export class AddonModDataFieldDateHandler implements AddonModDataFieldHandler {
|
||||||
|
|
||||||
if (inputData[enabledName] && typeof inputData[fieldName] == 'string') {
|
if (inputData[enabledName] && typeof inputData[fieldName] == 'string') {
|
||||||
const values = [],
|
const values = [],
|
||||||
date = inputData[fieldName].split('-'),
|
date = inputData[fieldName].substr(0, 10).split('-'),
|
||||||
year = date[0],
|
year = date[0],
|
||||||
month = date[1],
|
month = date[1],
|
||||||
day = date[2];
|
day = date[2];
|
||||||
|
@ -88,9 +88,9 @@ export class AddonModDataFieldDateHandler implements AddonModDataFieldHandler {
|
||||||
getFieldEditData(field: any, inputData: any, originalFieldData: any): any {
|
getFieldEditData(field: any, inputData: any, originalFieldData: any): any {
|
||||||
const fieldName = 'f_' + field.id;
|
const fieldName = 'f_' + field.id;
|
||||||
|
|
||||||
if (inputData[fieldName]) {
|
if (typeof inputData[fieldName] == 'string') {
|
||||||
const values = [],
|
const values = [],
|
||||||
date = inputData[fieldName].split('-'),
|
date = inputData[fieldName].substr(0, 10).split('-'),
|
||||||
year = date[0],
|
year = date[0],
|
||||||
month = date[1],
|
month = date[1],
|
||||||
day = date[2];
|
day = date[2];
|
||||||
|
@ -126,7 +126,7 @@ export class AddonModDataFieldDateHandler implements AddonModDataFieldHandler {
|
||||||
*/
|
*/
|
||||||
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | boolean {
|
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | boolean {
|
||||||
const fieldName = 'f_' + field.id,
|
const fieldName = 'f_' + field.id,
|
||||||
input = inputData[fieldName] || '';
|
input = inputData[fieldName] && inputData[fieldName].substr(0, 10) || '';
|
||||||
|
|
||||||
originalFieldData = (originalFieldData && originalFieldData.content &&
|
originalFieldData = (originalFieldData && originalFieldData.content &&
|
||||||
new Date(originalFieldData.content * 1000).toISOString().substr(0, 10)) || '';
|
new Date(originalFieldData.content * 1000).toISOString().substr(0, 10)) || '';
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
<span *ngIf="mode == 'edit'" [formGroup]="form">
|
<span *ngIf="mode == 'edit'">
|
||||||
<span [core-mark-required]="field.required"></span>
|
<span [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||||
<core-input-errors *ngIf="error" [errorMessages]="error"></core-input-errors>
|
|
||||||
<core-attachments [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component" [componentId]="componentId" [allowOffline]="true"></core-attachments>
|
<core-attachments [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component" [componentId]="componentId" [allowOffline]="true"></core-attachments>
|
||||||
|
<core-input-errors *ngIf="error" [errorText]="error"></core-input-errors>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span *ngIf="mode == 'search'" [formGroup]="form">
|
<span *ngIf="mode == 'search'" [formGroup]="form">
|
||||||
<ion-input type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input>
|
<ion-input type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<ng-container *ngIf="mode == 'show'">
|
<ng-container *ngIf="isShowOrListMode()">
|
||||||
<div *ngFor="let file of files" no-lines>
|
<div *ngFor="let file of files" no-lines>
|
||||||
<!-- Files already attached to the submission. -->
|
<!-- Files already attached to the submission. -->
|
||||||
<core-file *ngIf="!file.name" [file]="file" [component]="component" [componentId]="componentId" [alwaysDownload]="true"></core-file>
|
<core-file *ngIf="!file.name" [file]="file" [component]="component" [componentId]="componentId" [alwaysDownload]="true"></core-file>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||||
import { CoreFileSessionProvider } from '@providers/file-session';
|
import { CoreFileSessionProvider } from '@providers/file-session';
|
||||||
|
@ -24,7 +24,7 @@ import { AddonModDataProvider } from '../../../providers/data';
|
||||||
selector: 'addon-mod-data-field-file',
|
selector: 'addon-mod-data-field-file',
|
||||||
templateUrl: 'file.html'
|
templateUrl: 'file.html'
|
||||||
})
|
})
|
||||||
export class AddonModDataFieldFileComponent extends AddonModDataFieldPluginComponent implements OnInit {
|
export class AddonModDataFieldFileComponent extends AddonModDataFieldPluginComponent {
|
||||||
|
|
||||||
files = [];
|
files = [];
|
||||||
component: string;
|
component: string;
|
||||||
|
@ -35,14 +35,6 @@ export class AddonModDataFieldFileComponent extends AddonModDataFieldPluginCompo
|
||||||
super(fb);
|
super(fb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Component being initialized.
|
|
||||||
*/
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.mode = this.mode == 'list' ? 'show' : this.mode;
|
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the files from the input value.
|
* Get the files from the input value.
|
||||||
*
|
*
|
||||||
|
@ -60,20 +52,32 @@ export class AddonModDataFieldFileComponent extends AddonModDataFieldPluginCompo
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): void {
|
/**
|
||||||
if (this.mode == 'show' || this.mode == 'edit') {
|
* Initialize field.
|
||||||
|
*/
|
||||||
|
protected init(): void {
|
||||||
|
if (this.mode != 'search') {
|
||||||
this.component = AddonModDataProvider.COMPONENT;
|
this.component = AddonModDataProvider.COMPONENT;
|
||||||
this.componentId = this.database.coursemodule;
|
this.componentId = this.database.coursemodule;
|
||||||
|
|
||||||
this.files = this.getFiles(this.value);
|
this.updateValue(this.value);
|
||||||
|
|
||||||
if (this.mode != 'show') {
|
if (this.mode == 'edit') {
|
||||||
// Edit mode, the list shouldn't change so there is no need to watch it.
|
|
||||||
this.maxSizeBytes = parseInt(this.field.param3, 10);
|
this.maxSizeBytes = parseInt(this.field.param3, 10);
|
||||||
this.fileSessionprovider.setFiles(this.component, this.database.id + '_' + this.field.id, this.files);
|
this.fileSessionprovider.setFiles(this.component, this.database.id + '_' + this.field.id, this.files);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
this.addControl('f_' + this.field.id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.addControl('f_' + this.field.id);
|
/**
|
||||||
|
* Update value being shown.
|
||||||
|
*
|
||||||
|
* @param {any} value New value to be set.
|
||||||
|
*/
|
||||||
|
protected updateValue(value: any): void {
|
||||||
|
this.value = value;
|
||||||
|
this.files = this.getFiles(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,19 @@
|
||||||
<span *ngIf="mode != 'show'" [formGroup]="form">
|
<span *ngIf="!isShowOrListMode()" [formGroup]="form">
|
||||||
<ion-input *ngIf="mode == 'search'" type="text" [placeholder]="field.name" [formControlName]="'f_'+field.id"></ion-input>
|
<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>
|
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||||
|
<div class="addon-data-lantlong">
|
||||||
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="errors"></core-input-errors>
|
<ion-input type="text" [formControlName]="'f_'+field.id+'_0'" maxlength="10"></ion-input>
|
||||||
|
|
||||||
<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>
|
<span class="placeholder-icon" item-right>°N</span>
|
||||||
</ion-item>
|
</div>
|
||||||
<ion-item *ngIf="mode == 'edit'" [formGroup]="form">
|
<div class="addon-data-lantlong">
|
||||||
<ion-input type="text" [formControlName]="'f_'+field.id+'_1'" [(ngModel)]="east" maxlength="10" core-input-errors></ion-input>
|
<ion-input type="text" [formControlName]="'f_'+field.id+'_1'" maxlength="10"></ion-input>
|
||||||
<span class="placeholder-icon" item-right>°E</span>
|
<span class="placeholder-icon" item-right>°E</span>
|
||||||
</ion-item>
|
</div>
|
||||||
|
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
|
||||||
<span *ngIf="mode == 'show' && value">
|
<span *ngIf="isShowOrListMode() && value">
|
||||||
<a [href]="getLatLongLink(north, east)">{{ formatLatLong(north, east) }}</a>
|
<a [href]="getLatLongLink(north, east)">{{ formatLatLong(north, east) }}</a>
|
||||||
</span>
|
</span>
|
|
@ -11,7 +11,7 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { Platform } from 'ionic-angular';
|
import { Platform } from 'ionic-angular';
|
||||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||||
|
@ -23,7 +23,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
|
||||||
selector: 'addon-mod-data-field-latlong',
|
selector: 'addon-mod-data-field-latlong',
|
||||||
templateUrl: 'latlong.html'
|
templateUrl: 'latlong.html'
|
||||||
})
|
})
|
||||||
export class AddonModDataFieldLatlongComponent extends AddonModDataFieldPluginComponent implements OnInit {
|
export class AddonModDataFieldLatlongComponent extends AddonModDataFieldPluginComponent {
|
||||||
|
|
||||||
north: number;
|
north: number;
|
||||||
east: number;
|
east: number;
|
||||||
|
@ -69,17 +69,11 @@ export class AddonModDataFieldLatlongComponent extends AddonModDataFieldPluginCo
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being initialized.
|
* Initialize field.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
protected init(): void {
|
||||||
this.mode = this.mode == 'list' ? 'show' : this.mode;
|
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): void {
|
|
||||||
if (this.value) {
|
if (this.value) {
|
||||||
this.north = (this.value && parseFloat(this.value.content)) || null;
|
this.updateValue(this.value);
|
||||||
this.east = (this.value && parseFloat(this.value.content1)) || null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.mode == 'edit') {
|
if (this.mode == 'edit') {
|
||||||
|
@ -89,4 +83,15 @@ export class AddonModDataFieldLatlongComponent extends AddonModDataFieldPluginCo
|
||||||
this.addControl('f_' + this.field.id);
|
this.addControl('f_' + this.field.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update value being shown.
|
||||||
|
*
|
||||||
|
* @param {any} value New value to be set.
|
||||||
|
*/
|
||||||
|
protected updateValue(value: any): void {
|
||||||
|
this.value = value;
|
||||||
|
this.north = (value && parseFloat(value.content)) || null;
|
||||||
|
this.east = (value && parseFloat(value.content1)) || null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
<span *ngIf="mode != 'show'" [formGroup]="form">
|
<span *ngIf="!isShowOrListMode()" [formGroup]="form">
|
||||||
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
|
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||||
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="error"></core-input-errors>
|
<ion-select [formControlName]="'f_'+field.id" [placeholder]="'addon.mod_data.menuchoose' | translate" [selectOptions]="{title: field.name}" interface="popover">
|
||||||
|
|
||||||
<ion-select [formControlName]="'f_'+field.id" [placeholder]="'addon.mod_data.menuchoose' | translate" core-input-errors [selectOptions]="{title: field.name}">
|
|
||||||
<ion-option value="">{{ 'addon.mod_data.menuchoose' | translate }}</ion-option>
|
<ion-option value="">{{ 'addon.mod_data.menuchoose' | translate }}</ion-option>
|
||||||
<ion-option *ngFor="let option of options" [value]="option">{{option}}</ion-option>
|
<ion-option *ngFor="let option of options" [value]="option">{{option}}</ion-option>
|
||||||
</ion-select>
|
</ion-select>
|
||||||
|
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<core-format-text *ngIf="mode == 'show' && value && value.content" [text]="value.content"></core-format-text>
|
<core-format-text *ngIf="isShowOrListMode() && value && value.content" [text]="value.content"></core-format-text>
|
|
@ -11,7 +11,7 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
|
||||||
selector: 'addon-mod-data-field-menu',
|
selector: 'addon-mod-data-field-menu',
|
||||||
templateUrl: 'menu.html'
|
templateUrl: 'menu.html'
|
||||||
})
|
})
|
||||||
export class AddonModDataFieldMenuComponent extends AddonModDataFieldPluginComponent implements OnInit {
|
export class AddonModDataFieldMenuComponent extends AddonModDataFieldPluginComponent {
|
||||||
|
|
||||||
options = [];
|
options = [];
|
||||||
|
|
||||||
|
@ -31,15 +31,10 @@ export class AddonModDataFieldMenuComponent extends AddonModDataFieldPluginCompo
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being initialized.
|
* Initialize field.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
protected init(): void {
|
||||||
this.mode = this.mode == 'list' ? 'show' : this.mode;
|
if (this.isShowOrListMode()) {
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): void {
|
|
||||||
if (this.mode == 'show') {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,6 @@ export class AddonModDataFieldMenuHandler implements AddonModDataFieldHandler {
|
||||||
*/
|
*/
|
||||||
getFieldSearchData(field: any, inputData: any): any {
|
getFieldSearchData(field: any, inputData: any): any {
|
||||||
const fieldName = 'f_' + field.id;
|
const fieldName = 'f_' + field.id;
|
||||||
|
|
||||||
if (inputData[fieldName]) {
|
if (inputData[fieldName]) {
|
||||||
return [{
|
return [{
|
||||||
name: fieldName,
|
name: fieldName,
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
<span *ngIf="mode != 'show'" [formGroup]="form">
|
<span *ngIf="!isShowOrListMode()" [formGroup]="form">
|
||||||
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
|
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||||
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="error"></core-input-errors>
|
<ion-select [formControlName]="'f_'+field.id" multiple="true" [placeholder]="'addon.mod_data.menuchoose' | translate" [selectOptions]="{title: field.name}" interface="popover">
|
||||||
|
|
||||||
<ion-select [formControlName]="'f_'+field.id" multiple="true" [placeholder]="'addon.mod_data.menuchoose' | translate" core-input-errors [selectOptions]="{title: field.name}">
|
|
||||||
<ion-option *ngFor="let option of options" [value]="option.value">{{option.key}}</ion-option>
|
<ion-option *ngFor="let option of options" [value]="option.value">{{option.key}}</ion-option>
|
||||||
</ion-select>
|
</ion-select>
|
||||||
|
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||||
|
|
||||||
|
|
||||||
<ion-item *ngIf="mode == 'search'">
|
<ion-item *ngIf="mode == 'search'">
|
||||||
|
@ -14,4 +13,4 @@
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<core-format-text *ngIf="mode == 'show' && value && value.content" [text]="value.content"></core-format-text>
|
<core-format-text *ngIf="isShowOrListMode() && value && value.content" [text]="value.content"></core-format-text>
|
|
@ -11,7 +11,7 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
|
||||||
selector: 'addon-mod-data-field-multimenu',
|
selector: 'addon-mod-data-field-multimenu',
|
||||||
templateUrl: 'multimenu.html'
|
templateUrl: 'multimenu.html'
|
||||||
})
|
})
|
||||||
export class AddonModDataFieldMultimenuComponent extends AddonModDataFieldPluginComponent implements OnInit {
|
export class AddonModDataFieldMultimenuComponent extends AddonModDataFieldPluginComponent {
|
||||||
|
|
||||||
options = [];
|
options = [];
|
||||||
|
|
||||||
|
@ -31,16 +31,11 @@ export class AddonModDataFieldMultimenuComponent extends AddonModDataFieldPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being initialized.
|
* Initialize field.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
protected init(): void {
|
||||||
this.mode = this.mode == 'list' ? 'show' : this.mode;
|
if (this.isShowOrListMode()) {
|
||||||
this.render();
|
this.updateValue(this.value);
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): void {
|
|
||||||
if (this.mode == 'show') {
|
|
||||||
this.value.content = this.value && this.value.content && this.value.content.split('##').join('<br>');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -49,11 +44,12 @@ export class AddonModDataFieldMultimenuComponent extends AddonModDataFieldPlugin
|
||||||
return { key: option, value: option };
|
return { key: option, value: option };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const values = [];
|
||||||
if (this.mode == 'edit' && this.value && this.value.content) {
|
if (this.mode == 'edit' && this.value && this.value.content) {
|
||||||
this.value.content.split('##').forEach((value) => {
|
this.value.content.split('##').forEach((value) => {
|
||||||
const x = this.options.findIndex((option) => value == option.key);
|
const x = this.options.findIndex((option) => value == option.key);
|
||||||
if (x >= 0) {
|
if (x >= 0) {
|
||||||
this.options[x].selected = true;
|
values.push(value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -62,6 +58,16 @@ export class AddonModDataFieldMultimenuComponent extends AddonModDataFieldPlugin
|
||||||
this.addControl('f_' + this.field.id + '_allreq');
|
this.addControl('f_' + this.field.id + '_allreq');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addControl('f_' + this.field.id);
|
this.addControl('f_' + this.field.id, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update value being shown.
|
||||||
|
*
|
||||||
|
* @param {any} value New value to be set.
|
||||||
|
*/
|
||||||
|
protected updateValue(value: any): void {
|
||||||
|
this.value = value;
|
||||||
|
this.value.content = value && value.content && value.content.split('##').join('<br>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,13 +81,10 @@ export class AddonModDataFieldMultimenuHandler implements AddonModDataFieldHandl
|
||||||
const fieldName = 'f_' + field.id;
|
const fieldName = 'f_' + field.id;
|
||||||
|
|
||||||
if (inputData[fieldName] && inputData[fieldName].length > 0) {
|
if (inputData[fieldName] && inputData[fieldName].length > 0) {
|
||||||
const options = inputData[fieldName].split('###');
|
return [{
|
||||||
if (options.length > 0) {
|
fieldid: field.id,
|
||||||
return [{
|
value: inputData[fieldName]
|
||||||
fieldid: field.id,
|
}];
|
||||||
value: options
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -102,11 +99,11 @@ export class AddonModDataFieldMultimenuHandler implements AddonModDataFieldHandl
|
||||||
* @return {Promise<boolean> | boolean} If the field has changes.
|
* @return {Promise<boolean> | boolean} If the field has changes.
|
||||||
*/
|
*/
|
||||||
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | boolean {
|
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | boolean {
|
||||||
const fieldName = 'f_' + field.id,
|
const fieldName = 'f_' + field.id;
|
||||||
input = inputData[fieldName] || '';
|
|
||||||
originalFieldData = (originalFieldData && originalFieldData.content) || '';
|
originalFieldData = (originalFieldData && originalFieldData.content) || '';
|
||||||
|
|
||||||
return input != originalFieldData;
|
return inputData[fieldName].join('##') != originalFieldData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<span *ngIf="mode != 'show'" [formGroup]="form">
|
<span *ngIf="!isShowOrListMode()" [formGroup]="form">
|
||||||
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
|
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||||
|
|
||||||
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="error"></core-input-errors>
|
|
||||||
|
|
||||||
<ion-input type="number" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input>
|
<ion-input type="number" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input>
|
||||||
|
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<core-format-text *ngIf="mode == 'show' && value && value.content" [text]="value.content"></core-format-text>
|
<core-format-text *ngIf="isShowOrListMode() && value && value.content" [text]="value.content"></core-format-text>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||||
|
|
||||||
|
@ -22,31 +22,26 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
|
||||||
selector: 'addon-mod-data-field-number',
|
selector: 'addon-mod-data-field-number',
|
||||||
templateUrl: 'number.html'
|
templateUrl: 'number.html'
|
||||||
})
|
})
|
||||||
export class AddonModDataFieldNumberComponent extends AddonModDataFieldPluginComponent implements OnInit {
|
export class AddonModDataFieldNumberComponent extends AddonModDataFieldPluginComponent{
|
||||||
|
|
||||||
val: number;
|
|
||||||
|
|
||||||
constructor(protected fb: FormBuilder) {
|
constructor(protected fb: FormBuilder) {
|
||||||
super(fb);
|
super(fb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being initialized.
|
* Initialize field.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
protected init(): void {
|
||||||
this.mode = this.mode == 'list' ? 'show' : this.mode;
|
if (this.isShowOrListMode()) {
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): void {
|
|
||||||
if (this.mode == 'show') {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let value;
|
||||||
if (this.mode == 'edit' && this.value) {
|
if (this.mode == 'edit' && this.value) {
|
||||||
this.val = this.value && parseFloat(this.value.content);
|
const v = parseFloat(this.value.content);
|
||||||
|
value = isNaN(v) ? '' : v;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addControl('f_' + this.field.id, this.val);
|
this.addControl('f_' + this.field.id, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,24 @@ export class AddonModDataFieldNumberHandler extends AddonModDataFieldTextHandler
|
||||||
return AddonModDataFieldNumberComponent;
|
return AddonModDataFieldNumberComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = typeof inputData[fieldName] != 'undefined' ? parseFloat(inputData[fieldName]) : '';
|
||||||
|
|
||||||
|
originalFieldData = (originalFieldData && typeof originalFieldData.content != 'undefined') ?
|
||||||
|
parseFloat(originalFieldData.content) : '';
|
||||||
|
|
||||||
|
return input != originalFieldData;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check and get field requeriments.
|
* Check and get field requeriments.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
<span *ngIf="mode == 'edit'" [formGroup]="form">
|
<span *ngIf="mode == 'edit'" [formGroup]="form">
|
||||||
<span [core-mark-required]="field.required"></span>
|
<span [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||||
|
<core-attachments [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component" [componentId]="componentId" [allowOffline]="true" acceptedTypes="image"></core-attachments>
|
||||||
|
<core-input-errors *ngIf="error" [errorText]="error"></core-input-errors>
|
||||||
|
|
||||||
<core-input-errors *ngIf="error" [errorMessages]="error"></core-input-errors>
|
<ion-label stacked>{{ 'addon.mod_data.alttext' | translate }}</ion-label>
|
||||||
|
<ion-input type="text" [formControlName]="'f_'+field.id+'_alttext'" [placeholder]=" 'addon.mod_data.alttext' | translate" ></ion-input>
|
||||||
<core-attachments [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component" [componentId]="componentId" [allowOffline]="true"></core-attachments>
|
|
||||||
|
|
||||||
<ion-item>
|
|
||||||
<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>
|
</span>
|
||||||
|
|
||||||
<span *ngIf="mode == 'search'" [formGroup]="form">
|
<span *ngIf="mode == 'search'" [formGroup]="form">
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||||
import { CoreFileSessionProvider } from '@providers/file-session';
|
import { CoreFileSessionProvider } from '@providers/file-session';
|
||||||
|
@ -24,7 +24,7 @@ import { AddonModDataProvider } from '../../../providers/data';
|
||||||
selector: 'addon-mod-data-field-picture',
|
selector: 'addon-mod-data-field-picture',
|
||||||
templateUrl: 'picture.html'
|
templateUrl: 'picture.html'
|
||||||
})
|
})
|
||||||
export class AddonModDataFieldPictureComponent extends AddonModDataFieldPluginComponent implements OnInit {
|
export class AddonModDataFieldPictureComponent extends AddonModDataFieldPluginComponent {
|
||||||
|
|
||||||
files = [];
|
files = [];
|
||||||
component: string;
|
component: string;
|
||||||
|
@ -35,7 +35,6 @@ export class AddonModDataFieldPictureComponent extends AddonModDataFieldPluginCo
|
||||||
entryId: number;
|
entryId: number;
|
||||||
imageUrl: string;
|
imageUrl: string;
|
||||||
title: string;
|
title: string;
|
||||||
alttext: string;
|
|
||||||
width: string;
|
width: string;
|
||||||
height: string;
|
height: string;
|
||||||
|
|
||||||
|
@ -43,13 +42,6 @@ export class AddonModDataFieldPictureComponent extends AddonModDataFieldPluginCo
|
||||||
super(fb);
|
super(fb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Component being initialized.
|
|
||||||
*/
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the files from the input value.
|
* Get the files from the input value.
|
||||||
*
|
*
|
||||||
|
@ -78,49 +70,67 @@ export class AddonModDataFieldPictureComponent extends AddonModDataFieldPluginCo
|
||||||
return files.find((file) => file.filename == filenameSeek) || false;
|
return files.find((file) => file.filename == filenameSeek) || false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): void {
|
/**
|
||||||
|
* Initialize field.
|
||||||
|
*/
|
||||||
|
protected init(): void {
|
||||||
if (this.mode != 'search') {
|
if (this.mode != 'search') {
|
||||||
this.component = AddonModDataProvider.COMPONENT;
|
this.component = AddonModDataProvider.COMPONENT;
|
||||||
this.componentId = this.database.coursemodule;
|
this.componentId = this.database.coursemodule;
|
||||||
|
|
||||||
// Edit mode, the list shouldn't change so there is no need to watch it.
|
this.updateValue(this.value);
|
||||||
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') {
|
if (this.mode == 'edit') {
|
||||||
this.maxSizeBytes = parseInt(this.field.param3, 10);
|
this.maxSizeBytes = parseInt(this.field.param3, 10);
|
||||||
this.fileSessionprovider.setFiles(this.component, this.database.id + '_' + this.field.id, this.files);
|
this.fileSessionprovider.setFiles(this.component, this.database.id + '_' + this.field.id, this.files);
|
||||||
this.alttext = (this.value && this.value.content1) || '';
|
|
||||||
} else {
|
const alttext = (this.value && this.value.content1) || '';
|
||||||
this.entryId = (this.value && this.value.recordid) || null;
|
this.addControl('f_' + this.field.id + '_alttext', alttext);
|
||||||
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 || '';
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
this.addControl('f_' + this.field.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update value being shown.
|
||||||
|
*
|
||||||
|
* @param {any} value New value to be set.
|
||||||
|
*/
|
||||||
|
protected updateValue(value: any): void {
|
||||||
|
this.value = value;
|
||||||
|
|
||||||
|
// Edit mode, the list shouldn't change so there is no need to watch it.
|
||||||
|
const files = value && value.files || [];
|
||||||
|
|
||||||
|
// Get image or thumb.
|
||||||
|
if (files.length > 0) {
|
||||||
|
const filenameSeek = this.mode == 'list' ? 'thumb_' + value.content : value.content;
|
||||||
|
this.image = this.findFile(files, filenameSeek);
|
||||||
|
|
||||||
|
if (!this.image && this.mode == 'list') {
|
||||||
|
this.image = this.findFile(files, value.content);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.files = [this.image];
|
||||||
|
} else {
|
||||||
|
this.image = false;
|
||||||
|
this.files = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addControl('f_' + this.field.id);
|
if (this.mode != 'edit') {
|
||||||
|
this.entryId = (value && value.recordid) || null;
|
||||||
|
this.title = (value && 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 || '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
<span *ngIf="mode != 'show'" [formGroup]="form">
|
<span *ngIf="!isShowOrListMode()" [formGroup]="form">
|
||||||
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
|
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||||
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="error"></core-input-errors>
|
<ion-select [formControlName]="'f_'+field.id" [placeholder]="'addon.mod_data.menuchoose' | translate" [selectOptions]="{title: field.name}" interface="popover">
|
||||||
|
|
||||||
<ion-select [formControlName]="'f_'+field.id" [placeholder]="'addon.mod_data.menuchoose' | translate" core-input-errors [selectOptions]="{title: field.name}">
|
|
||||||
<ion-option value="">{{ 'addon.mod_data.menuchoose' | translate }}</ion-option>
|
<ion-option value="">{{ 'addon.mod_data.menuchoose' | translate }}</ion-option>
|
||||||
<ion-option *ngFor="let option of options" [value]="option">{{option}}</ion-option>
|
<ion-option *ngFor="let option of options" [value]="option">{{option}}</ion-option>
|
||||||
</ion-select>
|
</ion-select>
|
||||||
|
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<core-format-text *ngIf="mode == 'show' && value && value.content" [text]="value.content"></core-format-text>
|
<core-format-text *ngIf="isShowOrListMode() && value && value.content" [text]="value.content"></core-format-text>
|
|
@ -11,7 +11,7 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
|
||||||
selector: 'addon-mod-data-field-radiobutton',
|
selector: 'addon-mod-data-field-radiobutton',
|
||||||
templateUrl: 'radiobutton.html'
|
templateUrl: 'radiobutton.html'
|
||||||
})
|
})
|
||||||
export class AddonModDataFieldRadiobuttonComponent extends AddonModDataFieldPluginComponent implements OnInit {
|
export class AddonModDataFieldRadiobuttonComponent extends AddonModDataFieldPluginComponent {
|
||||||
|
|
||||||
options = [];
|
options = [];
|
||||||
|
|
||||||
|
@ -31,15 +31,10 @@ export class AddonModDataFieldRadiobuttonComponent extends AddonModDataFieldPlug
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being initialized.
|
* Initialize field.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
protected init(): void {
|
||||||
this.mode = this.mode == 'list' ? 'show' : this.mode;
|
if (this.isShowOrListMode()) {
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): void {
|
|
||||||
if (this.mode == 'show') {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<span *ngIf="mode != 'show'" [formGroup]="form">
|
<span *ngIf="!isShowOrListMode()" [formGroup]="form">
|
||||||
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
|
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||||
|
<ion-input type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input>
|
||||||
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="error"></core-input-errors>
|
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||||
|
|
||||||
<ion-input type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name" [(ngModel)]="val"></ion-input>
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<core-format-text *ngIf="mode == 'show' && value && value.content" [text]="value.content"></core-format-text>
|
<core-format-text *ngIf="isShowOrListMode() && value && value.content" [text]="value.content"></core-format-text>
|
|
@ -11,7 +11,7 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||||
|
|
||||||
|
@ -22,31 +22,25 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
|
||||||
selector: 'addon-mod-data-field-text',
|
selector: 'addon-mod-data-field-text',
|
||||||
templateUrl: 'text.html'
|
templateUrl: 'text.html'
|
||||||
})
|
})
|
||||||
export class AddonModDataFieldTextComponent extends AddonModDataFieldPluginComponent implements OnInit {
|
export class AddonModDataFieldTextComponent extends AddonModDataFieldPluginComponent {
|
||||||
|
|
||||||
val: number;
|
|
||||||
|
|
||||||
constructor(protected fb: FormBuilder) {
|
constructor(protected fb: FormBuilder) {
|
||||||
super(fb);
|
super(fb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being initialized.
|
* Initialize field.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
protected init(): void {
|
||||||
this.mode = this.mode == 'list' ? 'show' : this.mode;
|
if (this.isShowOrListMode()) {
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): void {
|
|
||||||
if (this.mode == 'show') {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let value;
|
||||||
if (this.mode == 'edit' && this.value) {
|
if (this.mode == 'edit' && this.value) {
|
||||||
this.val = this.value.content;
|
value = this.value.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addControl('f_' + this.field.id, this.val);
|
this.addControl('f_' + this.field.id, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
<span *ngIf="mode != 'show'" [formGroup]="form">
|
<span *ngIf="!isShowOrListMode()" [formGroup]="form">
|
||||||
|
|
||||||
<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 == 'search'" type="text" [placeholder]="field.name" [formControlName]="'f_'+field.id"></ion-input>
|
<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" class="core-mark-required"></span>
|
||||||
<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>
|
<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" -->
|
<!-- @todo: [component]="component" [componentId]="componentId" -->
|
||||||
|
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<core-format-text *ngIf="mode == 'show' && value" [text]="value.content" [component]="component" [componentId]="componentId"></core-format-text>
|
<core-format-text *ngIf="isShowOrListMode() && value" [text]="format(value)" [component]="component" [componentId]="componentId"></core-format-text>
|
|
@ -11,7 +11,7 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
import { AddonModDataProvider } from '../../../providers/data';
|
import { AddonModDataProvider } from '../../../providers/data';
|
||||||
|
@ -24,7 +24,7 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
|
||||||
selector: 'addon-mod-data-field-textarea',
|
selector: 'addon-mod-data-field-textarea',
|
||||||
templateUrl: 'textarea.html'
|
templateUrl: 'textarea.html'
|
||||||
})
|
})
|
||||||
export class AddonModDataFieldTextareaComponent extends AddonModDataFieldPluginComponent implements OnInit {
|
export class AddonModDataFieldTextareaComponent extends AddonModDataFieldPluginComponent {
|
||||||
|
|
||||||
component: string;
|
component: string;
|
||||||
componentId: number;
|
componentId: number;
|
||||||
|
@ -33,6 +33,12 @@ export class AddonModDataFieldTextareaComponent extends AddonModDataFieldPluginC
|
||||||
super(fb);
|
super(fb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format value to be shown. Replacing plugin file Urls.
|
||||||
|
*
|
||||||
|
* @param {any} value Value to replace.
|
||||||
|
* @return {string} Replaced string to be rendered.
|
||||||
|
*/
|
||||||
format(value: any): string {
|
format(value: any): string {
|
||||||
const files = (value && value.files) || [];
|
const files = (value && value.files) || [];
|
||||||
|
|
||||||
|
@ -40,27 +46,23 @@ export class AddonModDataFieldTextareaComponent extends AddonModDataFieldPluginC
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being initialized.
|
* Initialize field.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
protected init(): void {
|
||||||
this.mode = this.mode == 'list' ? 'show' : this.mode;
|
if (this.isShowOrListMode()) {
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): void {
|
|
||||||
if (this.mode == 'show') {
|
|
||||||
this.component = AddonModDataProvider.COMPONENT;
|
this.component = AddonModDataProvider.COMPONENT;
|
||||||
this.componentId = this.database.coursemodule;
|
this.componentId = this.database.coursemodule;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let text;
|
||||||
// Check if rich text editor is enabled.
|
// Check if rich text editor is enabled.
|
||||||
if (this.mode == 'edit') {
|
if (this.mode == 'edit') {
|
||||||
const files = (this.value && this.value.files) || [],
|
const files = (this.value && this.value.files) || [];
|
||||||
text = this.value ? this.textUtils.replacePluginfileUrls(this.value.content, files) : '';
|
text = this.value ? this.textUtils.replacePluginfileUrls(this.value.content, files) : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addControl('f_' + this.field.id, '');
|
this.addControl('f_' + this.field.id, text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<span *ngIf="mode != 'show'" [formGroup]="form">
|
<span *ngIf="!isShowOrListMode()" [formGroup]="form">
|
||||||
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required"></span>
|
<span *ngIf="mode == 'edit'" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||||
|
<ion-input type="url" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input>
|
||||||
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorMessages]="error"></core-input-errors>
|
<core-input-errors *ngIf="error && mode == 'edit'" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors>
|
||||||
|
|
||||||
<ion-input type="url" [formControlName]="'f_'+field.id" [placeholder]="field.name" [(ngModel)]="val"></ion-input>
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<a *ngIf="mode == 'show' && value && value.content" [href]="value.content" core-link capture="true">{{field.name}}</a>
|
<a *ngIf="isShowOrListMode() && value && value.content" [href]="value.content" core-link capture="true">{{field.name}}</a>
|
|
@ -11,7 +11,7 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { FormBuilder } from '@angular/forms';
|
import { FormBuilder } from '@angular/forms';
|
||||||
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||||
|
|
||||||
|
@ -22,31 +22,25 @@ import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-
|
||||||
selector: 'addon-mod-data-field-url',
|
selector: 'addon-mod-data-field-url',
|
||||||
templateUrl: 'url.html'
|
templateUrl: 'url.html'
|
||||||
})
|
})
|
||||||
export class AddonModDataFieldUrlComponent extends AddonModDataFieldPluginComponent implements OnInit {
|
export class AddonModDataFieldUrlComponent extends AddonModDataFieldPluginComponent {
|
||||||
|
|
||||||
val: number;
|
|
||||||
|
|
||||||
constructor(protected fb: FormBuilder) {
|
constructor(protected fb: FormBuilder) {
|
||||||
super(fb);
|
super(fb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being initialized.
|
* Initialize field.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
protected init(): void {
|
||||||
this.mode = this.mode == 'list' ? 'show' : this.mode;
|
if (this.isShowOrListMode()) {
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): void {
|
|
||||||
if (this.mode == 'show') {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let value;
|
||||||
if (this.mode == 'edit' && this.value) {
|
if (this.mode == 'edit' && this.value) {
|
||||||
this.val = this.value.content;
|
value = this.value.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addControl('f_' + this.field.id, this.val);
|
this.addControl('f_' + this.field.id, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<ion-header>
|
||||||
|
<ion-navbar>
|
||||||
|
<ion-title><core-format-text [text]="title"></core-format-text></ion-title>
|
||||||
|
<ion-buttons end>
|
||||||
|
<button ion-button icon-only (click)="save()" [attr.aria-label]="'core.save' | translate">
|
||||||
|
<ion-icon name="send"></ion-icon>
|
||||||
|
</button>
|
||||||
|
</ion-buttons>
|
||||||
|
</ion-navbar>
|
||||||
|
</ion-header>
|
||||||
|
<ion-content>
|
||||||
|
<core-loading [hideUntil]="loaded">
|
||||||
|
<ion-item text-wrap *ngIf="groupInfo && (groupInfo.separateGroups || groupInfo.visibleGroups)">
|
||||||
|
<ion-label id="addon-data-groupslabel" *ngIf="groupInfo.separateGroups">{{ 'core.groupsseparate' | translate }}</ion-label>
|
||||||
|
<ion-label id="addon-data-groupslabel" *ngIf="groupInfo.visibleGroups">{{ 'core.groupsvisible' | translate }}</ion-label>
|
||||||
|
<ion-select [(ngModel)]="selectedGroup" (ionChange)="setGroup(selectedGroup)" aria-labelledby="addon-data-groupslabel">
|
||||||
|
<ion-option *ngFor="let groupOpt of groupInfo.groups" [value]="groupOpt.id">{{groupOpt.name}}</ion-option>
|
||||||
|
</ion-select>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<div class="addon-data-contents {{cssClass}}">
|
||||||
|
<style *ngIf="cssTemplate">
|
||||||
|
{{ cssTemplate }}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<form (ngSubmit)="save()" [formGroup]="editForm">
|
||||||
|
<core-compile-html [text]="editFormRender" [jsData]="jsData" [extraImports]="extraImports"></core-compile-html>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</core-loading>
|
||||||
|
</ion-content>
|
|
@ -0,0 +1,39 @@
|
||||||
|
// (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 { IonicPageModule } from 'ionic-angular';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||||
|
import { CoreComponentsModule } from '@components/components.module';
|
||||||
|
import { CoreCommentsComponentsModule } from '@core/comments/components/components.module';
|
||||||
|
import { CoreCompileHtmlComponentModule } from '@core/compile/components/compile-html/compile-html.module';
|
||||||
|
import { AddonModDataComponentsModule } from '../../components/components.module';
|
||||||
|
import { AddonModDataEditPage } from './edit';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AddonModDataEditPage,
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CoreDirectivesModule,
|
||||||
|
CoreComponentsModule,
|
||||||
|
AddonModDataComponentsModule,
|
||||||
|
CoreCompileHtmlComponentModule,
|
||||||
|
CoreCommentsComponentsModule,
|
||||||
|
IonicPageModule.forChild(AddonModDataEditPage),
|
||||||
|
TranslateModule.forChild()
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class AddonModDataEditPageModule {}
|
|
@ -0,0 +1,373 @@
|
||||||
|
// (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, ViewChild } from '@angular/core';
|
||||||
|
import { Content, IonicPage, NavParams, NavController } from 'ionic-angular';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
|
import { CoreGroupsProvider } from '@providers/groups';
|
||||||
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
|
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
|
||||||
|
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||||
|
import { AddonModDataProvider } from '../../providers/data';
|
||||||
|
import { AddonModDataHelperProvider } from '../../providers/helper';
|
||||||
|
import { AddonModDataOfflineProvider } from '../../providers/offline';
|
||||||
|
import { AddonModDataFieldsDelegate } from '../../providers/fields-delegate';
|
||||||
|
import { AddonModDataComponentsModule } from '../../components/components.module';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page that displays the view edit page.
|
||||||
|
*/
|
||||||
|
@IonicPage({ segment: 'addon-mod-data-edit' })
|
||||||
|
@Component({
|
||||||
|
selector: 'page-addon-mod-data-edit',
|
||||||
|
templateUrl: 'edit.html',
|
||||||
|
})
|
||||||
|
export class AddonModDataEditPage {
|
||||||
|
@ViewChild(Content) content: Content;
|
||||||
|
|
||||||
|
protected module: any;
|
||||||
|
protected courseId: number;
|
||||||
|
protected data: any;
|
||||||
|
protected entryId: number;
|
||||||
|
protected entry: any;
|
||||||
|
protected offlineActions = [];
|
||||||
|
protected fields = {};
|
||||||
|
protected fieldsArray = [];
|
||||||
|
protected siteId: string;
|
||||||
|
protected offline: boolean;
|
||||||
|
protected forceLeave = false; // To allow leaving the page without checking for changes.
|
||||||
|
|
||||||
|
title = '';
|
||||||
|
component = AddonModDataProvider.COMPONENT;
|
||||||
|
loaded = false;
|
||||||
|
selectedGroup = 0;
|
||||||
|
cssClass = '';
|
||||||
|
cssTemplate = '';
|
||||||
|
groupInfo: any;
|
||||||
|
editFormRender = '';
|
||||||
|
editForm: FormGroup;
|
||||||
|
extraImports = [AddonModDataComponentsModule];
|
||||||
|
jsData: any;
|
||||||
|
errors = {};
|
||||||
|
|
||||||
|
constructor(params: NavParams, protected utils: CoreUtilsProvider, protected groupsProvider: CoreGroupsProvider,
|
||||||
|
protected domUtils: CoreDomUtilsProvider, protected fieldsDelegate: AddonModDataFieldsDelegate,
|
||||||
|
protected courseProvider: CoreCourseProvider, protected dataProvider: AddonModDataProvider,
|
||||||
|
protected dataOffline: AddonModDataOfflineProvider, protected dataHelper: AddonModDataHelperProvider,
|
||||||
|
sitesProvider: CoreSitesProvider, protected navCtrl: NavController, protected translate: TranslateService,
|
||||||
|
protected eventsProvider: CoreEventsProvider, protected fileUploaderProvider: CoreFileUploaderProvider) {
|
||||||
|
this.module = params.get('module') || {};
|
||||||
|
this.entryId = params.get('entryId') || null;
|
||||||
|
this.courseId = params.get('courseId');
|
||||||
|
this.selectedGroup = params.get('group') || 0;
|
||||||
|
|
||||||
|
this.siteId = sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
|
this.title = this.module.name;
|
||||||
|
|
||||||
|
this.editForm = new FormGroup({});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View loaded.
|
||||||
|
*/
|
||||||
|
ionViewDidLoad(): void {
|
||||||
|
this.fetchEntryData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if we can leave the page or not and ask to confirm the lost of data.
|
||||||
|
*
|
||||||
|
* @return {boolean | Promise<void>} Resolved if we can leave it, rejected if not.
|
||||||
|
*/
|
||||||
|
ionViewCanLeave(): boolean | Promise<void> {
|
||||||
|
if (this.forceLeave) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputData = this.editForm.value;
|
||||||
|
|
||||||
|
return this.dataHelper.hasEditDataChanged(inputData, this.fieldsArray, this.data.id,
|
||||||
|
this.entry.contents).then((changed) => {
|
||||||
|
if (!changed) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show confirmation if some data has been modified.
|
||||||
|
return this.domUtils.showConfirm(this.translate.instant('core.confirmcanceledit'));
|
||||||
|
}).then(() => {
|
||||||
|
// Delete the local files from the tmp folder.
|
||||||
|
return this.dataHelper.getEditTmpFiles(inputData, this.fieldsArray, this.data.id,
|
||||||
|
this.entry.contents).then((files) => {
|
||||||
|
this.fileUploaderProvider.clearTmpFiles(files);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the entry data.
|
||||||
|
*
|
||||||
|
* @return {Promise<any>} Resolved when done.
|
||||||
|
*/
|
||||||
|
protected fetchEntryData(): Promise<any> {
|
||||||
|
return this.dataProvider.getDatabase(this.courseId, this.module.id).then((data) => {
|
||||||
|
this.title = data.name || this.title;
|
||||||
|
this.data = data;
|
||||||
|
this.cssClass = 'addon-data-entries-' + data.id;
|
||||||
|
|
||||||
|
return this.dataProvider.getDatabaseAccessInformation(data.id);
|
||||||
|
}).then((accessData) => {
|
||||||
|
this.cssTemplate = this.dataHelper.prefixCSS(this.data.csstemplate, '.' + this.cssClass);
|
||||||
|
|
||||||
|
if (this.entryId) {
|
||||||
|
return this.groupsProvider.getActivityGroupInfo(this.data.coursemodule, accessData.canmanageentries)
|
||||||
|
.then((groupInfo) => {
|
||||||
|
this.groupInfo = groupInfo;
|
||||||
|
|
||||||
|
// Check selected group is accessible.
|
||||||
|
if (groupInfo && groupInfo.groups && groupInfo.groups.length > 0) {
|
||||||
|
if (!groupInfo.groups.some((group) => this.selectedGroup == group.id)) {
|
||||||
|
this.selectedGroup = groupInfo.groups[0].id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).then(() => {
|
||||||
|
return this.dataOffline.getEntryActions(this.data.id, this.entryId);
|
||||||
|
}).then((actions) => {
|
||||||
|
this.offlineActions = actions;
|
||||||
|
|
||||||
|
return this.dataProvider.getFields(this.data.id);
|
||||||
|
}).then((fieldsData) => {
|
||||||
|
this.fields = {};
|
||||||
|
fieldsData.forEach((field) => {
|
||||||
|
this.fields[field.id] = field;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.fieldsArray = fieldsData;
|
||||||
|
|
||||||
|
return this.dataHelper.getEntry(this.data, this.entryId, this.offlineActions);
|
||||||
|
}).then((entry) => {
|
||||||
|
if (entry) {
|
||||||
|
entry = entry.entry;
|
||||||
|
|
||||||
|
// Index contents by fieldid.
|
||||||
|
const contents = {};
|
||||||
|
entry.contents.forEach((field) => {
|
||||||
|
contents[field.fieldid] = field;
|
||||||
|
});
|
||||||
|
entry.contents = contents;
|
||||||
|
} else {
|
||||||
|
entry = {
|
||||||
|
contents: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.dataHelper.applyOfflineActions(entry, this.offlineActions, this.fieldsArray);
|
||||||
|
}).then((entryData) => {
|
||||||
|
this.entry = entryData;
|
||||||
|
|
||||||
|
this.editFormRender = this.displayEditFields();
|
||||||
|
}).catch((message) => {
|
||||||
|
this.domUtils.showErrorModalDefault(message, 'core.course.errorgetmodule', true);
|
||||||
|
|
||||||
|
return Promise.reject(null);
|
||||||
|
}).finally(() => {
|
||||||
|
this.loaded = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves data.
|
||||||
|
*
|
||||||
|
* @return {Promise<any>} Resolved when done.
|
||||||
|
*/
|
||||||
|
save(): Promise<any> {
|
||||||
|
const inputData = this.editForm.value;
|
||||||
|
|
||||||
|
return this.dataHelper.hasEditDataChanged(inputData, this.fieldsArray, this.data.id,
|
||||||
|
this.entry.contents).then((changed) => {
|
||||||
|
|
||||||
|
if (!changed) {
|
||||||
|
if (this.entryId) {
|
||||||
|
return this.returnToEntryList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// New entry, no changes means no field filled, warn the user.
|
||||||
|
return Promise.reject('addon.mod_data.emptyaddform');
|
||||||
|
}
|
||||||
|
|
||||||
|
const modal = this.domUtils.showModalLoading('core.sending', true);
|
||||||
|
|
||||||
|
// Create an ID to assign files.
|
||||||
|
const entryTemp = this.entryId ? this.entryId : - (new Date().getTime());
|
||||||
|
|
||||||
|
return this.dataHelper.getEditDataFromForm(inputData, this.fieldsArray, this.data.id, entryTemp, this.entry.contents,
|
||||||
|
this.offline).catch((e) => {
|
||||||
|
if (!this.offline) {
|
||||||
|
// Cannot submit in online, prepare for offline usage.
|
||||||
|
this.offline = true;
|
||||||
|
|
||||||
|
return this.dataHelper.getEditDataFromForm(inputData, this.fieldsArray, this.data.id, entryTemp,
|
||||||
|
this.entry.contents, this.offline);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(e);
|
||||||
|
}).then((editData) => {
|
||||||
|
if (editData.length > 0) {
|
||||||
|
if (this.entryId) {
|
||||||
|
return this.dataProvider.editEntry(this.data.id, this.entryId, this.courseId, editData, this.fields,
|
||||||
|
undefined, this.offline);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.dataProvider.addEntry(this.data.id, entryTemp, this.courseId, editData, this.selectedGroup,
|
||||||
|
this.fields, undefined, this.offline);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}).then((result: any) => {
|
||||||
|
if (!result) {
|
||||||
|
// No field filled, warn the user.
|
||||||
|
return Promise.reject('addon.mod_data.emptyaddform');
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is done if entry is updated when editing or creating if not.
|
||||||
|
if ((this.entryId && result.updated) || (!this.entryId && result.newentryid)) {
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
|
this.entryId = this.entryId || result.newentryid;
|
||||||
|
|
||||||
|
promises.push(this.dataProvider.invalidateEntryData(this.data.id, this.entryId, this.siteId));
|
||||||
|
promises.push(this.dataProvider.invalidateEntriesData(this.data.id, this.siteId));
|
||||||
|
|
||||||
|
return Promise.all(promises).then(() => {
|
||||||
|
this.eventsProvider.trigger(AddonModDataProvider.ENTRY_CHANGED,
|
||||||
|
{ dataId: this.data.id, entryId: this.entryId } , this.siteId);
|
||||||
|
}).finally(() => {
|
||||||
|
return this.returnToEntryList();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.errors = {};
|
||||||
|
result.fieldnotifications.forEach((fieldNotif) => {
|
||||||
|
const field = this.fieldsArray.find((field) => field.name == fieldNotif.fieldname);
|
||||||
|
if (field) {
|
||||||
|
this.errors[field.id] = fieldNotif.notification;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.jsData['errors'] = this.errors;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.scrollToFirstError();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
modal.dismiss();
|
||||||
|
});
|
||||||
|
}).catch((error) => {
|
||||||
|
this.domUtils.showErrorModalDefault(error, 'Cannot edit entry', true);
|
||||||
|
|
||||||
|
return Promise.reject(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set group to see the database.
|
||||||
|
*
|
||||||
|
* @param {number} groupId Group identifier to set.
|
||||||
|
* @return {Promise<any>} Resolved when done.
|
||||||
|
*/
|
||||||
|
setGroup(groupId: number): Promise<any> {
|
||||||
|
this.selectedGroup = groupId;
|
||||||
|
this.loaded = false;
|
||||||
|
|
||||||
|
return this.fetchEntryData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays Edit Search Fields.
|
||||||
|
*
|
||||||
|
* @return {string} Generated HTML.
|
||||||
|
*/
|
||||||
|
protected displayEditFields(): string {
|
||||||
|
if (!this.data.addtemplate) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.jsData = {
|
||||||
|
fields: this.fields,
|
||||||
|
contents: this.entry.contents,
|
||||||
|
form: this.editForm,
|
||||||
|
data: this.data,
|
||||||
|
errors: this.errors
|
||||||
|
};
|
||||||
|
|
||||||
|
let replace,
|
||||||
|
render,
|
||||||
|
template = this.data.addtemplate;
|
||||||
|
|
||||||
|
// Replace the fields found on template.
|
||||||
|
this.fieldsArray.forEach((field) => {
|
||||||
|
replace = '[[' + field.name + ']]';
|
||||||
|
replace = replace.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
||||||
|
replace = new RegExp(replace, 'gi');
|
||||||
|
|
||||||
|
// Replace field by a generic directive.
|
||||||
|
render = '<addon-mod-data-field-plugin mode="edit" [field]="fields[' + field.id + ']"\
|
||||||
|
[value]="contents[' + field.id + ']" [form]="form" [database]="data" [error]="errors[' + field.id + ']">\
|
||||||
|
</addon-mod-data-field-plugin>';
|
||||||
|
template = template.replace(replace, render);
|
||||||
|
|
||||||
|
// Replace the field id tag.
|
||||||
|
replace = '[[' + field.name + '#id]]';
|
||||||
|
replace = replace.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
||||||
|
replace = new RegExp(replace, 'gi');
|
||||||
|
|
||||||
|
template = template.replace(replace, 'field_' + field.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return to the entry list (previous page) discarding temp data.
|
||||||
|
*
|
||||||
|
* @return {Promise<any>} Resolved when done.
|
||||||
|
*/
|
||||||
|
protected returnToEntryList(): Promise<any> {
|
||||||
|
const inputData = this.editForm.value;
|
||||||
|
|
||||||
|
return this.dataHelper.getEditTmpFiles(inputData, this.fieldsArray, this.data.id,
|
||||||
|
this.entry.contents).then((files) => {
|
||||||
|
this.fileUploaderProvider.clearTmpFiles(files);
|
||||||
|
}).finally(() => {
|
||||||
|
// Go back to entry list.
|
||||||
|
this.forceLeave = true;
|
||||||
|
this.navCtrl.pop();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll to first error or to the top if not found.
|
||||||
|
*/
|
||||||
|
protected scrollToFirstError(): void {
|
||||||
|
if (!this.domUtils.scrollToElementBySelector(this.content, '.addon-data-error')) {
|
||||||
|
this.content.scrollToTop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Component, ViewChild } from '@angular/core';
|
import { Component, ViewChild, OnDestroy } from '@angular/core';
|
||||||
import { Content, IonicPage, NavParams, NavController } from 'ionic-angular';
|
import { Content, IonicPage, NavParams, NavController } from 'ionic-angular';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
|
@ -35,7 +35,7 @@ import { AddonModDataComponentsModule } from '../../components/components.module
|
||||||
selector: 'page-addon-mod-data-entry',
|
selector: 'page-addon-mod-data-entry',
|
||||||
templateUrl: 'entry.html',
|
templateUrl: 'entry.html',
|
||||||
})
|
})
|
||||||
export class AddonModDataEntryPage {
|
export class AddonModDataEntryPage implements OnDestroy {
|
||||||
@ViewChild(Content) content: Content;
|
@ViewChild(Content) content: Content;
|
||||||
|
|
||||||
protected module: any;
|
protected module: any;
|
||||||
|
@ -107,7 +107,7 @@ export class AddonModDataEntryPage {
|
||||||
|
|
||||||
// Refresh entry on change.
|
// Refresh entry on change.
|
||||||
this.entryChangedObserver = this.eventsProvider.on(AddonModDataProvider.ENTRY_CHANGED, (data) => {
|
this.entryChangedObserver = this.eventsProvider.on(AddonModDataProvider.ENTRY_CHANGED, (data) => {
|
||||||
if (data.entryId == this.entryId && data.id == data.dataId) {
|
if (data.entryId == this.entryId && this.data.id == data.dataId) {
|
||||||
if (data.deleted) {
|
if (data.deleted) {
|
||||||
// If deleted, go back.
|
// If deleted, go back.
|
||||||
this.navCtrl.pop();
|
this.navCtrl.pop();
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<ion-input type="text" placeholder="{{ 'addon.mod_data.search' | translate}}" [(ngModel)]="search.text" name="text" formControlName="text"></ion-input>
|
<ion-input type="text" placeholder="{{ 'addon.mod_data.search' | translate}}" [(ngModel)]="search.text" name="text" formControlName="text"></ion-input>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item text-wrap>
|
<ion-item text-wrap>
|
||||||
<ion-label>{{ 'core.sortby' | translate }}</ion-label>
|
<ion-label stacked>{{ 'core.sortby' | translate }}</ion-label>
|
||||||
<ion-select interface="popover" name="sortBy" formControlName="sortBy">
|
<ion-select interface="popover" name="sortBy" formControlName="sortBy">
|
||||||
<optgroup *ngIf="fieldsArray.length" label="{{ 'addon.mod_data.fields' | translate }}">
|
<optgroup *ngIf="fieldsArray.length" label="{{ 'addon.mod_data.fields' | translate }}">
|
||||||
<ion-option *ngFor="let field of fieldsArray" [value]="field.id">{{field.name}}</ion-option>
|
<ion-option *ngFor="let field of fieldsArray" [value]="field.id">{{field.name}}</ion-option>
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
page-addon-mod-data-search {
|
|
||||||
form {
|
|
||||||
background-color: $list-background-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
td {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.addon-data-advanced-search {
|
|
||||||
background-color: $list-background-color;
|
|
||||||
|
|
||||||
@if ($text-input-md-show-focus-highlight) {
|
|
||||||
.input-md input:focus {
|
|
||||||
@include md-input-highlight($text-input-md-highlight-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-md input {
|
|
||||||
@include padding-horizontal(null, ($item-md-padding-end / 2));
|
|
||||||
border-bottom: 1px solid $list-md-border-color;
|
|
||||||
&:focus {
|
|
||||||
@include md-input-highlight($text-input-md-highlight-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-ios input {
|
|
||||||
@include padding-horizontal(null, $item-ios-padding-end / 2);
|
|
||||||
@include safe-area-padding-horizontal(null, $item-ios-padding-end / 2);
|
|
||||||
border-bottom: $hairlines-width solid $list-ios-border-color;
|
|
||||||
&:focus {
|
|
||||||
@include ios-input-highlight($text-input-ios-highlight-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-wp input {
|
|
||||||
@include padding-horizontal(null, ($item-wp-padding-end / 2));
|
|
||||||
border-bottom: 1px solid $list-wp-border-color;
|
|
||||||
&:focus {
|
|
||||||
border-color: $text-input-wp-highlight-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ion-select {
|
|
||||||
width: 100%;
|
|
||||||
left: 0;
|
|
||||||
max-width: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.core-item-has-rich-text-editor {
|
|
||||||
margin-right: 1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -52,8 +52,8 @@ export class AddonModDataSearchPage {
|
||||||
|
|
||||||
this.searchForm = fb.group({
|
this.searchForm = fb.group({
|
||||||
text: [this.search.text],
|
text: [this.search.text],
|
||||||
sortBy: [this.search.sortBy],
|
sortBy: [this.search.sortBy || 0],
|
||||||
sortDirection: [this.search.sortDirection],
|
sortDirection: [this.search.sortDirection || 'DESC'],
|
||||||
firstname: [this.search.advanced['firstname'] || ''],
|
firstname: [this.search.advanced['firstname'] || ''],
|
||||||
lastname: [this.search.advanced['lastname'] || '']
|
lastname: [this.search.advanced['lastname'] || '']
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,12 +13,13 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
import { CoreAppProvider } from '@providers/app';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||||
import { AddonModDataOfflineProvider } from './offline';
|
import { AddonModDataOfflineProvider } from './offline';
|
||||||
import { CoreAppProvider } from '@providers/app';
|
import { AddonModDataFieldsDelegate } from './fields-delegate';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service that provides some features for databases.
|
* Service that provides some features for databases.
|
||||||
|
@ -34,10 +35,58 @@ export class AddonModDataProvider {
|
||||||
|
|
||||||
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider,
|
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider,
|
||||||
private filepoolProvider: CoreFilepoolProvider, private dataOffline: AddonModDataOfflineProvider,
|
private filepoolProvider: CoreFilepoolProvider, private dataOffline: AddonModDataOfflineProvider,
|
||||||
private appProvider: CoreAppProvider) {
|
private appProvider: CoreAppProvider, private fieldsDelegate: AddonModDataFieldsDelegate) {
|
||||||
this.logger = logger.getInstance('AddonModDataProvider');
|
this.logger = logger.getInstance('AddonModDataProvider');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new entry to a database.
|
||||||
|
*
|
||||||
|
* @param {number} dataId Data instance ID.
|
||||||
|
* @param {number} entryId EntryId or provisional entry ID when offline.
|
||||||
|
* @param {number} courseId Course ID.
|
||||||
|
* @param {any} contents The fields data to be created.
|
||||||
|
* @param {number} [groupId] Group id, 0 means that the function will determine the user group.
|
||||||
|
* @param {any} fields The fields that define the contents.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @param {boolean} [forceOffline] Force editing entry in offline.
|
||||||
|
* @return {Promise<any>} Promise resolved when the action is done.
|
||||||
|
*/
|
||||||
|
addEntry(dataId: number, entryId: number, courseId: number, contents: any, groupId: number = 0, fields: any, siteId?: string,
|
||||||
|
forceOffline: boolean = false): Promise<any> {
|
||||||
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
|
// Convenience function to store a data to be synchronized later.
|
||||||
|
const storeOffline = (): Promise<any> => {
|
||||||
|
return this.dataOffline.saveEntry(dataId, entryId, 'add', courseId, groupId, contents, undefined, siteId)
|
||||||
|
.then((entry) => {
|
||||||
|
return {
|
||||||
|
// Return provissional entry Id.
|
||||||
|
newentryid: entry[1]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!this.appProvider.isOnline() || forceOffline) {
|
||||||
|
const notifications = this.checkFields(fields, contents);
|
||||||
|
if (notifications) {
|
||||||
|
return Promise.resolve({
|
||||||
|
fieldnotifications: notifications
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.addEntryOnline(dataId, contents, groupId, siteId).catch((error) => {
|
||||||
|
if (this.utils.isWebServiceError(error)) {
|
||||||
|
// The WebService has thrown an error, this means that responses cannot be submitted.
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Couldn't connect to server, store in offline.
|
||||||
|
return storeOffline();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new entry to a database. It does not cache calls. It will fail if offline or cannot connect.
|
* Adds a new entry to a database. It does not cache calls. It will fail if offline or cannot connect.
|
||||||
*
|
*
|
||||||
|
@ -79,7 +128,7 @@ export class AddonModDataProvider {
|
||||||
const storeOffline = (): Promise<any> => {
|
const storeOffline = (): Promise<any> => {
|
||||||
const action = approve ? 'approve' : 'disapprove';
|
const action = approve ? 'approve' : 'disapprove';
|
||||||
|
|
||||||
return this.dataOffline.saveEntry(dataId, entryId, action, courseId, null, null, null, siteId);
|
return this.dataOffline.saveEntry(dataId, entryId, action, courseId, undefined, undefined, undefined, siteId);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get if the opposite action is not synced.
|
// Get if the opposite action is not synced.
|
||||||
|
@ -126,6 +175,38 @@ export class AddonModDataProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function to check fields requeriments here named "notifications".
|
||||||
|
*
|
||||||
|
* @param {any} fields The fields that define the contents.
|
||||||
|
* @param {any} contents The contents data of the fields.
|
||||||
|
* @return {any} Array of notifications if any or false.
|
||||||
|
*/
|
||||||
|
protected checkFields(fields: any, contents: any): any {
|
||||||
|
const notifications = [],
|
||||||
|
contentsIndexed = {};
|
||||||
|
|
||||||
|
contents.forEach((content) => {
|
||||||
|
if (typeof contentsIndexed[content.fieldid] == 'undefined') {
|
||||||
|
contentsIndexed[content.fieldid] = [];
|
||||||
|
}
|
||||||
|
contentsIndexed[content.fieldid].push(content);
|
||||||
|
});
|
||||||
|
|
||||||
|
// App is offline, check required fields.
|
||||||
|
fields.forEach((field) => {
|
||||||
|
const notification = this.fieldsDelegate.getFieldsNotifications(field, contentsIndexed[field.id]);
|
||||||
|
if (notification) {
|
||||||
|
notifications.push({
|
||||||
|
fieldname: field.name,
|
||||||
|
notification: notification
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return notifications.length ? notifications : false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes an entry.
|
* Deletes an entry.
|
||||||
*
|
*
|
||||||
|
@ -140,7 +221,7 @@ export class AddonModDataProvider {
|
||||||
|
|
||||||
// Convenience function to store a data to be synchronized later.
|
// Convenience function to store a data to be synchronized later.
|
||||||
const storeOffline = (): Promise<any> => {
|
const storeOffline = (): Promise<any> => {
|
||||||
return this.dataOffline.saveEntry(dataId, entryId, 'delete', courseId, null, null, null, siteId);
|
return this.dataOffline.saveEntry(dataId, entryId, 'delete', courseId, undefined, undefined, undefined, siteId);
|
||||||
};
|
};
|
||||||
|
|
||||||
let justAdded = false;
|
let justAdded = false;
|
||||||
|
@ -199,6 +280,89 @@ export class AddonModDataProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates an existing entry.
|
||||||
|
*
|
||||||
|
* @param {number} dataId Database ID.
|
||||||
|
* @param {number} entryId Entry ID.
|
||||||
|
* @param {number} courseId Course ID.
|
||||||
|
* @param {any} contents The contents data to be updated.
|
||||||
|
* @param {any} fields The fields that define the contents.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @param {boolean} forceOffline Force editing entry in offline.
|
||||||
|
* @return {Promise<any>} Promise resolved when the action is done.
|
||||||
|
*/
|
||||||
|
editEntry(dataId: number, entryId: number, courseId: number, contents: any, fields: any, siteId?: string,
|
||||||
|
forceOffline: boolean = false): Promise<any> {
|
||||||
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
|
// Convenience function to store a data to be synchronized later.
|
||||||
|
const storeOffline = (): Promise<any> => {
|
||||||
|
return this.dataOffline.saveEntry(dataId, entryId, 'edit', courseId, undefined, contents, undefined, siteId)
|
||||||
|
.then(() => {
|
||||||
|
return {
|
||||||
|
updated: true
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let justAdded = false,
|
||||||
|
groupId;
|
||||||
|
|
||||||
|
if (!this.appProvider.isOnline() || forceOffline) {
|
||||||
|
const notifications = this.checkFields(fields, contents);
|
||||||
|
if (notifications) {
|
||||||
|
return Promise.resolve({
|
||||||
|
fieldnotifications: notifications
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get other not not synced actions.
|
||||||
|
return this.dataOffline.getEntryActions(dataId, entryId, siteId).then((entries) => {
|
||||||
|
if (entries && entries.length) {
|
||||||
|
// Found. Delete add and edit actions first.
|
||||||
|
const proms = [];
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
if (entry.action == 'add') {
|
||||||
|
justAdded = true;
|
||||||
|
groupId = entry.groupid;
|
||||||
|
proms.push(this.dataOffline.deleteEntry(dataId, entryId, entry.action, siteId));
|
||||||
|
} else if (entry.action == 'edit') {
|
||||||
|
proms.push(this.dataOffline.deleteEntry(dataId, entryId, entry.action, siteId));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(proms);
|
||||||
|
}
|
||||||
|
}).then(() => {
|
||||||
|
if (justAdded) {
|
||||||
|
// The field was added offline, add again and stop.
|
||||||
|
return this.addEntry(dataId, entryId, courseId, contents, groupId, fields, siteId, forceOffline)
|
||||||
|
.then((result) => {
|
||||||
|
result.updated = true;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.appProvider.isOnline() || forceOffline) {
|
||||||
|
// App is offline, store the action.
|
||||||
|
return storeOffline();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.editEntryOnline(entryId, contents, siteId).catch((error) => {
|
||||||
|
if (this.utils.isWebServiceError(error)) {
|
||||||
|
// The WebService has thrown an error, this means that responses cannot be submitted.
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Couldn't connect to server, store in offline.
|
||||||
|
return storeOffline();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates an existing entry. It does not cache calls. It will fail if offline or cannot connect.
|
* Updates an existing entry. It does not cache calls. It will fail if offline or cannot connect.
|
||||||
*
|
*
|
||||||
|
|
|
@ -188,9 +188,98 @@ export class AddonModDataHelperProvider {
|
||||||
Promise<any> {
|
Promise<any> {
|
||||||
return this.dataProvider.fetchAllEntries(dataId, groupId, undefined, undefined, undefined, forceCache, ignoreCache, siteId)
|
return this.dataProvider.fetchAllEntries(dataId, groupId, undefined, undefined, undefined, forceCache, ignoreCache, siteId)
|
||||||
.then((entries) => {
|
.then((entries) => {
|
||||||
return entries.map((entry) => {
|
return entries.map((entry) => entry.id);
|
||||||
return entry.id;
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the entered data in the edit form.
|
||||||
|
* We don't use ng-model because it doesn't detect changes done by JavaScript.
|
||||||
|
*
|
||||||
|
* @param {any} inputData Array with the entered form values.
|
||||||
|
* @param {Array} fields Fields that defines every content in the entry.
|
||||||
|
* @param {number} [dataId] Database Id. If set, files will be uploaded and itemId set.
|
||||||
|
* @param {number} entryId Entry Id.
|
||||||
|
* @param {any} entryContents Original entry contents indexed by field id.
|
||||||
|
* @param {boolean} offline True to prepare the data for an offline uploading, false otherwise.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<any>} That contains object with the answers.
|
||||||
|
*/
|
||||||
|
getEditDataFromForm(inputData: any, fields: any, dataId: number, entryId: number, entryContents: any, offline: boolean = false,
|
||||||
|
siteId?: string): Promise<any> {
|
||||||
|
if (!inputData) {
|
||||||
|
return Promise.resolve({});
|
||||||
|
}
|
||||||
|
|
||||||
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
|
// Filter and translate fields to each field plugin.
|
||||||
|
const edit = [],
|
||||||
|
promises = [];
|
||||||
|
fields.forEach((field) => {
|
||||||
|
promises.push(Promise.resolve(this.fieldsDelegate.getFieldEditData(field, inputData, entryContents[field.id]))
|
||||||
|
.then((fieldData) => {
|
||||||
|
if (fieldData) {
|
||||||
|
const proms = [];
|
||||||
|
|
||||||
|
fieldData.forEach((data) => {
|
||||||
|
let dataProm;
|
||||||
|
|
||||||
|
// Upload Files if asked.
|
||||||
|
if (dataId && data.files) {
|
||||||
|
dataProm = this.uploadOrStoreFiles(dataId, 0, entryId, data.fieldid, data.files, offline, siteId)
|
||||||
|
.then((filesResult) => {
|
||||||
|
delete data.files;
|
||||||
|
data.value = filesResult;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
dataProm = Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
proms.push(dataProm.then(() => {
|
||||||
|
if (data.value) {
|
||||||
|
data.value = JSON.stringify(data.value);
|
||||||
|
}
|
||||||
|
if (typeof data.subfield == 'undefined') {
|
||||||
|
data.subfield = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// WS wants values in Json format.
|
||||||
|
edit.push(data);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(proms);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises).then(() => {
|
||||||
|
return edit;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the temp files to be updated.
|
||||||
|
*
|
||||||
|
* @param {any} inputData Array with the entered form values.
|
||||||
|
* @param {Array} fields Fields that defines every content in the entry.
|
||||||
|
* @param {number} [dataId] Database Id. If set, fils will be uploaded and itemId set.
|
||||||
|
* @param {any} entryContents Original entry contents indexed by field id.
|
||||||
|
* @return {Promise<any>} That contains object with the files.
|
||||||
|
*/
|
||||||
|
getEditTmpFiles(inputData: any, fields: any, dataId: number, entryContents: any): Promise<any> {
|
||||||
|
if (!inputData) {
|
||||||
|
return Promise.resolve([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter and translate fields to each field plugin.
|
||||||
|
const promises = fields.map((field) => {
|
||||||
|
return Promise.resolve(this.fieldsDelegate.getFieldEditFiles(field, inputData, entryContents[field.id]));
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises).then((fieldsFiles) => {
|
||||||
|
return fieldsFiles.reduce((files: any[], fieldFiles: any) => files.concat(fieldFiles), []);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,9 +300,7 @@ export class AddonModDataHelperProvider {
|
||||||
|
|
||||||
// It's an offline entry, search it in the offline actions.
|
// It's an offline entry, search it in the offline actions.
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const offlineEntry = offlineActions.find((offlineAction) => {
|
const offlineEntry = offlineActions.find((offlineAction) => offlineAction.action == 'add');
|
||||||
return offlineAction.action == 'add';
|
|
||||||
});
|
|
||||||
|
|
||||||
if (offlineEntry) {
|
if (offlineEntry) {
|
||||||
const siteInfo = site.getInfo();
|
const siteInfo = site.getInfo();
|
||||||
|
@ -249,9 +336,7 @@ export class AddonModDataHelperProvider {
|
||||||
getPageInfoByEntry(dataId: number, entryId: number, groupId: number, forceCache: boolean = false,
|
getPageInfoByEntry(dataId: number, entryId: number, groupId: number, forceCache: boolean = false,
|
||||||
ignoreCache: boolean = false, siteId?: string): Promise<any> {
|
ignoreCache: boolean = false, siteId?: string): Promise<any> {
|
||||||
return this.getAllEntriesIds(dataId, groupId, forceCache, ignoreCache, siteId).then((entries) => {
|
return this.getAllEntriesIds(dataId, groupId, forceCache, ignoreCache, siteId).then((entries) => {
|
||||||
const index = entries.findIndex((entry) => {
|
const index = entries.findIndex((entry) => entry == entryId);
|
||||||
return entry == entryId;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
return {
|
return {
|
||||||
|
@ -316,6 +401,30 @@ export class AddonModDataHelperProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if data has been changed by the user.
|
||||||
|
*
|
||||||
|
* @param {any} inputData Array with the entered form values.
|
||||||
|
* @param {any} fields Fields that defines every content in the entry.
|
||||||
|
* @param {number} [dataId] Database Id. If set, fils will be uploaded and itemId set.
|
||||||
|
* @param {any} entryContents Original entry contents indexed by field id.
|
||||||
|
* @return {Promise<boolean>} True if changed, false if not.
|
||||||
|
*/
|
||||||
|
hasEditDataChanged(inputData: any, fields: any, dataId: number, entryContents: any): Promise<boolean> {
|
||||||
|
const promises = fields.map((field) => {
|
||||||
|
return this.fieldsDelegate.hasFieldDataChanged(field, inputData, entryContents[field.id]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Will reject on first change detected.
|
||||||
|
return Promise.all(promises).then(() => {
|
||||||
|
// No changes.
|
||||||
|
return false;
|
||||||
|
}).catch(() => {
|
||||||
|
// Has changes.
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a prefix to all rules in a CSS string.
|
* Add a prefix to all rules in a CSS string.
|
||||||
*
|
*
|
||||||
|
|
|
@ -24,6 +24,6 @@ export class AddonModDataLinkHandler extends CoreContentLinksModuleIndexHandler
|
||||||
name = 'AddonModDataLinkHandler';
|
name = 'AddonModDataLinkHandler';
|
||||||
|
|
||||||
constructor(courseHelper: CoreCourseHelperProvider) {
|
constructor(courseHelper: CoreCourseHelperProvider) {
|
||||||
super(courseHelper, AddonModDataLinkHandler.name, 'data');
|
super(courseHelper, 'AddonModData', 'data');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,22 +13,29 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Injectable, Injector } from '@angular/core';
|
import { Injectable, Injector } from '@angular/core';
|
||||||
|
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||||
|
import { CoreGroupsProvider } from '@providers/groups';
|
||||||
|
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||||
|
import { CoreCommentsProvider } from '@core/comments/providers/comments';
|
||||||
|
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||||
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
|
import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler';
|
||||||
import { AddonModDataProvider } from './data';
|
import { AddonModDataProvider } from './data';
|
||||||
import { AddonModDataHelperProvider } from './helper';
|
import { AddonModDataHelperProvider } from './helper';
|
||||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler to prefetch databases.
|
* Handler to prefetch databases.
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AddonModDataPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
|
export class AddonModDataPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
|
||||||
name = 'data';
|
name = 'AddonModData';
|
||||||
|
modName = 'data';
|
||||||
component = AddonModDataProvider.COMPONENT;
|
component = AddonModDataProvider.COMPONENT;
|
||||||
updatesNames = /^configuration$|^.*files$|^entries$|^gradeitems$|^outcomes$|^comments$|^ratings/;
|
updatesNames = /^configuration$|^.*files$|^entries$|^gradeitems$|^outcomes$|^comments$|^ratings/;
|
||||||
|
|
||||||
constructor(injector: Injector, protected dataProvider: AddonModDataProvider,
|
constructor(injector: Injector, protected dataProvider: AddonModDataProvider, protected timeUtils: CoreTimeUtilsProvider,
|
||||||
protected filepoolProvider: CoreFilepoolProvider, protected dataHelper: AddonModDataHelperProvider) {
|
protected filepoolProvider: CoreFilepoolProvider, protected dataHelper: AddonModDataHelperProvider,
|
||||||
|
protected groupsProvider: CoreGroupsProvider, protected commentsProvider: CoreCommentsProvider,
|
||||||
|
protected courseProvider: CoreCourseProvider) {
|
||||||
super(injector);
|
super(injector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,16 +51,159 @@ export class AddonModDataPrefetchHandler extends CoreCourseModulePrefetchHandler
|
||||||
* @return {Promise<any>} Promise resolved when all content is downloaded. Data returned is not reliable.
|
* @return {Promise<any>} Promise resolved when all content is downloaded. Data returned is not reliable.
|
||||||
*/
|
*/
|
||||||
downloadOrPrefetch(module: any, courseId: number, prefetch?: boolean, dirPath?: string): Promise<any> {
|
downloadOrPrefetch(module: any, courseId: number, prefetch?: boolean, dirPath?: string): Promise<any> {
|
||||||
const promises = [];
|
const promises = [],
|
||||||
|
siteId = this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
promises.push(super.downloadOrPrefetch(module, courseId, prefetch));
|
promises.push(super.downloadOrPrefetch(module, courseId, prefetch));
|
||||||
promises.push(this.dataProvider.getDatabase(courseId, module.id).then((data) => {
|
promises.push(this.getDatabaseInfoHelper(module, courseId, false, false, true, siteId).then((info) => {
|
||||||
// @TODO
|
// Prefetch the database data.
|
||||||
|
const database = info.database,
|
||||||
|
promises = [];
|
||||||
|
|
||||||
|
promises.push(this.dataProvider.getFields(database.id, false, true, siteId));
|
||||||
|
|
||||||
|
promises.push(this.filepoolProvider.addFilesToQueue(siteId, info.files, this.component, module.id));
|
||||||
|
|
||||||
|
info.groups.forEach((group) => {
|
||||||
|
promises.push(this.dataProvider.getDatabaseAccessInformation(database.id, group.id, false, true, siteId));
|
||||||
|
});
|
||||||
|
|
||||||
|
info.entries.forEach((entry) => {
|
||||||
|
promises.push(this.dataProvider.getEntry(database.id, entry.id, siteId));
|
||||||
|
if (database.comments) {
|
||||||
|
promises.push(this.commentsProvider.getComments('module', database.coursemodule, 'mod_data', entry.id,
|
||||||
|
'database_entry', 0, siteId));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add Basic Info to manage links.
|
||||||
|
promises.push(this.courseProvider.getModuleBasicInfoByInstance(database.id, 'data', siteId));
|
||||||
|
|
||||||
|
return Promise.all(promises);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all the entries for all the groups and then returns only unique entries.
|
||||||
|
*
|
||||||
|
* @param {number} dataId Database Id.
|
||||||
|
* @param {any[]} groups Array of groups in the activity.
|
||||||
|
* @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
|
* @param {string} [siteId] Site ID.
|
||||||
|
* @return {Promise<any>} All unique entries.
|
||||||
|
*/
|
||||||
|
protected getAllUniqueEntries(dataId: number, groups: any[], forceCache: boolean = false, ignoreCache: boolean = false,
|
||||||
|
siteId?: string): Promise<any> {
|
||||||
|
const promises = groups.map((group) => {
|
||||||
|
return this.dataProvider.fetchAllEntries(dataId, group.id, undefined, undefined, undefined, forceCache, ignoreCache,
|
||||||
|
siteId);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises).then((responses) => {
|
||||||
|
const uniqueEntries = {};
|
||||||
|
|
||||||
|
responses.forEach((groupEntries) => {
|
||||||
|
groupEntries.forEach((entry) => {
|
||||||
|
uniqueEntries[entry.id] = entry;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.utils.objectToArray(uniqueEntries);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to get all database info just once.
|
||||||
|
*
|
||||||
|
* @param {any} module Module to get the files.
|
||||||
|
* @param {number} courseId Course ID the module belongs to.
|
||||||
|
* @param {boolean} [omitFail] True to always return even if fails. Default false.
|
||||||
|
* @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
|
* @param {string} siteId Site ID.
|
||||||
|
* @return {Promise<any>} Promise resolved with the info fetched.
|
||||||
|
*/
|
||||||
|
protected getDatabaseInfoHelper(module: any, courseId: number, omitFail: boolean = false, forceCache: boolean = false,
|
||||||
|
ignoreCache: boolean = false, siteId?: string): Promise<any> {
|
||||||
|
let database,
|
||||||
|
groups = [],
|
||||||
|
entries = [],
|
||||||
|
files = [];
|
||||||
|
|
||||||
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
|
return this.dataProvider.getDatabase(courseId, module.id, siteId, forceCache).then((data) => {
|
||||||
|
files = this.getIntroFilesFromInstance(module, data);
|
||||||
|
database = data;
|
||||||
|
|
||||||
|
return this.groupsProvider.getActivityGroupInfo(module.id, false, undefined, siteId).then((groupInfo) => {
|
||||||
|
if (!groupInfo.groups || groupInfo.groups.length == 0) {
|
||||||
|
groupInfo.groups = [{id: 0}];
|
||||||
|
}
|
||||||
|
groups = groupInfo.groups;
|
||||||
|
|
||||||
|
return this.getAllUniqueEntries(database.id, groups, forceCache, ignoreCache, siteId);
|
||||||
|
});
|
||||||
|
}).then((uniqueEntries) => {
|
||||||
|
entries = uniqueEntries;
|
||||||
|
files = files.concat(this.getEntriesFiles(entries));
|
||||||
|
|
||||||
|
return {
|
||||||
|
database: database,
|
||||||
|
groups: groups,
|
||||||
|
entries: entries,
|
||||||
|
files: files
|
||||||
|
};
|
||||||
|
}).catch((message): any => {
|
||||||
|
if (omitFail) {
|
||||||
|
// Any error, return the info we have.
|
||||||
|
return {
|
||||||
|
database: database,
|
||||||
|
groups: groups,
|
||||||
|
entries: entries,
|
||||||
|
files: files
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the file contained in the entries.
|
||||||
|
*
|
||||||
|
* @param {any[]} entries List of entries to get files from.
|
||||||
|
* @return {any[]} List of files.
|
||||||
|
*/
|
||||||
|
protected getEntriesFiles(entries: any[]): any[] {
|
||||||
|
let files = [];
|
||||||
|
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
entry.contents.forEach((content) => {
|
||||||
|
files = files.concat(content.files);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of downloadable files.
|
||||||
|
*
|
||||||
|
* @param {any} module Module to get the files.
|
||||||
|
* @param {number} courseId Course ID the module belongs to.
|
||||||
|
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
|
||||||
|
* @return {Promise<any>} Promise resolved with the list of files.
|
||||||
|
*/
|
||||||
|
getFiles(module: any, courseId: number, single?: boolean): Promise<any[]> {
|
||||||
|
return this.getDatabaseInfoHelper(module, courseId, true).then((info) => {
|
||||||
|
return info.files;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns data intro files.
|
* Returns data intro files.
|
||||||
*
|
*
|
||||||
|
@ -91,6 +241,35 @@ export class AddonModDataPrefetchHandler extends CoreCourseModulePrefetchHandler
|
||||||
return this.dataProvider.invalidateDatabaseData(courseId);
|
return this.dataProvider.invalidateDatabaseData(courseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a database is downloadable.
|
||||||
|
* A database isn't downloadable if it's not open yet.
|
||||||
|
*
|
||||||
|
* @param {any} module Module to check.
|
||||||
|
* @param {number} courseId Course ID the module belongs to.
|
||||||
|
* @return {Promise<any>} Promise resolved with true if downloadable, resolved with false otherwise.
|
||||||
|
*/
|
||||||
|
isDownloadable(module: any, courseId: number): boolean | Promise<boolean> {
|
||||||
|
return this.dataProvider.getDatabase(courseId, module.id, undefined, true).then((database) => {
|
||||||
|
return this.dataProvider.getDatabaseAccessInformation(database.id).then((accessData) => {
|
||||||
|
// Check if database is restricted by time.
|
||||||
|
if (!accessData.timeavailable) {
|
||||||
|
const time = this.timeUtils.timestamp();
|
||||||
|
|
||||||
|
// It is restricted, checking times.
|
||||||
|
if (database.timeavailablefrom && time < database.timeavailablefrom) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (database.timeavailableto && time > database.timeavailableto) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not the handler is enabled on a site level.
|
* Whether or not the handler is enabled on a site level.
|
||||||
*
|
*
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { CoreContentLinksModuleIndexHandler } from '@core/contentlinks/classes/module-index-handler';
|
import { CoreContentLinksModuleIndexHandler } from '@core/contentlinks/classes/module-index-handler';
|
||||||
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
|
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
|
||||||
import { AddonModFeedbackProvider } from './feedback';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler to treat links to feedback.
|
* Handler to treat links to feedback.
|
||||||
|
@ -25,6 +24,6 @@ export class AddonModFeedbackLinkHandler extends CoreContentLinksModuleIndexHand
|
||||||
name = 'AddonModFeedbackLinkHandler';
|
name = 'AddonModFeedbackLinkHandler';
|
||||||
|
|
||||||
constructor(courseHelper: CoreCourseHelperProvider) {
|
constructor(courseHelper: CoreCourseHelperProvider) {
|
||||||
super(courseHelper, AddonModFeedbackProvider.COMPONENT, 'feedback');
|
super(courseHelper, 'AddonModFeedback', 'feedback');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,9 +124,9 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseModulePrefetchHan
|
||||||
/**
|
/**
|
||||||
* Get the list of downloadable files.
|
* Get the list of downloadable files.
|
||||||
*
|
*
|
||||||
* @param {any} module Module to get the files.
|
* @param {any} module Module to get the files.
|
||||||
* @param {number} courseId Course ID the module belongs to.
|
* @param {number} courseId Course ID the module belongs to.
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
|
||||||
* @return {Promise<any>} Promise resolved with the list of files.
|
* @return {Promise<any>} Promise resolved with the list of files.
|
||||||
*/
|
*/
|
||||||
getFiles(module: any, courseId: number, single?: boolean): Promise<any[]> {
|
getFiles(module: any, courseId: number, single?: boolean): Promise<any[]> {
|
||||||
|
|
|
@ -6,5 +6,5 @@
|
||||||
<!-- Edit. -->
|
<!-- Edit. -->
|
||||||
<ion-item *ngIf="edit && field && field.shortname" text-wrap [formGroup]="form">
|
<ion-item *ngIf="edit && field && field.shortname" text-wrap [formGroup]="form">
|
||||||
<ion-label stacked [core-mark-required]="field.required">{{ field.name }}</ion-label>
|
<ion-label stacked [core-mark-required]="field.required">{{ field.name }}</ion-label>
|
||||||
<ion-datetime [formControlName]="field.modelName" [placeholder]="'core.choosedots' | translate" [displayFormat]="field.format" core-input-errors [max]="field.max" [min]="field.min"></ion-datetime>
|
<ion-datetime [formControlName]="field.modelName" [placeholder]="'core.choosedots' | translate" [displayFormat]="field.format" [max]="field.max" [min]="field.min"></ion-datetime>
|
||||||
</ion-item>
|
</ion-item>
|
|
@ -6,7 +6,7 @@
|
||||||
<!-- Edit. -->
|
<!-- Edit. -->
|
||||||
<ion-item *ngIf="edit && field && field.shortname" text-wrap [formGroup]="form">
|
<ion-item *ngIf="edit && field && field.shortname" text-wrap [formGroup]="form">
|
||||||
<ion-label stacked [core-mark-required]="field.required">{{ field.name }}</ion-label>
|
<ion-label stacked [core-mark-required]="field.required">{{ field.name }}</ion-label>
|
||||||
<ion-select [formControlName]="field.modelName" [placeholder]="'core.choosedots' | translate" core-input-errors interface="popover">
|
<ion-select [formControlName]="field.modelName" [placeholder]="'core.choosedots' | translate" interface="popover">
|
||||||
<ion-option value="">{{ 'core.choosedots' | translate }}</ion-option>
|
<ion-option value="">{{ 'core.choosedots' | translate }}</ion-option>
|
||||||
<ion-option *ngFor="let option of field.options" [value]="option">{{option}}</ion-option>
|
<ion-option *ngFor="let option of field.options" [value]="option">{{option}}</ion-option>
|
||||||
</ion-select>
|
</ion-select>
|
||||||
|
|
|
@ -6,5 +6,5 @@
|
||||||
<!-- Edit. -->
|
<!-- Edit. -->
|
||||||
<ion-item *ngIf="edit && field && field.shortname" text-wrap [formGroup]="form">
|
<ion-item *ngIf="edit && field && field.shortname" text-wrap [formGroup]="form">
|
||||||
<ion-label stacked [core-mark-required]="field.required">{{ field.name }}</ion-label>
|
<ion-label stacked [core-mark-required]="field.required">{{ field.name }}</ion-label>
|
||||||
<ion-input [type]="field.inputType" [formControlName]="field.modelName" [placeholder]="field.name" maxlength="{{field.maxlength}}" core-input-errors></ion-input>
|
<ion-input [type]="field.inputType" [formControlName]="field.modelName" [placeholder]="field.name" maxlength="{{field.maxlength}}"></ion-input>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
<div class="core-input-error-container" *ngIf="formControl.dirty && !formControl.valid" role="alert">
|
<div class="core-input-error-container" role="alert" *ngIf="(formControl && formControl.dirty && !formControl.valid) || errorText">
|
||||||
<ng-container *ngFor="let error of errorKeys">
|
<ng-container *ngIf="formControl && formControl.dirty && !formControl.valid">
|
||||||
<div *ngIf="formControl.hasError(error)" class="core-input-error">{{errorMessages[error]}}</div>
|
<ng-container *ngFor="let error of errorKeys">
|
||||||
|
<div *ngIf="formControl.hasError(error)" class="core-input-error">{{errorMessages[error]}}</div>
|
||||||
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
<div *ngIf="errorText" class="core-input-error">{{ errorText }}</div>
|
||||||
</div>
|
</div>
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit, OnChanges, SimpleChange } from '@angular/core';
|
||||||
import { FormControl } from '@angular/forms';
|
import { FormControl } from '@angular/forms';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
@ -42,9 +42,10 @@ import { TranslateService } from '@ngx-translate/core';
|
||||||
selector: 'core-input-errors',
|
selector: 'core-input-errors',
|
||||||
templateUrl: 'input-errors.html'
|
templateUrl: 'input-errors.html'
|
||||||
})
|
})
|
||||||
export class CoreInputErrorsComponent implements OnInit {
|
export class CoreInputErrorsComponent implements OnInit, OnChanges {
|
||||||
@Input('control') formControl: FormControl;
|
@Input('control') formControl?: FormControl;
|
||||||
@Input() errorMessages?: any;
|
@Input() errorMessages?: any;
|
||||||
|
@Input() errorText?: string; // Set other non automatic errors.
|
||||||
errorKeys: any[];
|
errorKeys: any[];
|
||||||
|
|
||||||
constructor(private translate: TranslateService) { }
|
constructor(private translate: TranslateService) { }
|
||||||
|
@ -53,9 +54,11 @@ export class CoreInputErrorsComponent implements OnInit {
|
||||||
* Component is being initialized.
|
* Component is being initialized.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.initErrorMessages();
|
if (this.formControl) {
|
||||||
|
this.initErrorMessages();
|
||||||
|
|
||||||
this.errorKeys = Object.keys(this.errorMessages);
|
this.errorKeys = Object.keys(this.errorMessages);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,4 +78,13 @@ export class CoreInputErrorsComponent implements OnInit {
|
||||||
// @todo: Check how to handle min/max errors once we have a test case to use. Also, review previous errors.
|
// @todo: Check how to handle min/max errors once we have a test case to use. Also, review previous errors.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component being changed.
|
||||||
|
*/
|
||||||
|
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
|
||||||
|
if (changes.errorText) {
|
||||||
|
this.errorText = changes.errorText.currentValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue