Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  browser_text_input.js   Sprache: JAVA

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


"use strict";

/* import-globals-from ../../mochitest/role.js */
/* import-globals-from ../../mochitest/states.js */
loadScripts(
  { name: "role.js", dir: MOCHITESTS_DIR },
  { name: "states.js", dir: MOCHITESTS_DIR }
);

function testValueChangedEventData(
  macIface,
  data,
  expectedId,
  expectedChangeValue,
  expectedEditType,
  expectedWordAtLeft
) {
  is(
    data.AXTextChangeElement.getAttributeValue("AXDOMIdentifier"),
    expectedId,
    "Correct AXTextChangeElement"
  );
  is(
    data.AXTextStateChangeType,
    AXTextStateChangeTypeEdit,
    "Correct AXTextStateChangeType"
  );

  let changeValues = data.AXTextChangeValues;
  is(changeValues.length, 1, "One element in AXTextChangeValues");
  is(
    changeValues[0].AXTextChangeValue,
    expectedChangeValue,
    "Correct AXTextChangeValue"
  );
  is(
    changeValues[0].AXTextEditType,
    expectedEditType,
    "Correct AXTextEditType"
  );

  let textMarker = changeValues[0].AXTextChangeValueStartMarker;
  ok(textMarker, "There is a AXTextChangeValueStartMarker");
  let range = macIface.getParameterizedAttributeValue(
    "AXLeftWordTextMarkerRangeForTextMarker",
    textMarker
  );
  let str = macIface.getParameterizedAttributeValue(
    "AXStringForTextMarkerRange",
    range,
    "correct word before caret"
  );
  is(str, expectedWordAtLeft);
}

// Return true if the first given object a subset of the second
function isSubset(subset, superset) {
  if (typeof subset != "object" || typeof superset != "object") {
    return superset == subset;
  }

  for (let [prop, val] of Object.entries(subset)) {
    if (!isSubset(val, superset[prop])) {
      return false;
    }
  }

  return true;
}

function matchWebArea(expectedId, expectedInfo) {
  return (iface, data) => {
    if (!data) {
      return false;
    }

    let textChangeElemID =
      data.AXTextChangeElement.getAttributeValue("AXDOMIdentifier");

    return (
      iface.getAttributeValue("AXRole") == "AXWebArea" &&
      textChangeElemID == expectedId &&
      isSubset(expectedInfo, data)
    );
  };
}

function matchInput(expectedId, expectedInfo) {
  return (iface, data) => {
    if (!data) {
      return false;
    }

    return (
      iface.getAttributeValue("AXDOMIdentifier") == expectedId &&
      isSubset(expectedInfo, data)
    );
  };
}

async function synthKeyAndTestSelectionChanged(
  synthKey,
  synthEvent,
  expectedId,
  expectedSelectionString,
  expectedSelectionInfo
) {
  let selectionChangedEvents = Promise.all([
    waitForMacEventWithInfo(
      "AXSelectedTextChanged",
      matchWebArea(expectedId, expectedSelectionInfo)
    ),
    waitForMacEventWithInfo(
      "AXSelectedTextChanged",
      matchInput(expectedId, expectedSelectionInfo)
    ),
  ]);

  EventUtils.synthesizeKey(synthKey, synthEvent);
  let [webareaEvent, inputEvent] = await selectionChangedEvents;
  is(
    inputEvent.data.AXTextChangeElement.getAttributeValue("AXDOMIdentifier"),
    expectedId,
    "Correct AXTextChangeElement"
  );

  let rangeString = inputEvent.macIface.getParameterizedAttributeValue(
    "AXStringForTextMarkerRange",
    inputEvent.data.AXSelectedTextMarkerRange
  );
  is(
    rangeString,
    expectedSelectionString,
    `selection has correct value (${expectedSelectionString})`
  );

  is(
    webareaEvent.macIface.getAttributeValue("AXDOMIdentifier"),
    "body",
    "Input event target is top-level WebArea"
  );
  rangeString = webareaEvent.macIface.getParameterizedAttributeValue(
    "AXStringForTextMarkerRange",
    inputEvent.data.AXSelectedTextMarkerRange
  );
  is(
    rangeString,
    expectedSelectionString,
    `selection has correct value (${expectedSelectionString}) via top document`
  );

  return inputEvent;
}

function testSelectionEventLeftChar(event, expectedChar) {
  const selStart = event.macIface.getParameterizedAttributeValue(
    "AXStartTextMarkerForTextMarkerRange",
    event.data.AXSelectedTextMarkerRange
  );
  const selLeft = event.macIface.getParameterizedAttributeValue(
    "AXPreviousTextMarkerForTextMarker",
    selStart
  );
  const leftCharRange = event.macIface.getParameterizedAttributeValue(
    "AXTextMarkerRangeForUnorderedTextMarkers",
    [selLeft, selStart]
  );
  const leftCharString = event.macIface.getParameterizedAttributeValue(
    "AXStringForTextMarkerRange",
    leftCharRange
  );
  is(leftCharString, expectedChar, "Left character is correct");
}

function testSelectionEventLine(event, expectedLine) {
  const selStart = event.macIface.getParameterizedAttributeValue(
    "AXStartTextMarkerForTextMarkerRange",
    event.data.AXSelectedTextMarkerRange
  );
  const lineRange = event.macIface.getParameterizedAttributeValue(
    "AXLineTextMarkerRangeForTextMarker",
    selStart
  );
  const lineString = event.macIface.getParameterizedAttributeValue(
    "AXStringForTextMarkerRange",
    lineRange
  );
  is(lineString, expectedLine, "Line is correct");
}

async function synthKeyAndTestValueChanged(
  synthKey,
  synthEvent,
  expectedId,
  expectedTextSelectionId,
  expectedChangeValue,
  expectedEditType,
  expectedWordAtLeft
) {
  let valueChangedEvents = Promise.all([
    waitForMacEvent(
      "AXSelectedTextChanged",
      matchWebArea(expectedTextSelectionId, {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
      })
    ),
    waitForMacEvent(
      "AXSelectedTextChanged",
      matchInput(expectedTextSelectionId, {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
      })
    ),
    waitForMacEventWithInfo(
      "AXValueChanged",
      matchWebArea(expectedId, {
        AXTextStateChangeType: AXTextStateChangeTypeEdit,
        AXTextChangeValues: [
          {
            AXTextChangeValue: expectedChangeValue,
            AXTextEditType: expectedEditType,
          },
        ],
      })
    ),
    waitForMacEventWithInfo(
      "AXValueChanged",
      matchInput(expectedId, {
        AXTextStateChangeType: AXTextStateChangeTypeEdit,
        AXTextChangeValues: [
          {
            AXTextChangeValue: expectedChangeValue,
            AXTextEditType: expectedEditType,
          },
        ],
      })
    ),
  ]);

  EventUtils.synthesizeKey(synthKey, synthEvent);
  let [, , webareaEvent, inputEvent] = await valueChangedEvents;

  testValueChangedEventData(
    webareaEvent.macIface,
    webareaEvent.data,
    expectedId,
    expectedChangeValue,
    expectedEditType,
    expectedWordAtLeft
  );
  testValueChangedEventData(
    inputEvent.macIface,
    inputEvent.data,
    expectedId,
    expectedChangeValue,
    expectedEditType,
    expectedWordAtLeft
  );
}

async function focusIntoInput(accDoc, inputId, innerContainerId) {
  let selectionId = innerContainerId ? innerContainerId : inputId;
  let input = getNativeInterface(accDoc, inputId);
  ok(!input.getAttributeValue("AXFocused"), "input is not focused");
  ok(input.isAttributeSettable("AXFocused"), "input is focusable");
  let events = Promise.all([
    waitForMacEvent(
      "AXFocusedUIElementChanged",
      iface => iface.getAttributeValue("AXDOMIdentifier") == inputId
    ),
    waitForMacEventWithInfo(
      "AXSelectedTextChanged",
      matchWebArea(selectionId, {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
      })
    ),
    waitForMacEventWithInfo(
      "AXSelectedTextChanged",
      matchInput(selectionId, {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
      })
    ),
  ]);
  input.setAttributeValue("AXFocused"true);
  await events;
}

async function focusIntoInputAndType(accDoc, inputId, innerContainerId) {
  let selectionId = innerContainerId ? innerContainerId : inputId;
  await focusIntoInput(accDoc, inputId, innerContainerId);

  async function testTextInput(
    synthKey,
    expectedChangeValue,
    expectedWordAtLeft
  ) {
    await synthKeyAndTestValueChanged(
      synthKey,
      null,
      inputId,
      selectionId,
      expectedChangeValue,
      AXTextEditTypeTyping,
      expectedWordAtLeft
    );
  }

  await testTextInput("h""h""h");
  await testTextInput("e""e""he");
  await testTextInput("l""l""hel");
  await testTextInput("l""l""hell");
  await testTextInput("o""o""hello");
  await testTextInput(" "" ""hello");
  // You would expect this to be useless but this is what VO
  // consumes. I guess it concats the inserted text data to the
  // word to the left of the marker.
  await testTextInput("w""w"" ");
  await testTextInput("o""o""wo");
  await testTextInput("r""r""wor");
  await testTextInput("l""l""worl");
  await testTextInput("d""d""world");

  async function testTextDelete(expectedChangeValue, expectedWordAtLeft) {
    await synthKeyAndTestValueChanged(
      "KEY_Backspace",
      null,
      inputId,
      selectionId,
      expectedChangeValue,
      AXTextEditTypeDelete,
      expectedWordAtLeft
    );
  }

  await testTextDelete("d""worl");
  await testTextDelete("l""wor");

  await synthKeyAndTestSelectionChanged(
    "KEY_ArrowLeft",
    null,
    selectionId,
    "",
    {
      AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
      AXTextSelectionDirection: AXTextSelectionDirectionPrevious,
      AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
    }
  );
  await synthKeyAndTestSelectionChanged(
    "KEY_ArrowLeft",
    { shiftKey: true },
    selectionId,
    "o",
    {
      AXTextStateChangeType: AXTextStateChangeTypeSelectionExtend,
      AXTextSelectionDirection: AXTextSelectionDirectionPrevious,
      AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
    }
  );
  await synthKeyAndTestSelectionChanged(
    "KEY_ArrowLeft",
    { shiftKey: true },
    selectionId,
    "wo",
    {
      AXTextStateChangeType: AXTextStateChangeTypeSelectionExtend,
      AXTextSelectionDirection: AXTextSelectionDirectionPrevious,
      AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
    }
  );
  await synthKeyAndTestSelectionChanged(
    "KEY_ArrowLeft",
    null,
    selectionId,
    "",
    { AXTextStateChangeType: AXTextStateChangeTypeSelectionMove }
  );
  await synthKeyAndTestSelectionChanged(
    "KEY_ArrowLeft",
    { shiftKey: true, metaKey: true },
    selectionId,
    "hello ",
    {
      AXTextStateChangeType: AXTextStateChangeTypeSelectionExtend,
      AXTextSelectionDirection: AXTextSelectionDirectionBeginning,
      AXTextSelectionGranularity: AXTextSelectionGranularityLine,
    }
  );
  await synthKeyAndTestSelectionChanged(
    "KEY_ArrowLeft",
    null,
    selectionId,
    "",
    { AXTextStateChangeType: AXTextStateChangeTypeSelectionMove }
  );
  await synthKeyAndTestSelectionChanged(
    "KEY_ArrowRight",
    { shiftKey: true, altKey: true },
    selectionId,
    "hello",
    {
      AXTextStateChangeType: AXTextStateChangeTypeSelectionExtend,
      AXTextSelectionDirection: AXTextSelectionDirectionNext,
      AXTextSelectionGranularity: AXTextSelectionGranularityWord,
    }
  );
}

// Test text input
addAccessibleTask(
  `<a href="#">link</a> <input id="input">`,
  async (browser, accDoc) => {
    await focusIntoInputAndType(accDoc, "input");
  },
  { topLevel: true, iframe: true, remoteIframe: true }
);

// Test content editable
addAccessibleTask(
  `<div id="input" contentEditable="true" tabindex="0" role="textbox" aria-multiline="true"><div id="inner"><br /></div></div>`,
  async (browser, accDoc) => {
    const inner = getNativeInterface(accDoc, "inner");
    const editableAncestor = inner.getAttributeValue("AXEditableAncestor");
    is(
      editableAncestor.getAttributeValue("AXDOMIdentifier"),
      "input",
      "Editable ancestor is input"
    );
    await focusIntoInputAndType(accDoc, "input");
  }
);

// Test input that gets role::EDITCOMBOBOX
addAccessibleTask(`<input type="text" id="box">`, async (browser, accDoc) => {
  const box = getNativeInterface(accDoc, "box");
  const editableAncestor = box.getAttributeValue("AXEditableAncestor");
  is(
    editableAncestor.getAttributeValue("AXDOMIdentifier"),
    "box",
    "Editable ancestor is box itself"
  );
  await focusIntoInputAndType(accDoc, "box");
});

// Test multiline caret control in a text area
addAccessibleTask(
  `<textarea id="input" cols="15">one two three four five six seven eight</textarea>`,
  async (browser, accDoc) => {
    await focusIntoInput(accDoc, "input");

    await synthKeyAndTestSelectionChanged("KEY_ArrowRight"null"input""", {
      AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
      AXTextSelectionDirection: AXTextSelectionDirectionNext,
      AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
    });

    await synthKeyAndTestSelectionChanged("KEY_ArrowDown"null"input""", {
      AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
      AXTextSelectionDirection: AXTextSelectionDirectionNext,
      AXTextSelectionGranularity: AXTextSelectionGranularityLine,
    });

    await synthKeyAndTestSelectionChanged(
      "KEY_ArrowLeft",
      { metaKey: true },
      "input",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionBeginning,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );

    await synthKeyAndTestSelectionChanged(
      "KEY_ArrowRight",
      { metaKey: true },
      "input",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionEnd,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
  },
  { topLevel: true, iframe: true, remoteIframe: true }
);

/**
 * Test that the caret returns the correct marker when it is positioned after
 * the last character (to facilitate appending text).
 */

addAccessibleTask(
  `<input id="input" value="abc">`,
  async function (browser, docAcc) {
    await focusIntoInput(docAcc, "input");

    let event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowRight",
      null,
      "input",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
      }
    );
    testSelectionEventLeftChar(event, "a");
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowRight",
      null,
      "input",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
      }
    );
    testSelectionEventLeftChar(event, "b");
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowRight",
      null,
      "input",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityCharacter,
      }
    );
    testSelectionEventLeftChar(event, "c");
  },
  { chrome: true, topLevel: true }
);

/**
 * Test that the caret returns the correct line when the caret is at the start
 * of the line.
 */

addAccessibleTask(
  `
<textarea id="hard">ab
cd
ef

gh
</textarea>
<div role="textbox" id="wrapped" contenteditable style="width: 1ch;">a b c</div>
  `,
  async function (browser, docAcc) {
    let hard = getNativeInterface(docAcc, "hard");
    await focusIntoInput(docAcc, "hard");
    is(hard.getAttributeValue("AXInsertionPointLineNumber"), 0);
    let event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowDown",
      null,
      "hard",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
    testSelectionEventLine(event, "cd");
    is(hard.getAttributeValue("AXInsertionPointLineNumber"), 1);
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowDown",
      null,
      "hard",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
    testSelectionEventLine(event, "ef");
    is(hard.getAttributeValue("AXInsertionPointLineNumber"), 2);
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowDown",
      null,
      "hard",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
    testSelectionEventLine(event, "");
    is(hard.getAttributeValue("AXInsertionPointLineNumber"), 3);
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowDown",
      null,
      "hard",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
    testSelectionEventLine(event, "gh");
    is(hard.getAttributeValue("AXInsertionPointLineNumber"), 4);
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowDown",
      null,
      "hard",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
    testSelectionEventLine(event, "");
    is(hard.getAttributeValue("AXInsertionPointLineNumber"), 5);

    let wrapped = getNativeInterface(docAcc, "wrapped");
    await focusIntoInput(docAcc, "wrapped");
    is(wrapped.getAttributeValue("AXInsertionPointLineNumber"), 0);
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowDown",
      null,
      "wrapped",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
    testSelectionEventLine(event, "b ");
    is(wrapped.getAttributeValue("AXInsertionPointLineNumber"), 1);
    event = await synthKeyAndTestSelectionChanged(
      "KEY_ArrowDown",
      null,
      "wrapped",
      "",
      {
        AXTextStateChangeType: AXTextStateChangeTypeSelectionMove,
        AXTextSelectionDirection: AXTextSelectionDirectionNext,
        AXTextSelectionGranularity: AXTextSelectionGranularityLine,
      }
    );
    testSelectionEventLine(event, "c");
    is(wrapped.getAttributeValue("AXInsertionPointLineNumber"), 2);
  },
  { chrome: true, topLevel: true }
);

Messung V0.5
C=90 H=97 G=93

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge