<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
<style>
#square {
    display: table-cell;
    vertical-align: middle;
    background: blue;
    width: 128px;
    height: 128px;
    color: white;
    text-align: center;
    padding: 10px;
    cursor: default;
    -webkit-user-drag: none;
    -webkit-user-select: none;
}
</style>
<script>
var didFireMousedownForFirstMouseButton;
var didFireMousedownForSecondMouseButton;
var firstMouseButtonElem;
var previouslyChosenFirstMouseButton = 0;
var secondMouseButtonElem;
var square;

// Extracted from the DOM Level 3 Events Mouse Event Types section <http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button>.
var LeftMouseButton = 0;
var MiddleMouseButton = 1;
var RightMouseButton = 2;

window.onload = function()
{
    firstMouseButtonElem = document.getElementById("firstMouseButton");
    secondMouseButtonElem = document.getElementById("secondMouseButton");
    firstMouseButtonElem.onchange = function() {
            disableIllogicalSecondMouseButtonOptions(); 
            resetTest();
    }
    secondMouseButtonElem.onchange = resetTest;

    square = document.getElementById("square");
    square.onmousedown = checkIfDoneOnMouseDown;
    square.onmouseup = checkIfDoneOnMouseUp;
    square.oncontextmenu = cancelContextMenu;
    resetTest();
    runTest();
}

function toBitmaskMouseButton(w3cButton)
{
    switch (w3cButton) {
    case LeftMouseButton:
        return 1 << 0;
    case MiddleMouseButton:
        return 1 << 1;
    case RightMouseButton:
        return 1 << 2;
    }
    return; // We shouldn't get here.
}

function shortMouseButtonName(w3cButton)
{
    switch (w3cButton) {
    case LeftMouseButton:
        return "left";
    case MiddleMouseButton:
        return "middle";
    case RightMouseButton:
        return "right";
    }
    return; // We shouldn't get here.
}

function mouseButtonName(w3cButton)
{
    return shortMouseButtonName(w3cButton) + " mouse button";
}

function cancelContextMenu(event)
{
    event = event || window.event;
    if (event.preventDefault)
        event.preventDefault();
    else {
        // Assume this script is executing within Internet Explorer.
        event.returnValue = false;
    }
}

function checkIfDoneOnMouseDown(event)
{
    var pressedButtons = event.buttons; // A bitmask that represents the combination of buttons that are currently being pressed.
    var chosenFirstMouseButton = firstMouseButtonElem.selectedIndex;
    var chosenSecondMouseButton = secondMouseButtonElem.selectedIndex;
    if (!didFireMousedownForFirstMouseButton && (pressedButtons & toBitmaskMouseButton(chosenFirstMouseButton)) == toBitmaskMouseButton(chosenFirstMouseButton)) {
        didFireMousedownForFirstMouseButton = true;
        square.innerHTML = "Now, " + shortMouseButtonName(chosenSecondMouseButton) + " click";
    } else if (didFireMousedownForFirstMouseButton && (pressedButtons & toBitmaskMouseButton(chosenSecondMouseButton)) == toBitmaskMouseButton(chosenSecondMouseButton))
        didFireMousedownForSecondMouseButton = true;
    if (didFireMousedownForFirstMouseButton && didFireMousedownForSecondMouseButton) {
        testPassed("received mousedown for the " + mouseButtonName(chosenSecondMouseButton) + " while pressing the " + mouseButtonName(chosenFirstMouseButton) + ".");
        resetTest();
    }
}

function checkIfDoneOnMouseUp()
{
    if (didFireMousedownForFirstMouseButton && !didFireMousedownForSecondMouseButton) {
        // Without loss of generality, either the mousedown for the right button button wasn't
        // dispatched or the user didn't press the right mouse button while pressing left mouse button.
        var chosenFirstMouseButton = firstMouseButtonElem.selectedIndex;
        var chosenSecondMouseButton = secondMouseButtonElem.selectedIndex;
        testFailed("didn't receive mousedown for the " + mouseButtonName(chosenSecondMouseButton) + " while pressing the " + mouseButtonName(chosenFirstMouseButton) + ".");
        resetTest();
    }
}

function resetTest()
{
    didFireMousedownForFirstMouseButton = false;
    didFireMousedownForSecondMouseButton = false;
    square.innerHTML = "Press and hold the " + mouseButtonName(firstMouseButtonElem.selectedIndex) + " on me";
}

function disableIllogicalSecondMouseButtonOptions()
{
    secondMouseButtonElem.options[previouslyChosenFirstMouseButton].disabled = false;
    if (firstMouseButtonElem.selectedIndex === secondMouseButtonElem.selectedIndex)
        secondMouseButtonElem.options[(secondMouseButtonElem.selectedIndex + 1) % secondMouseButtonElem.length].selected = true;
    secondMouseButtonElem.options[firstMouseButtonElem.selectedIndex].disabled = true;
    previouslyChosenFirstMouseButton = firstMouseButtonElem.selectedIndex;
}

function runTest()
{
    if (!window.eventSender)
        return;

    var numFirstMouseButtonOptions = firstMouseButtonElem.options.length;
    var numSecondMouseButtonOptions = secondMouseButtonElem.options.length;
    eventSender.mouseMoveTo(square.offsetLeft + 10, square.offsetTop + 10);
    var firstMouseButton = 0;
    var secondMouseButton = 0;
    while (firstMouseButton < numFirstMouseButtonOptions) {
        if (firstMouseButton === secondMouseButton)
            ++secondMouseButton;
        if (secondMouseButton >= numSecondMouseButtonOptions) {
            ++firstMouseButton;
            secondMouseButton = 0;
        }
        if (firstMouseButton >= numFirstMouseButtonOptions)
            break;

        firstMouseButtonElem.options[firstMouseButton].selected = true;
        secondMouseButtonElem.options[secondMouseButton].selected = true;
        if (secondMouseButton % numSecondMouseButtonOptions === 0)
            debug('<br />When pressing and holding the "' + mouseButtonName(firstMouseButton) + '"<br />');
        eventSender.mouseDown(firstMouseButton);
        eventSender.leapForward(100);
        eventSender.mouseDown(secondMouseButton);
        eventSender.mouseUp(secondMouseButton);
        eventSender.mouseUp(firstMouseButton);
        eventSender.leapForward(100);
        ++secondMouseButton;
        resetTest(); // We reset the test here in case neither a mousedown nor mouseup event was fired.
    }
    document.body.removeChild(document.getElementById("test-container"));
    debug('<br /><span class="pass">TEST COMPLETE</span>');
}
</script>
</head>
<body>
<p id="description"></p>
<div id="test-container">
    <p>Note: Ensure mouse gestures are disabled when running this test in Opera. In Opera 11.10 you can disable gestures by selecting Opera > Preferences > Advanced > Shortcuts. Then uncheck Enable mouse gestures. Also, to test &quot;pressing-and-holding the right mouse button then clicking the left mouse&quot; (*) ensure that Enable Mouse Flips is disabled. To disable it open <a href="opera:config" target="_blank">opera:config</a> then search for &quot;Enable Mouse Flips&quot; and uncheck it. As of 04/15/2011, for some reason (*) neither <span class="pass">PASS</span>es nor <span class="fail">FAIL</span>s.</p>
    <!-- The <option>s in these <select>s are explicitly ordered to match the DOM Level 3 Events mouse button values for Left, Middle, and Right mouse buttons. -->
    <label for="firstMouseButton">Will press and hold</label> <select id="firstMouseButton">
        <option>Left mouse button</option>
        <option>Middle mouse button</option>
        <option>Right mouse button</option>
    </select>
    <span>on blue square then</span>
    <label for="secondMouseButton">click</label> <select id="secondMouseButton">
        <option disabled>Left mouse button</option>
        <option selected>Middle mouse button</option>
        <option>Right mouse button</option>
    </select>
    <br/><br/>
    <div id="square"></div>
</div>
<hr/>
<div id="console"></div>
<script>
    description("This test verifies that we fire a mousedown event whenever pressing and holding a mouse button A while simultaneously " +
                "clicking with mouse button B, where A != B.<br/>" +
                "For each mouse button that is pressed and held, iterates through the possible second mouse buttons that can be clicked.");
</script>
</body>
</html>
