<commit_before>var i, style, xMirrorStyle, yMirrorStyle, xyMirrorStyle,
    COLOR = [0, 0, 0],
    BACKGROUND_COLOR = [250, 250, 250],
    SCREEN_WIDTH = window.innerWidth,
    SCREEN_HEIGHT = window.innerHeight,
    container, foregroundColorSelector, backgroundColorSelector, menu, about, canvas, flattenCanvas, context, mouseX = 0,
    mouseY = 0,
    isForegroundColorSelectorVisible = false,
    isBackgroundColorSelectorVisible = false,
    isAboutVisible = false;
isForegroundColorSelectorMouseDown = false,
isBackgroundColorSelectorMouseDown = false,
isMenuMouseOver = false,
isMouseDown = false,
controlKeyIsDown = false,
xMirrorIsDown = false,
yMirrorIsDown = false,
xyMirrorIsDown = false;
init();

function init() {
    var hash, palette;
    document.body.style.backgroundColor = "rgb(" + BACKGROUND_COLOR[0] + ", " + BACKGROUND_COLOR[1] + ", " + BACKGROUND_COLOR[2] + ")";
    container = document.createElement("div");
    document.body.appendChild(container);
    canvas = document.createElement("canvas");
    canvas.width = SCREEN_WIDTH;
    canvas.height = SCREEN_HEIGHT;
    canvas.style.cursor = "crosshair";
    container.appendChild(canvas);
    flattenCanvas = document.createElement("canvas");
    flattenCanvas.width = SCREEN_WIDTH;
    flattenCanvas.height = SCREEN_HEIGHT;
    palette = new Palette();
    foregroundColorSelector = new ColorSelector(palette);
    foregroundColorSelector.container.onmousedown = onForegroundColorSelectorMouseDown;
    foregroundColorSelector.container.onmouseup = onForegroundColorSelectorMouseUp;
    foregroundColorSelector.container.onmousemove = onForegroundColorSelectorMouseMove;
    container.appendChild(foregroundColorSelector.container);
    backgroundColorSelector = new ColorSelector(palette);
    backgroundColorSelector.container.onmousedown = onBackgroundColorSelectorMouseDown;
    backgroundColorSelector.container.onmouseup = onBackgroundColorSelectorMouseUp;
    backgroundColorSelector.container.onmousemove = onBackgroundColorSelectorMouseMove;
    container.appendChild(backgroundColorSelector.container);
    menu = new Menu();
    menu.foregroundColor.addEventListener("click", onMenuForegroundColor, false);
    menu.backgroundColor.addEventListener("click", onMenuBackgroundColor, false);
    menu.selector.onchange = onMenuSelectorChange;
    menu.xMirror.addEventListener("click", onMenuXMirror, false);
    menu.yMirror.addEventListener("click", onMenuYMirror, false);
    menu.xyMirror.addEventListener("click", onMenuXYMirror, false);
    menu.save.addEventListener("click", onMenuSave, false);
    menu.clear.addEventListener("click", onMenuClear, false);
    menu.about.addEventListener("click", onMenuAbout, false);
    menu.container.onmouseover = onMenuMouseOver;
    menu.container.onmouseout = onMenuMouseOut;
    container.appendChild(menu.container);
    context = canvas.getContext("2d");
    if (window.location.hash) {
        hash = window.location.hash.substr(1, window.location.hash.length);
        for (i = 0; i < STYLES.length; i++) {
            if (hash == STYLES[i]) {
                style = eval("new " + STYLES[i] + "(context)");
                xMirrorStyle = eval("new " + STYLES[i] + "(context)"); // XXX: hack
                yMirrorStyle = eval("new " + STYLES[i] + "(context)"); // XXX: hack
                xyMirrorStyle = eval("new " + STYLES[i] + "(context)"); // XXX: hack
                menu.selector.selectedIndex = i;
                break
            }
        }
    }
    if (!style) {
        style = eval("new " + STYLES[0] + "(context)");
        xMirrorStyle = eval("new " + STYLES[0] + "(context)"); // XXX: hack
        yMirrorStyle = eval("new " + STYLES[0] + "(context)"); // XXX: hack
        xyMirrorStyle = eval("new " + STYLES[0] + "(context)"); // XXX: hack
    }

    about = new About();
    container.appendChild(about.container);
    window.onresize = onWindowResize;
    window.onkeydown = onDocumentKeyDown;
    window.onkeyup = onDocumentKeyUp;
    document.onmousedown = onDocumentMouseDown;
    document.onmouseout = onCanvasMouseUp;
    canvas.onmousedown = onCanvasMouseDown;
    canvas.onmouseup = onCanvasMouseUp;
    canvas.onmousemove = onCanvasMouseMove;
    canvas.ontouchstart = onCanvasTouchStart;
    canvas.ontouchend = onCanvasTouchEnd;
    canvas.ontouchmove = onCanvasTouchMove;
    onWindowResize(null)
}
function onWindowResize(a) {
    SCREEN_WIDTH = window.innerWidth;
    SCREEN_HEIGHT = window.innerHeight;
    menu.container.style.left = ((SCREEN_WIDTH - menu.container.offsetWidth) / 2) + "px";
    about.container.style.left = ((SCREEN_WIDTH - about.container.offsetWidth) / 2) + "px";
    about.container.style.top = ((SCREEN_HEIGHT - about.container.offsetHeight) / 2) + "px"
}
function onDocumentMouseDown(a) {
    return isMenuMouseOver
}
function onDocumentKeyDown(a) {
    switch (a.keyCode) {
    case 16:
        if(controlKeyIsDown) {
            controlKeyIsDown = false;
            foregroundColorSelector.container.style.visibility = "hidden";
        }
        else {
            controlKeyIsDown = true;
            foregroundColorSelector.container.style.left = mouseX - 125 + "px";
            foregroundColorSelector.container.style.top = mouseY - 125 + "px";
            foregroundColorSelector.container.style.visibility = "visible";
        }
        break
    }
}
function onDocumentKeyUp(a) {
    //switch (a.keyCode) {
    //case 16:
        //break
    //}
}
function onForegroundColorSelectorMouseDown(a) {
    isForegroundColorSelectorMouseDown = true
}
function onForegroundColorSelectorMouseUp(a) {
    isForegroundColorSelectorMouseDown = false;
    foregroundColorSelector.update(a);
    COLOR = foregroundColorSelector.getColor();
    menu.setForegroundColor(COLOR)
}
function onForegroundColorSelectorMouseMove(a) {
    if (!isForegroundColorSelectorMouseDown) {
        return
    }
    foregroundColorSelector.update(a);
    COLOR = foregroundColorSelector.getColor();
    menu.setForegroundColor(COLOR)
}
function onBackgroundColorSelectorMouseDown(a) {
    isBackgroundColorSelectorMouseDown = true
}
function onBackgroundColorSelectorMouseUp(a) {
    isBackgroundColorSelectorMouseDown = false;
    backgroundColorSelector.update(a);
    BACKGROUND_COLOR = backgroundColorSelector.getColor();
    menu.setBackgroundColor(BACKGROUND_COLOR);
    document.body.style.backgroundColor = "rgb(" + BACKGROUND_COLOR[0] + ", " + BACKGROUND_COLOR[1] + ", " + BACKGROUND_COLOR[2] + ")"
}
function onBackgroundColorSelectorMouseMove(a) {
    if (!isBackgroundColorSelectorMouseDown) {
        return
    }
    backgroundColorSelector.update(a);
    BACKGROUND_COLOR = backgroundColorSelector.getColor();
    menu.setBackgroundColor(BACKGROUND_COLOR);
    document.body.style.backgroundColor = "rgb(" + BACKGROUND_COLOR[0] + ", " + BACKGROUND_COLOR[1] + ", " + BACKGROUND_COLOR[2] + ")"
}
function onMenuForegroundColor(a) {
    cleanPopUps();
    foregroundColorSelector.show();
    foregroundColorSelector.container.style.left = ((SCREEN_WIDTH - foregroundColorSelector.container.offsetWidth) / 2) + "px";
    foregroundColorSelector.container.style.top = ((SCREEN_HEIGHT - foregroundColorSelector.container.offsetHeight) / 2) + "px";
    isForegroundColorSelectorVisible = true
}
function onMenuBackgroundColor(a) {
    cleanPopUps();
    backgroundColorSelector.show();
    backgroundColorSelector.container.style.left = ((SCREEN_WIDTH - backgroundColorSelector.container.offsetWidth) / 2) + "px";
    backgroundColorSelector.container.style.top = ((SCREEN_HEIGHT - backgroundColorSelector.container.offsetHeight) / 2) + "px";
    isBackgroundColorSelectorVisible = true
}
function onMenuSelectorChange(e) {
    if (STYLES[menu.selector.selectedIndex] == "") {
        return
    }
    style.destroy();
    style = eval("new " + STYLES[menu.selector.selectedIndex] + "(context)");
    window.location.hash = STYLES[menu.selector.selectedIndex]
}
function onMenuMouseOver(a) {
    isMenuMouseOver = true
}
function onMenuMouseOut(a) {
    isMenuMouseOver = false
}
function onMenuXMirror() {
    // XXX: this should set button state to pressed/released via css class
    xMirrorIsDown = !xMirrorIsDown;
}
function onMenuYMirror() {
    // XXX: this should set button state to pressed/released via css class
    yMirrorIsDown = !yMirrorIsDown;
}
function onMenuXYMirror() {
    // XXX: this should set button state to pressed/released via css class
    xyMirrorIsDown = !xyMirrorIsDown;
}
function onMenuSave() {
    var a = flattenCanvas.getContext("2d");
    a.fillStyle = "rgb(" + BACKGROUND_COLOR[0] + ", " + BACKGROUND_COLOR[1] + ", " + BACKGROUND_COLOR[2] + ")";
    a.fillRect(0, 0, canvas.width, canvas.height);
    a.drawImage(canvas, 0, 0);
    window.open(flattenCanvas.toDataURL("image/png"), "mywindow")
}
function onMenuClear() {
    context.clearRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
    style = eval("new " + STYLES[menu.selector.selectedIndex] + "(context)");
    xMirrorStyle = eval("new " + STYLES[menu.selector.selectedIndex] + "(context)"); // XXX: hack
    yMirrorStyle = eval("new " + STYLES[menu.selector.selectedIndex] + "(context)"); // XXX: hack
    xyMirrorStyle = eval("new " + STYLES[menu.selector.selectedIndex] + "(context)"); // XXX: hack
}
function onMenuAbout(a) {
    cleanPopUps();
    isAboutVisible = true;
    about.show()
}
function onCanvasMouseDown(a) {
    cleanPopUps();
    isMouseDown = true;

    style.strokeStart(mouseX, mouseY);

    mirrorX = canvas.width - mouseX;
    mirrorY = canvas.height - mouseY;

    if(xMirrorIsDown) {
        xMirrorStyle.strokeStart(mirrorX, mouseY);
    }

    if(yMirrorIsDown) {
        yMirrorStyle.strokeStart(mouseX, mirrorY);
    }

    if((xMirrorIsDown && yMirrorIsDown) || xyMirrorIsDown) {
        xyMirrorStyle.strokeStart(mirrorX, mirrorY);
    }
}
function onCanvasMouseUp(a) {
    isMouseDown = false;
    style.strokeEnd(mouseX, mouseY)

    mirrorX = canvas.width - mouseX;
    mirrorY = canvas.height - mouseY;

    if(xMirrorIsDown) {
        xMirrorStyle.strokeEnd(mirrorX, mouseY);
    }

    if(yMirrorIsDown) {
        yMirrorStyle.strokeEnd(mouseX, mirrorY);
    }

    if((xMirrorIsDown && yMirrorIsDown) || xyMirrorIsDown) {
        xyMirrorStyle.strokeEnd(mirrorX, mirrorY);
    }
}
function onCanvasMouseMove(a) {
    if (!a) {
        a = window.event
    }

    mouseX = a.clientX;
    mouseY = a.clientY;
    if (!isMouseDown) {
        return
    }

    style.stroke(mouseX, mouseY)

    mirrorX = canvas.width - mouseX;
    mirrorY = canvas.height - mouseY;

    if(xMirrorIsDown) {
        xMirrorStyle.stroke(mirrorX, mouseY);
    }

    if(yMirrorIsDown) {
        yMirrorStyle.stroke(mouseX, mirrorY);
    }

    if((xMirrorIsDown && yMirrorIsDown) || xyMirrorIsDown) {
        xyMirrorStyle.stroke(mirrorX, mirrorY);
    }
}
function onCanvasTouchStart(a) {
    if (a.touches.length == 1) {
        var b = a.touches[0];
        style.strokeStart(b.pageX, b.pageY);
        return false
    }
}
function onCanvasTouchEnd(a) {
    if (a.touches.length == 1) {
        var b = a.touches[0];
        style.strokeEnd(b.pageX, b.pageY);
        return false
    }
}
function onCanvasTouchMove(a) {
    if (a.touches.length == 1) {
        var b = a.touches[0];
        style.stroke(b.pageX, b.pageY);
        return false
    }
}
function cleanPopUps() {
    if (isForegroundColorSelectorVisible) {
        foregroundColorSelector.hide();
        isForegroundColorSelectorVisible = false
    }
    if (isBackgroundColorSelectorVisible) {
        backgroundColorSelector.hide();
        isBackgroundColorSelectorVisible = false
    }
    if (isAboutVisible) {
        about.hide();
        isAboutVisible = false
    }
};<commit_msg>Added some UI candy to mirror toggles.<commit_after>var i, style, xMirrorStyle, yMirrorStyle, xyMirrorStyle,
    COLOR = [0, 0, 0],
    BACKGROUND_COLOR = [250, 250, 250],
    SCREEN_WIDTH = window.innerWidth,
    SCREEN_HEIGHT = window.innerHeight,
    container, foregroundColorSelector, backgroundColorSelector, menu, about, canvas, flattenCanvas, context, mouseX = 0,
    mouseY = 0,
    isForegroundColorSelectorVisible = false,
    isBackgroundColorSelectorVisible = false,
    isAboutVisible = false;
isForegroundColorSelectorMouseDown = false,
isBackgroundColorSelectorMouseDown = false,
isMenuMouseOver = false,
isMouseDown = false,
controlKeyIsDown = false,
xMirrorIsDown = false,
yMirrorIsDown = false,
xyMirrorIsDown = false;
init();

function init() {
    var hash, palette;
    document.body.style.backgroundColor = "rgb(" + BACKGROUND_COLOR[0] + ", " + BACKGROUND_COLOR[1] + ", " + BACKGROUND_COLOR[2] + ")";
    container = document.createElement("div");
    document.body.appendChild(container);
    canvas = document.createElement("canvas");
    canvas.width = SCREEN_WIDTH;
    canvas.height = SCREEN_HEIGHT;
    canvas.style.cursor = "crosshair";
    container.appendChild(canvas);
    flattenCanvas = document.createElement("canvas");
    flattenCanvas.width = SCREEN_WIDTH;
    flattenCanvas.height = SCREEN_HEIGHT;
    palette = new Palette();
    foregroundColorSelector = new ColorSelector(palette);
    foregroundColorSelector.container.onmousedown = onForegroundColorSelectorMouseDown;
    foregroundColorSelector.container.onmouseup = onForegroundColorSelectorMouseUp;
    foregroundColorSelector.container.onmousemove = onForegroundColorSelectorMouseMove;
    container.appendChild(foregroundColorSelector.container);
    backgroundColorSelector = new ColorSelector(palette);
    backgroundColorSelector.container.onmousedown = onBackgroundColorSelectorMouseDown;
    backgroundColorSelector.container.onmouseup = onBackgroundColorSelectorMouseUp;
    backgroundColorSelector.container.onmousemove = onBackgroundColorSelectorMouseMove;
    container.appendChild(backgroundColorSelector.container);
    menu = new Menu();
    menu.foregroundColor.addEventListener("click", onMenuForegroundColor, false);
    menu.backgroundColor.addEventListener("click", onMenuBackgroundColor, false);
    menu.selector.onchange = onMenuSelectorChange;
    menu.xMirror.addEventListener("click", onMenuXMirror, false);
    menu.yMirror.addEventListener("click", onMenuYMirror, false);
    menu.xyMirror.addEventListener("click", onMenuXYMirror, false);
    menu.save.addEventListener("click", onMenuSave, false);
    menu.clear.addEventListener("click", onMenuClear, false);
    menu.about.addEventListener("click", onMenuAbout, false);
    menu.container.onmouseover = onMenuMouseOver;
    menu.container.onmouseout = onMenuMouseOut;
    container.appendChild(menu.container);
    context = canvas.getContext("2d");
    if (window.location.hash) {
        hash = window.location.hash.substr(1, window.location.hash.length);
        for (i = 0; i < STYLES.length; i++) {
            if (hash == STYLES[i]) {
                style = eval("new " + STYLES[i] + "(context)");
                xMirrorStyle = eval("new " + STYLES[i] + "(context)"); // XXX: hack
                yMirrorStyle = eval("new " + STYLES[i] + "(context)"); // XXX: hack
                xyMirrorStyle = eval("new " + STYLES[i] + "(context)"); // XXX: hack
                menu.selector.selectedIndex = i;
                break
            }
        }
    }
    if (!style) {
        style = eval("new " + STYLES[0] + "(context)");
        xMirrorStyle = eval("new " + STYLES[0] + "(context)"); // XXX: hack
        yMirrorStyle = eval("new " + STYLES[0] + "(context)"); // XXX: hack
        xyMirrorStyle = eval("new " + STYLES[0] + "(context)"); // XXX: hack
    }

    about = new About();
    container.appendChild(about.container);
    window.onresize = onWindowResize;
    window.onkeydown = onDocumentKeyDown;
    window.onkeyup = onDocumentKeyUp;
    document.onmousedown = onDocumentMouseDown;
    document.onmouseout = onCanvasMouseUp;
    canvas.onmousedown = onCanvasMouseDown;
    canvas.onmouseup = onCanvasMouseUp;
    canvas.onmousemove = onCanvasMouseMove;
    canvas.ontouchstart = onCanvasTouchStart;
    canvas.ontouchend = onCanvasTouchEnd;
    canvas.ontouchmove = onCanvasTouchMove;
    onWindowResize(null)
}
function onWindowResize(a) {
    SCREEN_WIDTH = window.innerWidth;
    SCREEN_HEIGHT = window.innerHeight;
    menu.container.style.left = ((SCREEN_WIDTH - menu.container.offsetWidth) / 2) + "px";
    about.container.style.left = ((SCREEN_WIDTH - about.container.offsetWidth) / 2) + "px";
    about.container.style.top = ((SCREEN_HEIGHT - about.container.offsetHeight) / 2) + "px"
}
function onDocumentMouseDown(a) {
    return isMenuMouseOver
}
function onDocumentKeyDown(a) {
    switch (a.keyCode) {
    case 16:
        if(controlKeyIsDown) {
            controlKeyIsDown = false;
            foregroundColorSelector.container.style.visibility = "hidden";
        }
        else {
            controlKeyIsDown = true;
            foregroundColorSelector.container.style.left = mouseX - 125 + "px";
            foregroundColorSelector.container.style.top = mouseY - 125 + "px";
            foregroundColorSelector.container.style.visibility = "visible";
        }
        break
    }
}
function onDocumentKeyUp(a) {
    //switch (a.keyCode) {
    //case 16:
        //break
    //}
}
function onForegroundColorSelectorMouseDown(a) {
    isForegroundColorSelectorMouseDown = true
}
function onForegroundColorSelectorMouseUp(a) {
    isForegroundColorSelectorMouseDown = false;
    foregroundColorSelector.update(a);
    COLOR = foregroundColorSelector.getColor();
    menu.setForegroundColor(COLOR)
}
function onForegroundColorSelectorMouseMove(a) {
    if (!isForegroundColorSelectorMouseDown) {
        return
    }
    foregroundColorSelector.update(a);
    COLOR = foregroundColorSelector.getColor();
    menu.setForegroundColor(COLOR)
}
function onBackgroundColorSelectorMouseDown(a) {
    isBackgroundColorSelectorMouseDown = true
}
function onBackgroundColorSelectorMouseUp(a) {
    isBackgroundColorSelectorMouseDown = false;
    backgroundColorSelector.update(a);
    BACKGROUND_COLOR = backgroundColorSelector.getColor();
    menu.setBackgroundColor(BACKGROUND_COLOR);
    document.body.style.backgroundColor = "rgb(" + BACKGROUND_COLOR[0] + ", " + BACKGROUND_COLOR[1] + ", " + BACKGROUND_COLOR[2] + ")"
}
function onBackgroundColorSelectorMouseMove(a) {
    if (!isBackgroundColorSelectorMouseDown) {
        return
    }
    backgroundColorSelector.update(a);
    BACKGROUND_COLOR = backgroundColorSelector.getColor();
    menu.setBackgroundColor(BACKGROUND_COLOR);
    document.body.style.backgroundColor = "rgb(" + BACKGROUND_COLOR[0] + ", " + BACKGROUND_COLOR[1] + ", " + BACKGROUND_COLOR[2] + ")"
}
function onMenuForegroundColor(a) {
    cleanPopUps();
    foregroundColorSelector.show();
    foregroundColorSelector.container.style.left = ((SCREEN_WIDTH - foregroundColorSelector.container.offsetWidth) / 2) + "px";
    foregroundColorSelector.container.style.top = ((SCREEN_HEIGHT - foregroundColorSelector.container.offsetHeight) / 2) + "px";
    isForegroundColorSelectorVisible = true
}
function onMenuBackgroundColor(a) {
    cleanPopUps();
    backgroundColorSelector.show();
    backgroundColorSelector.container.style.left = ((SCREEN_WIDTH - backgroundColorSelector.container.offsetWidth) / 2) + "px";
    backgroundColorSelector.container.style.top = ((SCREEN_HEIGHT - backgroundColorSelector.container.offsetHeight) / 2) + "px";
    isBackgroundColorSelectorVisible = true
}
function onMenuSelectorChange(e) {
    if (STYLES[menu.selector.selectedIndex] == "") {
        return
    }
    style.destroy();
    style = eval("new " + STYLES[menu.selector.selectedIndex] + "(context)");
    window.location.hash = STYLES[menu.selector.selectedIndex]
}
function onMenuMouseOver(a) {
    isMenuMouseOver = true
}
function onMenuMouseOut(a) {
    isMenuMouseOver = false
}

function setToggle(e, state) {
    // XXX: could be nicer (set via css class or so)
    if(state) {
        e.style.color = '#00DD00';
    }
    else {
        e.style.color = '#000000';
    }
}
function onMenuXMirror(a) {
    xMirrorIsDown = !xMirrorIsDown;

    setToggle(this, xMirrorIsDown);
}
function onMenuYMirror() {
    yMirrorIsDown = !yMirrorIsDown;

    setToggle(this, yMirrorIsDown);
}
function onMenuXYMirror() {
    xyMirrorIsDown = !xyMirrorIsDown;

    setToggle(this, xyMirrorIsDown);
}

function onMenuSave() {
    var a = flattenCanvas.getContext("2d");
    a.fillStyle = "rgb(" + BACKGROUND_COLOR[0] + ", " + BACKGROUND_COLOR[1] + ", " + BACKGROUND_COLOR[2] + ")";
    a.fillRect(0, 0, canvas.width, canvas.height);
    a.drawImage(canvas, 0, 0);
    window.open(flattenCanvas.toDataURL("image/png"), "mywindow")
}
function onMenuClear() {
    context.clearRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
    style = eval("new " + STYLES[menu.selector.selectedIndex] + "(context)");
    xMirrorStyle = eval("new " + STYLES[menu.selector.selectedIndex] + "(context)"); // XXX: hack
    yMirrorStyle = eval("new " + STYLES[menu.selector.selectedIndex] + "(context)"); // XXX: hack
    xyMirrorStyle = eval("new " + STYLES[menu.selector.selectedIndex] + "(context)"); // XXX: hack
}
function onMenuAbout(a) {
    cleanPopUps();
    isAboutVisible = true;
    about.show()
}
function onCanvasMouseDown(a) {
    cleanPopUps();
    isMouseDown = true;

    style.strokeStart(mouseX, mouseY);

    mirrorX = canvas.width - mouseX;
    mirrorY = canvas.height - mouseY;

    if(xMirrorIsDown) {
        xMirrorStyle.strokeStart(mirrorX, mouseY);
    }

    if(yMirrorIsDown) {
        yMirrorStyle.strokeStart(mouseX, mirrorY);
    }

    if((xMirrorIsDown && yMirrorIsDown) || xyMirrorIsDown) {
        xyMirrorStyle.strokeStart(mirrorX, mirrorY);
    }
}
function onCanvasMouseUp(a) {
    isMouseDown = false;
    style.strokeEnd(mouseX, mouseY)

    mirrorX = canvas.width - mouseX;
    mirrorY = canvas.height - mouseY;

    if(xMirrorIsDown) {
        xMirrorStyle.strokeEnd(mirrorX, mouseY);
    }

    if(yMirrorIsDown) {
        yMirrorStyle.strokeEnd(mouseX, mirrorY);
    }

    if((xMirrorIsDown && yMirrorIsDown) || xyMirrorIsDown) {
        xyMirrorStyle.strokeEnd(mirrorX, mirrorY);
    }
}
function onCanvasMouseMove(a) {
    if (!a) {
        a = window.event
    }

    mouseX = a.clientX;
    mouseY = a.clientY;
    if (!isMouseDown) {
        return
    }

    style.stroke(mouseX, mouseY)

    mirrorX = canvas.width - mouseX;
    mirrorY = canvas.height - mouseY;

    if(xMirrorIsDown) {
        xMirrorStyle.stroke(mirrorX, mouseY);
    }

    if(yMirrorIsDown) {
        yMirrorStyle.stroke(mouseX, mirrorY);
    }

    if((xMirrorIsDown && yMirrorIsDown) || xyMirrorIsDown) {
        xyMirrorStyle.stroke(mirrorX, mirrorY);
    }
}
function onCanvasTouchStart(a) {
    if (a.touches.length == 1) {
        var b = a.touches[0];
        style.strokeStart(b.pageX, b.pageY);
        return false
    }
}
function onCanvasTouchEnd(a) {
    if (a.touches.length == 1) {
        var b = a.touches[0];
        style.strokeEnd(b.pageX, b.pageY);
        return false
    }
}
function onCanvasTouchMove(a) {
    if (a.touches.length == 1) {
        var b = a.touches[0];
        style.stroke(b.pageX, b.pageY);
        return false
    }
}
function cleanPopUps() {
    if (isForegroundColorSelectorVisible) {
        foregroundColorSelector.hide();
        isForegroundColorSelectorVisible = false
    }
    if (isBackgroundColorSelectorVisible) {
        backgroundColorSelector.hide();
        isBackgroundColorSelectorVisible = false
    }
    if (isAboutVisible) {
        about.hide();
        isAboutVisible = false
    }
};<|endoftext|>


<commit_before>var util = require('util'),
    webutil = require('../util/web'),
    Tab = require('../client/tab').Tab,
    Amount = ripple.Amount,
    Base = ripple.Base,
    rewriter = require('../util/jsonrewriter'),
    Currency = ripple.Currency;

var ExchangeTab = function ()
{
  Tab.call(this);
};

util.inherits(ExchangeTab, Tab);

ExchangeTab.prototype.tabName = 'exchange';
ExchangeTab.prototype.mainMenu = 'exchange';

ExchangeTab.prototype.generateHtml = function ()
{
  return require('../../jade/tabs/exchange.jade')();
};

ExchangeTab.prototype.angular = function (module)
{
  module.controller('ExchangeCtrl', ['$scope', '$timeout', '$routeParams',
    'rpId', 'rpNetwork', 'rpTracker', 'rpKeychain', '$rootScope', '$location',
    function ($scope, $timeout, $routeParams, id, network, rpTracker, keychain, $rootScope, $location)
    {
      var pathUpdateTimeout;

      var timer, pf;

      // Remember user preference on Convert vs. Trade
      $rootScope.ripple_exchange_selection_trade = false;

      var xrpCurrency = Currency.from_json('XRP');

      $scope.xrp = {
        name: xrpCurrency.to_human({full_name:$scope.currencies_all_keyed.XRP.name}),
        code: xrpCurrency.get_iso(),
        currency: xrpCurrency
      };

      $scope.$watch('exchange.amount', function () {
        $scope.update_exchange();
      }, true);

      $scope.$watch('exchange.currency_name', function () {
        var exchange = $scope.exchange;
        var currency = Currency.from_human($scope.exchange.currency_name ? $scope.exchange.currency_name : 'XRP');
        exchange.currency_obj = currency;
        exchange.currency_code = currency.get_iso();
        exchange.currency_name = currency.to_human({
          full_name: $scope.currencies_all_keyed[currency.get_iso()] ? $scope.currencies_all_keyed[currency.get_iso()].name : null
        });
        $scope.update_exchange();
      }, true);

      $scope.gotoFund = function() {
        $location.path('/xrp');
      };

      $scope.reset_paths = function () {
        var exchange = $scope.exchange;

        exchange.alternatives = [];
      };

      $scope.update_exchange = function () {
        var exchange = $scope.exchange;
        var currency = ripple.Currency.from_human(exchange.currency_name);

        $scope.reset_paths();

        // if formatted or money to exchange is 0 then don't calculate paths or offer to exchange
        if (parseFloat(exchange.amount) === 0 || !exchange.currency_name)
        {
          $scope.error_type = 'required';
          return false;
        }

        else {
          $scope.error_type = '';
        }

        var matchedCurrency = currency.has_interest() ? currency.to_hex() : currency.get_iso();
        var match = /^([a-zA-Z0-9]{3}|[A-Fa-f0-9]{40})\b/.exec(matchedCurrency);

        if (!match) {
          // Currency code not recognized, should have been caught by
          // form validator.
          return;
        }

        // Demurrage: Get a reference date five minutes in the future
        //
        // Normally, when using demurrage currencies, we would immediately round
        // down (e.g. 0.99999 instead of 1) as demurrage occurs continuously. Not
        // a good user experience.
        //
        // By choosing a date in the future, this gives us a time window before
        // this rounding down occurs. Note that for positive interest currencies
        // this actually *causes* the same odd rounding problem, so in the future
        // we'll want a better solution, but for right now this does what we need.
        var refDate = new Date(new Date().getTime() + 5 * 60000);

        exchange.amount_feedback = Amount.from_human('' + exchange.amount + ' ' + matchedCurrency, { reference_date: refDate });
        exchange.amount_feedback.set_issuer(id.account);

        if (exchange.amount_feedback.is_valid() && exchange.amount_feedback.is_positive()) {
          exchange.path_status = 'pending';
          exchange.alt = null;

          if (pathUpdateTimeout) clearTimeout(pathUpdateTimeout);
          pathUpdateTimeout = $timeout($scope.update_paths, 500);
        } else {
          exchange.path_status = 'waiting';
        }
      };

      $scope.update_paths = function () {
        $scope.$apply(function () {
          $scope.exchange.path_status = 'pending';
          var amount = $scope.exchange.amount_feedback;

          if (amount.is_zero()) return;

          // Start path find
          pf = network.remote.path_find(id.account,
              id.account,
              amount);
              // $scope.generate_src_currencies());
              // XXX: Roll back pathfinding changes temporarily
          var isIssuer = $scope.generate_issuer_currencies();

          var lastUpdate;

          pf.on('update', function (upd) {
            $scope.$apply(function () {
              lastUpdate = new Date();

              clearInterval(timer);
              timer = setInterval(function(){
                $scope.$apply(function(){
                  var seconds = Math.round((new Date() - lastUpdate) / 1000);
                  $scope.lastUpdate = seconds || 0;
                });
              }, 1000);

              if (!upd.alternatives || !upd.alternatives.length) {
                $scope.exchange.path_status  = 'no-path';
                $scope.exchange.alternatives = [];
              } else {
                var currencies = {};
                $scope.exchange.path_status  = 'done';
                $scope.exchange.alternatives = _.filter(_.map(upd.alternatives, function (raw) {
                  var alt = {};
                  alt.amount   = Amount.from_json(raw.source_amount);
                  alt.rate     = alt.amount.ratio_human(amount);
                  alt.send_max = alt.amount.product_human(Amount.from_json('1.01'));
                  alt.paths    = raw.paths_computed
                      ? raw.paths_computed
                      : raw.paths_canonical;

                  if (alt.amount.issuer().to_json() != $scope.address && !isIssuer[alt.amount.currency().to_hex()]) {
                    currencies[alt.amount.currency().to_hex()] = true;
                  }

                  return alt;
                }), function(alt) {
                  // XXX: Roll back pathfinding changes temporarily
                  /* if (currencies[alt.amount.currency().to_hex()]) {
                    return alt.amount.issuer().to_json() != $scope.address;
                  } */
                  // return false;
                  return !(alt.amount.is_native() && $scope.account.max_spend
                    && $scope.account.max_spend.to_number() > 1
                    && $scope.account.max_spend.compareTo(alt.amount) < 0);
                });
                if (!$scope.exchange.alternatives.length) {
                  $scope.exchange.path_status  = 'no-path';
                  $scope.exchange.alternatives = [];
                }
              }
            });
          });
        });
      };

      var updateCurrencyOptions = function(){
        // create a list of currency codes from the trust line objects
        var currencies = _.uniq(_.map($scope.lines, function (line) {
          return line.currency;
        }));

        // add XRP
        currencies.unshift('XRP');

        // create a currency object for each of the currency codes
        for (var i = 0; i < currencies.length; i++) {
          currencies[i] = ripple.Currency.from_json(currencies[i]);
        }

        // create the display version of the currencies
        currencies = _.map(currencies, function (currency) {
          if ($scope.currencies_all_keyed[currency.get_iso()]) {
            return currency.to_human({full_name:$scope.currencies_all_keyed[currency.get_iso()].name});
          }

          return currency.get_iso();
        });

        $scope.currency_choices = currencies;
      };

      $scope.$on('$balancesUpdate', updateCurrencyOptions);

      $scope.reset = function () {
        $scope.mode = 'form';

        // XXX Most of these variables should be properties of $scope.exchange.
        //     The Angular devs recommend that models be objects due to the way
        //     scope inheritance works.
        $scope.exchange = {
          amount: '',
          currency_name: $scope.xrp.name,
          currency_code: $scope.xrp.code,
          currency_obj: $scope.xrp.currency,
          path_status: 'waiting',
          fund_status: 'none'
        };
        $scope.nickname = '';
        $scope.error_type = '';
        if ($scope.exchangeForm) $scope.exchangeForm.$setPristine(true);
      };

      $scope.cancelConfirm = function () {
        $scope.mode = 'form';
        $scope.exchange.alt = null;
      };

      $scope.reset_goto = function (tabName) {
        $scope.reset();

        // TODO do something clever instead of document.location
        // because goToTab does $scope.$digest() which we don't need
        document.location = '#' + tabName;
      };

      /**
       * N3. Confirmation page
       */
      $scope.exchange_prepared = function () {
        $scope.confirm_wait = true;
        $timeout(function () {
          $scope.confirm_wait = false;
        }, 1000, true);

        $scope.mode = 'confirm';
      };

      /**
       * N4. Waiting for transaction result page
       */
      $scope.exchange_confirmed = function () {

        // parse the currency name and extract the iso
        var currency = Currency.from_human($scope.exchange.currency_name);
        currency = currency.has_interest() ? currency.to_hex() : currency.get_iso();
        var amount = Amount.from_human('' + $scope.exchange.amount + ' ' + currency);

        amount.set_issuer(id.account);

        var tx = network.remote.transaction();

        // Add memo to tx
        tx.addMemo('client', 'rt' + $rootScope.version);

        // Destination tag
        tx.destination_tag(webutil.getDestTagFromAddress(id.account));
        tx.payment(id.account, id.account, amount.to_json());
        tx.send_max($scope.exchange.alt.send_max);
        tx.paths($scope.exchange.alt.paths);

        if ($scope.exchange.secret) {
          tx.secret($scope.exchange.secret);
        } else {
          // Get secret asynchronously
          keychain.requestSecret(id.account, id.username,
            function (err, secret) {
              if (err) {
                console.log('client: exchange tab: error while ' +
                  'unlocking wallet: ', err);
                $scope.mode = 'error';
                $scope.error_type = 'unlockFailed';

                return;
              }

              $scope.exchange.secret = secret;
              $scope.exchange_confirmed();
            });
          return;
        }

        tx.on('proposed', function (res) {
          $scope.$apply(function () {
            setEngineStatus(res, false);
            $scope.exchanged(tx.hash);

            // Remember currency and increase order
            var found;

            for (var i = 0; i < $scope.currencies_all.length; i++) {
              if ($scope.currencies_all[i].value.toLowerCase() === $scope.exchange.amount_feedback.currency().get_iso().toLowerCase()) {
                $scope.currencies_all[i].order++;
                found = true;
                break;
              }
            }

            // // Removed feature until a permanent fix
            // if (!found) {
            //   $scope.currencies_all.push({
            //     name' $scope.exchange.amount_feedback.currency().to_human().toUpperCase(),
            //     value: $scope.exchange.amount_feedback.currency().to_human().toUpperCase(),
            //     order: 1
            //   });
            // }
          });
        });
        tx.on('success', function(res) {
          setEngineStatus(res, true);
          try {
            var tx = rewriter.processTxn(res.tx_json, res.metadata, id.account);
            var ccPairs = _.map(tx.affectedCurrencies, function(currencyCode) {
              if (currencyCode != 'XRP') {
                var balanceChangeEffect = _.filter(tx.effects, function(effect) {
                  return effect.type = 'trust_change_balance' && effect.currency == currencyCode;
                })[0];
                var res =  currencyCode + '.' + id.resolveNameSync(balanceChangeEffect.amount.issuer().to_json(), { tilde: true });
                return res;
              }
              return currencyCode;
            });
            var ccyPair = ccPairs.join('/');
            var eventProp = {
              Status: 'success',
              'Currency pair': ccyPair,
              Address: $scope.userBlob.data.account_id,
              'Transaction ID': res.tx_json.hash,
              Amount: amount.to_number(false)
            };
            rpTracker.track('Convert order result', eventProp);
          } catch (err) {
            console.warn(err);
          }
        });
        tx.on('error', function(res) {
          setImmediate(function () {
            $scope.$apply(function () {
              $scope.mode = 'rippleerror';
              setEngineStatus(res, false);

              if (res.error === 'remoteError' &&
                  res.remote.error === 'noPath') {
                $scope.mode = 'status';
                $scope.tx_result = 'noPath';
              }
            });
          });
          try {
            var curAltCode = $scope.exchange.alt.amount.currency().get_iso();
            var ccyPair = $scope.exchange.currency_code + '/' + curAltCode;
            var eventProp = {
              Status: 'error',
              Message: res.engine_result,
              'Currency pair': ccyPair,
              Address: $scope.userBlob.data.account_id
            };
            rpTracker.track('Convert order result', eventProp);
          } catch (err) {
            console.warn(err);
          }
        });
        tx.submit();

        $scope.mode = 'sending';
      };

      /**
       * N6. exchanged page
       */
      $scope.exchanged = function (hash) {
        $scope.mode = 'status';
        network.remote.on('transaction', handleAccountEvent);

        function handleAccountEvent(e) {
          $scope.$apply(function () {
            if (e.transaction.hash === hash) {
              setEngineStatus(e, true);
              network.remote.removeListener('transaction', handleAccountEvent);
            }
          });
        }
      };

      function setEngineStatus(res, accepted) {
        $scope.engine_result = res.engine_result;
        $scope.engine_result_message = res.engine_result_message;
        $scope.engine_status_accepted = accepted;

        switch (res.engine_result.slice(0, 3)) {
          case 'tes':
            $scope.tx_result = accepted ? 'cleared' : 'pending';
            break;
          case 'tem':
            $scope.tx_result = 'malformed';
            break;
          case 'ter':
            $scope.tx_result = 'failed';
            break;
          case 'tep':
            $scope.tx_result = 'partial';
            break;
          case 'tec':
            $scope.tx_result = 'claim';
            break;
          case 'tef':
            $scope.tx_result = 'failure';
            break;
          case 'tel':
            $scope.tx_result = 'local';
            break;
          default:
            $scope.tx_result = 'unknown';
            console.warn('Unhandled engine status encountered!');
        }
      }

      $scope.reset();

      updateCurrencyOptions();

      // Stop the pathfinding when leaving the page
      $scope.$on('$destroy', function(){
        if (pf && 'function' === typeof pf.close) {
          pf.close();
        }
      });
    }]);
};

module.exports = ExchangeTab;
<commit_msg>[TASK] Convert: not report first paths (RT-2176)<commit_after>var util = require('util'),
    webutil = require('../util/web'),
    Tab = require('../client/tab').Tab,
    Amount = ripple.Amount,
    Base = ripple.Base,
    rewriter = require('../util/jsonrewriter'),
    Currency = ripple.Currency;

var ExchangeTab = function ()
{
  Tab.call(this);
};

util.inherits(ExchangeTab, Tab);

ExchangeTab.prototype.tabName = 'exchange';
ExchangeTab.prototype.mainMenu = 'exchange';

ExchangeTab.prototype.generateHtml = function ()
{
  return require('../../jade/tabs/exchange.jade')();
};

ExchangeTab.prototype.angular = function (module)
{
  module.controller('ExchangeCtrl', ['$scope', '$timeout', '$routeParams',
    'rpId', 'rpNetwork', 'rpTracker', 'rpKeychain', '$rootScope', '$location',
    function ($scope, $timeout, $routeParams, id, network, rpTracker, keychain, $rootScope, $location)
    {
      var pathUpdateTimeout;

      var timer, pf;

      // Remember user preference on Convert vs. Trade
      $rootScope.ripple_exchange_selection_trade = false;

      var xrpCurrency = Currency.from_json('XRP');

      $scope.xrp = {
        name: xrpCurrency.to_human({full_name:$scope.currencies_all_keyed.XRP.name}),
        code: xrpCurrency.get_iso(),
        currency: xrpCurrency
      };

      $scope.$watch('exchange.amount', function () {
        $scope.update_exchange();
      }, true);

      $scope.$watch('exchange.currency_name', function () {
        var exchange = $scope.exchange;
        var currency = Currency.from_human($scope.exchange.currency_name ? $scope.exchange.currency_name : 'XRP');
        exchange.currency_obj = currency;
        exchange.currency_code = currency.get_iso();
        exchange.currency_name = currency.to_human({
          full_name: $scope.currencies_all_keyed[currency.get_iso()] ? $scope.currencies_all_keyed[currency.get_iso()].name : null
        });
        $scope.update_exchange();
      }, true);

      $scope.gotoFund = function() {
        $location.path('/xrp');
      };

      $scope.reset_paths = function () {
        var exchange = $scope.exchange;

        exchange.alternatives = [];
      };

      $scope.update_exchange = function () {
        var exchange = $scope.exchange;
        var currency = ripple.Currency.from_human(exchange.currency_name);

        $scope.reset_paths();

        // if formatted or money to exchange is 0 then don't calculate paths or offer to exchange
        if (parseFloat(exchange.amount) === 0 || !exchange.currency_name)
        {
          $scope.error_type = 'required';
          return false;
        }

        else {
          $scope.error_type = '';
        }

        var matchedCurrency = currency.has_interest() ? currency.to_hex() : currency.get_iso();
        var match = /^([a-zA-Z0-9]{3}|[A-Fa-f0-9]{40})\b/.exec(matchedCurrency);

        if (!match) {
          // Currency code not recognized, should have been caught by
          // form validator.
          return;
        }

        // Demurrage: Get a reference date five minutes in the future
        //
        // Normally, when using demurrage currencies, we would immediately round
        // down (e.g. 0.99999 instead of 1) as demurrage occurs continuously. Not
        // a good user experience.
        //
        // By choosing a date in the future, this gives us a time window before
        // this rounding down occurs. Note that for positive interest currencies
        // this actually *causes* the same odd rounding problem, so in the future
        // we'll want a better solution, but for right now this does what we need.
        var refDate = new Date(new Date().getTime() + 5 * 60000);

        exchange.amount_feedback = Amount.from_human('' + exchange.amount + ' ' + matchedCurrency, { reference_date: refDate });
        exchange.amount_feedback.set_issuer(id.account);

        if (exchange.amount_feedback.is_valid() && exchange.amount_feedback.is_positive()) {
          exchange.path_status = 'pending';
          exchange.alt = null;

          if (pathUpdateTimeout) clearTimeout(pathUpdateTimeout);
          pathUpdateTimeout = $timeout($scope.update_paths, 500);
        } else {
          exchange.path_status = 'waiting';
        }
      };

      $scope.update_paths = function () {
        $scope.$apply(function () {
          $scope.exchange.path_status = 'pending';
          var amount = $scope.exchange.amount_feedback;

          if (amount.is_zero()) return;

          // Start path find
          pf = network.remote.path_find(id.account,
              id.account,
              amount);
              // $scope.generate_src_currencies());
              // XXX: Roll back pathfinding changes temporarily
          var isIssuer = $scope.generate_issuer_currencies();
          var pathfindJustStarted = true;

          var lastUpdate;

          pf.on('update', function (upd) {
            // if no paths found and it is first update - skip it, it often wrong
            if (pathfindJustStarted && (!upd.alternatives || !upd.alternatives.length)) {
              pathfindJustStarted = false;
              return;
            }
            pathfindJustStarted = false;
            $scope.$apply(function () {
              lastUpdate = new Date();

              clearInterval(timer);
              timer = setInterval(function(){
                $scope.$apply(function(){
                  var seconds = Math.round((new Date() - lastUpdate) / 1000);
                  $scope.lastUpdate = seconds || 0;
                });
              }, 1000);

              if (!upd.alternatives || !upd.alternatives.length) {
                $scope.exchange.path_status  = 'no-path';
                $scope.exchange.alternatives = [];
              } else {
                var currencies = {};
                $scope.exchange.path_status  = 'done';
                $scope.exchange.alternatives = _.filter(_.map(upd.alternatives, function (raw) {
                  var alt = {};
                  alt.amount   = Amount.from_json(raw.source_amount);
                  alt.rate     = alt.amount.ratio_human(amount);
                  alt.send_max = alt.amount.product_human(Amount.from_json('1.01'));
                  alt.paths    = raw.paths_computed
                      ? raw.paths_computed
                      : raw.paths_canonical;

                  if (alt.amount.issuer().to_json() != $scope.address && !isIssuer[alt.amount.currency().to_hex()]) {
                    currencies[alt.amount.currency().to_hex()] = true;
                  }

                  return alt;
                }), function(alt) {
                  // XXX: Roll back pathfinding changes temporarily
                  /* if (currencies[alt.amount.currency().to_hex()]) {
                    return alt.amount.issuer().to_json() != $scope.address;
                  } */
                  // return false;
                  return !(alt.amount.is_native() && $scope.account.max_spend
                    && $scope.account.max_spend.to_number() > 1
                    && $scope.account.max_spend.compareTo(alt.amount) < 0);
                });
                if (!$scope.exchange.alternatives.length) {
                  $scope.exchange.path_status  = 'no-path';
                  $scope.exchange.alternatives = [];
                }
              }
            });
          });
        });
      };

      var updateCurrencyOptions = function(){
        // create a list of currency codes from the trust line objects
        var currencies = _.uniq(_.map($scope.lines, function (line) {
          return line.currency;
        }));

        // add XRP
        currencies.unshift('XRP');

        // create a currency object for each of the currency codes
        for (var i = 0; i < currencies.length; i++) {
          currencies[i] = ripple.Currency.from_json(currencies[i]);
        }

        // create the display version of the currencies
        currencies = _.map(currencies, function (currency) {
          if ($scope.currencies_all_keyed[currency.get_iso()]) {
            return currency.to_human({full_name:$scope.currencies_all_keyed[currency.get_iso()].name});
          }

          return currency.get_iso();
        });

        $scope.currency_choices = currencies;
      };

      $scope.$on('$balancesUpdate', updateCurrencyOptions);

      $scope.reset = function () {
        $scope.mode = 'form';

        // XXX Most of these variables should be properties of $scope.exchange.
        //     The Angular devs recommend that models be objects due to the way
        //     scope inheritance works.
        $scope.exchange = {
          amount: '',
          currency_name: $scope.xrp.name,
          currency_code: $scope.xrp.code,
          currency_obj: $scope.xrp.currency,
          path_status: 'waiting',
          fund_status: 'none'
        };
        $scope.nickname = '';
        $scope.error_type = '';
        if ($scope.exchangeForm) $scope.exchangeForm.$setPristine(true);
      };

      $scope.cancelConfirm = function () {
        $scope.mode = 'form';
        $scope.exchange.alt = null;
      };

      $scope.reset_goto = function (tabName) {
        $scope.reset();

        // TODO do something clever instead of document.location
        // because goToTab does $scope.$digest() which we don't need
        document.location = '#' + tabName;
      };

      /**
       * N3. Confirmation page
       */
      $scope.exchange_prepared = function () {
        $scope.confirm_wait = true;
        $timeout(function () {
          $scope.confirm_wait = false;
        }, 1000, true);

        $scope.mode = 'confirm';
      };

      /**
       * N4. Waiting for transaction result page
       */
      $scope.exchange_confirmed = function () {

        // parse the currency name and extract the iso
        var currency = Currency.from_human($scope.exchange.currency_name);
        currency = currency.has_interest() ? currency.to_hex() : currency.get_iso();
        var amount = Amount.from_human('' + $scope.exchange.amount + ' ' + currency);

        amount.set_issuer(id.account);

        var tx = network.remote.transaction();

        // Add memo to tx
        tx.addMemo('client', 'rt' + $rootScope.version);

        // Destination tag
        tx.destination_tag(webutil.getDestTagFromAddress(id.account));
        tx.payment(id.account, id.account, amount.to_json());
        tx.send_max($scope.exchange.alt.send_max);
        tx.paths($scope.exchange.alt.paths);

        if ($scope.exchange.secret) {
          tx.secret($scope.exchange.secret);
        } else {
          // Get secret asynchronously
          keychain.requestSecret(id.account, id.username,
            function (err, secret) {
              if (err) {
                console.log('client: exchange tab: error while ' +
                  'unlocking wallet: ', err);
                $scope.mode = 'error';
                $scope.error_type = 'unlockFailed';

                return;
              }

              $scope.exchange.secret = secret;
              $scope.exchange_confirmed();
            });
          return;
        }

        tx.on('proposed', function (res) {
          $scope.$apply(function () {
            setEngineStatus(res, false);
            $scope.exchanged(tx.hash);

            // Remember currency and increase order
            var found;

            for (var i = 0; i < $scope.currencies_all.length; i++) {
              if ($scope.currencies_all[i].value.toLowerCase() === $scope.exchange.amount_feedback.currency().get_iso().toLowerCase()) {
                $scope.currencies_all[i].order++;
                found = true;
                break;
              }
            }

            // // Removed feature until a permanent fix
            // if (!found) {
            //   $scope.currencies_all.push({
            //     name' $scope.exchange.amount_feedback.currency().to_human().toUpperCase(),
            //     value: $scope.exchange.amount_feedback.currency().to_human().toUpperCase(),
            //     order: 1
            //   });
            // }
          });
        });
        tx.on('success', function(res) {
          setEngineStatus(res, true);
          try {
            var tx = rewriter.processTxn(res.tx_json, res.metadata, id.account);
            var ccPairs = _.map(tx.affectedCurrencies, function(currencyCode) {
              if (currencyCode != 'XRP') {
                var balanceChangeEffect = _.filter(tx.effects, function(effect) {
                  return effect.type = 'trust_change_balance' && effect.currency == currencyCode;
                })[0];
                var res =  currencyCode + '.' + id.resolveNameSync(balanceChangeEffect.amount.issuer().to_json(), { tilde: true });
                return res;
              }
              return currencyCode;
            });
            var ccyPair = ccPairs.join('/');
            var eventProp = {
              Status: 'success',
              'Currency pair': ccyPair,
              Address: $scope.userBlob.data.account_id,
              'Transaction ID': res.tx_json.hash,
              Amount: amount.to_number(false)
            };
            rpTracker.track('Convert order result', eventProp);
          } catch (err) {
            console.warn(err);
          }
        });
        tx.on('error', function(res) {
          setImmediate(function () {
            $scope.$apply(function () {
              $scope.mode = 'rippleerror';
              setEngineStatus(res, false);

              if (res.error === 'remoteError' &&
                  res.remote.error === 'noPath') {
                $scope.mode = 'status';
                $scope.tx_result = 'noPath';
              }
            });
          });
          try {
            var curAltCode = $scope.exchange.alt.amount.currency().get_iso();
            var ccyPair = $scope.exchange.currency_code + '/' + curAltCode;
            var eventProp = {
              Status: 'error',
              Message: res.engine_result,
              'Currency pair': ccyPair,
              Address: $scope.userBlob.data.account_id
            };
            rpTracker.track('Convert order result', eventProp);
          } catch (err) {
            console.warn(err);
          }
        });
        tx.submit();

        $scope.mode = 'sending';
      };

      /**
       * N6. exchanged page
       */
      $scope.exchanged = function (hash) {
        $scope.mode = 'status';
        network.remote.on('transaction', handleAccountEvent);

        function handleAccountEvent(e) {
          $scope.$apply(function () {
            if (e.transaction.hash === hash) {
              setEngineStatus(e, true);
              network.remote.removeListener('transaction', handleAccountEvent);
            }
          });
        }
      };

      function setEngineStatus(res, accepted) {
        $scope.engine_result = res.engine_result;
        $scope.engine_result_message = res.engine_result_message;
        $scope.engine_status_accepted = accepted;

        switch (res.engine_result.slice(0, 3)) {
          case 'tes':
            $scope.tx_result = accepted ? 'cleared' : 'pending';
            break;
          case 'tem':
            $scope.tx_result = 'malformed';
            break;
          case 'ter':
            $scope.tx_result = 'failed';
            break;
          case 'tep':
            $scope.tx_result = 'partial';
            break;
          case 'tec':
            $scope.tx_result = 'claim';
            break;
          case 'tef':
            $scope.tx_result = 'failure';
            break;
          case 'tel':
            $scope.tx_result = 'local';
            break;
          default:
            $scope.tx_result = 'unknown';
            console.warn('Unhandled engine status encountered!');
        }
      }

      $scope.reset();

      updateCurrencyOptions();

      // Stop the pathfinding when leaving the page
      $scope.$on('$destroy', function(){
        if (pf && 'function' === typeof pf.close) {
          pf.close();
        }
      });
    }]);
};

module.exports = ExchangeTab;
<|endoftext|>


<commit_before>var jumprDB = new Firebase('https://glowing-torch-883.firebaseio.com');

/* hide the template of the order */
//$(".template").hide();

/* Get User Info*/

var authData = jumprDB.getAuth();
if (authData) {
    jumprDB.child("users").child(authData.uid).once("value", function(snapshot) {
        /* get cafe id*/

        var store = snapshot.child("cafe").val();
        console.log(store);
        var cafeDB =  jumprDB.child("cafes").child(store);
        var historyDB = jumprDB.child("history");

        // Create a callback which logs the current auth state
        function authDataCallback(authData) {
            if (authData) {
                console.log("User " + authData.uid + " is logged in with " + authData.provider);
            } else {
                console.log("User is logged out");
            }
        }
        // Register the callback to be fired every time auth state changes
        jumprDB.onAuth(authDataCallback);

        cafeDB.child("name").once("value", function(snapshot) {
            $("#storeName").text(snapshot.val());
        }, function (errorObject) {
            console.log("The read failed: " + errorObject.code);
        });

        historyDB.on('child_added', function(snapshot, prevChildKey) {
            function getPickUpTimeAndName($order) {
                return $order.find(".timeAndName").text();
            }

            /* Display order info on the dashboard */
            function addOrder(name, timeOfOrder, timeOfPickUp, items, orderId) {
                var timeAndName = timeOfPickUp + " " + name;

                $orders = $(".orders")
                $orderBottom = $orders.children(".order.template");
                $orderAfter = $orderBottom;

                $order = $orders.children(".order.template").clone();
                $order.removeClass("template");
                $order.show();

                $order.attr("id", orderId);

                $order.find(".timeAndName").text(timeAndName);
                $order.find(".itemList").append(items);
                $order.find(".orderId").text("Order ID : " + orderId);
                $order.find(".timeOfOrder").text("This oreder was created on " + timeOfOrder);

                /* find the best place to display the order */
                while( getPickUpTimeAndName($order) < getPickUpTimeAndName($orderAfter.prev()) ){
                    $orderAfter = $orderAfter.prev();
                }

                $orderAfter.before($order);
            }

            var newOrder = snapshot.val();

            var name = newOrder.name,
                timeOfPickUp = newOrder.timeOfPickUp,
                timeOfOrder = newOrder.timeOfOrder,
                orderId = snapshot.key();

            var itemsObj = snapshot.child("items");
            var itemsHtml = "
";
            itemsObj.forEach(function(childSnapshot) {
                itemsHtml += '
' + childSnapshot.key() + " " + childSnapshot.val() +'
';
            });
            itemsHtml += "
";

            addOrder(name, timeOfOrder, timeOfPickUp, itemsHtml, orderId);

        });

        history.on('child_removed', function(dataSnapshot) {
            function removeOrder(orderID) {
                $order = $(".orders").children(".order#" + orderID).remove();
            }

            var orderIdToBeDeleted = dataSnapshot.ref().key();
            removeOrder(orderIdToBeDeleted);
        });

        /* logout */
        $(document).on("click", "#logout", function(){
            jumprDB.unauth();
            top.location.href = "./login.html";
        });

    }, function (errorObject) {
        console.log("The read failed: " + errorObject.code);
    });
}

/*
$(document).on("click", ".order", function(){
    //window.alert("deleting the item");
    var orderId = $(this).attr("id");
    removeOrder(orderId);
    //window.alert(orderId + " was removed");
});
*/

<commit_msg>history for cafe<commit_after>var jumprDB = new Firebase('https://glowing-torch-883.firebaseio.com');

/* hide the template of the order */
$(".template").hide();

/* Get User Info*/

var authData = jumprDB.getAuth();
if (authData) {
    jumprDB.child("users").child(authData.uid).once("value", function(snapshot) {
        /* get cafe id*/

        var store = snapshot.child("cafe").val();
        var cafeDB =  jumprDB.child("cafes").child(store);
        var historyDB = jumprDB.child("history");

        // Create a callback which logs the current auth state
        function authDataCallback(authData) {
            if (authData) {
                console.log("User " + authData.uid + " is logged in with " + authData.provider);
            } else {
                console.log("User is logged out");
            }
        }
        // Register the callback to be fired every time auth state changes
        jumprDB.onAuth(authDataCallback);

        cafeDB.child("name").once("value", function(snapshot) {
            $("#storeName").text(snapshot.val());
        }, function (errorObject) {
            console.log("The read failed: " + errorObject.code);
        });

        cafeDB.child("history").once("value", function(snapshot) {
            function addOrderById (orderID) {
                historyDB.child(orderID).once("value", function(snap) {
                    /* Display order info on the dashboard */
                    function addOrder(name, timeOfOrder, timeOfPickUp, items, orderId) {
                        function getPickUpTimeAndName($order) {
                            return $order.find(".timeAndName").text();
                        }

                        var timeAndName = timeOfPickUp + " " + name;

                        $orders = $(".orders")
                        $orderBottom = $orders.children(".order.template");
                        $orderAfter = $orderBottom;

                        $order = $orders.children(".order.template").clone();
                        $order.removeClass("template");
                        $order.show();

                        $order.attr("id", orderId);

                        $order.find(".timeAndName").text(timeAndName);
                        $order.find(".itemList").append(items);
                        $order.find(".orderId").text("Order ID : " + orderId);
                        $order.find(".timeOfOrder").text("This oreder was created on " + timeOfOrder);

                        /* find the best place to display the order */
                        while( getPickUpTimeAndName($order) < getPickUpTimeAndName($orderAfter.prev()) ){
                            $orderAfter = $orderAfter.prev();
                        }

                        $orderAfter.before($order);
                    }

                    var newOrder = snap.val();
                    var name = newOrder.name,
                        timeOfPickUp = newOrder.timeOfPickUp,
                        timeOfOrder = newOrder.timeOfOrder,
                        orderId = snapshot.key();

                    var itemsObj = snapshot.child("items");
                    var itemsHtml = "
";
                    itemsObj.forEach(function(childSnapshot) {
                        itemsHtml += '
' + childSnapshot.key() + " " + childSnapshot.val() +'
';
                    });
                    itemsHtml += "
";

                    addOrder(name, timeOfOrder, timeOfPickUp, itemsHtml, orderId);
                });
            }

            snapshot.forEach(function(childSnapshot) {
                addOrderById(childSnapshot.val());
            });
        });

        /* logout */
        $(document).on("click", "#logout", function(){
            jumprDB.unauth();
            top.location.href = "./login.html";
        });

    }, function (errorObject) {
        console.log("The read failed: " + errorObject.code);
    });
}

/*
$(document).on("click", ".order", function(){
    //window.alert("deleting the item");
    var orderId = $(this).attr("id");
    removeOrder(orderId);
    //window.alert(orderId + " was removed");
});
*/

<|endoftext|>


<commit_before>import { attr } from './attr';
import { inBrowser } from './env';
import { closest, index, matches, parent } from './filter';
import { isDocument, isString, memoize, toNode, toNodes } from './lang';

export function query(selector, context) {
    return find(selector, getContext(selector, context));
}

export function queryAll(selector, context) {
    return findAll(selector, getContext(selector, context));
}

function getContext(selector, context = document) {
    return (isString(selector) && isContextSelector(selector)) || isDocument(context)
        ? context
        : context.ownerDocument;
}

export function find(selector, context) {
    return toNode(_query(selector, context, 'querySelector'));
}

export function findAll(selector, context) {
    return toNodes(_query(selector, context, 'querySelectorAll'));
}

function _query(selector, context = document, queryFn) {
    if (!selector || !isString(selector)) {
        return selector;
    }

    selector = selector.replace(contextSanitizeRe, '$1 *');

    if (isContextSelector(selector)) {
        selector = splitSelector(selector)
            .map((selector) => {
                let ctx = context;

                if (selector[0] === '!') {
                    const selectors = selector.substr(1).trim().split(' ');
                    ctx = closest(parent(context), selectors[0]);
                    selector = selectors.slice(1).join(' ').trim();
                }

                if (selector[0] === '-') {
                    const selectors = selector.substr(1).trim().split(' ');
                    const prev = (ctx || context).previousElementSibling;
                    ctx = matches(prev, selector.substr(1)) ? prev : null;
                    selector = selectors.slice(1).join(' ');
                }

                if (!ctx) {
                    return null;
                }

                return `${domPath(ctx)} ${selector}`;
            })
            .filter(Boolean)
            .join(',');

        context = document;
    }

    try {
        return context[queryFn](selector);
    } catch (e) {
        return null;
    }
}

const contextSelectorRe = /(^|[^\\],)\s*[!>+~-]/;
const contextSanitizeRe = /([!>+~-])(?=\s+[!>+~-]|\s*$)/g;

const isContextSelector = memoize((selector) => selector.match(contextSelectorRe));

const selectorRe = /.*?[^\\](?:,|$)/g;

const splitSelector = memoize((selector) =>
    selector.match(selectorRe).map((selector) => selector.replace(/,$/, '').trim())
);

function domPath(element) {
    const names = [];
    while (element.parentNode) {
        const id = attr(element, 'id');
        if (id) {
            names.unshift(`#${escape(id)}`);
            break;
        } else {
            let { tagName } = element;
            if (tagName !== 'HTML') {
                tagName += `:nth-child(${index(element) + 1})`;
            }
            names.unshift(tagName);
            element = element.parentNode;
        }
    }
    return names.join(' > ');
}

const escapeFn =
    (inBrowser && window.CSS && CSS.escape) ||
    function (css) {
        return css.replace(/([^\x7f-\uFFFF\w-])/g, (match) => `\\${match}`);
    };
export function escape(css) {
    return isString(css) ? escapeFn.call(null, css) : '';
}
<commit_msg>refactor: remove check for window.CSS<commit_after>import { attr } from './attr';
import { closest, index, matches, parent } from './filter';
import { isDocument, isString, memoize, toNode, toNodes } from './lang';

export function query(selector, context) {
    return find(selector, getContext(selector, context));
}

export function queryAll(selector, context) {
    return findAll(selector, getContext(selector, context));
}

function getContext(selector, context = document) {
    return (isString(selector) && isContextSelector(selector)) || isDocument(context)
        ? context
        : context.ownerDocument;
}

export function find(selector, context) {
    return toNode(_query(selector, context, 'querySelector'));
}

export function findAll(selector, context) {
    return toNodes(_query(selector, context, 'querySelectorAll'));
}

function _query(selector, context = document, queryFn) {
    if (!selector || !isString(selector)) {
        return selector;
    }

    selector = selector.replace(contextSanitizeRe, '$1 *');

    if (isContextSelector(selector)) {
        selector = splitSelector(selector)
            .map((selector) => {
                let ctx = context;

                if (selector[0] === '!') {
                    const selectors = selector.substr(1).trim().split(' ');
                    ctx = closest(parent(context), selectors[0]);
                    selector = selectors.slice(1).join(' ').trim();
                }

                if (selector[0] === '-') {
                    const selectors = selector.substr(1).trim().split(' ');
                    const prev = (ctx || context).previousElementSibling;
                    ctx = matches(prev, selector.substr(1)) ? prev : null;
                    selector = selectors.slice(1).join(' ');
                }

                if (!ctx) {
                    return null;
                }

                return `${domPath(ctx)} ${selector}`;
            })
            .filter(Boolean)
            .join(',');

        context = document;
    }

    try {
        return context[queryFn](selector);
    } catch (e) {
        return null;
    }
}

const contextSelectorRe = /(^|[^\\],)\s*[!>+~-]/;
const contextSanitizeRe = /([!>+~-])(?=\s+[!>+~-]|\s*$)/g;

const isContextSelector = memoize((selector) => selector.match(contextSelectorRe));

const selectorRe = /.*?[^\\](?:,|$)/g;

const splitSelector = memoize((selector) =>
    selector.match(selectorRe).map((selector) => selector.replace(/,$/, '').trim())
);

function domPath(element) {
    const names = [];
    while (element.parentNode) {
        const id = attr(element, 'id');
        if (id) {
            names.unshift(`#${escape(id)}`);
            break;
        } else {
            let { tagName } = element;
            if (tagName !== 'HTML') {
                tagName += `:nth-child(${index(element) + 1})`;
            }
            names.unshift(tagName);
            element = element.parentNode;
        }
    }
    return names.join(' > ');
}

export function escape(css) {
    return isString(css) ? CSS.escape(css) : '';
}
<|endoftext|>


<commit_before>function draw(){
    if(game_running){
        frames += 1;

        // if new obstacle should be added this frame, add one
        if(frames % frames_per_obstacle === 0){
            i = random_number(15) + 20;
            obstacles.splice(
                0,
                0,
                [
                    x + i,
                    random_number(500) - 250,
                    i,
                    random_number(15) + 20
                ]
            );
        }

        // if obstacle frequency increase should happen this frame, do it
        if(settings[4] > 0 && frames_per_obstacle > 1 && frames % settings[4] === 0){
            // obstacle frequency increase
            frames_per_obstacle -= 1;
        }

        // if the player has activated jetpack, increase y speed and add smoke
        if(key_jetpack){
            player_speed += settings[2];// jetpack power
            smoke.splice(
                0,
                0,
                [
                    -20,
                    player_y - 10
                ]
            );

        // else apply gravity
        }else{
            player_speed -= settings[1];// gravity
        }

        player_y += player_speed;
    }

    if(settings[8]){// clear?
        buffer.clearRect(
            0,
            0,
            width,
            height
        );
    }

    // draw corridor over grey background
    buffer.fillStyle = '#000';
    buffer.fillRect(
        0,
        y - 250,
        width,
        500
    );

    // draw player body
    buffer.fillStyle = '#090';
    buffer.fillRect(
        x,
        y - player_y - 25,
        25,
        50
    );

    // draw jetpack
    buffer.fillStyle = '#aaa';
    buffer.fillRect(
        x - 25,
        y - player_y - 15,
        25,
        20
    );

    // draw activated jetpack fire
    if(game_running && key_jetpack){
        buffer.fillStyle = '#f00';
        buffer.fillRect(
            x - 22,
            y - player_y + 5,
            18,
            10
        );
    }

    // check if player is outside of game boundaries
    if(player_y + 25 > 250 || player_y - 25 < -250){
        game_running = 0;
        update_best();
    }

    i = obstacles.length - 1;
    if(i >= 0){
        if(game_running){
            do{
                // delete obstacles that are past left side of screen
                if(obstacles[i][0] < -x - 70){
                    obstacles.splice(i, 1);

                }else{
                    // move obstacles left
                    obstacles[i][0] -= 10;

                    // check for player collision with obstacle
                    if(obstacles[i][0] >= -30
                     && obstacles[i][0] <=  obstacles[i][2]
                     && obstacles[i][1] >= -player_y - 25 - obstacles[i][3] * 2
                     && obstacles[i][1] <= -player_y + 25){
                        game_running = 0;
                        update_best();
                    }
                }
            }while(i--);

            // get new amount of obstacles, some may have been spliced
            i = obstacles.length - 1;
        }

        // draw obstacles
        if(i >= 0){
            buffer.fillStyle = '#555';
            do{
                buffer.fillRect(
                    x + obstacles[i][0],
                    y + obstacles[i][1],
                    obstacles[i][2] * 2,
                    obstacles[i][3] * 2
                );
            }while(i--);
        }
    }

    i = smoke.length-1;
    if(i >= 0){
        if(game_running){
            // delete smoke trails past left side of screen, else move left
            do{
                if(smoke[i][0] < -x){
                    smoke.splice(i, 1);

                }else if(game_running){
                    smoke[i][0] -= 10;
                }
            }while(i--);

            // get new amount of smoke, some may have been spliced
            i = smoke.length - 1;
        }

        // draw smoke trails behind the player
        if(i >= 0){
            buffer.fillStyle = '#777';
            do{
                buffer.fillRect(
                    x + smoke[i][0],
                    y - smoke[i][1],
                    10,
                    10
                );
            }while(i--);
        }
    }

    // setup text display
    buffer.font = '23pt sans-serif';
    buffer.textAlign = 'center';
    buffer.textBaseline = 'top';
    buffer.fillStyle = '#fff';

    // if game is over, display game over messages
    if(!game_running){
        if(!played_explosion_sound){
            if(settings[5] > 0){// audio volume
                // play explode sound
            }
            played_explosion_sound = 1;
        }

        i = y / 2;
        if(frames > best_display){
            buffer.fillText(
                'NEW BEST SCORE!',
                x,
                i - 60
            );
        }
        buffer.fillText(
            'You crashed... ☹',
            x,
            i
        );
        buffer.fillText(
            settings[7] + ' = Restart',// restart key
            x,
            i + 60
        );
        buffer.fillText(
            'ESC = Main Menu',
            x,
            i+120
        );
    }

    // top left text displays
    buffer.textAlign = 'left';
    buffer.fillText(
        frames,
        5,
        0
    );
    buffer.fillText(
        best_display,
        5,
        32
    );

    if(settings[8]){// clear?
        canvas.clearRect(
            0,
            0,
            width,
            height
        );
    }
    canvas.drawImage(
        get('buffer'),
        0,
        0
    );
}

function get(i){
    return document.getElementById(i);
}

function random_number(i){
    return Math.floor(Math.random() * i);
}

function resize(){
    if(mode > 0){
        width = window.innerWidth;
        get('buffer').width = width;
        get('canvas').width = width;

        height = window.innerHeight;
        get('buffer').height = height;
        get('canvas').height = height;

        x = width / 2;
        y = height / 2;
    }
}

function save(){
    i = 3;
    do{
        if(isNaN(get(['ms-per-frame', 'obstacle-frequency', 'obstacle-increase', 'audio-volume'][i]).value)
              || get(['ms-per-frame', 'obstacle-frequency', 'obstacle-increase', 'audio-volume'][i]).value < [1, 1, 0, 0][i]){
            get('si').value = [
                30,
                23,
                115,
                1
            ][i];
        }
    }while(i--);

    i = 5;
    do{
        j = [
            'ms-per-frame',
            'gravity',
            'jetpack-power',
            'obstacle-frequency',
            'obstacle-increase',
            'audio-volume'
        ][i];

        if(isNaN(get(j).value) || get(j).value === [30, 1, 2, 23, 115, 1][i]){
            ls.removeItem('jetpack-' + i);
            settings[i] = [
                30,
                1,
                2,
                23,
                115,
                1
            ][i];
            get(j).value = settings[i];

        }else{
            settings[i] = parseFloat(get(j).value);
            ls.setItem(
                'jetpack-' + i,
                settings[i]
            );
        }
    }while(i--);

    if(get('jetpack-key').value === 'W'){
        ls.removeItem('jetpack-6');
        settings[6] = 'W';

    }else{
        settings[6] = get('jetpack-key').value;
        ls.setItem(
            'jetpack-6',
            settings[6]
        );
    }

    if(get('restart-key').value === 'H'){
        ls.removeItem('jetpack-7');
        settings[7] = 'H';

    }else{
        settings[7] = get('restart-key').value;
        ls.setItem(
            'jetpack-7',
            settings[7]
        );
    }

    settings[8] = get('clear').checked;
    if(settings[8]){
        ls.removeItem('jetpack-8');

    }else{
        ls.setItem(
            'jetpack-8',
            0
        );
    }
}

function setmode(newmode){
    clearInterval(interval);

    obstacles = [];
    smoke = [];
    best_display = best;
    mode = newmode;

    // play game mode
    if(mode > 0){
        save();

        frames = 0;
        frames_per_obstacle = settings[3];// obstacle frequency
        game_running = 1;
        played_explosion_sound = 0;
        player_speed = 0;
        player_y = 0;

        get('page').innerHTML='<canvas id=canvas></canvas>';
        buffer = get('buffer').getContext('2d');
        canvas = get('canvas').getContext('2d');

        resize();

        interval = setInterval('draw()', settings[0]);// ms/frame

    // main menu mode
    }else{
        buffer = 0;
        canvas = 0;

        get('page').innerHTML='

Jetpack

Cave Corridor (Best: '
            + best + ')

Reset Best

<input disabled size=9 style=border:0 value="Mouse Click">Activate Jetpack
<input id=jetpack-key maxlength=1 size=9 value='
            + settings[6] + '>Activate Jetpack
<input disabled size=9 style=border:0 value=ESC>Main Menu
<input id=restart-key maxlength=1 size=9 value='
            + settings[7] + '>Restart

<input id=audio-volume max=1 min=0 step=.01 type=range value='
            + settings[5] + '>Audio
<input '
            + (settings[8] ? 'checked ' : '')+'id=clear type=checkbox>Clear
Reset Settings
Hack

<input id=gravity size=1 value='
            + settings[1] + '>Gravity
<input id=jetpack-power size=1 value='
            + settings[2] + '>Jetpack Power
<input id=ms-per-frame size=1 value='
            + settings[0] + '>ms/Frame
<input id=obstacle-frequency size=1 value='
            + settings[3] + '>Obstacle Frequency
<input id=obstacle-increase size=1 value='
            + settings[4] + '>Obstacle Increase

';
    }
}

function update_best(){
    if(frames > best){
        best = frames;
    }

    if(best > 0){
        ls.setItem(
            'jetpack-best',
            best
        );

    }else{
        ls.removeItem('jetpack-best');
    }
}

var ls = window.localStorage;

var best = ls.getItem('jetpack-best') === null ? 0 : parseInt(ls.getItem('jetpack-best'));
var best_display = 0;
var buffer = 0;
var canvas = 0;
var frames = 0;
var game_running = 0;
var height = 0;
var i = 0;
var interval = 0;
var j = 0;
var key_jetpack = 0;
var mode = 0;
var obstacles = [];
var played_explosion_sound = 0;
var player_speed = 0;
var player_y = 0;
var frames_per_obstacle = 0;
var settings = [
    ls.getItem('jetpack-0') === null ?  30 : parseInt(ls.getItem('jetpack-0')),// ms/frame
    ls.getItem('jetpack-1') === null ?   1 : parseFloat(ls.getItem('jetpack-1')),// gravity
    ls.getItem('jetpack-2') === null ?   2 : parseFloat(ls.getItem('jetpack-2')),// jetpack power
    ls.getItem('jetpack-3') === null ?  23 : parseInt(ls.getItem('jetpack-3')),// obstacle frequency
    ls.getItem('jetpack-4') === null ? 115 : parseInt(ls.getItem('jetpack-4')),// obstacle increase
    ls.getItem('jetpack-5') === null ?   1 : parseFloat(ls.getItem('jetpack-5')),// audio volume
    ls.getItem('jetpack-6') === null ? 'W' : ls.getItem('jetpack-6'),// activate jetpack key
    ls.getItem('jetpack-7') === null ? 'H' : ls.getItem('jetpack-7'),// restart key
    ls.getItem('jetpack-8') === null// clear?
];
var smoke = [];
var width = 0;
var x = 0;
var y = 0;

setmode(0);

window.onkeydown = function(e){
    if(mode > 0){
        i = window.event ? event : e;
        i = i.charCode ? i.charCode : i.keyCode;

        if(String.fromCharCode(i) === settings[6]){// activate jetpack key
            key_jetpack = 1;

        }else if(String.fromCharCode(i) === settings[7]){// restart key
            update_best();

            best_display = best;
            frames = 0;
            frames_per_obstacle = settings[3];// obstacle frequency
            game_running = 1;
            obstacles = [];
            played_explosion_sound = 0;
            player_speed = 0;
            player_y = 0;
            smoke = [];

        }else if(i === 27){// ESC
            update_best();
            setmode(0);
        }
    }
};

window.onkeyup = function(e){
    i = window.event ? event : e;
    i = i.charCode ? i.charCode : i.keyCode;

    if(String.fromCharCode(i) === settings[6]){// activate jetpack key
        key_jetpack = 0;
    }
};

window.onmousedown = function(e){
    if(mode > 0){
        e.preventDefault();
        key_jetpack = 1;
    }
};

window.onmouseup = function(e){
    key_jetpack = 0;
};

window.onresize = resize;
<commit_msg>obstacle collision improvements<commit_after>function draw(){
    if(game_running){
        frames += 1;

        // if new obstacle should be added this frame, add one
        if(frames % frames_per_obstacle === 0){
            i = random_number(15) + 20;
            obstacles.splice(
                0,
                0,
                [
                    x + i,
                    random_number(500) - 250,
                    i,
                    random_number(15) + 20
                ]
            );
        }

        // if obstacle frequency increase should happen this frame, do it
        if(settings[4] > 0 && frames_per_obstacle > 1 && frames % settings[4] === 0){
            // obstacle frequency increase
            frames_per_obstacle -= 1;
        }

        // if the player has activated jetpack, increase y speed and add smoke
        if(key_jetpack){
            player_speed += settings[2];// jetpack power
            smoke.splice(
                0,
                0,
                [
                    -20,
                    player_y - 10
                ]
            );

        // else apply gravity
        }else{
            player_speed -= settings[1];// gravity
        }

        player_y += player_speed;
    }

    if(settings[8]){// clear?
        buffer.clearRect(
            0,
            0,
            width,
            height
        );
    }

    // draw corridor over grey background
    buffer.fillStyle = '#000';
    buffer.fillRect(
        0,
        y - 250,
        width,
        500
    );

    // draw player body
    buffer.fillStyle = '#090';
    buffer.fillRect(
        x,
        y - player_y - 25,
        25,
        50
    );

    // draw jetpack
    buffer.fillStyle = '#aaa';
    buffer.fillRect(
        x - 25,
        y - player_y - 15,
        25,
        20
    );

    // draw activated jetpack fire
    if(game_running && key_jetpack){
        buffer.fillStyle = '#f00';
        buffer.fillRect(
            x - 22,
            y - player_y + 5,
            18,
            10
        );
    }

    // check if player is outside of game boundaries
    if(player_y + 25 > 250 || player_y - 25 < -250){
        game_running = 0;
        update_best();
    }

    i = obstacles.length - 1;
    if(i >= 0){
        if(game_running){
            do{
                // delete obstacles that are past left side of screen
                if(obstacles[i][0] < -x - 70){
                    obstacles.splice(i, 1);

                }else{
                    // move obstacles left
                    obstacles[i][0] -= 10;

                    // check for player collision with obstacle
                    if(obstacles[i][0] > -obstacles[i][2] * 2
                     && obstacles[i][0] < obstacles[i][2]
                     && obstacles[i][1] > -player_y - 25 - obstacles[i][3] * 2
                     && obstacles[i][1] < -player_y + 25){
                        game_running = 0;
                        update_best();
                    }
                }
            }while(i--);

            // get new amount of obstacles, some may have been spliced
            i = obstacles.length - 1;
        }

        // draw obstacles
        if(i >= 0){
            buffer.fillStyle = '#555';
            do{
                buffer.fillRect(
                    x + obstacles[i][0],
                    y + obstacles[i][1],
                    obstacles[i][2] * 2,
                    obstacles[i][3] * 2
                );
            }while(i--);
        }
    }

    i = smoke.length-1;
    if(i >= 0){
        if(game_running){
            // delete smoke trails past left side of screen, else move left
            do{
                if(smoke[i][0] < -x){
                    smoke.splice(i, 1);

                }else if(game_running){
                    smoke[i][0] -= 10;
                }
            }while(i--);

            // get new amount of smoke, some may have been spliced
            i = smoke.length - 1;
        }

        // draw smoke trails behind the player
        if(i >= 0){
            buffer.fillStyle = '#777';
            do{
                buffer.fillRect(
                    x + smoke[i][0],
                    y - smoke[i][1],
                    10,
                    10
                );
            }while(i--);
        }
    }

    // setup text display
    buffer.font = '23pt sans-serif';
    buffer.textAlign = 'center';
    buffer.textBaseline = 'top';
    buffer.fillStyle = '#fff';

    // if game is over, display game over messages
    if(!game_running){
        if(!played_explosion_sound){
            if(settings[5] > 0){// audio volume
                // play explode sound
            }
            played_explosion_sound = 1;
        }

        i = y / 2;
        if(frames > best_display){
            buffer.fillText(
                'NEW BEST SCORE!',
                x,
                i - 60
            );
        }
        buffer.fillText(
            'You crashed... ☹',
            x,
            i
        );
        buffer.fillText(
            settings[7] + ' = Restart',// restart key
            x,
            i + 60
        );
        buffer.fillText(
            'ESC = Main Menu',
            x,
            i+120
        );
    }

    // top left text displays
    buffer.textAlign = 'left';
    buffer.fillText(
        frames,
        5,
        0
    );
    buffer.fillText(
        best_display,
        5,
        32
    );

    if(settings[8]){// clear?
        canvas.clearRect(
            0,
            0,
            width,
            height
        );
    }
    canvas.drawImage(
        get('buffer'),
        0,
        0
    );
}

function get(i){
    return document.getElementById(i);
}

function random_number(i){
    return Math.floor(Math.random() * i);
}

function resize(){
    if(mode > 0){
        width = window.innerWidth;
        get('buffer').width = width;
        get('canvas').width = width;

        height = window.innerHeight;
        get('buffer').height = height;
        get('canvas').height = height;

        x = width / 2;
        y = height / 2;
    }
}

function save(){
    i = 3;
    do{
        if(isNaN(get(['ms-per-frame', 'obstacle-frequency', 'obstacle-increase', 'audio-volume'][i]).value)
              || get(['ms-per-frame', 'obstacle-frequency', 'obstacle-increase', 'audio-volume'][i]).value < [1, 1, 0, 0][i]){
            get('si').value = [
                30,
                23,
                115,
                1
            ][i];
        }
    }while(i--);

    i = 5;
    do{
        j = [
            'ms-per-frame',
            'gravity',
            'jetpack-power',
            'obstacle-frequency',
            'obstacle-increase',
            'audio-volume'
        ][i];

        if(isNaN(get(j).value) || get(j).value === [30, 1, 2, 23, 115, 1][i]){
            ls.removeItem('jetpack-' + i);
            settings[i] = [
                30,
                1,
                2,
                23,
                115,
                1
            ][i];
            get(j).value = settings[i];

        }else{
            settings[i] = parseFloat(get(j).value);
            ls.setItem(
                'jetpack-' + i,
                settings[i]
            );
        }
    }while(i--);

    if(get('jetpack-key').value === 'W'){
        ls.removeItem('jetpack-6');
        settings[6] = 'W';

    }else{
        settings[6] = get('jetpack-key').value;
        ls.setItem(
            'jetpack-6',
            settings[6]
        );
    }

    if(get('restart-key').value === 'H'){
        ls.removeItem('jetpack-7');
        settings[7] = 'H';

    }else{
        settings[7] = get('restart-key').value;
        ls.setItem(
            'jetpack-7',
            settings[7]
        );
    }

    settings[8] = get('clear').checked;
    if(settings[8]){
        ls.removeItem('jetpack-8');

    }else{
        ls.setItem(
            'jetpack-8',
            0
        );
    }
}

function setmode(newmode){
    clearInterval(interval);

    obstacles = [];
    smoke = [];
    best_display = best;
    mode = newmode;

    // play game mode
    if(mode > 0){
        save();

        frames = 0;
        frames_per_obstacle = settings[3];// obstacle frequency
        game_running = 1;
        played_explosion_sound = 0;
        player_speed = 0;
        player_y = 0;

        get('page').innerHTML='<canvas id=canvas></canvas>';
        buffer = get('buffer').getContext('2d');
        canvas = get('canvas').getContext('2d');

        resize();

        interval = setInterval('draw()', settings[0]);// ms/frame

    // main menu mode
    }else{
        buffer = 0;
        canvas = 0;

        get('page').innerHTML='

Jetpack

Cave Corridor (Best: '
            + best + ')

Reset Best

<input disabled size=9 style=border:0 value="Mouse Click">Activate Jetpack
<input id=jetpack-key maxlength=1 size=9 value='
            + settings[6] + '>Activate Jetpack
<input disabled size=9 style=border:0 value=ESC>Main Menu
<input id=restart-key maxlength=1 size=9 value='
            + settings[7] + '>Restart

<input id=audio-volume max=1 min=0 step=.01 type=range value='
            + settings[5] + '>Audio
<input '
            + (settings[8] ? 'checked ' : '')+'id=clear type=checkbox>Clear
Reset Settings
Hack

<input id=gravity size=1 value='
            + settings[1] + '>Gravity
<input id=jetpack-power size=1 value='
            + settings[2] + '>Jetpack Power
<input id=ms-per-frame size=1 value='
            + settings[0] + '>ms/Frame
<input id=obstacle-frequency size=1 value='
            + settings[3] + '>Obstacle Frequency
<input id=obstacle-increase size=1 value='
            + settings[4] + '>Obstacle Increase

';
    }
}

function update_best(){
    if(frames > best){
        best = frames;
    }

    if(best > 0){
        ls.setItem(
            'jetpack-best',
            best
        );

    }else{
        ls.removeItem('jetpack-best');
    }
}

var ls = window.localStorage;

var best = ls.getItem('jetpack-best') === null ? 0 : parseInt(ls.getItem('jetpack-best'));
var best_display = 0;
var buffer = 0;
var canvas = 0;
var frames = 0;
var game_running = 0;
var height = 0;
var i = 0;
var interval = 0;
var j = 0;
var key_jetpack = 0;
var mode = 0;
var obstacles = [];
var played_explosion_sound = 0;
var player_speed = 0;
var player_y = 0;
var frames_per_obstacle = 0;
var settings = [
    ls.getItem('jetpack-0') === null ?  30 : parseInt(ls.getItem('jetpack-0')),// ms/frame
    ls.getItem('jetpack-1') === null ?   1 : parseFloat(ls.getItem('jetpack-1')),// gravity
    ls.getItem('jetpack-2') === null ?   2 : parseFloat(ls.getItem('jetpack-2')),// jetpack power
    ls.getItem('jetpack-3') === null ?  23 : parseInt(ls.getItem('jetpack-3')),// obstacle frequency
    ls.getItem('jetpack-4') === null ? 115 : parseInt(ls.getItem('jetpack-4')),// obstacle increase
    ls.getItem('jetpack-5') === null ?   1 : parseFloat(ls.getItem('jetpack-5')),// audio volume
    ls.getItem('jetpack-6') === null ? 'W' : ls.getItem('jetpack-6'),// activate jetpack key
    ls.getItem('jetpack-7') === null ? 'H' : ls.getItem('jetpack-7'),// restart key
    ls.getItem('jetpack-8') === null// clear?
];
var smoke = [];
var width = 0;
var x = 0;
var y = 0;

setmode(0);

window.onkeydown = function(e){
    if(mode > 0){
        i = window.event ? event : e;
        i = i.charCode ? i.charCode : i.keyCode;

        if(String.fromCharCode(i) === settings[6]){// activate jetpack key
            key_jetpack = 1;

        }else if(String.fromCharCode(i) === settings[7]){// restart key
            update_best();

            best_display = best;
            frames = 0;
            frames_per_obstacle = settings[3];// obstacle frequency
            game_running = 1;
            obstacles = [];
            played_explosion_sound = 0;
            player_speed = 0;
            player_y = 0;
            smoke = [];

        }else if(i === 27){// ESC
            update_best();
            setmode(0);
        }
    }
};

window.onkeyup = function(e){
    i = window.event ? event : e;
    i = i.charCode ? i.charCode : i.keyCode;

    if(String.fromCharCode(i) === settings[6]){// activate jetpack key
        key_jetpack = 0;
    }
};

window.onmousedown = function(e){
    if(mode > 0){
        e.preventDefault();
        key_jetpack = 1;
    }
};

window.onmouseup = function(e){
    key_jetpack = 0;
};

window.onresize = resize;
<|endoftext|>