From d817747f8df76e39fab57aa8b668d451c9550058 Mon Sep 17 00:00:00 2001 From: Even Oscar Andersen Date: Thu, 27 Mar 2025 14:43:31 +0100 Subject: [PATCH] wasm: a11y - refactor set/get attribute/property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add setAttribute, setProperty, addEventHandler functions to reduce linelength and improve readability. Task-number: QTBUG-134657 Change-Id: I7deb1ac13872291b848c191198d741669d852e3a Reviewed-by: Morten Johan Sørvig --- .../platforms/wasm/qwasmaccessibility.cpp | 203 ++++++++++-------- .../platforms/wasm/qwasmaccessibility.h | 13 ++ 2 files changed, 126 insertions(+), 90 deletions(-) diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.cpp b/src/plugins/platforms/wasm/qwasmaccessibility.cpp index c58819923b3..10627370002 100644 --- a/src/plugins/platforms/wasm/qwasmaccessibility.cpp +++ b/src/plugins/platforms/wasm/qwasmaccessibility.cpp @@ -81,7 +81,7 @@ void QWasmAccessibility::addAccessibilityEnableButtonImpl(QWindow *window) emscripten::val container = getContainer(window); emscripten::val document = getDocument(container); emscripten::val button = document.call("createElement", std::string("button")); - button.set("innerText", std::string("Enable Screen Reader")); + setProperty(button, "innerText", "Enable Screen Reader"); button["classList"].call("add", emscripten::val("hidden-visually-read-by-screen-reader")); container.call("appendChild", button); @@ -163,6 +163,53 @@ emscripten::val QWasmAccessibility::getDocument(QAccessibleInterface *iface) return getDocument(getContainer(iface)); } +void QWasmAccessibility::setAttribute(emscripten::val element, const std::string &attr, + const std::string &val) +{ + if (val != "") + element.call("setAttribute", attr, val); + else + element.call("removeAttribute", attr); +} + +void QWasmAccessibility::setAttribute(emscripten::val element, const std::string &attr, + const char *val) +{ + setAttribute(element, attr, std::string(val)); +} + +void QWasmAccessibility::setAttribute(emscripten::val element, const std::string &attr, bool val) +{ + if (val) + element.call("setAttribute", attr, val); + else + element.call("removeAttribute", attr); +} + +void QWasmAccessibility::setProperty(emscripten::val element, const std::string &property, + const std::string &val) +{ + element.set(property, val); +} + +void QWasmAccessibility::setProperty(emscripten::val element, const std::string &property, const char *val) +{ + setProperty(element, property, std::string(val)); +} + +void QWasmAccessibility::setProperty(emscripten::val element, const std::string &property, bool val) +{ + element.set(property, val); +} + + +void QWasmAccessibility::addEventListener(emscripten::val element, const char *eventType) +{ + element.call("addEventListener", emscripten::val(eventType), + QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex), + true); +} + emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *iface) { // Get the html container element for the interface; this depends on which @@ -185,54 +232,45 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac case QAccessible::Button: { element = document.call("createElement", std::string("button")); - - element.call("addEventListener", emscripten::val("click"), - QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex), true); - + addEventListener(element, "click"); } break; case QAccessible::CheckBox: { element = document.call("createElement", std::string("input")); - element.call("setAttribute", std::string("type"), std::string("checkbox")); - if (iface->state().checked) { - element.call("setAttribute", std::string("checked"), std::string("true")); - } - element.call("addEventListener", emscripten::val("change"), - QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex), true); + setAttribute(element, "type", "checkbox"); + setAttribute(element, "checked", iface->state().checked); + addEventListener(element, "change"); } break; case QAccessible::RadioButton: { element = document.call("createElement", std::string("input")); - element.call("setAttribute", std::string("type"), std::string("radio")); - if (iface->state().checked) { - element.call("setAttribute", std::string("checked"), std::string("true")); - } - element.set(std::string("name"), std::string("buttonGroup")); - element.call("addEventListener", emscripten::val("change"), - QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex), true); + setAttribute(element, "type", "radio"); + setAttribute(element, "checked", iface->state().checked); + setProperty(element, "name", "buttonGroup"); + addEventListener(element, "change"); } break; case QAccessible::SpinBox: { + const std::string valueString = + iface->valueInterface()->currentValue().toString().toStdString(); element = document.call("createElement", std::string("input")); - element.call("setAttribute", std::string("type"), std::string("number")); - std::string valueString = iface->valueInterface()->currentValue().toString().toStdString(); - element.call("setAttribute", std::string("value"), valueString); - element.call("addEventListener", emscripten::val("change"), - QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex), true); + setAttribute(element, "type", "number"); + setAttribute(element, "value", valueString); + addEventListener(element, "change"); } break; case QAccessible::Slider: { + const std::string valueString = + iface->valueInterface()->currentValue().toString().toStdString(); element = document.call("createElement", std::string("input")); - element.call("setAttribute", std::string("type"), std::string("range")); - std::string valueString = iface->valueInterface()->currentValue().toString().toStdString(); - element.call("setAttribute", std::string("value"), valueString); - element.call("addEventListener", emscripten::val("change"), - QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex), true); + setAttribute(element, "type", "range"); + setAttribute(element, "value", valueString); + addEventListener(element, "change"); } break; case QAccessible::PageTabList:{ element = document.call("createElement", std::string("div")); - element.call("setAttribute", std::string("role"), std::string("tablist")); + setAttribute(element, "role", "tablist"); for (int i = 0; i < iface->childCount(); ++i) { if (iface->child(i)->role() == QAccessible::PageTab){ @@ -244,79 +282,70 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac } break; case QAccessible::PageTab:{ + const QString text = iface->text(QAccessible::Name); element = document.call("createElement", std::string("button")); - element.call("setAttribute", std::string("role"), std::string("tab")); - QString text = iface->text(QAccessible::Name); - element.call("setAttribute", std::string("title"), text.toStdString()); - element.call("addEventListener", emscripten::val("click"), - QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex), true); + setAttribute(element, "role", "tab"); + setAttribute(element, "title", text.toStdString()); + addEventListener(element, "click"); } break; case QAccessible::ScrollBar: { + const std::string valueString = + iface->valueInterface()->currentValue().toString().toStdString(); element = document.call("createElement", std::string("div")); - element.call("setAttribute", std::string("role"), std::string("scrollbar")); - std::string valueString = iface->valueInterface()->currentValue().toString().toStdString(); - element.call("setAttribute", std::string("aria-valuenow"), valueString); - element.call("addEventListener", emscripten::val("change"), - QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex), true); + setAttribute(element, "role", "scrollbar"); + setAttribute(element, "aria-valuenow", valueString); + addEventListener(element, "change"); } break; case QAccessible::StaticText: { element = document.call("createElement", std::string("textarea")); - element.call("setAttribute", std::string("readonly"), std::string("true")); + setAttribute(element, "readonly", "true"); } break; case QAccessible::Dialog: { element = document.call("createElement", std::string("dialog")); }break; case QAccessible::ToolBar:{ + const QString text = iface->text(QAccessible::Name); element = document.call("createElement", std::string("div")); - QString text = iface->text(QAccessible::Name); - - element.call("setAttribute", std::string("role"), std::string("toolbar")); - element.call("setAttribute", std::string("title"), text.toStdString()); - element.call("addEventListener", emscripten::val("click"), - QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex), true); + setAttribute(element, "role", "toolbar"); + setAttribute(element, "title", text.toStdString()); + addEventListener(element, "click"); }break; case QAccessible::MenuItem: case QAccessible::ButtonMenu: { + const QString text = iface->text(QAccessible::Name); element = document.call("createElement", std::string("button")); - QString text = iface->text(QAccessible::Name); - - element.call("setAttribute", std::string("role"), std::string("menuitem")); - element.call("setAttribute", std::string("title"), text.toStdString()); - element.call("addEventListener", emscripten::val("click"), - QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex), true); + setAttribute(element, "role", "menuitem"); + setAttribute(element, "title", text.toStdString()); + addEventListener(element, "click"); }break; case QAccessible::MenuBar: case QAccessible::PopupMenu: { - element = document.call("createElement",std::string("div")); - QString text = iface->text(QAccessible::Name); - element.call("setAttribute", std::string("role"), std::string("menubar")); - element.call("setAttribute", std::string("title"), text.toStdString()); - for (int i = 0; i < iface->childCount(); ++i) { + const QString text = iface->text(QAccessible::Name); + element = document.call("createElement", std::string("div")); + setAttribute(element, "role", "menubar"); + setAttribute(element, "title", text.toStdString()); + for (int i = 0; i < iface->childCount(); ++i) { emscripten::val childElement = emscripten::val::undefined(); childElement= ensureHtmlElement(iface->child(i)); - childElement.call("setAttribute", std::string("aria-owns"), text.toStdString()); + setAttribute(childElement, "aria-owns", text.toStdString()); setHtmlElementTextName(iface->child(i)); setHtmlElementGeometry(iface->child(i)); - } + } }break; case QAccessible::EditableText: { element = document.call("createElement", std::string("input")); - element.call("setAttribute", std::string("type"),std::string("text")); - element.call("addEventListener", emscripten::val("input"), - QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex), true); + setAttribute(element, "type", "text"); + addEventListener(element, "input"); } break; default: qCDebug(lcQpaAccessibility) << "TODO: createHtmlElement() handle" << iface->role(); element = document.call("createElement", std::string("div")); } - element.call("addEventListener", emscripten::val("focus"), - QWasmSuspendResumeControl::get()->jsEventHandlerAt(m_eventHandlerIndex), - true); - + addEventListener(element, "focus"); return element; }(); @@ -360,7 +389,7 @@ void QWasmAccessibility::setHtmlElementVisibility(QAccessibleInterface *iface, b container.call("appendChild", element); visible = visible && !iface->state().invisible && !iface->state().disabled; - element.set("ariaHidden", !visible); // ariaHidden mean completely hidden; maybe some sort of soft-hidden should be used. + setProperty(element, "ariaHidden", !visible); // ariaHidden mean completely hidden; maybe some sort of soft-hidden should be used. } void QWasmAccessibility::setHtmlElementGeometry(QAccessibleInterface *iface) @@ -397,24 +426,21 @@ void QWasmAccessibility::setHtmlElementTextName(QAccessibleInterface *iface) { emscripten::val element = ensureHtmlElement(iface); const QString name = iface->text(QAccessible::Name); - if (name.isEmpty()) - element.call("removeAttribute", std::string("aria-label")); - else - element.call("setAttribute", std::string("aria-label"), name.toStdString()); + setAttribute(element, "aria-label", name.toStdString()); } void QWasmAccessibility::setHtmlElementTextNameLE(QAccessibleInterface *iface) { emscripten::val element = ensureHtmlElement(iface); QString text = iface->text(QAccessible::Name); - element.call("setAttribute", std::string("name"), text.toStdString()); + setAttribute(element, "name", text.toStdString()); QString value = iface->text(QAccessible::Value); - element.set("innerHTML", value.toStdString()); + setProperty(element, "innerHTML", value.toStdString()); } void QWasmAccessibility::setHtmlElementDescription(QAccessibleInterface *iface) { emscripten::val element = ensureHtmlElement(iface); QString desc = iface->text(QAccessible::Description); - element.call("setAttribute", std::string("aria-description"), desc.toStdString()); + setAttribute(element, "aria-description", desc.toStdString()); } void QWasmAccessibility::setHtmlElementFocus(QAccessibleInterface *iface) @@ -438,8 +464,8 @@ void QWasmAccessibility::handleStaticTextUpdate(QAccessibleEvent *event) } } -void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event) { - +void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event) +{ switch (event->type()) { case QAccessible::NameChanged: { setHtmlElementTextName(event->accessibleInterface()); @@ -515,8 +541,8 @@ void QWasmAccessibility::handleCheckBoxUpdate(QAccessibleEvent *event) case QAccessible::StateChanged: { QAccessibleInterface *accessible = event->accessibleInterface(); emscripten::val element = ensureHtmlElement(accessible); - bool checkedString = accessible->state().checked ? true : false; - element.call("setAttribute", std::string("checked"), checkedString); + + setAttribute(element, "checked", accessible->state().checked); } break; case QAccessible::DescriptionChanged: { setHtmlElementDescription(event->accessibleInterface()); @@ -535,7 +561,7 @@ void QWasmAccessibility::handleToolUpdate(QAccessibleEvent *event) case QAccessible::NameChanged: case QAccessible::StateChanged:{ emscripten::val element = ensureHtmlElement(iface); - element.call("setAttribute", std::string("title"), text.toStdString()); + setAttribute(element, "title", text.toStdString()); } break; case QAccessible::DescriptionChanged: { setHtmlElementDescription(event->accessibleInterface()); @@ -556,7 +582,7 @@ void QWasmAccessibility::handleMenuUpdate(QAccessibleEvent *event) case QAccessible::MenuStart ://"TODO: To implement later case QAccessible::StateChanged:{ emscripten::val element = ensureHtmlElement(iface); - element.call("setAttribute", std::string("title"), text.toStdString()); + setAttribute(element, "title", text.toStdString()); } break; case QAccessible::PopupMenuStart: { ensureHtmlElement(iface); @@ -622,8 +648,7 @@ void QWasmAccessibility::handleRadioButtonUpdate(QAccessibleEvent *event) case QAccessible::StateChanged: { QAccessibleInterface *accessible = event->accessibleInterface(); emscripten::val element = ensureHtmlElement(accessible); - std::string checkedString = accessible->state().checked ? "true" : "false"; - element.call("setAttribute", std::string("checked"), checkedString); + setAttribute(element, "checked", accessible->state().checked); } break; case QAccessible::DescriptionChanged: { setHtmlElementDescription(event->accessibleInterface()); @@ -645,11 +670,12 @@ void QWasmAccessibility::handleSpinBoxUpdate(QAccessibleEvent *event) QAccessibleInterface *accessible = event->accessibleInterface(); emscripten::val element = ensureHtmlElement(accessible); std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString(); - element.call("setAttribute", std::string("value"), valueString); + setAttribute(element, "value", valueString); } break; case QAccessible::DescriptionChanged: { setHtmlElementDescription(event->accessibleInterface()); } break; + default: qDebug() << "TODO: implement handleSpinBoxUpdate for event" << event->type(); break; @@ -667,7 +693,7 @@ void QWasmAccessibility::handleSliderUpdate(QAccessibleEvent *event) QAccessibleInterface *accessible = event->accessibleInterface(); emscripten::val element = ensureHtmlElement(accessible); std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString(); - element.call("setAttribute", std::string("value"), valueString); + setAttribute(element, "value", valueString); } break; case QAccessible::DescriptionChanged: { setHtmlElementDescription(event->accessibleInterface()); @@ -689,7 +715,7 @@ void QWasmAccessibility::handleScrollBarUpdate(QAccessibleEvent *event) QAccessibleInterface *accessible = event->accessibleInterface(); emscripten::val element = ensureHtmlElement(accessible); std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString(); - element.call("setAttribute", std::string("aria-valuenow"), valueString); + setAttribute(element, "aria-valuenow", valueString); } break; case QAccessible::DescriptionChanged: { setHtmlElementDescription(event->accessibleInterface()); @@ -747,17 +773,14 @@ void QWasmAccessibility::handleIdentifierUpdate(QAccessibleInterface *iface) id = QString::fromUtf8(oss.str()); } + setAttribute(element, "id", id.toStdString()); if (!id.isEmpty()) { - element.call("setAttribute", std::string("id"), id.toStdString()); - if (iface->role() == QAccessible::PageTabList) { for (int i = 0; i < iface->childCount(); ++i) { auto child = ensureHtmlElement(iface->child(i)); - child.call("setAttribute", std::string("aria-owns"), id.toStdString()); + setAttribute(child, "aria-owns", id.toStdString()); } } - } else { - element.call("removeAttribute", std::string("id")); } } diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.h b/src/plugins/platforms/wasm/qwasmaccessibility.h index 2f8d55a8f99..aba39a7ca84 100644 --- a/src/plugins/platforms/wasm/qwasmaccessibility.h +++ b/src/plugins/platforms/wasm/qwasmaccessibility.h @@ -79,6 +79,19 @@ private: void initialize() override; void cleanup() override; + void setAttribute(emscripten::val element, const std::string &attr, const std::string &val); + void setAttribute(emscripten::val element, const std::string &attr, const char *val); + void setAttribute(emscripten::val element, const std::string &attr, bool val); + + void setProperty(emscripten::val element, const std::string &attr, const std::string &val); + void setProperty(emscripten::val element, const std::string &attr, const char *val); + void setProperty(emscripten::val element, const std::string &attr, bool val); + + void addEventListener(emscripten::val element, const char *eventType); + +public: // public for EMSCRIPTEN_BINDINGS + static void onHtmlEventReceived(emscripten::val event); + private: static QWasmAccessibility *s_instance; QObject *m_rootObject = nullptr;