<!DOCTYPE html>
<html>
<head>
    <title>Touch Adjustment : Testing that a drag/drop will start on a long press - bug 92914</title>
    <script src="../fast/js/resources/js-test-pre.js"></script>
    <script src="resources/touchadjustment.js"></script>
    <style>
        #sandbox {
            position: absolute;
            left: 0px;
            top: 0px;
        }
    </style>
</head>

<body>

<div id="sandbox">
<p><a href="" id="link1">I</a> propose to consider <a href="" id="link2">the question</a>, "Can machines think?"<br>This should begin with definitions of the meaning of the terms "machine" and <a href="" id="link3">"think."</a></p>
</div>

<p id='description'></p>
<div id='console'></div>

<script>
    var element;
    var adjustedNode;
    // Set up shortcut access to elements
    var e = {};
    ['sandbox', 'link1', 'link2', 'link3'].forEach(function(a) {
        e[a] = document.getElementById(a);
    });

    document.ondragstart = function(e) { debug("PASS"); e.preventDefault();}

    function testLongPress(touchpoint)
    {
        if (eventSender.gestureLongPress)
            eventSender.gestureLongPress(touchpoint.x, touchpoint.y, touchpoint.width, touchpoint.height);
        else
            debug("gestureLongPress not implemented by this platform.");
    }

    function testDirectTouch(element)
    {
        // Touch directly in the center of the element.
        var touchpoint = offsetTouchPoint(findAbsoluteBounds(element), 'center', 0, 20, 30);
        if (document.elementFromPoint(touchpoint.x, touchpoint.y) != element)
            testFailed('Direct touch ended up on some other element');
        testLongPress(touchpoint);
    }

    function testIndirectTouch(element)
    {
        // Touch just right of the element.
        var touchpoint = offsetTouchPoint(findAbsoluteBounds(element), 'right', 10, 30, 20);
        if (isDescendantOf(element, document.elementFromPoint(touchpoint.x, touchpoint.y)))
            testFailed('Indirect touch ended up still on top of the element');
        testLongPress(touchpoint);
    }

    function isDescendantOf(parent, child)
    {
        var n = child;
        while(n) {
            if(n==parent)
                return true;
            n = n.parentNode;
        }
        return false;
    }

    function testDirectTouches()
    {
        debug('Testing direct hits.');
        testDirectTouch(e.link1);
        testDirectTouch(e.link2);
        testDirectTouch(e.link3);
    }

    function testIndirectTouches()
    {
        debug('Testing indirect hits.');
        testIndirectTouch(e.link1);
        testIndirectTouch(e.link2);
        testIndirectTouch(e.link3);
    }

    function runTests()
    {
        if (window.testRunner && window.internals && internals.touchNodeAdjustedToBestClickableNode) {
            internals.settings.setTouchDragDropEnabled(true);
            description('Tests if a long press gesture on links will trigger a drag/drop when touch adjustment is used.');
            testDirectTouches();
            testIndirectTouches();
            e.sandbox.style.display = 'none';
        }
    }
    runTests();
</script>
<script src="../fast/js/resources/js-test-post.js"></script>
</body>
</html>
