packages feed

elm-core-sources-1.0.0: src/Native/Touch.js

Elm.Native = Elm.Native || {};
Elm.Native.Touch = {};
Elm.Native.Touch.make = function(localRuntime) {

    localRuntime.Native = localRuntime.Native || {};
    localRuntime.Native.Touch = localRuntime.Native.Touch || {};
    if (localRuntime.Native.Touch.values) {
        return localRuntime.Native.Touch.values;
    }

    var Signal = Elm.Signal.make(localRuntime);
    var List = Elm.Native.List.make(localRuntime);
    var Utils = Elm.Native.Utils.make(localRuntime);

    function Dict() {
        this.keys = [];
        this.values = [];

        this.insert = function(key,value) {
            this.keys.push(key);
            this.values.push(value);
        };
        this.lookup = function(key) {
            var i = this.keys.indexOf(key)
            return i >= 0 ? this.values[i] : {x:0,y:0,t:0};
        };
        this.remove = function(key) {
            var i = this.keys.indexOf(key);
            if (i < 0) return;
            var t = this.values[i];
            this.keys.splice(i,1);
            this.values.splice(i,1);
            return t;
        };
        this.clear = function() {
            this.keys = [];
            this.values = [];
        };
    }
    
    var root = Signal.constant([]),
    tapTime = 500,
    hasTap = false,
    tap = {_:{},x:0,y:0},
    dict = new Dict();

    function touch(t) {
        var r = dict.lookup(t.identifier);
        var point = Utils.getXY(t);
        return {
            _ : {},
            id: t.identifier,
            x : point._0,
            y : point._1,
            x0: r.x,
            y0: r.y,
            t0: r.t
         };
    }

    var node = localRuntime.isFullscreen()
        ? document
        : localRuntime.node;

    function start(e) {
        var point = Utils.getXY(e);
        dict.insert(e.identifier, {
            x: point._0,
            y: point._1,
            t: localRuntime.timer.now()
        });
    }
    function end(e) {
        var t = dict.remove(e.identifier);
        if (localRuntime.timer.now() - t.t < tapTime) {
            hasTap = true;
            tap = {
                _: {},
                x: t.x,
                y: t.y
            };
        }
    }

    function listen(name, f) {
        function update(e) {
            for (var i = e.changedTouches.length; i--; ) {
                f(e.changedTouches[i]);
            }
            var ts = new Array(e.touches.length);
            for (var i = e.touches.length; i--; ) {
                ts[i] = touch(e.touches[i]);
            }
            localRuntime.notify(root.id, ts);
            e.preventDefault();
        }
        localRuntime.addListener([root.id], node, name, update);
    }

    listen("touchstart", start);
    listen("touchmove", function(_){});
    listen("touchend", end);
    listen("touchcancel", end);
    listen("touchleave", end);

    var mouseID = -1;
    function move(e) {
        var point = Utils.getXY(e);
        for (var i = root.value.length; i--; ) {
            if (root.value[i].id === mouseID) {
                root.value[i].x = point._0;
                root.value[i].y = point._1;
                localRuntime.notify(root.id, root.value);
                break;
            }
        }
    }
    localRuntime.addListener([root.id], node, "mousedown", function down(e) {
        node.addEventListener("mousemove", move);
        e.identifier = mouseID;
        start(e);
        root.value.push(touch(e));
        localRuntime.notify(root.id, root.value);
    });
    localRuntime.addListener([root.id], document, "mouseup", function up(e) {
        node.removeEventListener("mousemove", move);
        e.identifier = mouseID;
        end(e);
        for (var i = root.value.length; i--; ) {
            if (root.value[i].id === mouseID) {
                root.value.splice(i, 1);
                --mouseID;
                break;
            }
        }
        localRuntime.notify(root.id, root.value);
    });
    localRuntime.addListener([root.id], node, "blur", function blur(e) {
        node.removeEventListener("mousemove", move);
        if (root.value.length > 0) {
            localRuntime.notify(root.id, []);
            --mouseID;
        }
        dict.clear();
    });

    function dependency(f) {
        var sig = A2( Signal.map, f, root );
        root.defaultNumberOfKids += 1;
        sig.defaultNumberOfKids = 0;
        return sig;
    }

    var touches = dependency(List.fromArray);

    var taps = function() {
        var sig = dependency(function(_) { return tap; });
        sig.defaultNumberOfKids = 1;
        function pred(_) {
            var b = hasTap;
            hasTap = false;
            return b;
        }
        var sig2 = A3( Signal.keepIf, pred, {_:{},x:0,y:0}, sig);
        sig2.defaultNumberOfKids = 0;
        return sig2;
    }();

    return localRuntime.Native.Touch.values = { touches: touches, taps: taps };

};