Skip to content

Commit

Permalink
Merge pull request #4291 from albertgasset/MOBILE-4595
Browse files Browse the repository at this point in the history
MOBILE-4595: WCAG 2.1 AA accessibility accreditation for version 4.5
  • Loading branch information
dpalou authored Jan 22, 2025
2 parents d05c11e + 6fa9d50 commit fba73ec
Show file tree
Hide file tree
Showing 81 changed files with 823 additions and 323 deletions.
3 changes: 2 additions & 1 deletion config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@
<preference name="prerendered-icon" value="true" />
<preference name="AppendUserAgent" value="MoodleMobile 5.0.0 (50000)" />
<preference name="BackupWebStorage" value="none" />
<preference name="ScrollEnabled" value="false" />
<preference name="ScrollEnabled" value="true" />
<preference name="KeyboardDisplayRequiresUserAction" value="false" />
<preference name="HideKeyboardFormAccessoryBar" value="false" />
<preference name="KeyboardResizeMode" value="ionic" />
<preference name="AllowInlineMediaPlayback" value="true" />
<preference name="LoadUrlTimeoutValue" value="60000" />
<preference name="load-url-timeout" value="60000" />
Expand Down
5 changes: 5 additions & 0 deletions cordova-plugin-moodleapp/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
<param name="android-package" value="com.moodle.moodlemobile.Diagnostic_Location"/>
<param name="onload" value="true" />
</feature>
<feature name="PinchToZoom">
<param name="android-package" value="com.moodle.moodlemobile.PinchToZoom"/>
<param name="onload" value="true" />
</feature>
</config-file>

<source-file src="src/android/Diagnostic.java" target-dir="src/cordova/plugins" />
Expand All @@ -37,6 +41,7 @@

<source-file src="src/android/SecureStorage.java" target-dir="src/com/moodle/moodlemobile" />
<source-file src="src/android/InstallReferrer.java" target-dir="src/com/moodle/moodlemobile" />
<source-file src="src/android/PinchToZoom.java" target-dir="src/com/moodle/moodlemobile" />
</platform>

<platform name="ios">
Expand Down
42 changes: 42 additions & 0 deletions cordova-plugin-moodleapp/src/android/PinchToZoom.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// (C) Copyright 2025 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.

package com.moodle.moodlemobile;

import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;

import android.util.Log;
import android.webkit.WebSettings;
import android.webkit.WebSettings.ZoomDensity;
import android.webkit.WebView;

public class PinchToZoom extends CordovaPlugin {

public static final String TAG = "PinchToZoom";

@Override
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
Log.d(TAG, "Initializing pinch-to-zoom");

super.initialize(cordova, webView);

WebSettings settings = ((WebView) webView.getView()).getSettings();
settings.setBuiltInZoomControls(true);
settings.setDefaultZoom(WebSettings.ZoomDensity.MEDIUM);
settings.setDisplayZoomControls(false);
settings.setSupportZoom(true);
}
}
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,10 @@
"cordova-plugin-local-notification": {
"ANDROID_SUPPORT_V4_VERSION": "26.+"
},
"cordova-plugin-moodleapp": {},
"cordova-plugin-moodleapp": {
"ANDROIDX_VERSION": "1.0.0",
"ANDROIDX_APPCOMPAT_VERSION": "1.3.1"
},
"cordova-plugin-network-information": {},
"cordova-plugin-prevent-override": {},
"cordova-plugin-screen-orientation": {},
Expand All @@ -238,4 +241,4 @@
"nl.kingsquare.cordova.background-audio": {}
}
}
}
}
45 changes: 45 additions & 0 deletions patches/@ionic+core+8.4.1.patch
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,48 @@ index c3d2d8e..bc40d4f 100644
const root = getElementRoot(baseEl);
const contentEl = root.querySelector('.popover-content');
const referenceSizeEl = trigger || ((_a = ev === null || ev === void 0 ? void 0 : ev.detail) === null || _a === void 0 ? void 0 : _a.ionShadowTarget) || (ev === null || ev === void 0 ? void 0 : ev.target);
diff --git a/node_modules/@ionic/core/dist/esm/input-shims-0314bbe5.js b/node_modules/@ionic/core/dist/esm/input-shims-0314bbe5.js
index dd9d410..846146f 100644
--- a/node_modules/@ionic/core/dist/esm/input-shims-0314bbe5.js
+++ b/node_modules/@ionic/core/dist/esm/input-shims-0314bbe5.js
@@ -338,7 +338,8 @@ const enableScrollAssist = (componentEl, inputEl, contentEl, footerEl, keyboardH
const focusOut = () => {
hasKeyboardBeenPresentedForTextField = false;
win === null || win === void 0 ? void 0 : win.removeEventListener('ionKeyboardDidShow', keyboardShow);
- componentEl.removeEventListener('focusout', focusOut);
+ // Patched: Attach focusin/focusout events to inputEl instead of componentEl to allow focusing buttons inside <ion-input>.
+ inputEl.removeEventListener('focusout', focusOut);
};
/**
* When the input is about to receive
@@ -358,13 +358,15 @@ const enableScrollAssist = (componentEl, inputEl, contentEl, footerEl, keyboardH
}
jsSetFocus(componentEl, inputEl, contentEl, footerEl, keyboardHeight, addScrollPadding, disableClonedInput, platformHeight);
win === null || win === void 0 ? void 0 : win.addEventListener('ionKeyboardDidShow', keyboardShow);
- componentEl.addEventListener('focusout', focusOut);
+ // Patched: Attach focusin/focusout events to inputEl instead of componentEl to allow focusing buttons inside <ion-input>.
+ inputEl.addEventListener('focusout', focusOut);
};
- componentEl.addEventListener('focusin', focusIn);
+ // Patched: Attach focusin/focusout events to inputEl instead of componentEl to allow focusing buttons inside <ion-input>.
+ inputEl.addEventListener('focusin', focusIn);
return () => {
- componentEl.removeEventListener('focusin', focusIn);
+ inputEl.removeEventListener('focusin', focusIn);
win === null || win === void 0 ? void 0 : win.removeEventListener('ionKeyboardDidShow', keyboardShow);
- componentEl.removeEventListener('focusout', focusOut);
+ inputEl.removeEventListener('focusout', focusOut);
};
};
/**
--- a/node_modules/@ionic/core/dist/esm/ion-item_8.entry.js
+++ b/node_modules/@ionic/core/dist/esm/ion-item_8.entry.js
@@ -109,7 +109,7 @@ const Item = class {
// inputs, then those need to individually get each click
hasCover() {
const inputs = this.el.querySelectorAll('ion-checkbox, ion-datetime, ion-select, ion-radio');
- return inputs.length === 1 && !this.multipleInputs;
+ return inputs.length === 1;
}
// If the item has an href or button property it will render a native
// anchor or button that is clickable
4 changes: 4 additions & 0 deletions scripts/langindex.json
Original file line number Diff line number Diff line change
Expand Up @@ -1743,6 +1743,7 @@
"core.decsep": "langconfig",
"core.defaultvalue": "tool_usertours",
"core.delete": "moodle",
"core.deleted": "moodle",
"core.deletedoffline": "local_moodlemobileapp",
"core.deleteduser": "bulkusers",
"core.deleting": "local_moodlemobileapp",
Expand Down Expand Up @@ -2165,6 +2166,7 @@
"core.login.login": "moodle",
"core.login.loginbutton": "local_moodlemobileapp",
"core.login.loginsteps": "moodle",
"core.login.logoof": "moodle",
"core.login.missingemail": "moodle",
"core.login.missingfirstname": "moodle",
"core.login.missinglastname": "moodle",
Expand Down Expand Up @@ -2450,6 +2452,7 @@
"core.selectall": "moodle",
"core.send": "message",
"core.sending": "chat",
"core.sent": "moodle",
"core.serverconnection": "local_moodlemobileapp",
"core.settings.about": "local_moodlemobileapp",
"core.settings.accessstatement": "access",
Expand Down Expand Up @@ -2487,6 +2490,7 @@
"core.settings.enableanalytics": "local_moodlemobileapp",
"core.settings.enableanalyticsdescription": "local_moodlemobileapp",
"core.settings.enabledownloadsection": "local_moodlemobileapp",
"core.settings.enablepinchtozoom": "local_moodlemobileapp",
"core.settings.enablerichtexteditor": "local_moodlemobileapp",
"core.settings.enablerichtexteditordescription": "local_moodlemobileapp",
"core.settings.encryptedpushsupported": "local_moodlemobileapp",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,12 @@ <h2>{{ 'addon.block_myoverview.pluginname' | translate }}</h2>
</ion-row>

<core-empty-box *ngIf="filteredCourses.length === 0" image="assets/img/icons/courses.svg">
<p *ngIf="hasCourses" class="item-heading">
<h3 *ngIf="hasCourses" class="item-heading">
{{'addon.block_myoverview.noresult' | translate}}
</p>
<p *ngIf="!hasCourses" class="item-heading">
</h3>
<h3 *ngIf="!hasCourses" class="item-heading">
{{'addon.block_myoverview.nocoursesenrolled' | translate}}
</p>
</h3>
<ng-container *ngIf="searchEnabled">
<p *ngIf="hasCourses" class="subdued">
{{'addon.block_myoverview.noresultdescription' | translate}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

core-empty-box {
.item-heading {
font-size: 1rem;
font-weight: bold;
margin-bottom: 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ <h3>
<ion-item-group *ngFor="let dayEvents of events">
<ion-item>
<ion-label>
<h4>{{ dayEvents.dayTimestamp * 1000 | coreFormatDate:"strftimedaydate" }}</h4>
@if (course) {
<h3><ng-container *ngTemplateOutlet="date" /></h3>
} @else {
<h4><ng-container *ngTemplateOutlet="date" /></h4>
}
<ng-template #date>
{{ dayEvents.dayTimestamp * 1000 | coreFormatDate:"strftimedaydate" }}
</ng-template>
</ion-label>
</ion-item>
<ng-container *ngFor="let event of dayEvents.events">
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
131 changes: 68 additions & 63 deletions src/addons/mod/forum/components/index/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -84,70 +84,75 @@
<p>{{ 'addon.mod_forum.errorloadingsortingorderdetails' | translate }}</p>
</core-empty-box>

<ion-item *ngFor="let discussion of discussionsItems" class="addon-mod-forum-discussion" [detail]="true"
[lines]="discussion.groupname && 'none'" [attr.aria-current]="discussions?.getItemAriaCurrent(discussion)"
(click)="discussions?.select(discussion)" button>
<ion-label>
<p class="addon-mod-forum-discussion-title ion-text-wrap item-heading">
<ion-icon name="fas-map-pin" *ngIf="discussion.pinned"
[attr.aria-label]="'addon.mod_forum.discussionpinned' | translate" />
<ion-icon name="fas-star" class="addon-forum-star" *ngIf="discussion.starred"
[attr.aria-label]="'addon.mod_forum.favourites' | translate" />
<core-format-text [text]="discussion.subject" contextLevel="module" [contextInstanceId]="module && module.id"
[courseId]="courseId" />
<ion-icon name="fas-lock" *ngIf="discussion.locked" class="addon-mod-forum-locked-icon"
[attr.aria-label]="'addon.mod_forum.discussionlocked' | translate" />
</p>
<div class="addon-mod-forum-discussion-info">
<core-user-avatar *ngIf="discussion.userfullname" [user]="discussion" slot="start" [courseId]="courseId"
[linkProfile]="false" />
<div class="addon-mod-forum-discussion-author">
<span *ngIf="discussion.userfullname" class="core-discussionusername">{{discussion.userfullname}}</span>
<p *ngIf="discussion.groupname" class="core-groupname">
<ion-icon name="fas-users" [attr.aria-label]="'addon.mod_forum.group' | translate" />
<core-format-text [text]="discussion.groupname" contextLevel="course" [contextInstanceId]="courseId"
[wsNotFiltered]="true" />
</p>
<p *ngIf="isOnlineDiscussion(discussion)">
{{discussion.created * 1000 | coreFormatDate: "strftimerecentfull"}}
</p>
<p *ngIf="isOfflineDiscussion(discussion)">
<ion-icon name="fas-clock" aria-hidden="true" />
{{ 'core.notsent' | translate }}
</p>
<div *ngFor="let discussion of discussionsItems" class="ion-activatable ripple-parent">
<ion-item class="addon-mod-forum-discussion" [detail]="true" [lines]="discussion.groupname && 'none'"
[attr.aria-current]="discussions?.getItemAriaCurrent(discussion)" (click)="discussions?.select(discussion)" tappable>
<ion-label>
<p class="addon-mod-forum-discussion-title ion-text-wrap item-heading">
<ion-icon name="fas-map-pin" *ngIf="discussion.pinned"
[attr.aria-label]="'addon.mod_forum.discussionpinned' | translate" />
<ion-icon name="fas-star" class="addon-forum-star" *ngIf="discussion.starred"
[attr.aria-label]="'addon.mod_forum.favourites' | translate" />
<span (ariaButtonClick)="discussions?.select(discussion)">
<core-format-text [text]="discussion.subject" contextLevel="module"
[contextInstanceId]="module && module.id" [courseId]="courseId" />
</span>
<ion-icon name="fas-lock" *ngIf="discussion.locked" class="addon-mod-forum-locked-icon"
[attr.aria-label]="'addon.mod_forum.discussionlocked' | translate" />
</p>
<div class="addon-mod-forum-discussion-info">
<core-user-avatar *ngIf="discussion.userfullname" [user]="discussion" slot="start" [courseId]="courseId"
[linkProfile]="false" />
<div class="addon-mod-forum-discussion-author">
<span *ngIf="discussion.userfullname" class="core-discussionusername">{{discussion.userfullname}}</span>
<p *ngIf="discussion.groupname" class="core-groupname">
<ion-icon name="fas-users" [attr.aria-label]="'addon.mod_forum.group' | translate" />
<core-format-text [text]="discussion.groupname" contextLevel="course" [contextInstanceId]="courseId"
[wsNotFiltered]="true" />
</p>
<p *ngIf="isOnlineDiscussion(discussion)">
{{discussion.created * 1000 | coreFormatDate: "strftimerecentfull"}}
</p>
<p *ngIf="isOfflineDiscussion(discussion)">
<ion-icon name="fas-clock" aria-hidden="true" />
{{ 'core.notsent' | translate }}
</p>
</div>
</div>
</div>
<ion-row *ngIf="isOnlineDiscussion(discussion)" class="ion-text-center addon-mod-forum-discussion-more-info">
<ion-col class="ion-text-start">
<ion-note>
<ion-icon name="fas-clock" aria-hidden="true" /> {{ 'addon.mod_forum.lastpost' | translate }}
<ng-container *ngIf="discussion.timemodified > discussion.created">
{{ discussion.timemodified | coreTimeAgo }}
</ng-container>
<ng-container *ngIf="discussion.timemodified <= discussion.created">
{{ discussion.created | coreTimeAgo }}
</ng-container>
</ion-note>
</ion-col>
<ion-col class="ion-text-end">
<ion-note>
<ion-icon name="fas-comments" aria-hidden="true" />
{{ 'addon.mod_forum.numreplies' | translate:{numreplies: discussion.numreplies} }}
<ion-badge *ngIf="discussion.numunread" class="ion-text-center">
<span aria-hidden="true">{{ discussion.numunread }}</span>
<span class="sr-only">
{{ 'addon.mod_forum.unreadpostsnumber' | translate:{ '$a' : discussion.numunread} }}
</span>
</ion-badge>
</ion-note>
</ion-col>
</ion-row>
</ion-label>
<ion-button *ngIf="canPin || discussion.canlock || discussion.canfavourite" fill="clear"
[ariaLabel]="('core.displayoptions' | translate)" (click)="showOptionsMenu($event, discussion)" slot="end">
<ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true" />
</ion-button>
</ion-item>
<ion-row *ngIf="isOnlineDiscussion(discussion)" class="ion-text-center addon-mod-forum-discussion-more-info">
<ion-col class="ion-text-start">
<ion-note>
<ion-icon name="fas-clock" aria-hidden="true" /> {{ 'addon.mod_forum.lastpost' | translate }}
<ng-container *ngIf="discussion.timemodified > discussion.created">
{{ discussion.timemodified | coreTimeAgo }}
</ng-container>
<ng-container *ngIf="discussion.timemodified <= discussion.created">
{{ discussion.created | coreTimeAgo }}
</ng-container>
</ion-note>
</ion-col>
<ion-col class="ion-text-end">
<ion-note>
<ion-icon name="fas-comments" aria-hidden="true" />
{{ 'addon.mod_forum.numreplies' | translate:{numreplies: discussion.numreplies} }}
<ion-badge *ngIf="discussion.numunread" class="ion-text-center">
<span aria-hidden="true">{{ discussion.numunread }}</span>
<span class="sr-only">
{{ 'addon.mod_forum.unreadpostsnumber' | translate:{ '$a' : discussion.numunread} }}
</span>
</ion-badge>
</ion-note>
</ion-col>
</ion-row>
</ion-label>
<ion-button *ngIf="canPin || discussion.canlock || discussion.canfavourite" fill="clear"
[ariaLabel]="('core.displayoptions' | translate)" (click)="showOptionsMenu($event, discussion)" slot="end">
<ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true" />
</ion-button>
</ion-item>
<ion-ripple-effect />
</div>


<core-infinite-loading [enabled]="discussions && discussions.loaded && !discussions.completed" [error]="fetchFailed"
(action)="fetchMoreDiscussions($event)" />
Expand Down
Loading

0 comments on commit fba73ec

Please sign in to comment.