MOBILE-3750 a11y: Listen resize events on scrolls

main
Noel De Martin 2021-05-13 11:35:03 +02:00
parent 255aec5897
commit 0048801fa3
11 changed files with 147 additions and 29 deletions

6
package-lock.json generated
View File

@ -4224,6 +4224,12 @@
"integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==",
"dev": true "dev": true
}, },
"@types/resize-observer-browser": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/@types/resize-observer-browser/-/resize-observer-browser-0.1.5.tgz",
"integrity": "sha512-8k/67Z95Goa6Lznuykxkfhq9YU3l1Qe6LNZmwde1u7802a3x8v44oq0j91DICclxatTr0rNnhXx7+VTIetSrSQ==",
"dev": true
},
"@types/source-list-map": { "@types/source-list-map": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",

View File

@ -140,6 +140,7 @@
"@ionic/v4-migration-tslint": "^1.7.1", "@ionic/v4-migration-tslint": "^1.7.1",
"@types/faker": "^5.1.3", "@types/faker": "^5.1.3",
"@types/node": "^12.12.64", "@types/node": "^12.12.64",
"@types/resize-observer-browser": "^0.1.5",
"@types/webpack-env": "^1.16.0", "@types/webpack-env": "^1.16.0",
"@typescript-eslint/eslint-plugin": "^4.22.0", "@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0", "@typescript-eslint/parser": "^4.22.0",

View File

@ -29,9 +29,11 @@
class="core-horizontal-scroll" class="core-horizontal-scroll"
(scroll)="scrollControls.updateScrollPosition()" (scroll)="scrollControls.updateScrollPosition()"
> >
<ng-container *ngFor="let course of courses"> <div (onResize)="scrollControls.updateScrollPosition()" class="flex-row">
<core-courses-course-progress [course]="course" class="core-recentlyaccessedcourses" <ng-container *ngFor="let course of courses">
[showDownload]="downloadCourseEnabled && downloadEnabled"></core-courses-course-progress> <core-courses-course-progress [course]="course" class="core-recentlyaccessedcourses"
</ng-container> [showDownload]="downloadCourseEnabled && downloadEnabled"></core-courses-course-progress>
</ng-container>
</div>
</div> </div>
</core-loading> </core-loading>

View File

@ -12,25 +12,27 @@
class="core-horizontal-scroll" class="core-horizontal-scroll"
(scroll)="scrollControls.updateScrollPosition()" (scroll)="scrollControls.updateScrollPosition()"
> >
<div *ngFor="let item of items"> <div *ngIf="items" (onResize)="scrollControls.updateScrollPosition()" class="flex-row">
<ion-card> <div *ngFor="let item of items">
<ion-item class="core-course-module-handler item-media ion-text-wrap" detail="false" (click)="action($event, item)" <ion-card>
button> <ion-item class="core-course-module-handler item-media ion-text-wrap" detail="false" (click)="action($event, item)"
<img slot="start" [src]="item.iconUrl" alt="" role="presentation" *ngIf="item.iconUrl" class="core-module-icon"> button>
<ion-label> <img slot="start" [src]="item.iconUrl" alt="" role="presentation" *ngIf="item.iconUrl" class="core-module-icon">
<!-- Add the icon title so accessibility tools read it. --> <ion-label>
<span class="sr-only" *ngIf="item.iconTitle">{{ item.iconTitle }}</span> <!-- Add the icon title so accessibility tools read it. -->
<h2> <span class="sr-only" *ngIf="item.iconTitle">{{ item.iconTitle }}</span>
<core-format-text [text]="item.name" contextLevel="module" [contextInstanceId]="item.cmid" <h2>
[courseId]="item.courseid"></core-format-text> <core-format-text [text]="item.name" contextLevel="module" [contextInstanceId]="item.cmid"
</h2> [courseId]="item.courseid"></core-format-text>
<p> </h2>
<core-format-text [text]="item.coursename" contextLevel="course" [contextInstanceId]="item.courseid"> <p>
</core-format-text> <core-format-text [text]="item.coursename" contextLevel="course" [contextInstanceId]="item.courseid">
</p> </core-format-text>
</ion-label> </p>
</ion-item> </ion-label>
</ion-card> </ion-item>
</ion-card>
</div>
</div> </div>
</div> </div>

View File

@ -1,7 +1,7 @@
@import "~theme/globals"; @import "~theme/globals";
:host { :host {
.core-horizontal-scroll > div { .core-horizontal-scroll > div > div {
@include horizontal_scroll_item(80%, 250px, 300px); @include horizontal_scroll_item(80%, 250px, 300px);
} }

View File

@ -30,9 +30,11 @@
class="core-horizontal-scroll" class="core-horizontal-scroll"
(scroll)="scrollControls.updateScrollPosition()" (scroll)="scrollControls.updateScrollPosition()"
> >
<ng-container *ngFor="let course of courses"> <div (onResize)="scrollControls.updateScrollPosition()" class="flex-row">
<core-courses-course-progress [course]="course" class="core-block_starredcourses" <ng-container *ngFor="let course of courses">
[showDownload]="downloadCourseEnabled && downloadEnabled"></core-courses-course-progress> <core-courses-course-progress [course]="course" class="core-block_starredcourses"
</ng-container> [showDownload]="downloadCourseEnabled && downloadEnabled"></core-courses-course-progress>
</ng-container>
</div>
</div> </div>
</core-loading> </core-loading>

View File

@ -25,6 +25,7 @@ import { CoreLongPressDirective } from './long-press';
import { CoreSupressEventsDirective } from './supress-events'; import { CoreSupressEventsDirective } from './supress-events';
import { CoreUserLinkDirective } from './user-link'; import { CoreUserLinkDirective } from './user-link';
import { CoreAriaButtonClickDirective } from './aria-button'; import { CoreAriaButtonClickDirective } from './aria-button';
import { CoreOnResizeDirective } from './on-resize';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -39,6 +40,7 @@ import { CoreAriaButtonClickDirective } from './aria-button';
CoreSupressEventsDirective, CoreSupressEventsDirective,
CoreUserLinkDirective, CoreUserLinkDirective,
CoreAriaButtonClickDirective, CoreAriaButtonClickDirective,
CoreOnResizeDirective,
], ],
exports: [ exports: [
CoreAutoFocusDirective, CoreAutoFocusDirective,
@ -52,6 +54,7 @@ import { CoreAriaButtonClickDirective } from './aria-button';
CoreSupressEventsDirective, CoreSupressEventsDirective,
CoreUserLinkDirective, CoreUserLinkDirective,
CoreAriaButtonClickDirective, CoreAriaButtonClickDirective,
CoreOnResizeDirective,
], ],
}) })
export class CoreDirectivesModule {} export class CoreDirectivesModule {}

View File

@ -0,0 +1,99 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Directive, ElementRef, OnInit, Output, EventEmitter, OnDestroy } from '@angular/core';
import { CoreUtils } from '@services/utils/utils';
/**
* Directive to listen for element resize events.
*/
@Directive({
selector: '[onResize]',
})
export class CoreOnResizeDirective implements OnInit, OnDestroy {
@Output() onResize = new EventEmitter();
private element: HTMLElement;
private resizeObserver?: ResizeObserver;
private mutationObserver?: MutationObserver;
constructor(element: ElementRef) {
this.element = element.nativeElement;
}
/**
* @inheritdoc
*/
ngOnInit(): void {
'ResizeObserver' in window
? this.watchResize()
: this.watchMutations();
}
/**
* @inheritdoc
*/
ngOnDestroy(): void {
this.resizeObserver?.disconnect();
this.mutationObserver?.disconnect();
}
/**
* Watch resize events.
*/
private watchResize(): void {
this.resizeObserver = new ResizeObserver(() => this.onResize.emit());
this.resizeObserver.observe(this.element);
}
/**
* Watch mutation events to detect resizing.
*/
private watchMutations(): void {
let size = this.getElementSize();
const onMutation = () => {
const newSize = this.getElementSize();
if (newSize.width !== size.width || newSize.height !== size.height) {
size = newSize;
this.onResize.emit();
}
};
// Debounce 20ms to let mutations resolve before checking the new size.
this.mutationObserver = new MutationObserver(CoreUtils.debounce(onMutation, 20));
this.mutationObserver.observe(this.element, {
subtree: true,
childList: true,
characterData: true,
});
}
/**
* Get element size.
*
* @returns Element size.
*/
private getElementSize(): { width: number; height: number } {
return {
width: this.element.clientWidth,
height: this.element.clientHeight,
};
}
}

View File

@ -8,6 +8,7 @@
"cordova", "cordova",
"dom-mediacapture-record", "dom-mediacapture-record",
"node", "node",
"resize-observer-browser",
"webpack-env" "webpack-env"
], ],
"paths": { "paths": {

View File

@ -27,6 +27,7 @@
"faker", "faker",
"jest", "jest",
"node", "node",
"resize-observer-browser",
"webpack-env" "webpack-env"
], ],
"paths": { "paths": {

View File

@ -12,7 +12,8 @@
"dom-mediacapture-record", "dom-mediacapture-record",
"faker", "faker",
"jest", "jest",
"node" "node",
"resize-observer-browser"
], ],
"paths": { "paths": {
"@addons/*": ["addons/*"], "@addons/*": ["addons/*"],