commit
c1ea233092
|
@ -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 { Input, OnInit, OnChanges, SimpleChange } from '@angular/core';
|
import { Input, Output, OnInit, OnChanges, SimpleChange, EventEmitter } from '@angular/core';
|
||||||
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,11 +23,13 @@ export class AddonModDataFieldPluginComponent implements OnInit, OnChanges {
|
||||||
@Input() value?: any; // The value of the field.
|
@Input() value?: any; // The value of the field.
|
||||||
@Input() database?: any; // Database object.
|
@Input() database?: any; // Database object.
|
||||||
@Input() error?: string; // Error when editing.
|
@Input() error?: string; // Error when editing.
|
||||||
@Input() viewAction?: string; // Action to perform.
|
@Output() gotoEntry?: EventEmitter<number>; // Action to perform.
|
||||||
@Input() form?: FormGroup; // Form where to add the form control. Just required for edit and search modes.
|
@Input() form?: FormGroup; // Form where to add the form control. Just required for edit and search modes.
|
||||||
@Input() search?: any; // The search value of all fields.
|
@Input() search?: any; // The search value of all fields.
|
||||||
|
|
||||||
constructor(protected fb: FormBuilder) { }
|
constructor(protected fb: FormBuilder) {
|
||||||
|
this.gotoEntry = new EventEmitter();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the form control for the search mode.
|
* Add the form control for the search mode.
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
<span *ngIf="action == 'timemodified'">{{ entry.timemodified * 1000 | coreFormatDate:"dffulldate" }}</span>
|
<span *ngIf="action == 'timemodified'">{{ entry.timemodified * 1000 | coreFormatDate:"dffulldate" }}</span>
|
||||||
|
|
||||||
<a *ngIf="action == 'userpicture'" core-user-link [courseId]="database.courseid" [userId]="entry.userid" [title]="entry.fullname">
|
<a *ngIf="action == 'userpicture'" core-user-link [courseId]="database.courseid" [userId]="entry.userid" [title]="entry.fullname">
|
||||||
<img class="avatar-round" [src]="userPicture" [alt]="'core.pictureof' | translate:{$a: user.fullname}" core-external-content onError="this.src='assets/img/user-avatar.png'" role="presentation">
|
<img class="avatar-round" [src]="userPicture" [alt]="'core.pictureof' | translate:{$a: entry.fullname}" core-external-content onError="this.src='assets/img/user-avatar.png'" role="presentation">
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a *ngIf="action == 'user'" core-user-link [courseId]="database.courseid" [userId]="entry.userid" [title]="entry.fullname">{{entry.fullname}}</a>
|
<a *ngIf="action == 'user' && entry" core-user-link [courseId]="database.courseid" [userId]="entry.userid" [title]="entry.fullname">{{entry.fullname}}</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, Input, OnInit, Injector, ViewChild, OnChanges, SimpleChange } from '@angular/core';
|
import { Component, Input, Output, OnInit, Injector, ViewChild, OnChanges, SimpleChange, EventEmitter } 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';
|
||||||
|
@ -32,7 +32,7 @@ export class AddonModDataFieldPluginComponent implements OnInit, OnChanges {
|
||||||
@Input() value?: any; // The value of the field.
|
@Input() value?: any; // The value of the field.
|
||||||
@Input() database?: any; // Database object.
|
@Input() database?: any; // Database object.
|
||||||
@Input() error?: string; // Error when editing.
|
@Input() error?: string; // Error when editing.
|
||||||
@Input() viewAction: string; // Action to perform.
|
@Output() gotoEntry: EventEmitter<number>; // Action to perform.
|
||||||
@Input() form?: FormGroup; // Form where to add the form control. Just required for edit and search modes.
|
@Input() form?: FormGroup; // Form where to add the form control. Just required for edit and search modes.
|
||||||
@Input() search?: any; // The search value of all fields.
|
@Input() search?: any; // The search value of all fields.
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ export class AddonModDataFieldPluginComponent implements OnInit, OnChanges {
|
||||||
|
|
||||||
constructor(protected injector: Injector, protected dataDelegate: AddonModDataFieldsDelegate,
|
constructor(protected injector: Injector, protected dataDelegate: AddonModDataFieldsDelegate,
|
||||||
protected dataProvider: AddonModDataProvider) {
|
protected dataProvider: AddonModDataProvider) {
|
||||||
|
this.gotoEntry = new EventEmitter();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,7 +67,7 @@ export class AddonModDataFieldPluginComponent implements OnInit, OnChanges {
|
||||||
value: this.value,
|
value: this.value,
|
||||||
database: this.database,
|
database: this.database,
|
||||||
error: this.error,
|
error: this.error,
|
||||||
viewAction: this.viewAction,
|
gotoEntry: this.gotoEntry,
|
||||||
form: this.form,
|
form: this.form,
|
||||||
search: this.search
|
search: this.search
|
||||||
};
|
};
|
||||||
|
|
|
@ -329,7 +329,8 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
||||||
this.jsData = {
|
this.jsData = {
|
||||||
fields: this.fields,
|
fields: this.fields,
|
||||||
entries: this.entries,
|
entries: this.entries,
|
||||||
data: this.data
|
data: this.data,
|
||||||
|
gotoEntry: this.gotoEntry.bind(this)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
} else if (!this.search.searching) {
|
} else if (!this.search.searching) {
|
||||||
|
|
|
@ -11,6 +11,6 @@
|
||||||
<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>
|
||||||
|
|
||||||
<span *ngIf="mode == 'list' && imageUrl" (click)="viewAction()"><img [src]="imageUrl" [alt]="title" [title]="title" class="core-media-adapt-width list_picture" core-external-content/></span>
|
<span *ngIf="mode == 'list' && imageUrl" (click)="gotoEntry.emit(entryId)"><img [src]="imageUrl" [alt]="title" [title]="title" class="core-media-adapt-width list_picture" core-external-content/></span>
|
||||||
|
|
||||||
<img *ngIf="mode == 'show' && imageUrl" [src]="imageUrl" [alt]="title" [title]="title" class="core-media-adapt-width list_picture" [width]="width" [height]="height" core-external-content/>
|
<img *ngIf="mode == 'show' && imageUrl" [src]="imageUrl" [alt]="title" [title]="title" class="core-media-adapt-width list_picture" [attr.width]="width" [attr.height]="height" core-external-content/>
|
||||||
|
|
|
@ -13,8 +13,9 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
import { Component } 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 { CoreFileSessionProvider } from '@providers/file-session';
|
import { CoreFileSessionProvider } from '@providers/file-session';
|
||||||
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
|
import { AddonModDataFieldPluginComponent } from '../../../classes/field-plugin-component';
|
||||||
import { AddonModDataProvider } from '../../../providers/data';
|
import { AddonModDataProvider } from '../../../providers/data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,7 +39,8 @@ export class AddonModDataFieldPictureComponent extends AddonModDataFieldPluginCo
|
||||||
width: string;
|
width: string;
|
||||||
height: string;
|
height: string;
|
||||||
|
|
||||||
constructor(protected fb: FormBuilder, private fileSessionprovider: CoreFileSessionProvider) {
|
constructor(protected fb: FormBuilder, private fileSessionprovider: CoreFileSessionProvider,
|
||||||
|
private domUtils: CoreDomUtilsProvider) {
|
||||||
super(fb);
|
super(fb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,8 +131,8 @@ export class AddonModDataFieldPictureComponent extends AddonModDataFieldPluginCo
|
||||||
this.imageUrl = (this.image && this.image.fileurl) || null;
|
this.imageUrl = (this.image && this.image.fileurl) || null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.width = this.field.param1 || '';
|
this.width = this.domUtils.formatPixelsSize(this.field.param1);
|
||||||
this.height = this.field.param2 || '';
|
this.height = this.domUtils.formatPixelsSize(this.field.param2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
<ion-navbar>
|
<ion-navbar>
|
||||||
<ion-title><core-format-text [text]="title"></core-format-text></ion-title>
|
<ion-title><core-format-text [text]="title"></core-format-text></ion-title>
|
||||||
<ion-buttons end>
|
<ion-buttons end>
|
||||||
<button ion-button icon-only (click)="save()" [attr.aria-label]="'core.save' | translate">
|
<button ion-button clear (click)="save()" [attr.aria-label]="'core.save' | translate">
|
||||||
<ion-icon name="send"></ion-icon>
|
{{ 'core.save' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
</ion-navbar>
|
</ion-navbar>
|
||||||
|
|
|
@ -253,12 +253,14 @@ export class AddonModDataEditPage {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.errors = {};
|
this.errors = {};
|
||||||
result.fieldnotifications.forEach((fieldNotif) => {
|
if (result.fieldnotifications) {
|
||||||
const field = this.fieldsArray.find((field) => field.name == fieldNotif.fieldname);
|
result.fieldnotifications.forEach((fieldNotif) => {
|
||||||
if (field) {
|
const field = this.fieldsArray.find((field) => field.name == fieldNotif.fieldname);
|
||||||
this.errors[field.id] = fieldNotif.notification;
|
if (field) {
|
||||||
}
|
this.errors[field.id] = fieldNotif.notification;
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
this.jsData['errors'] = this.errors;
|
this.jsData['errors'] = this.errors;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
|
@ -62,7 +62,7 @@ export class AddonModDataProvider {
|
||||||
.then((entry) => {
|
.then((entry) => {
|
||||||
return {
|
return {
|
||||||
// Return provissional entry Id.
|
// Return provissional entry Id.
|
||||||
newentryid: entry[1]
|
newentryid: entry
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -194,8 +194,9 @@ export class AddonModDataProvider {
|
||||||
});
|
});
|
||||||
|
|
||||||
// App is offline, check required fields.
|
// App is offline, check required fields.
|
||||||
fields.forEach((field) => {
|
Object.keys(fields).forEach((key) => {
|
||||||
const notification = this.fieldsDelegate.getFieldsNotifications(field, contentsIndexed[field.id]);
|
const field = fields[key],
|
||||||
|
notification = this.fieldsDelegate.getFieldsNotifications(field, contentsIndexed[field.id]);
|
||||||
if (notification) {
|
if (notification) {
|
||||||
notifications.push({
|
notifications.push({
|
||||||
fieldname: field.name,
|
fieldname: field.name,
|
||||||
|
|
|
@ -119,7 +119,7 @@ export class AddonModDataHelperProvider {
|
||||||
|
|
||||||
// Replace field by a generic directive.
|
// Replace field by a generic directive.
|
||||||
render = '<addon-mod-data-field-plugin [field]="fields[' + field.id + ']" [value]="entries[' + entry.id +
|
render = '<addon-mod-data-field-plugin [field]="fields[' + field.id + ']" [value]="entries[' + entry.id +
|
||||||
'].contents[' + field.id + ']" mode="' + mode + '" [database]="data" (viewAction)="gotoEntry(' + entry.id +
|
'].contents[' + field.id + ']" mode="' + mode + '" [database]="data" (gotoEntry)="gotoEntry(' + entry.id +
|
||||||
')"></addon-mod-data-field-plugin>';
|
')"></addon-mod-data-field-plugin>';
|
||||||
template = template.replace(replace, render);
|
template = template.replace(replace, render);
|
||||||
});
|
});
|
||||||
|
|
|
@ -46,6 +46,7 @@ import { Subscription } from 'rxjs';
|
||||||
export class CoreRichTextEditorComponent implements AfterContentInit, OnDestroy {
|
export class CoreRichTextEditorComponent implements AfterContentInit, OnDestroy {
|
||||||
// Based on: https://github.com/judgewest2000/Ionic3RichText/
|
// Based on: https://github.com/judgewest2000/Ionic3RichText/
|
||||||
// @todo: Anchor button, fullscreen...
|
// @todo: Anchor button, fullscreen...
|
||||||
|
// @todo: Textarea height is not being updated when editor is resized. Height is calculated if any css is changed.
|
||||||
|
|
||||||
@Input() placeholder = ''; // Placeholder to set in textarea.
|
@Input() placeholder = ''; // Placeholder to set in textarea.
|
||||||
@Input() control: FormControl; // Form control.
|
@Input() control: FormControl; // Form control.
|
||||||
|
@ -154,14 +155,21 @@ export class CoreRichTextEditorComponent implements AfterContentInit, OnDestroy
|
||||||
*/
|
*/
|
||||||
protected maximizeEditorSize(): Promise<number> {
|
protected maximizeEditorSize(): Promise<number> {
|
||||||
this.content.resize();
|
this.content.resize();
|
||||||
|
const contentVisibleHeight = this.content.contentHeight;
|
||||||
|
|
||||||
const deferred = this.utils.promiseDefer();
|
const deferred = this.utils.promiseDefer();
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const contentVisibleHeight = this.content.contentHeight;
|
const contentVisibleHeight = this.content.contentHeight;
|
||||||
|
|
||||||
// Editor is ready, adjust Height if needed.
|
if (contentVisibleHeight <= 0) {
|
||||||
if (contentVisibleHeight > 0) {
|
deferred.resolve(0);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// Editor is ready, adjust Height if needed.
|
||||||
const height = this.getSurroundingHeight(this.element);
|
const height = this.getSurroundingHeight(this.element);
|
||||||
if (contentVisibleHeight > height) {
|
if (contentVisibleHeight > height) {
|
||||||
this.element.style.height = this.domUtils.formatPixelsSize(contentVisibleHeight - height);
|
this.element.style.height = this.domUtils.formatPixelsSize(contentVisibleHeight - height);
|
||||||
|
@ -170,11 +178,7 @@ export class CoreRichTextEditorComponent implements AfterContentInit, OnDestroy
|
||||||
}
|
}
|
||||||
|
|
||||||
deferred.resolve(contentVisibleHeight - height);
|
deferred.resolve(contentVisibleHeight - height);
|
||||||
|
}, 100);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
deferred.resolve(0);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
|
@ -206,6 +210,13 @@ export class CoreRichTextEditorComponent implements AfterContentInit, OnDestroy
|
||||||
height += this.domUtils.getComputedStyleMeasure(cs, 'paddingTop') +
|
height += this.domUtils.getComputedStyleMeasure(cs, 'paddingTop') +
|
||||||
this.domUtils.getComputedStyleMeasure(cs, 'paddingBottom');
|
this.domUtils.getComputedStyleMeasure(cs, 'paddingBottom');
|
||||||
|
|
||||||
|
if (element && element.parentNode && element.parentNode.tagName == 'ION-CONTENT') {
|
||||||
|
const cs2 = getComputedStyle(element);
|
||||||
|
|
||||||
|
height -= this.domUtils.getComputedStyleMeasure(cs2, 'paddingTop') +
|
||||||
|
this.domUtils.getComputedStyleMeasure(cs2, 'paddingBottom');
|
||||||
|
}
|
||||||
|
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,7 +498,6 @@ export class CoreRichTextEditorComponent implements AfterContentInit, OnDestroy
|
||||||
*/
|
*/
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.valueChangeSubscription && this.valueChangeSubscription.unsubscribe();
|
this.valueChangeSubscription && this.valueChangeSubscription.unsubscribe();
|
||||||
this.keyboardObs && this.keyboardObs.off();
|
|
||||||
window.removeEventListener('resize', this.resizeFunction);
|
window.removeEventListener('resize', this.resizeFunction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,4 +7,10 @@ page-core-mainmenu {
|
||||||
@extend .fa-graduation-cap;
|
@extend .fa-graduation-cap;
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ion-ios-fa-graduation-cap-outline {
|
||||||
|
color: transparent;
|
||||||
|
-webkit-text-stroke-width: 0.8px;
|
||||||
|
-webkit-text-stroke-color: $tabs-tab-color-inactive;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue