2
0
Fork 0

Merge pull request #3884 from crazyserver/MOBILE-3947

Mobile 3947
main
Noel De Martin 2023-12-19 09:51:41 +01:00 committed by GitHub
commit ef2cc0c5e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 171 additions and 145 deletions

View File

@ -28,7 +28,7 @@
--a11y-min-target-size: 40px; --a11y-min-target-size: 40px;
} }
ion-searchbar { ion-searchbar {
padding: 0; padding: 0;
--height: 40px; --height: 40px;
} }

View File

@ -19,7 +19,7 @@
<ion-row class="ion-justify-content-between ion-align-items-center ion-no-padding"> <ion-row class="ion-justify-content-between ion-align-items-center ion-no-padding">
<ion-col class="addon-block-timeline-activity-main ion-no-padding"> <ion-col class="addon-block-timeline-activity-main ion-no-padding">
<ion-row class="ion-justify-content-between ion-align-items-center ion-nowrap ion-no-padding"> <ion-row class="ion-justify-content-between ion-align-items-center ion-nowrap ion-no-padding">
<ion-col class="addon-block-timeline-activity-time ion-no-padding"> <ion-col class="addon-block-timeline-activity-time ion-no-padding ion-text-nowrap">
<small>{{event.timesort * 1000 | coreFormatDate:"strftimetime24" }}</small> <small>{{event.timesort * 1000 | coreFormatDate:"strftimetime24" }}</small>
<core-mod-icon *ngIf="event.iconUrl" [modicon]="event.iconUrl" [componentId]="event.instance" <core-mod-icon *ngIf="event.iconUrl" [modicon]="event.iconUrl" [componentId]="event.instance"
[modname]="event.modulename" [purpose]="event.purpose" /> [modname]="event.modulename" [purpose]="event.purpose" />

View File

@ -14,7 +14,6 @@ Feature: Test messages navigation in the app
| teacher | C1 | editingteacher | | teacher | C1 | editingteacher |
| student | C1 | student | | student | C1 | student |
@ionic7_failure
Scenario: Avoid recursive links to profile Scenario: Avoid recursive links to profile
Given I entered the app as "teacher" Given I entered the app as "teacher"
When I press "Messages" in the app When I press "Messages" in the app

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -58,7 +58,6 @@ Feature: Test basic usage of assignment activity in app
Then I should find "Online text submissions" in the app Then I should find "Online text submissions" in the app
And I should find "Submission test edited" in the app And I should find "Submission test edited" in the app
@ionic7_failure
Scenario: Edit/Add submission (online text) & Add new attempt from previous submission & Submit for grading Scenario: Edit/Add submission (online text) & Add new attempt from previous submission & Submit for grading
# Submit first attempt as a student # Submit first attempt as a student
Given I entered the assign activity "assignment1" on course "Course 1" as "student1" in the app Given I entered the assign activity "assignment1" on course "Course 1" as "student1" in the app

View File

@ -26,7 +26,6 @@ Feature: Users can manage entries in database activities
| data1 | text | URL | URL link | | data1 | text | URL | URL link |
| data1 | text | Description | Link description | | data1 | text | Description | Link description |
@ionic7_failure
Scenario: Create entry Scenario: Create entry
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
Then I should find "No entries yet" in the app Then I should find "No entries yet" in the app
@ -38,7 +37,6 @@ Feature: Users can manage entries in database activities
Then I should find "https://moodle.org/" in the app Then I should find "https://moodle.org/" in the app
And I should find "Moodle community site" in the app And I should find "Moodle community site" in the app
@ionic7_failure
Scenario: Browse entry Scenario: Browse entry
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
@ -72,7 +70,6 @@ Feature: Users can manage entries in database activities
And I should find "Moodle community site" in the app And I should find "Moodle community site" in the app
And I should find "Moodle Cloud" in the app And I should find "Moodle Cloud" in the app
@ionic7_failure
Scenario: Students can not edit or delete other user's entries from list and single view in the app Scenario: Students can not edit or delete other user's entries from list and single view in the app
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
And I press "Add entries" in the app And I press "Add entries" in the app
@ -88,7 +85,6 @@ Feature: Users can manage entries in database activities
And "Edit" "link" should not exist And "Edit" "link" should not exist
And "Delete" "link" should not exist And "Delete" "link" should not exist
@ionic7_failure
Scenario: Delete entry (student) & Update entry (student) Scenario: Delete entry (student) & Update entry (student)
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
And I press "Add entries" in the app And I press "Add entries" in the app
@ -148,7 +144,6 @@ Feature: Users can manage entries in database activities
And I should not find "Moodle Cloud" in the app And I should not find "Moodle Cloud" in the app
And I should find "No entries yet" in the app And I should find "No entries yet" in the app
@ionic7_failure
Scenario: Delete entry (teacher) & Update entry (teacher) Scenario: Delete entry (teacher) & Update entry (teacher)
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
And I press "Add entries" in the app And I press "Add entries" in the app
@ -212,7 +207,6 @@ Feature: Users can manage entries in database activities
And I press "Delete" in the app And I press "Delete" in the app
And I should not find "Moodle Cloud" in the app And I should not find "Moodle Cloud" in the app
@ionic7_failure
Scenario: Handle number 0 correctly when creating entries Scenario: Handle number 0 correctly when creating entries
Given the following "activities" exist: Given the following "activities" exist:
| activity | name | intro | course | idnumber | | activity | name | intro | course | idnumber |

View File

@ -26,7 +26,6 @@ Feature: Users can store entries in database activities when offline and sync wh
| data1 | text | URL | URL link | | data1 | text | URL | URL link |
| data1 | text | Description | Link description | | data1 | text | Description | Link description |
@ionic7_failure
Scenario: Create entry (offline) Scenario: Create entry (offline)
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
And I switch network connection to offline And I switch network connection to offline
@ -46,7 +45,6 @@ Feature: Users can store entries in database activities when offline and sync wh
And I should find "Moodle community site" in the app And I should find "Moodle community site" in the app
And I should not find "This Database has offline data to be synchronised" in the app And I should not find "This Database has offline data to be synchronised" in the app
@ionic7_failure
Scenario: Update entry (offline) & Delete entry (offline) Scenario: Update entry (offline) & Delete entry (offline)
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
And I should find "No entries yet" in the app And I should find "No entries yet" in the app
@ -97,7 +95,6 @@ Feature: Users can store entries in database activities when offline and sync wh
And I should not find "Moodle Cloud" in the app And I should not find "Moodle Cloud" in the app
And I should not find "This Database has offline data to be synchronised" in the app And I should not find "This Database has offline data to be synchronised" in the app
@ionic7_failure
Scenario: Students can undo deleting entries to a database in the app while offline Scenario: Students can undo deleting entries to a database in the app while offline
Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app Given I entered the data activity "Web links" on course "Course 1" as "student1" in the app
And I should find "No entries yet" in the app And I should find "No entries yet" in the app

View File

@ -50,7 +50,6 @@ Feature: Test basic usage of forum activity in app
Then I should find "My happy subject" in the app Then I should find "My happy subject" in the app
And I should find "An awesome message" inside the split-view content in the app And I should find "An awesome message" inside the split-view content in the app
@ionic7_failure
Scenario: Reply a post Scenario: Reply a post
Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app
When I replace "/.*/" within ".addon-mod-forum-discussion-author p" with "[Publication date]" When I replace "/.*/" within ".addon-mod-forum-discussion-author p" with "[Publication date]"
@ -179,7 +178,6 @@ Feature: Test basic usage of forum activity in app
And I press "Save changes" in the app And I press "Save changes" in the app
Then I should find "Auto-test message edited" in the app Then I should find "Auto-test message edited" in the app
@ionic7_failure
Scenario: Delete a forum post (only online) Scenario: Delete a forum post (only online)
Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app Given I entered the forum activity "Test forum name" on course "Course 1" as "student1" in the app
When I press "Add discussion topic" in the app When I press "Add discussion topic" in the app

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -191,7 +191,6 @@ Feature: Attempt a quiz in app
Then I should find "The correct answer is: Berlin" in the app Then I should find "The correct answer is: Berlin" in the app
And I should find "Mark 1.00 out of 1.00" in the app And I should find "Mark 1.00 out of 1.00" in the app
@ionic7_failure
Scenario: Submit a quiz & Review a quiz attempt Scenario: Submit a quiz & Review a quiz attempt
Given I entered the quiz activity "Quiz 1" on course "Course 1" as "student1" in the app Given I entered the quiz activity "Quiz 1" on course "Course 1" as "student1" in the app
When I press "Attempt quiz now" in the app When I press "Attempt quiz now" in the app

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -40,8 +40,7 @@ Feature: Notifications
| Test 30 | student2 | student1 | 1649766629 | null | | Test 30 | student2 | student1 | 1649766629 | null |
Scenario: Mobile navigation Scenario: Mobile navigation
Given I enter the app Given I entered the app as "student1"
And I log in as "student1"
And I press "Notifications" in the app And I press "Notifications" in the app
Then I should find "Test 30" in the app Then I should find "Test 30" in the app
But I should not find "Test 10" in the app But I should not find "Test 10" in the app
@ -81,9 +80,8 @@ Feature: Notifications
@ionic7_failure @ionic7_failure
Scenario: Tablet navigation Scenario: Tablet navigation
Given I enter the app Given I entered the app as "student1"
And I change viewport size to "1200x640" in the app And I change viewport size to "1200x640" in the app
And I log in as "student1"
And I press "Notifications" in the app And I press "Notifications" in the app
Then I should find "Test 30" in the app Then I should find "Test 30" in the app
But I should not find "Test 10" in the app But I should not find "Test 10" in the app

View File

@ -10,20 +10,20 @@
<ion-select id="{{row.id}}" [name]="row.name" [(ngModel)]="row.selected" interface="action-sheet" [disabled]="row.disabled" <ion-select id="{{row.id}}" [name]="row.name" [(ngModel)]="row.selected" interface="action-sheet" [disabled]="row.disabled"
[cancelText]="'core.cancel' | translate" [cancelText]="'core.cancel' | translate"
[ngClass]="{'addon-qtype-match-correct': row.isCorrect === 1,'addon-qtype-match-incorrect': row.isCorrect === 0}"> [ngClass]="{'addon-qtype-match-correct': row.isCorrect === 1,'addon-qtype-match-incorrect': row.isCorrect === 0}">
<div slot="label"> <div slot="label" class="flew-row">
<core-format-text [component]="component" [componentId]="componentId" [text]="row.text" [contextLevel]="contextLevel" <core-format-text [component]="component" [componentId]="componentId" [text]="row.text" [contextLevel]="contextLevel"
[contextInstanceId]="contextInstanceId" [courseId]="courseId" /> [contextInstanceId]="contextInstanceId" [courseId]="courseId" />
<label class="accesshide" for="{{row.id}}" *ngIf="row.accessibilityLabel"> <label class="accesshide" for="{{row.id}}" *ngIf="row.accessibilityLabel">
{{ row.accessibilityLabel }} {{ row.accessibilityLabel }}
</label> </label>
<ion-icon *ngIf="row.isCorrect === 1" class="core-correct-icon" name="fas-check" color="success" slot="end"
[attr.aria-label]="'core.question.correct' | translate" />
<ion-icon *ngIf="row.isCorrect === 0" class="core-correct-icon" name="fas-xmark" color="danger" slot="end"
[attr.aria-label]="'core.question.incorrect' | translate" />
</div> </div>
<ion-select-option *ngFor="let option of row.options" [value]="option.value"> <ion-select-option *ngFor="let option of row.options" [value]="option.value">
{{option.label}} {{option.label}}
</ion-select-option> </ion-select-option>
</ion-select> </ion-select>
<ion-icon *ngIf="row.isCorrect === 1" class="core-correct-icon" name="fas-check" color="success" slot="end"
[attr.aria-label]="'core.question.correct' | translate" />
<ion-icon *ngIf="row.isCorrect === 0" class="core-correct-icon" name="fas-xmark" color="danger" slot="end"
[attr.aria-label]="'core.question.incorrect' | translate" />
</ion-item> </ion-item>
</section> </section>

View File

@ -10,4 +10,16 @@
.addon-qtype-match-incorrect { .addon-qtype-match-incorrect {
color: var(--danger); color: var(--danger);
} }
ion-select::part(label) {
flex-grow: 1;
}
div.flew-row {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
} }

View File

@ -18,21 +18,22 @@
<ion-item class="ion-text-wrap answer" *ngFor="let option of question.options"> <ion-item class="ion-text-wrap answer" *ngFor="let option of question.options">
<ion-checkbox [attr.name]="option.name" [(ngModel)]="option.checked" [disabled]="option.disabled" <ion-checkbox [attr.name]="option.name" [(ngModel)]="option.checked" [disabled]="option.disabled"
[color]='(option.isCorrect === 1 ? "success": "") + (option.isCorrect === 0 ? "danger": "")'> [color]='(option.isCorrect === 1 ? "success": "") + (option.isCorrect === 0 ? "danger": "")'>
<div [class]="option.class"> <div>
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text" [contextLevel]="contextLevel" <div [class]="option.class">
[contextInstanceId]="contextInstanceId" [courseId]="courseId" /> <core-format-text [component]="component" [componentId]="componentId" [text]="option.text"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" />
</div>
<div *ngIf="option.feedback" class="specificfeedback"> <div *ngIf="option.feedback" class="specificfeedback">
<core-format-text [component]="component" [componentId]="componentId" [text]="option.feedback" <core-format-text [component]="component" [componentId]="componentId" [text]="option.feedback"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" /> [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" />
</div> </div>
</div> </div>
<ion-icon *ngIf="option.isCorrect === 1" class="core-correct-icon" name="fas-check" color="success"
[attr.aria-label]="'core.question.correct' | translate" />
<ion-icon *ngIf="option.isCorrect === 0" class="core-correct-icon" name="fas-xmark" color="danger"
[attr.aria-label]="'core.question.incorrect' | translate" />
</ion-checkbox> </ion-checkbox>
<ion-icon slot="end" *ngIf="option.isCorrect === 1" class="core-correct-icon" name="fas-check" color="success"
[attr.aria-label]="'core.question.correct' | translate" />
<ion-icon slot="end" *ngIf="option.isCorrect === 0" class="core-correct-icon" name="fas-xmark" color="danger"
[attr.aria-label]="'core.question.incorrect' | translate" />
<!-- ion-checkbox doesn't use an input. Create a hidden input to hold the value. --> <!-- ion-checkbox doesn't use an input. Create a hidden input to hold the value. -->
<input type="hidden" [ngModel]="option.checked" [attr.name]="option.name"> <input type="hidden" [ngModel]="option.checked" [attr.name]="option.name">
</ion-item> </ion-item>
@ -43,20 +44,21 @@
<ion-item class="ion-text-wrap answer" *ngFor="let option of question.options"> <ion-item class="ion-text-wrap answer" *ngFor="let option of question.options">
<ion-radio [value]="option.value" [disabled]="option.disabled" <ion-radio [value]="option.value" [disabled]="option.disabled"
[color]='(option.isCorrect === 1 ? "success": "") + (option.isCorrect === 0 ? "danger": "")'> [color]='(option.isCorrect === 1 ? "success": "") + (option.isCorrect === 0 ? "danger": "")'>
<div [class]="option.class"> <div>
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text" [contextLevel]="contextLevel" <div [class]="option.class">
[contextInstanceId]="contextInstanceId" [courseId]="courseId" /> <core-format-text [component]="component" [componentId]="componentId" [text]="option.text"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" />
</div>
<div *ngIf="option.feedback" class="specificfeedback"> <div *ngIf="option.feedback" class="specificfeedback">
<core-format-text [component]="component" [componentId]="componentId" [text]="option.feedback" <core-format-text [component]="component" [componentId]="componentId" [text]="option.feedback"
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" /> [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId" />
</div> </div>
</div> </div>
<ion-icon *ngIf="option.isCorrect === 1" class="core-correct-icon" name="fas-check" color="success"
[attr.aria-label]="'core.question.correct' | translate" />
<ion-icon *ngIf="option.isCorrect === 0" class="core-correct-icon" name="fas-xmark" color="danger"
[attr.aria-label]="'core.question.incorrect' | translate" />
</ion-radio> </ion-radio>
<ion-icon slot="end" *ngIf="option.isCorrect === 1" class="core-correct-icon" name="fas-check" color="success"
[attr.aria-label]="'core.question.correct' | translate" />
<ion-icon slot="end" *ngIf="option.isCorrect === 0" class="core-correct-icon" name="fas-xmark" color="danger"
[attr.aria-label]="'core.question.incorrect' | translate" />
</ion-item> </ion-item>
<ion-button *ngIf="!question.disabled" class="ion-text-wrap ion-margin-top" expand="block" fill="outline" <ion-button *ngIf="!question.disabled" class="ion-text-wrap ion-margin-top" expand="block" fill="outline"
[disabled]="!question.singleChoiceModel" (click)="clear()" type="button"> [disabled]="!question.singleChoiceModel" (click)="clear()" type="button">

View File

@ -6,15 +6,24 @@
padding: 0 .7em; padding: 0 .7em;
} }
.answer {
line-height: 2em;
}
.d-flex { .d-flex {
display: flex !important; display: flex !important;
} }
.answer .answernumber { .answer {
min-width: 1.5em; line-height: 2em;
.answernumber {
min-width: 1.5em;
}
ion-checkbox::part(label),
ion-radio::part(label) {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
} }
} }

View File

@ -1,4 +1,8 @@
@use "theme/globals" as *;
:host { :host {
display: contents;
--textarea-background: var(--core-input-background); --textarea-background: var(--core-input-background);
--textarea-color: var(--core-input-text); --textarea-color: var(--core-input-text);
--textarea-border-width: var(--core-input-border-width); --textarea-border-width: var(--core-input-border-width);
@ -6,7 +10,6 @@
--textarea-radius: var(--radius-xl); --textarea-radius: var(--radius-xl);
form { form {
position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
width: 100%; width: 100%;
@ -27,10 +30,15 @@
min-height: var(--a11y-min-target-size); min-height: var(--a11y-min-target-size);
line-height: 20px; line-height: 20px;
padding: 10px; padding: 10px;
margin: 4px 8px; @include margin(4px, 0px, 4px, 8px);
resize: vertical; resize: vertical;
} }
ion-button {
--padding-start: 16px;
--padding-end: 16px;
}
.core-send-message-input::placeholder { .core-send-message-input::placeholder {
color: var(--ion-placeholder-color); color: var(--ion-placeholder-color);
} }

View File

@ -26,7 +26,6 @@ Feature: Test basic usage of comments in app
| database | type | name | description | | database | type | name | description |
| data1 | text | Test field name | Test field description | | data1 | text | Test field name | Test field description |
@ionic7_failure
Scenario: Add comments & Delete comments (database) Scenario: Add comments & Delete comments (database)
# Create database entry and comment as a teacher # Create database entry and comment as a teacher
Given I entered the data activity "Data" on course "Course 1" as "teacher1" in the app Given I entered the data activity "Data" on course "Course 1" as "teacher1" in the app
@ -65,7 +64,6 @@ Feature: Test basic usage of comments in app
When I press the back button in the app When I press the back button in the app
Then I should find "Comments (1)" in the app Then I should find "Comments (1)" in the app
@ionic7_failure
Scenario: Add comments offline & Delete comments offline & Sync comments (database) Scenario: Add comments offline & Delete comments offline & Sync comments (database)
Given I entered the data activity "Data" on course "Course 1" as "teacher1" in the app Given I entered the data activity "Data" on course "Course 1" as "teacher1" in the app
And I press "Add entries" in the app And I press "Add entries" in the app
@ -152,7 +150,6 @@ Feature: Test basic usage of comments in app
When I press the back button in the app When I press the back button in the app
And I should find "Comments (1)" in the app And I should find "Comments (1)" in the app
@ionic7_failure
Scenario: Add comments offline & Delete comments offline & Sync comments (glossary) Scenario: Add comments offline & Delete comments offline & Sync comments (glossary)
Given I entered the glossary activity "Test glossary" on course "Course 1" as "teacher1" in the app Given I entered the glossary activity "Test glossary" on course "Course 1" as "teacher1" in the app
And I press "Add a new entry" in the app And I press "Add a new entry" in the app
@ -231,7 +228,6 @@ Feature: Test basic usage of comments in app
When I press the back button in the app When I press the back button in the app
Then I should find "Comments (0)" in the app Then I should find "Comments (0)" in the app
@ionic7_failure
Scenario: Add comments offline & Delete comments offline & Sync comments (blogs) Scenario: Add comments offline & Delete comments offline & Sync comments (blogs)
# Create blog as a teacher # Create blog as a teacher
Given the following "core_blog > entries" exist: Given the following "core_blog > entries" exist:

View File

@ -114,42 +114,41 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy, DoCheck {
* @inheritdoc * @inheritdoc
*/ */
async ngOnChanges(changes: Record<string, SimpleChange>): Promise<void> { async ngOnChanges(changes: Record<string, SimpleChange>): Promise<void> {
if (!this.container) { // Only compile if text/javascript has changed or the forceCompile flag has been set to true.
if (this.text === undefined ||
!(changes.text || changes.javascript || (changes.forceCompile && CoreUtils.isTrueOrOne(this.forceCompile)))) {
return; return;
} }
// Only compile if text/javascript has changed or the forceCompile flag has been set to true. // Create a new component and a new module.
if (this.text !== undefined && (changes.text || changes.javascript || this.creatingComponent = true;
(changes.forceCompile && CoreUtils.isTrueOrOne(this.forceCompile)))) { this.compiling.emit(true);
// Create a new component and a new module. try {
this.creatingComponent = true; const componentClass = await this.getComponentClass();
this.compiling.emit(true);
try { // Destroy previous components.
const componentClass = await this.getComponentClass(); this.componentRef?.destroy();
// Destroy previous components. // Create the component.
this.componentRef?.destroy(); if (this.container) {
// Create the component.
this.componentRef = await CoreCompile.createAndCompileComponent( this.componentRef = await CoreCompile.createAndCompileComponent(
this.text, this.text,
componentClass, componentClass,
this.container, this.container,
this.extraImports, this.extraImports,
); );
this.componentRef && this.created.emit(this.componentRef.instance);
this.loaded = true;
} catch (error) {
CoreDomUtils.showErrorModal(error);
this.loaded = true;
} finally {
this.creatingComponent = false;
this.compiling.emit(false);
} }
this.componentRef && this.created.emit(this.componentRef.instance);
this.loaded = true;
} catch (error) {
CoreDomUtils.showErrorModal(error);
this.loaded = true;
} finally {
this.creatingComponent = false;
this.compiling.emit(false);
} }
} }

View File

@ -80,7 +80,6 @@ Feature: Test basic usage of one course in app
And I click on "Move right" "link" in the "assignment" activity And I click on "Move right" "link" in the "assignment" activity
And I log out And I log out
@ionic7_failure
Scenario: View course contents Scenario: View course contents
When I entered the course "Course 1" as "student1" in the app When I entered the course "Course 1" as "student1" in the app
Then the header should be "Course 1" in the app Then the header should be "Course 1" in the app

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -66,10 +66,6 @@
} }
.core-login-methods { .core-login-methods {
form .item.item-input {
margin-bottom: 16px;
}
form .item, form .item,
form .item ion-label { form .item ion-label {
--background: var(--core-login-input-background); --background: var(--core-login-input-background);

View File

@ -41,7 +41,7 @@
<div class="core-login-methods"> <div class="core-login-methods">
<form [formGroup]="credForm" (ngSubmit)="login($event)" class="core-login-form" #credentialsForm *ngIf="!isBrowserSSO"> <form [formGroup]="credForm" (ngSubmit)="login($event)" class="core-login-form" #credentialsForm *ngIf="!isBrowserSSO">
<ion-item lines="inset"> <ion-item class="ion-margin-bottom" lines="inset">
<ion-input type="text" name="username" placeholder="{{ 'core.login.username' | translate }}" <ion-input type="text" name="username" placeholder="{{ 'core.login.username' | translate }}"
formControlName="username" autocapitalize="none" autocorrect="off" autocomplete="username" enterkeyhint="next" formControlName="username" autocapitalize="none" autocorrect="off" autocomplete="username" enterkeyhint="next"
required="true" [attr.aria-label]="'core.login.username' | translate " /> required="true" [attr.aria-label]="'core.login.username' | translate " />

View File

@ -25,7 +25,6 @@ Feature: Test basic usage of login in app
Then I should not find "Skip" in the app Then I should not find "Skip" in the app
And I should find "Connect to Moodle" in the app And I should find "Connect to Moodle" in the app
@ionic7_failure
Scenario: Add a new account in the app & Site name in displayed when adding a new account Scenario: Add a new account in the app & Site name in displayed when adding a new account
When I launch the app When I launch the app
And I set the field "Your site" to "$WWWROOT" in the app And I set the field "Your site" to "$WWWROOT" in the app
@ -49,8 +48,7 @@ Feature: Test basic usage of login in app
Then I should find "Can't connect to site" in the app Then I should find "Can't connect to site" in the app
Scenario: Add a non existing account from accounts switcher Scenario: Add a non existing account from accounts switcher
When I enter the app Given I entered the app as "student1"
And I log in as "student1"
And I press the user menu button in the app And I press the user menu button in the app
And I press "Switch account" in the app And I press "Switch account" in the app
And I press "Add" in the app And I press "Add" in the app

View File

@ -119,8 +119,7 @@ Feature: Report builder
| student1 | Lionel | Smith | lionel@example.com | Bilbao | | student1 | Lionel | Smith | lionel@example.com | Bilbao |
Scenario: Open report in mobile Scenario: Open report in mobile
Given I enter the app Given I entered the app as "student1"
And I log in as "student1"
And I press the user menu button in the app And I press the user menu button in the app
When I press "Reports" in the app When I press "Reports" in the app
@ -132,9 +131,8 @@ Feature: Report builder
But I should not find "My report 02" in the app But I should not find "My report 02" in the app
Scenario: Open report in tablet Scenario: Open report in tablet
Given I enter the app Given I entered the app as "student1"
And I change viewport size to "1200x640" in the app And I change viewport size to "1200x640" in the app
And I log in as "student1"
And I press the user menu button in the app And I press the user menu button in the app
When I press "Reports" in the app When I press "Reports" in the app

View File

@ -1,8 +1,7 @@
<form (ngSubmit)="submitForm($event)" role="search" #searchForm> <form (ngSubmit)="submitForm($event)" role="search" #searchForm>
<ion-item class="search-box"> <ion-input [attr.aria-label]="placeholder" type="search" name="search" [(ngModel)]="searchText" [placeholder]="placeholder"
<ion-input [attr.aria-label]="placeholder" type="search" name="search" [(ngModel)]="searchText" [placeholder]="placeholder" [autocorrect]="autocorrect" [spellcheck]="spellcheck" [core-auto-focus]="autoFocus" [disabled]="disabled" role="searchbox"
[autocorrect]="autocorrect" [spellcheck]="spellcheck" [core-auto-focus]="autoFocus" [disabled]="disabled" role="searchbox" (ionFocus)="focus($event)">
(ionFocus)="focus($event)" />
<ion-button slot="end" fill="clear" type="submit" [attr.aria-label]="searchLabel" <ion-button slot="end" fill="clear" type="submit" [attr.aria-label]="searchLabel"
[disabled]="disabled || !searchText || (searchText.length < lengthCheck)"> [disabled]="disabled || !searchText || (searchText.length < lengthCheck)">
<ion-icon name="fas-magnifying-glass" slot="icon-only" aria-hidden="true" /> <ion-icon name="fas-magnifying-glass" slot="icon-only" aria-hidden="true" />
@ -11,7 +10,7 @@
[disabled]="searched === '' || disabled" (click)="clearForm()"> [disabled]="searched === '' || disabled" (click)="clearForm()">
<ion-icon name="fas-delete-left" slot="icon-only" aria-hidden="true" flip-rtl /> <ion-icon name="fas-delete-left" slot="icon-only" aria-hidden="true" flip-rtl />
</ion-button> </ion-button>
</ion-item> </ion-input>
<ion-list class="core-search-history" [hidden]="!historyShown"> <ion-list class="core-search-history" [hidden]="!historyShown">
<ion-item button class="ion-text-wrap" *ngFor="let item of history" (click)="historyClicked($event, item.searchedtext)" tabindex="0" <ion-item button class="ion-text-wrap" *ngFor="let item of history" (click)="historyClicked($event, item.searchedtext)" tabindex="0"
[detail]="true"> [detail]="true">

View File

@ -17,14 +17,21 @@
background: var(--core-search-box-background); background: var(--core-search-box-background);
color: var(--core-search-box-border-color); color: var(--core-search-box-border-color);
.search-box { --min-height: var(--search-height);
--min-height: var(--search-height);
border-radius: var(--core-search-box-border-radius); ion-input {
--padding-start: 16px;
--padding-end: 16px;
--border-radius: var(--core-search-box-border-radius);
min-height: var(--search-height);
} }
ion-button.button { ion-button.button {
margin: 0; margin: 0;
--a11y-min-target-size: var(--search-height); --a11y-min-target-size: var(--search-height);
--padding-start: 0px;
--padding-end: 0px;
font-size: 12px;
} }
} }
@ -41,23 +48,15 @@
--background: var(--light); --background: var(--light);
cursor: pointer; cursor: pointer;
} }
}
ion-label { ion-item {
margin: 0; --min-height: var(--a11y-min-target-size);
} --border-width: 0px;
--background: var(--core-search-box-background);
ion-input { ion-label {
--padding-start: 0px; margin: 0;
--padding-end: 0px; }
padding-left: 0; }
padding-right: 0;
}
ion-item {
--min-height: var(--a11y-min-target-size);
--border-width: 0px;
--background: var(--core-search-box-background);
} }
} }

View File

@ -14,14 +14,14 @@
</ion-refresher> </ion-refresher>
<core-loading [hideUntil]="userLoaded"> <core-loading [hideUntil]="userLoaded">
<ion-list *ngIf="user"> <ion-list *ngIf="user">
<ion-item class="ion-text-center core-user-profile-maininfo ion-text-wrap" [lines]="user.description ? null : 'full'"> <ion-item class="ion-text-center core-user-profile-maininfo ion-text-wrap" [lines]="user.description ? 'none' : 'full'">
<core-user-avatar [user]="user" [userId]="user.id" [linkProfile]="false" [checkOnline]="!canChangeProfilePicture">
<ion-button class="edit-avatar" *ngIf="canChangeProfilePicture" (click)="changeProfilePicture()"
[attr.aria-label]="'core.user.newpicture' | translate" fill="clear">
<ion-icon slot="icon-only" name="fas-pen" aria-hidden="true" />
</ion-button>
</core-user-avatar>
<ion-label> <ion-label>
<core-user-avatar [user]="user" [userId]="user.id" [linkProfile]="false" [checkOnline]="!canChangeProfilePicture">
<ion-button class="edit-avatar" *ngIf="canChangeProfilePicture" (click)="changeProfilePicture()"
[attr.aria-label]="'core.user.newpicture' | translate" fill="clear">
<ion-icon slot="icon-only" name="fas-pen" aria-hidden="true" />
</ion-button>
</core-user-avatar>
<h2>{{ user.fullname }}</h2> <h2>{{ user.fullname }}</h2>
</ion-label> </ion-label>
</ion-item> </ion-item>

View File

@ -1,8 +1,15 @@
:host { :host {
.core-user-profile-maininfo { .core-user-profile-maininfo {
padding-top: 16px; padding-top: 16px;
&::part(native) { ion-label {
display: flex;
flex-direction: column; flex-direction: column;
align-items: center;
margin-top: 0px;
h2 {
margin-top: 10px;
}
} }
} }
core-user-avatar { core-user-avatar {

View File

@ -54,7 +54,6 @@ Feature: Test basic usage of user features
When I press "Reconnect" in the app When I press "Reconnect" in the app
Then I should find "Acceptance test site" in the app Then I should find "Acceptance test site" in the app
@ionic7_failure
Scenario: View profile Scenario: View profile
Given the following "custom profile fields" exist: Given the following "custom profile fields" exist:
| datatype | shortname | name | required | param1 | | datatype | shortname | name | required | param1 |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -186,17 +186,20 @@ export class TestingBehatRuntimeService {
closePopup(): string { closePopup(): string {
this.log('Action - Close popup'); this.log('Action - Close popup');
let backdrops = Array.from(document.querySelectorAll('ion-backdrop')); const backdrops = Array
backdrops = backdrops.filter((backdrop) => !!backdrop.offsetParent); .from(document.querySelectorAll('ion-popover, ion-modal'))
.map(popover => popover.shadowRoot?.querySelector('ion-backdrop'))
.filter(backdrop => !!backdrop);
if (!backdrops.length) { if (!backdrops.length) {
return 'ERROR: Could not find backdrop'; return 'ERROR: Could not find backdrop';
} }
if (backdrops.length > 1) { if (backdrops.length > 1) {
return 'ERROR: Found too many backdrops ('+backdrops.length+')'; return 'ERROR: Found too many backdrops ('+backdrops.length+')';
} }
const backdrop = backdrops[0];
backdrop.click(); backdrops[0]?.click();
// Mark busy until the click finishes processing. // Mark busy until the click finishes processing.
TestingBehatBlocking.delay(); TestingBehatBlocking.delay();

View File

@ -18,7 +18,6 @@ Feature: It opens external links properly.
| forum | user | name | message | | forum | user | name | message |
| Test forum | student1 | Forum topic | See <a href="https://moodle.org/">moodle.org external link</a> | | Test forum | student1 | Forum topic | See <a href="https://moodle.org/">moodle.org external link</a> |
@ionic7_failure
Scenario: Click an external link Scenario: Click an external link
Given I entered the forum activity "Test forum" on course "Course 1" as "student1" in the app Given I entered the forum activity "Test forum" on course "Course 1" as "student1" in the app
When I press "Forum topic" in the app When I press "Forum topic" in the app

View File

@ -72,7 +72,6 @@ Feature: It navigates properly in pages with a split-view component.
And I should find "User account" in the app And I should find "User account" in the app
But I should not find "Back" in the app But I should not find "Back" in the app
@ionic7_failure
Scenario: Navigate in grades tab on tablet Scenario: Navigate in grades tab on tablet
# Open user menu # Open user menu

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -253,6 +253,9 @@ ion-tabs.hide-header ion-header {
ion-footer { ion-footer {
background-color: var(--contrast-background); background-color: var(--contrast-background);
> ion-toolbar:only-child {
top: 1px;
}
} }
// Ionic icon. // Ionic icon.
@ -290,6 +293,11 @@ button,
[role="button"] { [role="button"] {
min-height: var(--a11y-min-target-size); min-height: var(--a11y-min-target-size);
min-width: var(--a11y-min-target-size); min-width: var(--a11y-min-target-size);
&.button-large {
min-height: 2.8em;
min-width: 2.8em
}
} }
ion-fab-button { ion-fab-button {
@ -1015,16 +1023,20 @@ ion-action-sheet.md {
ion-radio, ion-radio,
input[type=radio], input[type=radio],
.select-alert.ios .alert-radio-icon { .select-alert.ios .alert-radio-icon {
--color: var(--text-color);
--color-checked: var(--color);
--border-radius: 50%; --border-radius: 50%;
--border-width: 2px; --border-width: 2px;
--outer-border-width: 2px; --outer-border-width: 2px;
--border-style: solid; --border-style: solid;
--inner-border-radius: 50%; --inner-border-radius: 50%;
--size: 20px; --size: 20px;
&:not(.ion-color) {
--color: var(--text-color);
--color-checked: var(--color);
}
} }
.ios ion-radio, .ios ion-radio,
.ios input[type=radio], .ios input[type=radio],
.select-alert.ios .alert-radio-icon { .select-alert.ios .alert-radio-icon {
@ -1108,15 +1120,19 @@ input[type=radio],
ion-checkbox, ion-checkbox,
input[type=checkbox] { input[type=checkbox] {
--border-radius: 2px; --border-radius: 2px;
--border-color-checked: var(--text-color);
--checkbox-background-checked: var(--text-color);
--checkmark-color: var(--contrast-background);
--border-width: 2px; --border-width: 2px;
--outer-border-width: 2px; --outer-border-width: 2px;
--border-style: solid; --border-style: solid;
--size: 20px; --size: 20px;
&:not(.ion-color) {
--border-color-checked: var(--text-color);
--checkbox-background-checked: var(--text-color);
--checkmark-color: var(--contrast-background);
}
} }
.ios input[type=checkbox] { .ios input[type=checkbox] {
--outer-border-width: 1px; --outer-border-width: 1px;
} }
@ -1406,23 +1422,27 @@ audio.core-media-adapt-width {
width: 100%; width: 100%;
} }
ion-item { ion-item.item-lines-default {
// font-size: var(--text-size);
--inner-border-width: 0px; --inner-border-width: 0px;
}
ion-item.item-lines-full {
--inner-border-width: 0px;
--border-width: 0 0 1px 0;
}
ion-item.item-lines-inset {
--inner-border-width: 0 0 1px 0;
--border-width: 0px; --border-width: 0px;
} }
ion-item.item-input.ios { ion-item.ion-valid,
ion-item.ion-invalid {
--inner-border-width: 0 0 1px 0; --inner-border-width: 0 0 1px 0;
&.ion-touched {
&.ion-invalid {
--ion-item-border-color: var(--highlight-color-invalid);
--highlight-background: var(--ion-item-border-color);
--border-color: var(--ion-item-border-color);
}
&.ion-valid {
--ion-item-border-color: var(--highlight-color-valid);
--highlight-background: var(--ion-item-border-color);
--border-color: var(--ion-item-border-color);
}
}
} }
// Fake item. // Fake item.