<!DOCTYPE html>
<html>
<head>
<script src="../../resources/js-test.js"></script>
<Script src="../../resources/ui-helper.js"></Script>
<script>
window.jsTestIsAsync = true;

let input;
let numberOfCharactersToOverflowFieldWhenCapsLockShown;

let tests = [
    // Test for caret selection
    // Empty field
    testFocusedEmptyFieldIsNotScrolled,
    testFieldDidNotScrollAfterCapsLockEnabled,
    testFieldDidNotScrollAfterCapsLockDisabled,

    // Non-empty field
    testFieldDidNotScrollAfterTyping,
    testFieldDidScrollAfterCapsLockEnabled,
    testFieldDidScrollAfterCapsLockDisabled,

    // Test for range selection
    // Select the first few characters
    testFieldDidNotScrollAfterSelectingPrefix,
    testFieldDidNotScrollAfterCapsLockEnabled,
    testFieldDidNotScrollAfterCapsLockDisabled,

    // Select the last few characters
    testFieldDidNotScrollAfterSelectingSuffix,
    testFieldDidScrollAfterCapsLockEnabled,
    testFieldDidScrollAfterCapsLockDisabled,
];

let currentTest = 0;

function runNextTest()
{
    if (currentTest >= tests.length) {
        done();
        return;
    }
    tests[currentTest++]();
}

function runTest()
{
    runNextTest();
}

function testFocusedEmptyFieldIsNotScrolled()
{
    debug("Case 1: Empty field:");
    function handleFocus() {
        shouldBeZero("document.getElementById('input').scrollLeft");
        runNextTest();
    }
    input.addEventListener("focus", handleFocus, { once: true });
    if (window.testRunner)
        UIHelper.activateElement(input);
    else
        input.focus();
}

function testFieldDidNotScrollAfterTyping()
{
    function checkFieldFilled(event) {
        console.assert(event.target === input);
        if (input.value.length < numberOfCharactersToOverflowFieldWhenCapsLockShown)
            return;
        input.oninput = null;
        shouldBeZero("document.getElementById('input').scrollLeft");
        runNextTest();
    }
    input.oninput = checkFieldFilled;

    debug("<br>Case 2: After typing into field:");
    if (window.testRunner) {
        for (let i = 0; i < numberOfCharactersToOverflowFieldWhenCapsLockShown; ++i)
            UIHelper.keyDown("a");
    }
}

function _toggleCapsLockWithCallbackAndRunNextTest(expectCapsLockEnabled, callback)
{
    if (window.internals)
        console.assert(internals.capsLockIsOn() != expectCapsLockEnabled);
    let newCapsLockStateDisplayName;
    let eventToListenFor;
    if (expectCapsLockEnabled) {
        newCapsLockStateDisplayName = "enabled";
        eventToListenFor = "keydown";
    } else {
        newCapsLockStateDisplayName = "disabled";
        eventToListenFor = "keyup";
    }

    let oldValue = document.getElementById("input").scrollLeft;
    function handleCapsLockChange(event) {
        requestAnimationFrame(() => {
            setTimeout(() => {
                console.assert(event.key === "CapsLock");
                callback(oldValue, document.getElementById("input").scrollLeft);
                runNextTest();
            }, 0);
        });
    }
    input.addEventListener(eventToListenFor, handleCapsLockChange, { once: true });
    debug(`<br>After caps lock ${newCapsLockStateDisplayName}:`);
    if (window.testRunner)
        UIHelper.toggleCapsLock();
}

function testFieldDidScrollAfterCapsLockEnabled()
{
    _toggleCapsLockWithCallbackAndRunNextTest(true, (oldValue, newValue) => {
        console.assert(oldValue != newValue);
        shouldBeNonZero("document.getElementById('input').scrollLeft");
    });
}

function testFieldDidScrollAfterCapsLockDisabled()
{
    _toggleCapsLockWithCallbackAndRunNextTest(false, (oldValue, newValue) => {
        console.assert(oldValue != newValue);
        shouldBeZero("document.getElementById('input').scrollLeft");
    });
}

function testFieldDidNotScrollAfterCapsLockEnabled()
{
    _toggleCapsLockWithCallbackAndRunNextTest(true, (oldValue, newValue) => {
        console.assert(oldValue == newValue);
        shouldBeZero("document.getElementById('input').scrollLeft");
    });
}

function testFieldDidNotScrollAfterCapsLockDisabled()
{
    _toggleCapsLockWithCallbackAndRunNextTest(false, (oldValue, newValue) => {
        console.assert(oldValue == newValue);
        shouldBeZero("document.getElementById('input').scrollLeft");
    });
}

function testFieldDidNotScrollAfterSelectingPrefix()
{
    let prefixLength = Math.floor(numberOfCharactersToOverflowFieldWhenCapsLockShown / 2);
    debug(`<br>Case 3: After selecting the first ${prefixLength} characters:`);
    input.setSelectionRange(0, prefixLength);
    shouldBeZero("document.getElementById('input').scrollLeft");
    runNextTest();
}

function testFieldDidNotScrollAfterSelectingSuffix()
{
    let suffixLength = Math.floor(numberOfCharactersToOverflowFieldWhenCapsLockShown / 2);
    debug(`<br>Case 4: After selecting the last ${suffixLength} characters:`);
    input.setSelectionRange(input.value.length - suffixLength, input.value.length);
    shouldBeZero("document.getElementById('input').scrollLeft");
    runNextTest();
}

function done()
{
    if (window.testRunner)
        document.body.removeChild(document.getElementById("input"));
    finishJSTest();
}
</script>
</head>
<body onload="runTest()">
<input type="password" id="input" size="5">
<script>
input = document.getElementById("input");
console.assert(input.hasAttribute("size"));
numberOfCharactersToOverflowFieldWhenCapsLockShown = input.size;

// FIXME: Find a way to compute the maximum number of visible characters the field can hold
// in a way that allows for running this test by hand.
let mayBeIOS = window.TouchEvent != undefined;
if (mayBeIOS) {
    // The look of the password field on iOS gives less space to the value than on Mac.
    --numberOfCharactersToOverflowFieldWhenCapsLockShown;
}
console.assert(numberOfCharactersToOverflowFieldWhenCapsLockShown >= 3);

description("Tests that the password field is scrolled when the caps lock indicator is toggled.");
</script>
</body>
</html>
