<commit_before>/**
 * A Keyboard module.
 *

 * @returns {{className: string}}
 * @constructor
 */
function Keyboard (svl, canvas, contextMenu, googleMap, ribbon, zoomControl) {
    var self = this;

    /**
     * fix for the shift-getting-stuck bug.
     * this is a documented issue, see here:
     * https://stackoverflow.com/questions/11225694/why-are-onkeyup-events-not-firing-in-javascript-game
     * essentially what's going on is that JS sometimes fires a final keydown after a keyup.
     * (usually happens when multiple events are fired)
     * so the log would look like keydown:shift, keydown: shift, keyup: shift, keydown: shift.
     * To fix this, we note the last time that shift was let go, then
     * ignore any keydown events that were made BEFORE shift was let go, but are executing AFTER.
     *
     * also, we added a buffer to the z key to fix inconsistent behavior when shift and z were pressed at the same time.
     * sometimes, the shift up was detected before the z up. Adding the 100ms buffer fixed this issue.
     */
    var lastShiftKeyUpTimestamp = new Date(0).getTime();
    var status = {
        focusOnTextField: false,
        isOnboarding: false,
        shiftDown: false,
        disableKeyboard: false,
        moving: false
    };

    this.disableKeyboard = function (){
        status.disableKeyboard = true;
    };
    this.enableKeyboard = function (){
        status.disableKeyboard = false;
    };
    // Move in the direction of a link closest to a given angle.
    // Todo: Get rid of dependency to svl.panorama. Inject a streetViewMap into this module and use its interface.
    // Todo. Make the method name more descriptive.
    this._movePano = function (angle) {
        if (googleMap.getStatus("disableWalking")) return;
        // take the cosine of the difference for each link to the current heading in radians and stores them to an array
        var cosines = svl.panorama.links.map(function(link) {
            var headingAngleOffset = util.math.toRadians(svl.panorama.pov.heading + angle) - util.math.toRadians(link.heading);
            return Math.cos(headingAngleOffset);
        });
        var maxVal = Math.max.apply(null, cosines);
        var maxIndex = cosines.indexOf(maxVal);
        if(cosines[maxIndex] > 0.5){
            var panoramaId = svl.panorama.links[maxIndex].pano;

            googleMap.setPano(panoramaId);
        }
    };

    /*
       Move user in specific angle relative to current view for a specific moveTime.
     */
    function timedMove(angle, moveTime){
        if (status.moving || svl.isOnboarding() || svl.popUpMessage.getStatus("isVisible")){
            svl.panorama.set("linksControl", false);
            return;
        }
        svl.contextMenu.hide();
        svl.ui.canvas.deleteIconHolder.css("visibility", "hidden");
        self._movePano(angle);
        //prevent user input of walking commands
        svl.map.timeoutWalking();
        //restore user ability to walk after param moveTime
        setTimeout(svl.map.resetWalking, moveTime);
        //additional check to hide arrows after the fact
        //pop-up may become visible during timeout period
        if (svl.popUpMessage.getStatus('isVisible')){
            svl.panorama.set('linksControl', false);//disable arrows
        }
    }

    this._moveForward = function (){
        timedMove(0, svl.map.getMoveDelay());
    };

    this._moveBackward = function (){
        timedMove(180, svl.map.getMoveDelay());
    };

    /**
     * Change the heading of the current panorama point of view by a particular degree value
     * Todo. Change the method name so it is more descriptive.
     * @param degree
     */
    this._rotatePov = function (degree){
        if (!svl.map.getStatus("disablePanning")){
            svl.contextMenu.hide();
            //panning hide label tag and delete icon
            var labels = svl.labelContainer.getCanvasLabels(),
                labelLen = labels.length;
            for (var i=0; i<labelLen; i++){
                labels[i].setTagVisibility('hidden');
                labels[i].resetTagCoordinate();
            }
            svl.ui.canvas.deleteIconHolder.css('visibility', 'hidden');
            var heading =  svl.panorama.pov.heading;
            var pitch = svl.panorama.pov.pitch;
            var zoom = svl.panorama.pov.zoom;
            heading = (heading + degree + 360) % 360;
            var pov = svl.map.restrictViewPort({
                heading: heading,
                pitch: pitch,
                zoom: zoom
            });
            svl.panorama.setPov({heading: pov.heading, pitch: pov.pitch, zoom: pov.zoom});
        }
    };

    /**
     * This is a callback for a key down event
     * @param {object} e An event object
     * @private
     */
    this._documentKeyDown = function (e) {
        // The callback method that is triggered with a keyUp event.
        //equal button || - button
        if (e.keyCode == 187 || e.keyCode == 189) {
            svl.contextMenu.hide();
            return;
        } else if (!status.focusOnTextField && !status.disableKeyboard) {
            //only set shift if the event was made after the keyup.
            if (e.timeStamp > lastShiftKeyUpTimestamp) {
                status.shiftDown = e.shiftKey;
            }
        }

        if (!status.disableKeyboard && !status.focusOnTextField) {
            if (contextMenu.isOpen()) {
                var label;
                switch (e.keyCode) {
                    case 49:  // "1"
                        contextMenu.checkRadioButton(1);
                        label = contextMenu.getTargetLabel();
                        if (label) {
                            label.setProperty('severity', 1);
                            svl.tracker.push("KeyboardShortcut_Severity_1", {
                                keyCode: e.keyCode
                            });
                            svl.canvas.clear().render2();
                        }
                        break;
                    case 50:  // "2"
                        contextMenu.checkRadioButton(2);
                        label = contextMenu.getTargetLabel();
                        if (label) {
                            label.setProperty('severity', 2);
                            svl.tracker.push("KeyboardShortcut_Severity_2", {
                                keyCode: e.keyCode
                            });
                            svl.canvas.clear().render2();
                        }
                        break;
                    case 51:  // "3"
                        contextMenu.checkRadioButton(3);
                        label = contextMenu.getTargetLabel();
                        if (label) {
                            label.setProperty('severity', 3);
                            svl.tracker.push("KeyboardShortcut_Severity_3", {
                                keyCode: e.keyCode
                            });
                            svl.canvas.clear().render2();
                        }
                        break;
                    case 52:  // "4"
                        contextMenu.checkRadioButton(4);
                        label = contextMenu.getTargetLabel();
                        if (label) {
                            label.setProperty('severity', 4);
                            svl.tracker.push("KeyboardShortcut_Severity_4", {
                                keyCode: e.keyCode
                            });
                            svl.canvas.clear().render2();
                        }
                        break;
                    case 53:  // "5"
                        contextMenu.checkRadioButton(5);
                        label = contextMenu.getTargetLabel();
                        if (label) {
                            label.setProperty('severity', 5);
                            svl.tracker.push("KeyboardShortcut_Severity_5", {
                                keyCode: e.keyCode
                            });
                            svl.canvas.clear().render2();
                        }
                        break;
                }
            } else {
                switch (e.keyCode) {
                    case 16:  // "Shift"
                        break;
                    case 37:  // "Left"
                        self._rotatePov(-2);
                        break;
                    case 39:  // "Right"
                        self._rotatePov(2);
                        break;
                    case 38:
                        self._moveForward();
                        break;
                    case 40:  // "down"
                        self._moveBackward();
                        break;
                }
                if ([37, 38, 39, 40].indexOf(e.keyCode) > -1) {
                    e.preventDefault();
                }
            }
        }
    };

    /**
     * This is a callback for a key up event.
     * @param {object} e An event object
     * @private
     */
    this._documentKeyUp = function (e) {
        if (!status.disableKeyboard) {
            /*
             This is a callback method that is triggered when a keyUp
             event occurs and focus is not on ContextMenu's textbox.
             */
            status.shiftDown = e.shiftKey;
            if (!status.focusOnTextField) {
                var label = contextMenu.isOpen() ? contextMenu.getTargetLabel() : undefined;
                switch (e.keyCode) {
                    case util.misc.getLabelDescriptions('Occlusion')['shortcut']['keyNumber']:
                        // "b" for a blocked view
                        ribbon.modeSwitch("Occlusion");
                        svl.tracker.push("KeyboardShortcut_ModeSwitch_Occlusion", {
                            keyCode: e.keyCode
                        });
                        break;
                    case util.misc.getLabelDescriptions('CurbRamp')['shortcut']['keyNumber']:
                        // "c" for CurbRamp. Switch the mode to the CurbRamp labeling mode.
                        if (!contextMenu.isOpen()) {
                            ribbon.modeSwitch("CurbRamp");
                            svl.tracker.push("KeyboardShortcut_ModeSwitch_CurbRamp", {
                                keyCode: e.keyCode
                            });
                        } else if (contextMenu.isOpen() && label.getProperty('labelType') === 'CurbRamp') {
                            contextMenu.hide();
                            svl.tracker.push("ContextMenu_CloseKeyboardShortcut", {
                                keyCode: e.keyCode
                            });
                            svl.tracker.push("KeyboardShortcut_CloseContextMenu");
                        }
                        break;
                    case util.misc.getLabelDescriptions('Walk')['shortcut']['keyNumber']:
                        // "e" for Explore. Switch the mode to Walk (camera) mode.
                        ribbon.modeSwitch("Walk");
                        svl.tracker.push("KeyboardShortcut_ModeSwitch_Walk", {
                            keyCode: e.keyCode
                        });
                        break;
                    case util.misc.getLabelDescriptions('NoCurbRamp')['shortcut']['keyNumber']:
                        // "m" for MissingCurbRamp. Switch the mode to the MissingCurbRamp labeling mode.
                        if (!contextMenu.isOpen()) {
                            ribbon.modeSwitch("NoCurbRamp");
                            svl.tracker.push("KeyboardShortcut_ModeSwitch_NoCurbRamp", {
                                keyCode: e.keyCode
                            });
                        } else if (contextMenu.isOpen() && label.getProperty('labelType') === 'NoCurbRamp') {
                            contextMenu.hide();
                            svl.tracker.push("ContextMenu_CloseKeyboardShortcut", {
                                keyCode: e.keyCode
                            });
                            svl.tracker.push("KeyboardShortcut_CloseContextMenu");
                        }
                        break;
                    case util.misc.getLabelDescriptions('NoSidewalk')['shortcut']['keyNumber']:
                        ribbon.modeSwitch("NoSidewalk");
                        svl.tracker.push("KeyboardShortcut_ModeSwitch_NoSidewalk", {
                            keyCode: e.keyCode
                        });
                        break;
                    case util.misc.getLabelDescriptions('Obstacle')['shortcut']['keyNumber']:
                        // "o" for Obstacle
                        if (!contextMenu.isOpen()) {
                            ribbon.modeSwitch("Obstacle");
                            svl.tracker.push("KeyboardShortcut_ModeSwitch_Obstacle", {
                                keyCode: e.keyCode
                            });
                        } else if (contextMenu.isOpen() && label.getProperty('labelType') === 'Obstacle') {
                            contextMenu.hide();
                            svl.tracker.push("ContextMenu_CloseKeyboardShortcut", {
                                keyCode: e.keyCode
                            });
                            svl.tracker.push("KeyboardShortcut_CloseContextMenu");
                        }
                        break;
                    case util.misc.getLabelDescriptions('SurfaceProblem')['shortcut']['keyNumber']:
                        if (!contextMenu.isOpen()) {
                            ribbon.modeSwitch("SurfaceProblem");
                            svl.tracker.push("KeyboardShortcut_ModeSwitch_SurfaceProblem", {
                                keyCode: e.keyCode
                            });
                        } else if (contextMenu.isOpen() && label.getProperty('labelType') === 'SurfaceProblem') {
                            contextMenu.hide();
                            svl.tracker.push("ContextMenu_CloseKeyboardShortcut", {
                                keyCode: e.keyCode
                            });
                            svl.tracker.push("KeyboardShortcut_CloseContextMenu");
                        }
                        break;
                    case 16: //shift
                        // store the timestamp here so that we can check if the z-up event is in the buffer range
                        lastShiftKeyUpTimestamp = e.timeStamp;
                        break;
                    case 90:
                        if (contextMenu.isOpen()) {
                            contextMenu.hide();
                            svl.tracker.push("KeyboardShortcut_CloseContextMenu");
                        }
                        // "z" for zoom. By default, it will zoom in. If "shift" is down, it will zoom out.
                        // if shift was down w/in 100 ms of the z up, then it will also zoom out.
                        // This is to catch the scenarios where shift up is detected before the z up.
                        if (status.shiftDown || (e.timeStamp - lastShiftKeyUpTimestamp) < 100) {
                            // Zoom out
                            zoomControl.zoomOut();
                            svl.tracker.push("KeyboardShortcut_ZoomOut", {
                                keyCode: e.keyCode
                            });
                        } else {
                            // Zoom in
                            zoomControl.zoomIn();
                            svl.tracker.push("KeyboardShortcut_ZoomIn", {
                                keyCode: e.keyCode
                            });
                        }
                }
            }

            /*
             This is a callback method that is triggered when a keyUp
             event occurs. It is not relevant to ContextMenu's textbox focus.
             */
            switch (e.keyCode) {
                case 13:
                    // "Enter"
                    if (contextMenu.isOpen()) {
                        contextMenu.hide();
                        contextMenu.handleSeverityPopup();
                        svl.tracker.push('ContextMenu_ClosePressEnter');
                        svl.tracker.push("KeyboardShortcut_CloseContextMenu");
                    }
                    break;
                case 27:
                    // "Escape"
                    if (contextMenu.isOpen()) {
                        contextMenu.hide();
                        svl.tracker.push("KeyboardShortcut_CloseContextMenu");
                    }

                    if (canvas.getStatus('drawing')) {
                        canvas.cancelDrawing();
                        svl.tracker.push("KeyboardShortcut_CancelDrawing");
                    } else {
                        ribbon.backToWalk();
                    }
                    svl.modalExample.hide();
                    break;
            }

            contextMenu.updateRadioButtonImages();
        }
    };

    /**
     * Get status
     * @param {string} key Field name
     * @returns {*}
     */
    this.getStatus = function  (key) {
        if (!(key in status)) {
            console.warn("You have passed an invalid key for status.")
        }
        return status[key];
    };

    /**
     * This method returns whether a shift key is currently pressed or not.
     * @returns {boolean}
     */
    this.isShiftDown = function () {
        return status.shiftDown;
    };

    /**
     * Set status
     * @param key Field name
     * @param value Field value
     * @returns {setStatus}
     */
    this.setStatus = function (key, value) {
        if (key in status) {
            status[key] = value;
        }
    };

    $(document).bind('keyup', this._documentKeyUp);
    $(document).bind('keydown', this._documentKeyDown);
}
<commit_msg>Allow any label keyboard shortcut to close context menu<commit_after>/**
 * A Keyboard module.
 *

 * @returns {{className: string}}
 * @constructor
 */
function Keyboard (svl, canvas, contextMenu, googleMap, ribbon, zoomControl) {
    var self = this;

    /**
     * fix for the shift-getting-stuck bug.
     * this is a documented issue, see here:
     * https://stackoverflow.com/questions/11225694/why-are-onkeyup-events-not-firing-in-javascript-game
     * essentially what's going on is that JS sometimes fires a final keydown after a keyup.
     * (usually happens when multiple events are fired)
     * so the log would look like keydown:shift, keydown: shift, keyup: shift, keydown: shift.
     * To fix this, we note the last time that shift was let go, then
     * ignore any keydown events that were made BEFORE shift was let go, but are executing AFTER.
     *
     * also, we added a buffer to the z key to fix inconsistent behavior when shift and z were pressed at the same time.
     * sometimes, the shift up was detected before the z up. Adding the 100ms buffer fixed this issue.
     */
    var lastShiftKeyUpTimestamp = new Date(0).getTime();
    var status = {
        focusOnTextField: false,
        isOnboarding: false,
        shiftDown: false,
        disableKeyboard: false,
        moving: false
    };

    this.disableKeyboard = function (){
        status.disableKeyboard = true;
    };
    this.enableKeyboard = function (){
        status.disableKeyboard = false;
    };
    // Move in the direction of a link closest to a given angle.
    // Todo: Get rid of dependency to svl.panorama. Inject a streetViewMap into this module and use its interface.
    // Todo. Make the method name more descriptive.
    this._movePano = function (angle) {
        if (googleMap.getStatus("disableWalking")) return;
        // take the cosine of the difference for each link to the current heading in radians and stores them to an array
        var cosines = svl.panorama.links.map(function(link) {
            var headingAngleOffset = util.math.toRadians(svl.panorama.pov.heading + angle) - util.math.toRadians(link.heading);
            return Math.cos(headingAngleOffset);
        });
        var maxVal = Math.max.apply(null, cosines);
        var maxIndex = cosines.indexOf(maxVal);
        if(cosines[maxIndex] > 0.5){
            var panoramaId = svl.panorama.links[maxIndex].pano;

            googleMap.setPano(panoramaId);
        }
    };

    /*
       Move user in specific angle relative to current view for a specific moveTime.
     */
    function timedMove(angle, moveTime){
        if (status.moving || svl.isOnboarding() || svl.popUpMessage.getStatus("isVisible")){
            svl.panorama.set("linksControl", false);
            return;
        }
        svl.contextMenu.hide();
        svl.ui.canvas.deleteIconHolder.css("visibility", "hidden");
        self._movePano(angle);
        //prevent user input of walking commands
        svl.map.timeoutWalking();
        //restore user ability to walk after param moveTime
        setTimeout(svl.map.resetWalking, moveTime);
        //additional check to hide arrows after the fact
        //pop-up may become visible during timeout period
        if (svl.popUpMessage.getStatus('isVisible')){
            svl.panorama.set('linksControl', false);//disable arrows
        }
    }

    this._moveForward = function (){
        timedMove(0, svl.map.getMoveDelay());
    };

    this._moveBackward = function (){
        timedMove(180, svl.map.getMoveDelay());
    };

    /**
     * Change the heading of the current panorama point of view by a particular degree value
     * Todo. Change the method name so it is more descriptive.
     * @param degree
     */
    this._rotatePov = function (degree){
        if (!svl.map.getStatus("disablePanning")){
            svl.contextMenu.hide();
            //panning hide label tag and delete icon
            var labels = svl.labelContainer.getCanvasLabels(),
                labelLen = labels.length;
            for (var i=0; i<labelLen; i++){
                labels[i].setTagVisibility('hidden');
                labels[i].resetTagCoordinate();
            }
            svl.ui.canvas.deleteIconHolder.css('visibility', 'hidden');
            var heading =  svl.panorama.pov.heading;
            var pitch = svl.panorama.pov.pitch;
            var zoom = svl.panorama.pov.zoom;
            heading = (heading + degree + 360) % 360;
            var pov = svl.map.restrictViewPort({
                heading: heading,
                pitch: pitch,
                zoom: zoom
            });
            svl.panorama.setPov({heading: pov.heading, pitch: pov.pitch, zoom: pov.zoom});
        }
    };

    /**
     * This is a callback for a key down event
     * @param {object} e An event object
     * @private
     */
    this._documentKeyDown = function (e) {
        // The callback method that is triggered with a keyUp event.
        //equal button || - button
        if (e.keyCode == 187 || e.keyCode == 189) {
            svl.contextMenu.hide();
            return;
        } else if (!status.focusOnTextField && !status.disableKeyboard) {
            //only set shift if the event was made after the keyup.
            if (e.timeStamp > lastShiftKeyUpTimestamp) {
                status.shiftDown = e.shiftKey;
            }
        }

        if (!status.disableKeyboard && !status.focusOnTextField) {
            if (contextMenu.isOpen()) {
                var label;
                switch (e.keyCode) {
                    case 49:  // "1"
                        contextMenu.checkRadioButton(1);
                        label = contextMenu.getTargetLabel();
                        if (label) {
                            label.setProperty('severity', 1);
                            svl.tracker.push("KeyboardShortcut_Severity_1", {
                                keyCode: e.keyCode
                            });
                            svl.canvas.clear().render2();
                        }
                        break;
                    case 50:  // "2"
                        contextMenu.checkRadioButton(2);
                        label = contextMenu.getTargetLabel();
                        if (label) {
                            label.setProperty('severity', 2);
                            svl.tracker.push("KeyboardShortcut_Severity_2", {
                                keyCode: e.keyCode
                            });
                            svl.canvas.clear().render2();
                        }
                        break;
                    case 51:  // "3"
                        contextMenu.checkRadioButton(3);
                        label = contextMenu.getTargetLabel();
                        if (label) {
                            label.setProperty('severity', 3);
                            svl.tracker.push("KeyboardShortcut_Severity_3", {
                                keyCode: e.keyCode
                            });
                            svl.canvas.clear().render2();
                        }
                        break;
                    case 52:  // "4"
                        contextMenu.checkRadioButton(4);
                        label = contextMenu.getTargetLabel();
                        if (label) {
                            label.setProperty('severity', 4);
                            svl.tracker.push("KeyboardShortcut_Severity_4", {
                                keyCode: e.keyCode
                            });
                            svl.canvas.clear().render2();
                        }
                        break;
                    case 53:  // "5"
                        contextMenu.checkRadioButton(5);
                        label = contextMenu.getTargetLabel();
                        if (label) {
                            label.setProperty('severity', 5);
                            svl.tracker.push("KeyboardShortcut_Severity_5", {
                                keyCode: e.keyCode
                            });
                            svl.canvas.clear().render2();
                        }
                        break;
                }
            } else {
                switch (e.keyCode) {
                    case 16:  // "Shift"
                        break;
                    case 37:  // "Left"
                        self._rotatePov(-2);
                        break;
                    case 39:  // "Right"
                        self._rotatePov(2);
                        break;
                    case 38:
                        self._moveForward();
                        break;
                    case 40:  // "down"
                        self._moveBackward();
                        break;
                }
                if ([37, 38, 39, 40].indexOf(e.keyCode) > -1) {
                    e.preventDefault();
                }
            }
        }
    };

    /**
     * This is a callback for a key up event.
     * @param {object} e An event object
     * @private
     */
    this._documentKeyUp = function (e) {
        if (!status.disableKeyboard) {
            /*
             This is a callback method that is triggered when a keyUp
             event occurs and focus is not on ContextMenu's textbox.
             */
            status.shiftDown = e.shiftKey;
            if (!status.focusOnTextField) {
                switch (e.keyCode) {
                    case util.misc.getLabelDescriptions('Occlusion')['shortcut']['keyNumber']:
                        // "b" for a blocked view
                        ribbon.modeSwitch("Occlusion");
                        svl.tracker.push("KeyboardShortcut_ModeSwitch_Occlusion", {
                            keyCode: e.keyCode
                        });
                        break;
                    case util.misc.getLabelDescriptions('CurbRamp')['shortcut']['keyNumber']:
                        // "c" for CurbRamp. Switch the mode to the CurbRamp labeling mode.
                        if (!contextMenu.isOpen()) {
                            ribbon.modeSwitch("CurbRamp");
                            svl.tracker.push("KeyboardShortcut_ModeSwitch_CurbRamp", {
                                keyCode: e.keyCode
                            });
                        } else {
                            _closeContextMenu(e.keyCode);
                        }
                        break;
                    case util.misc.getLabelDescriptions('Walk')['shortcut']['keyNumber']:
                        // "e" for Explore. Switch the mode to Walk (camera) mode.
                        ribbon.modeSwitch("Walk");
                        svl.tracker.push("KeyboardShortcut_ModeSwitch_Walk", {
                            keyCode: e.keyCode
                        });
                        break;
                    case util.misc.getLabelDescriptions('NoCurbRamp')['shortcut']['keyNumber']:
                        // "m" for MissingCurbRamp. Switch the mode to the MissingCurbRamp labeling mode.
                        if (!contextMenu.isOpen()) {
                            ribbon.modeSwitch("NoCurbRamp");
                            svl.tracker.push("KeyboardShortcut_ModeSwitch_NoCurbRamp", {
                                keyCode: e.keyCode
                            });
                        } else {
                            _closeContextMenu(e.keyCode);
                        }
                        break;
                    case util.misc.getLabelDescriptions('NoSidewalk')['shortcut']['keyNumber']:
                        ribbon.modeSwitch("NoSidewalk");
                        svl.tracker.push("KeyboardShortcut_ModeSwitch_NoSidewalk", {
                            keyCode: e.keyCode
                        });
                        break;
                    case util.misc.getLabelDescriptions('Obstacle')['shortcut']['keyNumber']:
                        // "o" for Obstacle
                        if (!contextMenu.isOpen()) {
                            ribbon.modeSwitch("Obstacle");
                            svl.tracker.push("KeyboardShortcut_ModeSwitch_Obstacle", {
                                keyCode: e.keyCode
                            });
                        } else {
                            _closeContextMenu(e.keyCode);
                        }
                        break;
                    case util.misc.getLabelDescriptions('SurfaceProblem')['shortcut']['keyNumber']:
                        if (!contextMenu.isOpen()) {
                            ribbon.modeSwitch("SurfaceProblem");
                            svl.tracker.push("KeyboardShortcut_ModeSwitch_SurfaceProblem", {
                                keyCode: e.keyCode
                            });
                        } else {
                            _closeContextMenu(e.keyCode);
                        }
                        break;
                    case 16: //shift
                        // store the timestamp here so that we can check if the z-up event is in the buffer range
                        lastShiftKeyUpTimestamp = e.timeStamp;
                        break;
                    case 90:
                        if (contextMenu.isOpen()) {
                            contextMenu.hide();
                            svl.tracker.push("KeyboardShortcut_CloseContextMenu");
                        }
                        // "z" for zoom. By default, it will zoom in. If "shift" is down, it will zoom out.
                        // if shift was down w/in 100 ms of the z up, then it will also zoom out.
                        // This is to catch the scenarios where shift up is detected before the z up.
                        if (status.shiftDown || (e.timeStamp - lastShiftKeyUpTimestamp) < 100) {
                            // Zoom out
                            zoomControl.zoomOut();
                            svl.tracker.push("KeyboardShortcut_ZoomOut", {
                                keyCode: e.keyCode
                            });
                        } else {
                            // Zoom in
                            zoomControl.zoomIn();
                            svl.tracker.push("KeyboardShortcut_ZoomIn", {
                                keyCode: e.keyCode
                            });
                        }
                }
            }

            /*
             This is a callback method that is triggered when a keyUp
             event occurs. It is not relevant to ContextMenu's textbox focus.
             */
            switch (e.keyCode) {
                case 13:
                    // "Enter"
                    if (contextMenu.isOpen()) {
                        contextMenu.hide();
                        contextMenu.handleSeverityPopup();
                        svl.tracker.push('ContextMenu_ClosePressEnter');
                        svl.tracker.push("KeyboardShortcut_CloseContextMenu");
                    }
                    break;
                case 27:
                    // "Escape"
                    if (contextMenu.isOpen()) {
                        contextMenu.hide();
                        svl.tracker.push("KeyboardShortcut_CloseContextMenu");
                    }

                    if (canvas.getStatus('drawing')) {
                        canvas.cancelDrawing();
                        svl.tracker.push("KeyboardShortcut_CancelDrawing");
                    } else {
                        ribbon.backToWalk();
                    }
                    svl.modalExample.hide();
                    break;
            }

            contextMenu.updateRadioButtonImages();
        }
    };

    function _closeContextMenu(key) {
        contextMenu.hide();
        svl.tracker.push("ContextMenu_CloseKeyboardShortcut", {
            keyCode: key
        });
        svl.tracker.push("KeyboardShortcut_CloseContextMenu");
    }

    /**
     * Get status
     * @param {string} key Field name
     * @returns {*}
     */
    this.getStatus = function  (key) {
        if (!(key in status)) {
            console.warn("You have passed an invalid key for status.")
        }
        return status[key];
    };

    /**
     * This method returns whether a shift key is currently pressed or not.
     * @returns {boolean}
     */
    this.isShiftDown = function () {
        return status.shiftDown;
    };

    /**
     * Set status
     * @param key Field name
     * @param value Field value
     * @returns {setStatus}
     */
    this.setStatus = function (key, value) {
        if (key in status) {
            status[key] = value;
        }
    };

    $(document).bind('keyup', this._documentKeyUp);
    $(document).bind('keydown', this._documentKeyDown);
}
<|endoftext|>


<commit_before>var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var sharedCanvases = {};
context.width = canvas.width;
context.height = canvas.height;
context.globalCompositeOperation = "destination-over";

var currentState = null;

var pauseKey = "p";
var canPauseOrResume = true;
var gamePaused = false;

var rad_to_deg = 180 / Math.PI;
var deg_to_rad = Math.PI / 180;

function init() {
  setInterval(tick, 16.666666666);
}

function tick() {
  if (gamePaused) {
    currentState.draw();

    if (isDown(pauseKey))
      pauseOrResumeGame();

    // TODO Draw Pause/Play huge icon on top
  } else {
    if (isDown(pauseKey))
      pauseOrResumeGame();

    currentState.update();
    currentState.draw();
  }
}

function pauseOrResumeGame() {
  if (canPauseOrResume) {
    gamePaused = !gamePaused;

    setTimeout(function() {
      canPauseOrResume = true;
    }, 1000);

    canPauseOrResume = false;
  }
}

function switchState(newState) {
  newState.setup();
  return currentState = newState;
}

function drawCircle(x, y, radius) {
  context.beginPath();
  context.arc(x, y, radius, 0, Math.PI * 2, false);
  context.stroke();
}

function drawRectangle(x, y, width, height, color) {
  if (color) {
    context.fillStyle = color;
    context.fillRect(x, y, width, height);
    context.fillStyle = "#FFFFFF";
  } else {
    context.fillRect(x, y, width, height);
  }
}

function clearCanvas() {
  context.clearRect(0, 0, context.width, context.height);
}

/*************************************** SPRITE */
Sprite = (function() {
  function constructor(image, x, y) {
    this.x = x;
    this.y = y;
    this.angle = 0;
    this.path = image;

    if (!image) {
      this.shared = true;
      this.loaded = true;
      console.log("Attempted to load null image.");
      return;
    }

    /* Try to retrieve a shared canvas instead of generating a new one */
    this.shared = true;
    if (this.path in sharedCanvases) {
      console.log("Loaded shared canvas.");
      var shared = sharedCanvases[this.path];
      this.internal = shared[0];
      this.internalctx = shared[1];
      this.loaded = shared[2].loaded;

      if (!this.loaded) {
        this.pending = [];
        shared[3].push(this);
      }
    } else {
      console.log("Loaded fresh canvas.");
      this.image = new Image();
      this.image.src = image;
      this.image.owner = this;
      this.loaded = false;
      this.pending = [];

      /* Cache image modifications to an internal canvas for performance and flexibility */
      this.internal = document.createElement("canvas");
      this.internalctx = this.internal.getContext("2d");

      /* Save the canvas to the global shared canvas map */
      sharedCanvases[this.path] = [this.internal, this.internalctx, this, []];

      /* Asynchronous image loading and caching */
      this.image.onload = function() {
        this.owner.internal.width = this.width.toString();
        this.owner.internal.height = this.height.toString();
        this.owner.internalctx.drawImage(this, 0, 0);

        /* Dump image reference, we no longer need it */
        delete this.owner.image;
        this.owner.loaded = true;
        this.owner.dispatchPending();

        /* Set all dependencies to loaded */
        var deps = sharedCanvases[this.owner.path][3];
        for (var i = 0; i < deps.length; i++) {
          deps[i].loaded = true;
          deps[i].dispatchPending();
        }
      }
    }
  }

  constructor.prototype = {
    draw: function() {
      // TODO: how about caching rotated sprites on their internal canvas?
      if (this.angle) {
        context.save();
        context.translate(this.x, this.y);
        context.rotate(this.angle * deg_to_rad);
        context.translate(-this.x, -this.y);
      }

      context.drawImage(this.internal, this.x, this.y);

      if (this.angle) {
        context.restore();
      }
    },

    makeGraphic: function(width, height, color) {
      if (this.shared) {
        this.releaseShared();
      }

      var ws = width.toString();
      var hs = height.toString();

      if (ws != this.internal.width && hs != this.internal.height) {
        this.internal.width = ws;
        this.internal.height = hs;
      }

      this.stampRect(0, 0, width, height, color);
    },

    makeLabel: function(text, size, font, color) {
      if (this.shared) {
        this.releaseShared();
      }

      this.internalctx.font = size + "px " + font;
      var metrics = this.internalctx.measureText(text);
      // TODO: figure out actual height instead of 2 * size (see stampText TODO)
      this.makeGraphic(metrics.width, size * 2, "rgba(0, 0, 0, 0)");
      this.stampText(0, 0, text, size, font, color);
    },

    stampText: function(x, y, text, size, font, color) {
      // TODO: write small function to extract and cache ACTUAL font height
      if (!this.loaded) {
        console.log("Queued text.");
        this.pending.push([this.stampText, x, y, text, font, size, color]);
      } else {
        if (this.shared) {
          this.releaseShared();
        }

        console.log("Drawing text.");
        this.internalctx.font = size + "px " + font
        this.internalctx.textAlign = "left";
        this.internalctx.fillStyle = color;
        this.internalctx.fillText(text, x, y + size);
      }
    },

    stampRect: function(x, y, width, height, color) {
      if (!this.loaded) {
        console.log("Queued rect.");
        this.pending.push([this.stampRect, x, y, width, height, color]);
      } else {
        if (this.shared) {
          this.releaseShared();
        }

        this.internalctx.fillStyle = color;
        this.internalctx.fillRect(x, y, width, height);
      }
    },

    dispatchPending: function() {
      /* Dispatch all pending sprite modifications */
      var pending = this.pending;
      for (var i = 0; i < pending.length; i++) {
        console.log("Dispatched pending.");
        pending[i][0].apply(this, Array.prototype.slice.call(pending[i], 1));
      }

      delete this.pending;
    },

    releaseShared: function() {
      /* Stop using the shared version of the internal canvas, we probably
       * need a dinamically modified sprite */
      var newInternal = document.createElement("canvas");
      this.internalctx = newInternal.getContext("2d");

      if (this.path) {
        newInternal.width = this.internal.width.toString();
        newInternal.height = this.internal.height.toString();
        this.internalctx.drawImage(sharedCanvases[this.path][0], 0, 0);
      }

      this.internal = newInternal;
      this.shared = false;
      console.log("Released shared canvas.");
    },
  }

  return constructor;
})();

SpriteList = (function() {
  function constructor() {
    this.sprites = [];
  }

  constructor.prototype = {
    draw: function() {
      for (var i = 0; i < this.sprites.length; i++) {
        this.sprites[i].draw();
      }
    },

    push: function(newSprite) {
      this.sprites.push(newSprite);
    }
  }

  return constructor;
})();

/*************************************** INPUT */
window.addEventListener("keydown", handleKeyDown);
window.addEventListener("keyup", handleKeyUp);

var keyCodeToString = [];
keyCodeToString[8] = "backspace";
keyCodeToString[9] = "tab";
keyCodeToString[13] = "enter";
keyCodeToString[16] = "shift";
keyCodeToString[17] = "ctrl";
keyCodeToString[18] = "alt";
keyCodeToString[19] = "pause";
keyCodeToString[20] = "capslock";
keyCodeToString[27] = "esc";
keyCodeToString[32] = "space";
keyCodeToString[33] = "pageup";
keyCodeToString[34] = "pagedown";
keyCodeToString[35] = "end";
keyCodeToString[36] = "home";
keyCodeToString[37] = "left";
keyCodeToString[38] = "up";
keyCodeToString[39] = "right";
keyCodeToString[40] = "down";
keyCodeToString[45] = "insert";
keyCodeToString[46] = "delete";

keyCodeToString[91] = "leftwindowkey";
keyCodeToString[92] = "rightwindowkey";
keyCodeToString[93] = "selectkey";
keyCodeToString[106] = "multiply";
keyCodeToString[107] = "add";
keyCodeToString[109] = "subtract";
keyCodeToString[110] = "decimalpoint";
keyCodeToString[111] = "divide";

keyCodeToString[144] = "numlock";
keyCodeToString[145] = "scrollock";
keyCodeToString[186] = "semicolon";
keyCodeToString[187] = "equalsign";
keyCodeToString[188] = "comma";
keyCodeToString[189] = "dash";
keyCodeToString[190] = "period";
keyCodeToString[191] = "forwardslash";
keyCodeToString[192] = "graveaccent";
keyCodeToString[219] = "openbracket";
keyCodeToString[220] = "backslash";
keyCodeToString[221] = "closebracket";
keyCodeToString[222] = "singlequote";

var numpadKeys = ["numpad1", "numpad2", "numpad3", "numpad4", "numpad5",
                  "numpad6", "numpad7", "numpad8", "numpad9"];

var numbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
var letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
               "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
               "u", "v", "w", "x", "y", "z"];

for (var i = 0; numbers[i]; i++) { keyCodeToString[48 + i] = numbers[i]; }
for (var i = 0; letters[i]; i++) { keyCodeToString[65 + i] = letters[i]; }
for (var i = 0; numpadKeys[i]; i++) { keyCodeToString[96 + i] = numpadKeys[i]; }

var pressedKeys = [];
var preventedKeys = [];

function preventKeys(keys) {
  preventedKeys = keys;
}

function handleKeyDown(e) {
  var event = (e) ? e : window.event;
  var name = keyCodeToString[event.keyCode];
  pressedKeys[name] = true;

  if (preventedKeys[name])
    e.preventDefault();
}

function handleKeyUp(e) {
  var event = (e) ? e : window.event;
  var name = keyCodeToString[event.keyCode];
  pressedKeys[name] = false;

  if (preventedKeys[name])
    e.preventDefault();
}

function isDown(name) {
  if (pressedKeys[name])
    return true;
}
<commit_msg>IE fix<commit_after>var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var sharedCanvases = {};
context.width = canvas.width;
context.height = canvas.height;
context.globalCompositeOperation = "destination-over";

var currentState = null;

var pauseKey = "p";
var canPauseOrResume = true;
var gamePaused = false;

var rad_to_deg = 180 / Math.PI;
var deg_to_rad = Math.PI / 180;

function init() {
  setInterval(tick, 16.666666666);
}

function tick() {
  if (gamePaused) {
    currentState.draw();

    if (isDown(pauseKey))
      pauseOrResumeGame();

    // TODO Draw Pause/Play huge icon on top
  } else {
    if (isDown(pauseKey))
      pauseOrResumeGame();

    currentState.update();
    currentState.draw();
  }
}

function pauseOrResumeGame() {
  if (canPauseOrResume) {
    gamePaused = !gamePaused;

    setTimeout(function() {
      canPauseOrResume = true;
    }, 1000);

    canPauseOrResume = false;
  }
}

function switchState(newState) {
  newState.setup();
  return currentState = newState;
}

function drawCircle(x, y, radius) {
  context.beginPath();
  context.arc(x, y, radius, 0, Math.PI * 2, false);
  context.stroke();
}

function drawRectangle(x, y, width, height, color) {
  if (color) {
    context.fillStyle = color;
    context.fillRect(x, y, width, height);
    context.fillStyle = "#FFFFFF";
  } else {
    context.fillRect(x, y, width, height);
  }
}

function clearCanvas() {
  context.clearRect(0, 0, context.width, context.height);
}

/*************************************** SPRITE */
Sprite = (function() {
  function constructor(image, x, y) {
    this.x = x;
    this.y = y;
    this.angle = 0;
    this.path = image;

    if (!image) {
      this.shared = true;
      this.loaded = true;
      console.log("Attempted to load null image.");
      return;
    }

    /* Try to retrieve a shared canvas instead of generating a new one */
    this.shared = true;
    if (this.path in sharedCanvases) {
      console.log("Loaded shared canvas.");
      var shared = sharedCanvases[this.path];
      this.internal = shared[0];
      this.internalctx = shared[1];
      this.loaded = shared[2].loaded;

      if (!this.loaded) {
        this.pending = [];
        shared[3].push(this);
      }
    } else {
      console.log("Loaded fresh canvas.");
      this.image = new Image();
      this.image.src = image;
      this.image.owner = this;
      this.loaded = false;
      this.pending = [];

      /* Cache image modifications to an internal canvas for performance and flexibility */
      this.internal = document.createElement("canvas");
      this.internalctx = this.internal.getContext("2d");

      /* Save the canvas to the global shared canvas map */
      sharedCanvases[this.path] = [this.internal, this.internalctx, this, []];

      /* Asynchronous image loading and caching */
      this.image.onload = function() {
        this.owner.internal.width = this.width.toString();
        this.owner.internal.height = this.height.toString();
        this.owner.internalctx.drawImage(this, 0, 0);

        /* Dump image reference, we no longer need it */
        delete this.owner.image;
        this.owner.loaded = true;
        this.owner.dispatchPending();

        /* Set all dependencies to loaded */
        var deps = sharedCanvases[this.owner.path][3];
        for (var i = 0; i < deps.length; i++) {
          deps[i].loaded = true;
          deps[i].dispatchPending();
        }
      }
    }
  }

  constructor.prototype = {
    draw: function() {
      // TODO: how about caching rotated sprites on their internal canvas?
      if (this.angle) {
        context.save();
        context.translate(this.x, this.y);
        context.rotate(this.angle * deg_to_rad);
        context.translate(-this.x, -this.y);
      }

      context.drawImage(this.internal, this.x, this.y);

      if (this.angle) {
        context.restore();
      }
    },

    makeGraphic: function(width, height, color) {
      if (this.shared) {
        this.releaseShared();
      }

      var ws = width.toString();
      var hs = height.toString();

      if (ws != this.internal.width && hs != this.internal.height) {
        this.internal.width = ws;
        this.internal.height = hs;
      }

      this.stampRect(0, 0, width, height, color);
    },

    makeLabel: function(text, size, font, color) {
      if (this.shared) {
        this.releaseShared();
      }

      this.internalctx.font = size + "px " + font;
      var metrics = this.internalctx.measureText(text);
      // TODO: figure out actual height instead of 2 * size (see stampText TODO)
      this.makeGraphic(metrics.width, size * 2, "rgba(0, 0, 0, 0)");
      this.stampText(0, 0, text, size, font, color);
    },

    stampText: function(x, y, text, size, font, color) {
      // TODO: write small function to extract and cache ACTUAL font height
      if (!this.loaded) {
        console.log("Queued text.");
        this.pending.push([this.stampText, x, y, text, font, size, color]);
      } else {
        if (this.shared) {
          this.releaseShared();
        }

        console.log("Drawing text.");
        this.internalctx.font = size + "px " + font
        this.internalctx.textAlign = "left";
        this.internalctx.fillStyle = color;
        this.internalctx.fillText(text, x, y + size);
      }
    },

    stampRect: function(x, y, width, height, color) {
      if (!this.loaded) {
        console.log("Queued rect.");
        this.pending.push([this.stampRect, x, y, width, height, color]);
      } else {
        if (this.shared) {
          this.releaseShared();
        }

        this.internalctx.fillStyle = color;
        this.internalctx.fillRect(x, y, width, height);
      }
    },

    dispatchPending: function() {
      /* Dispatch all pending sprite modifications */
      var pending = this.pending;
      for (var i = 0; i < pending.length; i++) {
        console.log("Dispatched pending.");
        pending[i][0].apply(this, Array.prototype.slice.call(pending[i], 1));
      }

      delete this.pending;
    },

    releaseShared: function() {
      /* Stop using the shared version of the internal canvas, we probably
       * need a dinamically modified sprite */
      var newInternal = document.createElement("canvas");
      this.internalctx = newInternal.getContext("2d");

      if (this.path) {
        newInternal.width = this.internal.width.toString();
        newInternal.height = this.internal.height.toString();
        this.internalctx.drawImage(sharedCanvases[this.path][0], 0, 0);
      }

      this.internal = newInternal;
      this.shared = false;
      console.log("Released shared canvas.");
    }
  }

  return constructor;
})();

SpriteList = (function() {
  function constructor() {
    this.sprites = [];
  }

  constructor.prototype = {
    draw: function() {
      for (var i = 0; i < this.sprites.length; i++) {
        this.sprites[i].draw();
      }
    },

    push: function(newSprite) {
      this.sprites.push(newSprite);
    }
  }

  return constructor;
})();

/*************************************** INPUT */
window.addEventListener("keydown", handleKeyDown);
window.addEventListener("keyup", handleKeyUp);

var keyCodeToString = [];
keyCodeToString[8] = "backspace";
keyCodeToString[9] = "tab";
keyCodeToString[13] = "enter";
keyCodeToString[16] = "shift";
keyCodeToString[17] = "ctrl";
keyCodeToString[18] = "alt";
keyCodeToString[19] = "pause";
keyCodeToString[20] = "capslock";
keyCodeToString[27] = "esc";
keyCodeToString[32] = "space";
keyCodeToString[33] = "pageup";
keyCodeToString[34] = "pagedown";
keyCodeToString[35] = "end";
keyCodeToString[36] = "home";
keyCodeToString[37] = "left";
keyCodeToString[38] = "up";
keyCodeToString[39] = "right";
keyCodeToString[40] = "down";
keyCodeToString[45] = "insert";
keyCodeToString[46] = "delete";

keyCodeToString[91] = "leftwindowkey";
keyCodeToString[92] = "rightwindowkey";
keyCodeToString[93] = "selectkey";
keyCodeToString[106] = "multiply";
keyCodeToString[107] = "add";
keyCodeToString[109] = "subtract";
keyCodeToString[110] = "decimalpoint";
keyCodeToString[111] = "divide";

keyCodeToString[144] = "numlock";
keyCodeToString[145] = "scrollock";
keyCodeToString[186] = "semicolon";
keyCodeToString[187] = "equalsign";
keyCodeToString[188] = "comma";
keyCodeToString[189] = "dash";
keyCodeToString[190] = "period";
keyCodeToString[191] = "forwardslash";
keyCodeToString[192] = "graveaccent";
keyCodeToString[219] = "openbracket";
keyCodeToString[220] = "backslash";
keyCodeToString[221] = "closebracket";
keyCodeToString[222] = "singlequote";

var numpadKeys = ["numpad1", "numpad2", "numpad3", "numpad4", "numpad5",
                  "numpad6", "numpad7", "numpad8", "numpad9"];

var numbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
var letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
               "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
               "u", "v", "w", "x", "y", "z"];

for (var i = 0; numbers[i]; i++) { keyCodeToString[48 + i] = numbers[i]; }
for (var i = 0; letters[i]; i++) { keyCodeToString[65 + i] = letters[i]; }
for (var i = 0; numpadKeys[i]; i++) { keyCodeToString[96 + i] = numpadKeys[i]; }

var pressedKeys = [];
var preventedKeys = [];

function preventKeys(keys) {
  preventedKeys = keys;
}

function handleKeyDown(e) {
  var event = (e) ? e : window.event;
  var name = keyCodeToString[event.keyCode];
  pressedKeys[name] = true;

  if (preventedKeys[name])
    e.preventDefault();
}

function handleKeyUp(e) {
  var event = (e) ? e : window.event;
  var name = keyCodeToString[event.keyCode];
  pressedKeys[name] = false;

  if (preventedKeys[name])
    e.preventDefault();
}

function isDown(name) {
  if (pressedKeys[name])
    return true;
}
<|endoftext|>


<commit_before>(function () {
  'use strict';

  var namespace = angular.module('app.directory-selector', [
    'hierarchical-selector',
    'app.acceptd.config'
  ]);

  namespace.directive('directorySelector', DirectorySelector);

  function DirectorySelector($q, $http, $timeout, AcceptdService) {
    return {
      restrict: 'AE',
      template: '<hierarchical-selector load-child-items="loadAsyncData(parent)"' +
      '                       selection="selection" on-selection-changed="onSelectionChanged(items)"' +
      '                       tag-name="tagName(item)">' +
      '</hierarchical-selector>',
      scope: {
        'script_params': '&',
        'selection': '&',
        'selected_project': '&'
      },
      link: function (scope, element, attributes) {
        //console.log(attributes.selectedProject);

        AcceptdService.load_config({}).success(function (result) {
          var id = result.selected_project;
          //var id = attributes.selectedProject;

          $http.get('/file_browser/node' + '?id=' + id).success(function (data) {
            //  //data['_hsmeta'] = {'isExpanded':false,'isActive':false,'selected':true};
            scope.selection = data;
          });
        });

        scope.loadAsyncData = function (parent) {
          var id = parent ? parent.id : '/';

          var defer = $q.defer();

          $http.get('/file_browser/tree' + '?id=' + id).success(function (data) {
            defer.resolve(data);
          }).error(function (data) {
            defer.reject(data);
          });

          return defer.promise;
        };

        scope.onSelectionChanged = function (items) {
          scope.mySelection = items;
        };

        scope.tagName = function (item) {
          return item.id;
        };
      }
    }
  }

})();

//$scope.testa = function () {
//  //angular.element(document.body).injector().get('AcceptdController')
//
//  //var root = angular.element(document.querySelector('.hierarchical-control'));
//  //var root_input = angular.element(document.querySelector('.hierarchical-input'));
//  //var tree_view = angular.element(document.querySelector('.tree-view'))
//
//  var root = $('.hierarchical-control');
//  var root_input = $('.hierarchical-input');
//  var tree_view = root.find('.tree-view');
//
//  root_input.click();
//
//  var items = tree_view.find('ul li');
//
//  for (var i = 0; i < items.size(); i++) {
//    var item = items[0];
//    console.log(item);
//    var el1 = $(item).find('.item-container span')[0];
//    el1.click();
//    var item2 = item.find('ul li');
//    var el2 = item2.find('.item-container span')[0];
//  }
//};

<commit_msg>simplify code<commit_after>(function () {
  'use strict';

  var namespace = angular.module('app.directory-selector', [
    'hierarchical-selector',
    'app.settings',
    'app.acceptd.config'
  ]);

  namespace.directive('directorySelector', DirectorySelector);

  function DirectorySelector($q, $http, $timeout, Settings, AcceptdService) {
    return {
      restrict: 'AE',
      template: '<hierarchical-selector load-child-items="loadAsyncData(parent)"' +
      '                       selection="selection" on-selection-changed="onSelectionChanged(items)"' +
      '                       tag-name="tagName(item)">' +
      '</hierarchical-selector>',
      scope: {
        'script_params': '&',
        'selection': '&'
      },
      link: function (scope, element, attributes) {
        AcceptdService.load_config({}).success(function (result) {
          var id = result.selected_project;
          //var id = attributes.selectedProject;

          $http.get(Settings.baseUrl + '/file_browser/node' + '?id=' + id).success(function (data) {
            //  //data['_hsmeta'] = {'isExpanded':false,'isActive':false,'selected':true};
            scope.selection = data;
          });
        });

        scope.loadAsyncData = function (parent) {
          var id = parent ? parent.id : '/';

          var defer = $q.defer();

          $http.get('/file_browser/tree' + '?id=' + id).success(function (data) {
            defer.resolve(data);
          }).error(function (data) {
            defer.reject(data);
          });

          return defer.promise;
        };

        scope.onSelectionChanged = function (items) {
          scope.mySelection = items;
        };

        scope.tagName = function (item) {
          return item.id;
        };
      }
    }
  }

})();

//$scope.testa = function () {
//  //angular.element(document.body).injector().get('AcceptdController')
//
//  //var root = angular.element(document.querySelector('.hierarchical-control'));
//  //var root_input = angular.element(document.querySelector('.hierarchical-input'));
//  //var tree_view = angular.element(document.querySelector('.tree-view'))
//
//  var root = $('.hierarchical-control');
//  var root_input = $('.hierarchical-input');
//  var tree_view = root.find('.tree-view');
//
//  root_input.click();
//
//  var items = tree_view.find('ul li');
//
//  for (var i = 0; i < items.size(); i++) {
//    var item = items[0];
//    console.log(item);
//    var el1 = $(item).find('.item-container span')[0];
//    el1.click();
//    var item2 = item.find('ul li');
//    var el2 = item2.find('.item-container span')[0];
//  }
//};

<|endoftext|>


<commit_before>'use strict';

describe('Action tests', function() {

  it('List action', function() {
    browser.get('#/action');

    var actions = element.all(by.repeater('action in actions'));
    expect(actions.count()).toEqual(3);
    expect(actions.get(0).getText()).toEqual('Sql-Fetch-Row');
    expect(actions.get(1).getText()).toEqual('Sql-Fetch-All');
    expect(actions.get(2).getText()).toEqual('Welcome');
  });

  it('Create action', function() {
    browser.get('#/action');

    var EC = protractor.ExpectedConditions;

    $('a.btn-primary').click();

    browser.wait(EC.visibilityOf($('div.modal-body')), 5000);

    element(by.model('action.name')).sendKeys('test-action');

    var actionOptions = element.all(by.options('action.class as action.name for action in actions'));
    expect(actionOptions.get(0).getText()).toEqual('Cache-Response');
    expect(actionOptions.get(1).getText()).toEqual('Composite');
    expect(actionOptions.get(2).getText()).toEqual('Condition');
    expect(actionOptions.get(3).getText()).toEqual('HTTP-Proxy');
    expect(actionOptions.get(4).getText()).toEqual('HTTP-Request');
    expect(actionOptions.get(5).getText()).toEqual('Mongo-Delete');
    expect(actionOptions.get(6).getText()).toEqual('Mongo-Fetch-All');
    expect(actionOptions.get(7).getText()).toEqual('Mongo-Fetch-Row');
    expect(actionOptions.get(8).getText()).toEqual('Mongo-Insert');
    expect(actionOptions.get(9).getText()).toEqual('Mongo-Update');
    expect(actionOptions.get(10).getText()).toEqual('MQ-Amqp');
    expect(actionOptions.get(11).getText()).toEqual('MQ-Beanstalk');
    expect(actionOptions.get(12).getText()).toEqual('Pipe');
    expect(actionOptions.get(13).getText()).toEqual('Processor');
    expect(actionOptions.get(14).getText()).toEqual('SQL-Builder');
    expect(actionOptions.get(15).getText()).toEqual('SQL-Execute');
    expect(actionOptions.get(16).getText()).toEqual('SQL-Fetch-All');
    expect(actionOptions.get(17).getText()).toEqual('SQL-Fetch-Row');
    expect(actionOptions.get(18).getText()).toEqual('Static-Response');
    expect(actionOptions.get(19).getText()).toEqual('Transform');
    expect(actionOptions.get(20).getText()).toEqual('Validator');

    actionOptions.get(18).click();

    browser.wait(EC.visibilityOf($('#config-statusCode')), 5000);

    element(by.cssContainingText('#config-statusCode option', 'OK')).click();
    element(by.css('textarea.ace_text-input')).sendKeys('{"foo": "bar"}');

    $('button.btn-primary').click();

    browser.wait(EC.visibilityOf($('div.alert-success')), 5000);

    expect($('div.alert-success > div').getText()).toEqual('Action successful created');
  });

  it('Update action', function() {
    browser.get('#/action');

    var EC = protractor.ExpectedConditions;

    element.all(by.css('div.fusio-options a:nth-child(1)')).first().click();

    browser.wait(EC.visibilityOf($('div.modal-body')), 5000);

    expect(element(by.model('action.name')).getAttribute('value')).toEqual('test-action');
    expect(element(by.model('action.class')).getAttribute('value')).toEqual('Fusio\\Impl\\Action\\StaticResponse');

    browser.wait(EC.visibilityOf($('#config-statusCode')), 5000);

    expect(element(by.model('action.config.statusCode')).getAttribute('value')).toEqual('200');

    $('button.btn-primary').click();

    browser.wait(EC.visibilityOf($('div.alert-success')), 5000);

    expect($('div.alert-success > div').getText()).toEqual('Action successful updated');
  });

  it('Delete action', function() {
    browser.get('#/action');

    var EC = protractor.ExpectedConditions;

    element.all(by.css('div.fusio-options a:nth-child(2)')).first().click();

    browser.wait(EC.visibilityOf($('div.modal-body')), 5000);

    expect(element(by.model('action.name')).getAttribute('value')).toEqual('test-action');

    $('button.btn-primary').click();

    browser.wait(EC.visibilityOf($('div.alert-success')), 5000);

    expect($('div.alert-success > div').getText()).toEqual('Action successful deleted');
  });

});
<commit_msg>add try catch action<commit_after>'use strict';

describe('Action tests', function() {

  it('List action', function() {
    browser.get('#/action');

    var actions = element.all(by.repeater('action in actions'));
    expect(actions.count()).toEqual(3);
    expect(actions.get(0).getText()).toEqual('Sql-Fetch-Row');
    expect(actions.get(1).getText()).toEqual('Sql-Fetch-All');
    expect(actions.get(2).getText()).toEqual('Welcome');
  });

  it('Create action', function() {
    browser.get('#/action');

    var EC = protractor.ExpectedConditions;

    $('a.btn-primary').click();

    browser.wait(EC.visibilityOf($('div.modal-body')), 5000);

    element(by.model('action.name')).sendKeys('test-action');

    var actionOptions = element.all(by.options('action.class as action.name for action in actions'));
    expect(actionOptions.get(0).getText()).toEqual('Cache-Response');
    expect(actionOptions.get(1).getText()).toEqual('Composite');
    expect(actionOptions.get(2).getText()).toEqual('Condition');
    expect(actionOptions.get(3).getText()).toEqual('HTTP-Proxy');
    expect(actionOptions.get(4).getText()).toEqual('HTTP-Request');
    expect(actionOptions.get(5).getText()).toEqual('Mongo-Delete');
    expect(actionOptions.get(6).getText()).toEqual('Mongo-Fetch-All');
    expect(actionOptions.get(7).getText()).toEqual('Mongo-Fetch-Row');
    expect(actionOptions.get(8).getText()).toEqual('Mongo-Insert');
    expect(actionOptions.get(9).getText()).toEqual('Mongo-Update');
    expect(actionOptions.get(10).getText()).toEqual('MQ-Amqp');
    expect(actionOptions.get(11).getText()).toEqual('MQ-Beanstalk');
    expect(actionOptions.get(12).getText()).toEqual('Pipe');
    expect(actionOptions.get(13).getText()).toEqual('Processor');
    expect(actionOptions.get(14).getText()).toEqual('SQL-Builder');
    expect(actionOptions.get(15).getText()).toEqual('SQL-Execute');
    expect(actionOptions.get(16).getText()).toEqual('SQL-Fetch-All');
    expect(actionOptions.get(17).getText()).toEqual('SQL-Fetch-Row');
    expect(actionOptions.get(18).getText()).toEqual('Static-Response');
    expect(actionOptions.get(19).getText()).toEqual('Transform');
    expect(actionOptions.get(20).getText()).toEqual('Try-Catch');
    expect(actionOptions.get(21).getText()).toEqual('Validator');

    actionOptions.get(18).click();

    browser.wait(EC.visibilityOf($('#config-statusCode')), 5000);

    element(by.cssContainingText('#config-statusCode option', 'OK')).click();
    element(by.css('textarea.ace_text-input')).sendKeys('{"foo": "bar"}');

    $('button.btn-primary').click();

    browser.wait(EC.visibilityOf($('div.alert-success')), 5000);

    expect($('div.alert-success > div').getText()).toEqual('Action successful created');
  });

  it('Update action', function() {
    browser.get('#/action');

    var EC = protractor.ExpectedConditions;

    element.all(by.css('div.fusio-options a:nth-child(1)')).first().click();

    browser.wait(EC.visibilityOf($('div.modal-body')), 5000);

    expect(element(by.model('action.name')).getAttribute('value')).toEqual('test-action');
    expect(element(by.model('action.class')).getAttribute('value')).toEqual('Fusio\\Impl\\Action\\StaticResponse');

    browser.wait(EC.visibilityOf($('#config-statusCode')), 5000);

    expect(element(by.model('action.config.statusCode')).getAttribute('value')).toEqual('200');

    $('button.btn-primary').click();

    browser.wait(EC.visibilityOf($('div.alert-success')), 5000);

    expect($('div.alert-success > div').getText()).toEqual('Action successful updated');
  });

  it('Delete action', function() {
    browser.get('#/action');

    var EC = protractor.ExpectedConditions;

    element.all(by.css('div.fusio-options a:nth-child(2)')).first().click();

    browser.wait(EC.visibilityOf($('div.modal-body')), 5000);

    expect(element(by.model('action.name')).getAttribute('value')).toEqual('test-action');

    $('button.btn-primary').click();

    browser.wait(EC.visibilityOf($('div.alert-success')), 5000);

    expect($('div.alert-success > div').getText()).toEqual('Action successful deleted');
  });

});
<|endoftext|>


<commit_before>// perf-view.js - Copyright (c) 2015 - Joseph Strommen - MIT License

var perfView = function() {

	if (!window.performance || !window.performance.timing) {
		return;
	}
	var navTiming = window.performance.timing;

	var options = {
		errorThreshold: 2000,
		containerId: 'perf-view',
		useDefaultCss: true
	};

	var container;

	function init(customOptions) {

		if (customOptions) {
			for (var key in customOptions) {
				options[key] = customOptions[key];
			}
		}

		var loadTime = navTiming.loadEventStart - navTiming.navigationStart;

		if (options.useDefaultCss) {
			var css = [
				'#perf-view {',
				'	background: #555;',
				'	color: #999;',
				'	padding: 15px 30px;',
				'	position: absolute;',
				'	box-sizing: border-box;',
				'	width: 100%;',
				'	top: 0;',
				'	z-index: 10000;',
				'	font-family: sans-serif;',
				'	line-height: 1.2;',
				'}',
				'.perf-view-message {',
				'	display: block;',
				'	text-align: center;',
				'}',
				'#perf-view a {',
				'	color: #7af;',
				'	text-decoration: underline;',
				'}',
				'#perf-view .perf-view-close {',
				'	display: inline-block;',
				'	padding-left: 30px;',
				'}',
				'#perf-view .perf-view-load-time {',
				'	color: #fff;',
				'	font-weight: bold;',
				'}',
				'#perf-view.perf-view-error .perf-view-load-time {',
				'	color: #f88;',
				'}',
				'.perf-view-chart {',
				'	width: 100%;',
				'	background: white;',
				'	padding-top: 15px;',
				'	margin: 15px 0;',
				'}',
				'.perf-view-chart-area {',
				'	position: relative;',
				'}',
				'.perf-view-gridline {',
				'	border-right: 1px solid rgba(0,0,0,0.3);',
				'	position: absolute;',
				'	top: 0;',
				'	left: 0;',
				'	height: 100%;',
				'}',
				'.perf-view-gridline-event {',
				'	border-color: blue;',
				'}',
				'.perf-view-gridline-label {',
				'	position: absolute;',
				'	top: -12px;',
				'	font-size: 10px;',
				'	text-align: center;',
				'}',
				'.perf-view-gridline-event-label {',
				// TODO rotate the text
				'	color: blue;',
				'}',
				'.perf-view-row {',
				'	border-bottom: 1px solid gray;',
				'	padding: 0 1px;',
				'	position: relative;',
				'}',
				'.perf-view-row:nth-child(2n+1) {',
				'	background: rgba(0, 0, 0, 0.1);',
				'}',
				'.perf-view-bar {',
				'	height: 12px;',
				'	display: inline-block;',
				'	z-index: -1;',
				'	box-sizing: border-box;',
				'	background: #05F;',
				'	margin-top: 1px;',
				'}',
				'.perf-view-bar-name {',
				'	position: absolute;',
				'	top: 3px;',
				'	font-size: 12px;',
				'	line-height: 1;',
				'	left: 3px;',
				'	color: #049;',
				'}',
				'.perf-view-bar-type-js {',
				'	background: darkgreen;',
				'}',
				'.perf-view-bar-type-css {',
				'	background: purple;',
				'}',
				'.perf-view-bar-type-jpeg, .perf-view-bar-type-jpg, .perf-view-bar-type-gif, .perf-view-bar-type-png {',
				'	background: #4f0;',
				'}',
				'.perf-view-bar-waiting {',
				'	visibility: hidden;',
				'}',
				'.perf-view-bar-latency {',
				'	opacity: 0.2;',
				'}',
				'.perf-view-bar-downloading {',
				'	opacity: 0.5;',
				'}',
				''
			].join('\r\n');
			var style = document.createElement("style");
			style.innerText = css;
			document.head.appendChild(style);
			// TODO adding the CSS doesn't seem to work in IE or Firefox
			// TODO figure out a build process to just add the CSS to the JS
		}

		container = document.getElementById(options.containerId);
		if (!container) {
			container = document.createElement('div');
			container.id = options.containerId;
			document.body.appendChild(container);
			// TODO move to iframe
		}
		if (loadTime > options.errorThreshold) {
			container.className += " perf-view-error";
		}
		container.innerHTML = [
			'',
				'This page loaded in ',
				'',
					loadTime,
					'ms',
				'',
				' (details)',
				'[X]',
			''
		].join('');
	}

	function showWaterfall() {
		var resourceTimings = window.performance.getEntriesByType("resource");
		var lastResponseEnd = 0;
		for (var i = 0; i < resourceTimings.length; i++) {
			var responseEnd = resourceTimings[i].responseEnd;
			if (responseEnd > lastResponseEnd) {
				lastResponseEnd = responseEnd;
			}
		}

		lastResponseEnd *= 1.2; // Extra space.

		// Size everything in terms of %.
		var chartContainer = document.createElement("div");
		chartContainer.className = "perf-view-chart";
		var chartArea = document.createElement("div");
		chartArea.className = "perf-view-chart-area";

		// Min of 4 gridlines.
		var gridlineIncrement = 100;
		var gridlineOptions = [2000, 1000, 500, 250, 100];
		for (var i = 0; i < gridlineOptions.length; i++) {
			if (gridlineOptions[i] * 4 < lastResponseEnd) {
				gridlineIncrement = gridlineOptions[i];
				break;
			}
		}

		var gridlineValue = gridlineIncrement;
		while (gridlineValue < lastResponseEnd) {
			addGridlineAndLabel(chartArea, gridlineValue, lastResponseEnd);

			gridlineValue += gridlineIncrement;
		}

		var domContentLoaded = navTiming.domContentLoadedEventStart - navTiming.navigationStart;
		addGridlineAndLabel(chartArea, domContentLoaded, lastResponseEnd, "DOMContentLoaded");

		var loadEvent = navTiming.loadEventStart - navTiming.navigationStart;
		addGridlineAndLabel(chartArea, loadEvent, lastResponseEnd, "window.onload");

		// TODO show user timings

		var htmlRow = createRowElement(document.location.href, 0, (navTiming.responseStart - navTiming.navigationStart), (navTiming.responseEnd - navTiming.navigationStart), lastResponseEnd);
		chartArea.appendChild(htmlRow);

		for (var i = 0; i < resourceTimings.length; i++) {
			var row = createRowElement(
				resourceTimings[i].name,
				resourceTimings[i].startTime,
				resourceTimings[i].responseStart || resourceTimings[i].startTime, // responseStart will be 0 for cross-origin resources
				resourceTimings[i].responseEnd,
				lastResponseEnd);
			chartArea.appendChild(row);
		}

		chartContainer.appendChild(chartArea);
		container.appendChild(chartContainer);
	}

	function formatTime(val) {
		// TODO round decimals
		return (val >= 1000) ? (val / 1000) + 's' : val + 'ms';
	}

	function addGridlineAndLabel(chartArea, gridlineValue, lastResponseEnd, eventName) {
		var gridline = createGridline(gridlineValue, lastResponseEnd);
		if (eventName) {
			gridline.className += " perf-view-gridline-event";
		}
		chartArea.appendChild(gridline);

		var domContentLoadedLabel = createGridlineLabel(gridlineValue, lastResponseEnd);
		if (eventName) {
			domContentLoadedLabel.innerText = eventName;
			domContentLoadedLabel.className += " perf-view-gridline-event-label";
		}
		chartArea.appendChild(domContentLoadedLabel);
	}

	function createGridline(gridlineValue, lastResponseEnd) {
		var gridlineRatio = gridlineValue / lastResponseEnd;
		var gridline = document.createElement("div");
		gridline.className = "perf-view-gridline";
		gridline.style.cssText = ['width: ', 100 * gridlineRatio, '%;'].join('');
		return gridline;
	}

	function createGridlineLabel(gridlineValue, lastResponseEnd) {
		var gridlineRatio = gridlineValue / lastResponseEnd;
		var labelText = formatTime(gridlineValue);
		var gridlineLabel = document.createElement("span");
		gridlineLabel.className = "perf-view-gridline-label";
		gridlineLabel.innerText = labelText;
		gridlineLabel.style.cssText = ['width: ', 200 * gridlineRatio, '%;'].join('');
		return gridlineLabel;
	}

	function createRowElement(href, requestStart, responseStart, responseEnd, totalEnd) {
		var name = href;
		var lastSlash = href.substring(0, href.length - 1).lastIndexOf('/');
		if (lastSlash >= 0) {
			name = name.substring(lastSlash + 1);
		}
		var query = name.indexOf('?');
		if (query >= 0) {
			name = name.substring(0, query);
		}

		var fileType;
		var lastDot = name.lastIndexOf('.');
		if (lastDot >= 0) {
			fileType = name.substring(lastDot + 1);
		}

		var waitingRatio = requestStart / totalEnd;
		var latencyValue = (responseStart - requestStart);
		var latencyRatio = latencyValue / totalEnd;
		var downloadingValue = (responseEnd - responseStart);
		var downloadingRatio = downloadingValue / totalEnd;

		var row = document.createElement("div");
		row.className = "perf-view-row";
		// TODO can we add resource size to this?
		row.title = ['waiting: ', formatTime(requestStart), ', latency: ', formatTime(latencyValue), ', download: ', formatTime(downloadingValue)].join('');

		var waiting = document.createElement("span");
		waiting.className = "perf-view-bar perf-view-bar-waiting";
		waiting.style.cssText = ['width: ', 100 * waitingRatio, '%;'].join('');
		row.appendChild(waiting);

		var latency = document.createElement("span");
		latency.className = "perf-view-bar perf-view-bar-latency";
		if (fileType) {
			latency.className += " perf-view-bar-type-" + fileType;
		}
		latency.style.cssText = ['width: ', 100 * latencyRatio, '%;'].join('');
		row.appendChild(latency);

		var downloading = document.createElement("span");
		downloading.className = "perf-view-bar perf-view-bar-downloading"
		if (fileType) {
			downloading.className += " perf-view-bar-type-" + fileType;
		}
		downloading.style.cssText = ['width: ', 100 * downloadingRatio, '%;'].join('');
		row.appendChild(downloading);

		var link = document.createElement("a");
		link.href = href;
		link.target = '_blank';
		link.className = "perf-view-bar-name";
		link.innerText = name;
		row.appendChild(link);

		return row;
	}

	return {
		init: init,
		showWaterfall: showWaterfall,
		hide: function() {
			document.body.removeChild(container);
			window.perfView = null;
		}
	}
}();

if (document.readyState === "complete") {
	perfView.init();
}
<commit_msg>Fixes to make it actually work outside of Chrome<commit_after>// perf-view.js - Copyright (c) 2015 - Joseph Strommen - MIT License

var perfView = function() {

	if (!window.performance || !window.performance.timing) {
		return;
	}
	var navTiming = window.performance.timing;

	var options = {
		errorThreshold: 2000,
		containerId: 'perf-view',
		useDefaultCss: true
	};

	var container;

	function init(customOptions) {

		if (customOptions) {
			for (var key in customOptions) {
				options[key] = customOptions[key];
			}
		}

		var loadTime = navTiming.loadEventStart - navTiming.navigationStart;

		if (options.useDefaultCss) {
			var css = [
				'#perf-view {',
				'	background: #555;',
				'	color: #999;',
				'	padding: 15px 30px;',
				'	position: absolute;',
				'	box-sizing: border-box;',
				'	width: 100%;',
				'	top: 0;',
				'	z-index: 10000;',
				'	font-family: sans-serif;',
				'	line-height: 1.2;',
				'}',
				'.perf-view-message {',
				'	display: block;',
				'	text-align: center;',
				'}',
				'#perf-view a {',
				'	color: #7af;',
				'	text-decoration: underline;',
				'}',
				'#perf-view .perf-view-close {',
				'	display: inline-block;',
				'	padding-left: 30px;',
				'}',
				'#perf-view .perf-view-load-time {',
				'	color: #fff;',
				'	font-weight: bold;',
				'}',
				'#perf-view.perf-view-error .perf-view-load-time {',
				'	color: #f88;',
				'}',
				'.perf-view-chart {',
				'	width: 100%;',
				'	background: white;',
				'	padding-top: 15px;',
				'	margin: 15px 0;',
				'}',
				'.perf-view-chart-area {',
				'	position: relative;',
				'}',
				'.perf-view-gridline {',
				'	border-right: 1px solid rgba(0,0,0,0.3);',
				'	position: absolute;',
				'	top: 0;',
				'	left: 0;',
				'	height: 100%;',
				'}',
				'.perf-view-gridline-event {',
				'	border-color: blue;',
				'}',
				'.perf-view-gridline-label {',
				'	position: absolute;',
				'	top: -12px;',
				'	font-size: 10px;',
				'	text-align: center;',
				'}',
				'.perf-view-gridline-event-label {',
				// TODO rotate the text
				'	color: blue;',
				'}',
				'.perf-view-row {',
				'	border-bottom: 1px solid gray;',
				'	padding: 0 1px;',
				'	position: relative;',
				'}',
				'.perf-view-row:nth-child(2n+1) {',
				'	background: rgba(0, 0, 0, 0.1);',
				'}',
				'.perf-view-bar {',
				'	height: 12px;',
				'	display: inline-block;',
				'	z-index: -1;',
				'	box-sizing: border-box;',
				'	background: #05F;',
				'	margin-top: 1px;',
				'}',
				'.perf-view-bar-name {',
				'	position: absolute;',
				'	top: 3px;',
				'	font-size: 12px;',
				'	line-height: 1;',
				'	left: 3px;',
				'	color: #049;',
				'}',
				'.perf-view-bar-type-js {',
				'	background: darkgreen;',
				'}',
				'.perf-view-bar-type-css {',
				'	background: purple;',
				'}',
				'.perf-view-bar-type-jpeg, .perf-view-bar-type-jpg, .perf-view-bar-type-gif, .perf-view-bar-type-png {',
				'	background: #4f0;',
				'}',
				'.perf-view-bar-waiting {',
				'	visibility: hidden;',
				'}',
				'.perf-view-bar-latency {',
				'	opacity: 0.2;',
				'}',
				'.perf-view-bar-downloading {',
				'	opacity: 0.5;',
				'}',
				''
			].join('\r\n');
			var style = document.createElement("style");
			style.type = "text/css";
			if (style.styleSheet) {
				style.styleSheet.cssText = css;
			} else {
				style.innerHTML = css;
			}
			document.head.appendChild(style);
			// TODO figure out a build process to just add the CSS to the JS
		}

		container = document.getElementById(options.containerId);
		if (!container) {
			container = document.createElement('div');
			container.id = options.containerId;
			document.body.appendChild(container);
			// TODO move to iframe
		}
		if (loadTime > options.errorThreshold) {
			container.className += " perf-view-error";
		}
		container.innerHTML = [
			'',
				'This page loaded in ',
				'',
					loadTime,
					'ms',
				'',
				' (details)',
				'[X]',
			''
		].join('');
	}

	function showWaterfall() {
		var resourceTimings = window.performance.getEntriesByType("resource");
		var lastResponseEnd = 0;
		for (var i = 0; i < resourceTimings.length; i++) {
			var responseEnd = resourceTimings[i].responseEnd;
			if (responseEnd > lastResponseEnd) {
				lastResponseEnd = responseEnd;
			}
		}

		lastResponseEnd *= 1.2; // Extra space.

		// Size everything in terms of %.
		var chartContainer = document.createElement("div");
		chartContainer.className = "perf-view-chart";
		var chartArea = document.createElement("div");
		chartArea.className = "perf-view-chart-area";

		// Min of 4 gridlines.
		var gridlineIncrement = 100;
		var gridlineOptions = [2000, 1000, 500, 250, 100];
		for (var i = 0; i < gridlineOptions.length; i++) {
			if (gridlineOptions[i] * 4 < lastResponseEnd) {
				gridlineIncrement = gridlineOptions[i];
				break;
			}
		}

		var gridlineValue = gridlineIncrement;
		while (gridlineValue < lastResponseEnd) {
			addGridlineAndLabel(chartArea, gridlineValue, lastResponseEnd);

			gridlineValue += gridlineIncrement;
		}

		var domContentLoaded = navTiming.domContentLoadedEventStart - navTiming.navigationStart;
		addGridlineAndLabel(chartArea, domContentLoaded, lastResponseEnd, "DOMContentLoaded");

		var loadEvent = navTiming.loadEventStart - navTiming.navigationStart;
		addGridlineAndLabel(chartArea, loadEvent, lastResponseEnd, "window.onload");

		// TODO show user timings

		var htmlRow = createRowElement(document.location.href, 0, (navTiming.responseStart - navTiming.navigationStart), (navTiming.responseEnd - navTiming.navigationStart), lastResponseEnd);
		chartArea.appendChild(htmlRow);

		for (var i = 0; i < resourceTimings.length; i++) {
			var row = createRowElement(
				resourceTimings[i].name,
				resourceTimings[i].startTime,
				resourceTimings[i].responseStart || resourceTimings[i].startTime, // responseStart will be 0 for cross-origin resources
				resourceTimings[i].responseEnd,
				lastResponseEnd);
			chartArea.appendChild(row);
		}

		chartContainer.appendChild(chartArea);
		container.appendChild(chartContainer);
	}

	function formatTime(val) {
		return (val >= 1000) ? (val / 1000).toFixed(1) + 's' : val.toFixed() + 'ms';
	}

	function addGridlineAndLabel(chartArea, gridlineValue, lastResponseEnd, eventName) {
		var gridline = createGridline(gridlineValue, lastResponseEnd);
		if (eventName) {
			gridline.className += " perf-view-gridline-event";
		}
		chartArea.appendChild(gridline);

		var domContentLoadedLabel = createGridlineLabel(gridlineValue, lastResponseEnd);
		if (eventName) {
			domContentLoadedLabel.textContent = eventName;
			domContentLoadedLabel.className += " perf-view-gridline-event-label";
		}
		chartArea.appendChild(domContentLoadedLabel);
	}

	function createGridline(gridlineValue, lastResponseEnd) {
		var gridlineRatio = gridlineValue / lastResponseEnd;
		var gridline = document.createElement("div");
		gridline.className = "perf-view-gridline";
		gridline.style.cssText = ['width: ', 100 * gridlineRatio, '%;'].join('');
		return gridline;
	}

	function createGridlineLabel(gridlineValue, lastResponseEnd) {
		var gridlineRatio = gridlineValue / lastResponseEnd;
		var labelText = formatTime(gridlineValue);
		var gridlineLabel = document.createElement("span");
		gridlineLabel.className = "perf-view-gridline-label";
		gridlineLabel.textContent = labelText;
		gridlineLabel.style.cssText = ['width: ', 200 * gridlineRatio, '%;'].join('');
		return gridlineLabel;
	}

	function createRowElement(href, requestStart, responseStart, responseEnd, totalEnd) {
		var name = href;
		var lastSlash = href.substring(0, href.length - 1).lastIndexOf('/');
		if (lastSlash >= 0) {
			name = name.substring(lastSlash + 1);
		}
		var query = name.indexOf('?');
		if (query >= 0) {
			name = name.substring(0, query);
		}

		var fileType;
		var lastDot = name.lastIndexOf('.');
		if (lastDot >= 0) {
			fileType = name.substring(lastDot + 1);
		}

		var waitingRatio = requestStart / totalEnd;
		var latencyValue = (responseStart - requestStart);
		var latencyRatio = latencyValue / totalEnd;
		var downloadingValue = (responseEnd - responseStart);
		var downloadingRatio = downloadingValue / totalEnd;

		var row = document.createElement("div");
		row.className = "perf-view-row";
		// TODO can we add resource size to this?
		row.title = ['waiting: ', formatTime(requestStart), ', latency: ', formatTime(latencyValue), ', download: ', formatTime(downloadingValue)].join('');

		var waiting = document.createElement("span");
		waiting.className = "perf-view-bar perf-view-bar-waiting";
		waiting.style.cssText = ['width: ', 100 * waitingRatio, '%;'].join('');
		row.appendChild(waiting);

		var latency = document.createElement("span");
		latency.className = "perf-view-bar perf-view-bar-latency";
		if (fileType) {
			latency.className += " perf-view-bar-type-" + fileType;
		}
		latency.style.cssText = ['width: ', 100 * latencyRatio, '%;'].join('');
		row.appendChild(latency);

		var downloading = document.createElement("span");
		downloading.className = "perf-view-bar perf-view-bar-downloading"
		if (fileType) {
			downloading.className += " perf-view-bar-type-" + fileType;
		}
		downloading.style.cssText = ['width: ', 100 * downloadingRatio, '%;'].join('');
		row.appendChild(downloading);

		var link = document.createElement("a");
		link.href = href;
		link.target = '_blank';
		link.className = "perf-view-bar-name";
		link.textContent = name;
		row.appendChild(link);

		return row;
	}

	return {
		init: init,
		showWaterfall: showWaterfall,
		hide: function() {
			document.body.removeChild(container);
			window.perfView = null;
		}
	}
}();

if (document.readyState === "complete") {
	perfView.init();
}
<|endoftext|>


<commit_before>/**
 * @license
 * lodash (Custom Build) /license | Underscore.js 1.8.3 underscorejs.org/LICENSE
 * Build: `lodash core -o ./dist/lodash.core.js`
 */
;(function(){function n(n){n=null==n?n:Object(n);var t,r=[];for(t in n)r.push(t);return r}function t(n){return mn(Object(n))}function r(n,t){return n.push.apply(n,t),n}function e(n,t,r,e,u){return u(n,function(n,u,o){r=e?(e=false,n):t(r,n,u,o)}),r}function u(n,t){return x(t,function(t){return n[t]})}function o(n){return n&&n.Object===Object?n:null}function i(n){return cn[n]}function c(n){return n instanceof f?n:new f(n)}function f(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t}function a(n,t,r,e){
var u;return(u=n===rn)||(u=hn[r],u=(n===u||n!==n&&u!==u)&&!vn.call(e,r)),u?t:n}function l(n){return L(n)?_n(n):{}}function p(n,t,r){if(typeof n!="function")throw new TypeError("Expected a function");return setTimeout(function(){n.apply(rn,r)},t)}function s(n,t){var r=true;return xn(n,function(n,e,u){return r=!!t(n,e,u)}),r}function h(n,t,r){for(var e=-1,u=n.length;++e<u;){var o=n[e],i=t(o);if(null!=i&&(c===rn?i===i:r(i,c)))var c=i,f=o}return f}function v(n,t){var r=[];return xn(n,function(n,e,u){t(n,e,u)&&r.push(n);
}),r}function y(n,t,e,u,o){var i=-1,c=n.length;for(e||(e=z),o||(o=[]);++i<c;){var f=n[i];t>0&&e(f)?t>1?y(f,t-1,e,u,o):r(o,f):u||(o[o.length]=f)}return o}function b(n,r){return n&&En(n,r,t)}function g(n,t){return v(t,function(t){return K(n[t])})}function _(n,t){return n>t}function j(n,t,r,e,u){return n===t?true:null==n||null==t||!L(n)&&!Q(t)?n!==n&&t!==t:d(n,t,j,r,e,u)}function d(n,t,r,e,u,o){var i=Tn(n),c=Tn(t),f="[object Array]",a="[object Array]";i||(f=bn.call(n),f="[object Arguments]"==f?"[object Object]":f),
c||(a=bn.call(t),a="[object Arguments]"==a?"[object Object]":a);var l="[object Object]"==f&&true,c="[object Object]"==a&&true,a=f==a;o||(o=[]);var p=kn(o,function(t){return t[0]===n});return p&&p[1]?p[1]==t:(o.push([n,t]),a&&!l?(r=i?I(n,t,r,e,u,o):q(n,t,f),o.pop(),r):2&u||(i=l&&vn.call(n,"__wrapped__"),f=c&&vn.call(t,"__wrapped__"),!i&&!f)?a?(r=$(n,t,r,e,u,o),o.pop(),r):false:(i=i?n.value():n,t=f?t.value():t,r=r(i,t,e,u,o),o.pop(),r))}function m(n){return typeof n=="function"?n:null==n?nn:(typeof n=="object"?E:w)(n);
}function O(n,t){return t>n}function x(n,t){var r=-1,e=H(n)?Array(n.length):[];return xn(n,function(n,u,o){e[++r]=t(n,u,o)}),e}function E(n){var r=t(n);return function(t){var e=r.length;if(null==t)return!e;for(t=Object(t);e--;){var u=r[e];if(!(u in t&&j(n[u],t[u],rn,3)))return false}return true}}function A(n,t){return n=Object(n),M(t,function(t,r){return r in n&&(t[r]=n[r]),t},{})}function w(n){return function(t){return null==t?rn:t[n]}}function k(n,t,r){var e=-1,u=n.length;for(0>t&&(t=-t>u?0:u+t),r=r>u?u:r,
0>r&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0,r=Array(u);++e<u;)r[e]=n[e+t];return r}function N(n){return k(n,0,n.length)}function S(n,t){var r;return xn(n,function(n,e,u){return r=t(n,e,u),!r}),!!r}function F(n,t){return M(t,function(n,t){return t.func.apply(t.thisArg,r([n],t.args))},n)}function T(n,t,r,e){r||(r={});for(var u=-1,o=t.length;++u<o;){var i=t[u],c=e?e(r[i],n[i],i,r,n):n[i],f=r,a=f[i];vn.call(f,i)&&(a===c||a!==a&&c!==c)&&(c!==rn||i in f)||(f[i]=c)}return r}function B(n){return U(function(t,r){var e=-1,u=r.length,o=u>1?r[u-1]:rn,o=n.length>3&&typeof o=="function"?(u--,
o):rn;for(t=Object(t);++e<u;){var i=r[e];i&&n(t,i,e,o)}return t})}function R(n){return function(){var t=arguments,r=l(n.prototype),t=n.apply(r,t);return L(t)?t:r}}function D(n,t,r){function e(){for(var o=-1,i=arguments.length,c=-1,f=r.length,a=Array(f+i),l=this&&this!==pn&&this instanceof e?u:n;++c<f;)a[c]=r[c];for(;i--;)a[c++]=arguments[++o];return l.apply(t,a)}if(typeof n!="function")throw new TypeError("Expected a function");var u=R(n);return e}function I(n,t,r,e,u,o){var i=n.length,c=t.length;
if(i!=c&&!(2&u&&c>i))return false;for(var c=-1,f=true,a=1&u?[]:rn;++c<i;){var l=n[c],p=t[c];if(void 0!==rn){f=false;break}if(a){if(!S(t,function(n,t){return G(a,t)||l!==n&&!r(l,n,e,u,o)?void 0:a.push(t)})){f=false;break}}else if(l!==p&&!r(l,p,e,u,o)){f=false;break}}return f}function q(n,t,r){switch(r){case"[object Boolean]":case"[object Date]":return+n==+t;case"[object Error]":return n.name==t.name&&n.message==t.message;case"[object Number]":return n!=+n?t!=+t:n==+t;case"[object RegExp]":case"[object String]":return n==t+"";
}return false}function $(n,r,e,u,o,i){var c=2&o,f=t(n),a=f.length,l=t(r).length;if(a!=l&&!c)return false;for(var p=a;p--;){var s=f[p];if(!(c?s in r:vn.call(r,s)))return false}for(l=true;++p<a;){var s=f[p],h=n[s],v=r[s];if(void 0!==rn||h!==v&&!e(h,v,u,o,i)){l=false;break}c||(c="constructor"==s)}return l&&!c&&(e=n.constructor,u=r.constructor,e!=u&&"constructor"in n&&"constructor"in r&&!(typeof e=="function"&&e instanceof e&&typeof u=="function"&&u instanceof u)&&(l=false)),l}function z(n){return Tn(n)||V(n)}function C(n){
return n&&n.length?n[0]:rn}function G(n,t,r){var e=n?n.length:0;r=typeof r=="number"?0>r?On(e+r,0):r:0,r=(r||0)-1;for(var u=t===t;++r<e;){var o=n[r];if(u?o===t:o!==o)return r}return-1}function J(n,t){return xn(n,m(t))}function M(n,t,r){return e(n,m(t),r,3>arguments.length,xn)}function P(n,t){var r;if(typeof t!="function")throw new TypeError("Expected a function");return n=Bn(n),function(){return 0<--n&&(r=t.apply(this,arguments)),1>=n&&(t=rn),r}}function U(n){var t;if(typeof n!="function")throw new TypeError("Expected a function");
return t=On(t===rn?n.length-1:Bn(t),0),function(){for(var r=arguments,e=-1,u=On(r.length-t,0),o=Array(u);++e<u;)o[e]=r[t+e];for(u=Array(t+1),e=-1;++e<t;)u[e]=r[e];return u[t]=o,n.apply(this,u)}}function V(n){return Q(n)&&H(n)&&vn.call(n,"callee")&&(!jn.call(n,"callee")||"[object Arguments]"==bn.call(n))}function H(n){var t;return(t=null!=n)&&(t=An(n),t=typeof t=="number"&&t>-1&&0==t%1&&9007199254740991>=t),t&&!K(n)}function K(n){return n=L(n)?bn.call(n):"","[object Function]"==n||"[object GeneratorFunction]"==n;
}function L(n){var t=typeof n;return!!n&&("object"==t||"function"==t)}function Q(n){return!!n&&typeof n=="object"}function W(n){return typeof n=="number"||Q(n)&&"[object Number]"==bn.call(n)}function X(n){return typeof n=="string"||!Tn(n)&&Q(n)&&"[object String]"==bn.call(n)}function Y(n){return typeof n=="string"?n:null==n?"":n+""}function Z(n){return n?u(n,t(n)):[]}function nn(n){return n}function tn(n,e,u){var o=t(e),i=g(e,o);null!=u||L(e)&&(i.length||!o.length)||(u=e,e=n,n=this,i=g(e,t(e)));var c=!(L(u)&&"chain"in u&&!u.chain),f=K(n);
return xn(i,function(t){var u=e[t];n[t]=u,f&&(n.prototype[t]=function(){var t=this.__chain__;if(c||t){var e=n(this.__wrapped__);return(e.__actions__=N(this.__actions__)).push({func:u,args:arguments,thisArg:n}),e.__chain__=t,e}return u.apply(n,r([this.value()],arguments))})}),n}var rn,en=1/0,un=/[&<>"'`]/g,on=RegExp(un.source),cn={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},fn=typeof exports=="object"&&exports,an=fn&&typeof module=="object"&&module,ln=o(typeof self=="object"&&self),pn=o(typeof global=="object"&&global)||ln||o(typeof this=="object"&&this)||Function("return this")(),sn=Array.prototype,hn=Object.prototype,vn=hn.hasOwnProperty,yn=0,bn=hn.toString,gn=pn._,_n=Object.create,jn=hn.propertyIsEnumerable,dn=pn.isFinite,mn=Object.keys,On=Math.max;
f.prototype=l(c.prototype),f.prototype.constructor=f;var xn=function(n,t){return function(r,e){if(null==r)return r;if(!H(r))return n(r,e);for(var u=r.length,o=t?u:-1,i=Object(r);(t?o--:++o<u)&&false!==e(i[o],o,i););return r}}(b),En=function(n){return function(t,r,e){var u=-1,o=Object(t);e=e(t);for(var i=e.length;i--;){var c=e[n?i:++u];if(false===r(o[c],c,o))break}return t}}(),An=w("length"),wn=String,kn=function(n){return function(r,e,u){var o=Object(r);if(e=m(e),!H(r))var i=t(r);return u=n(i||r,function(n,t){
return i&&(t=n,n=o[t]),e(n,t,o)},u),u>-1?r[i?i[u]:u]:rn}}(function(n,t,r){var e=n?n.length:0;if(!e)return-1;r=null==r?0:Bn(r),0>r&&(r=On(e+r,0));n:{for(t=m(t),e=n.length,r+=-1;++r<e;)if(t(n[r],r,n)){n=r;break n}n=-1}return n}),Nn=U(function(n,t,r){return D(n,t,r)}),Sn=U(function(n,t){return p(n,1,t)}),Fn=U(function(n,t,r){return p(n,Rn(t)||0,r)}),Tn=Array.isArray,Bn=Number,Rn=Number,Dn=B(function(n,r){T(r,t(r),n)}),In=B(function(t,r){T(r,n(r),t)}),qn=B(function(t,r,e,u){T(r,n(r),t,u)}),$n=U(function(n){
return n.push(rn,a),qn.apply(rn,n)}),zn=U(function(n,t){return null==n?{}:A(n,x(y(t,1),wn))});c.assignIn=In,c.before=P,c.bind=Nn,c.chain=function(n){return n=c(n),n.__chain__=true,n},c.compact=function(n){return v(n,Boolean)},c.concat=function(){for(var n=arguments.length,t=Array(n?n-1:0),e=arguments[0],u=n;u--;)t[u-1]=arguments[u];return n?r(Tn(e)?N(e):[e],y(t,1)):[]},c.create=function(n,t){var r=l(n);return t?Dn(r,t):r},c.defaults=$n,c.defer=Sn,c.delay=Fn,c.filter=function(n,t){return v(n,m(t))},
c.flatten=function(n){return n&&n.length?y(n,1):[]},c.flattenDeep=function(n){return n&&n.length?y(n,en):[]},c.iteratee=m,c.keys=t,c.map=function(n,t){return x(n,m(t))},c.matches=function(n){return E(Dn({},n))},c.mixin=tn,c.negate=function(n){if(typeof n!="function")throw new TypeError("Expected a function");return function(){return!n.apply(this,arguments)}},c.once=function(n){return P(2,n)},c.pick=zn,c.slice=function(n,t,r){var e=n?n.length:0;return r=r===rn?e:+r,e?k(n,null==t?0:+t,r):[]},c.sortBy=function(n,t){
var r=0;return t=m(t),x(x(n,function(n,e,u){return{value:n,index:r++,criteria:t(n,e,u)}}).sort(function(n,t){var r;n:{r=n.criteria;var e=t.criteria;if(r!==e){var u=r!==rn,o=null===r,i=r===r,c=e!==rn,f=null===e,a=e===e;if(!f&&r>e||o&&c&&a||!u&&a||!i){r=1;break n}if(!o&&e>r||f&&u&&i||!c&&i||!a){r=-1;break n}}r=0}return r||n.index-t.index}),w("value"))},c.tap=function(n,t){return t(n),n},c.thru=function(n,t){return t(n)},c.toArray=function(n){return H(n)?n.length?N(n):[]:Z(n)},c.values=Z,c.extend=In,
tn(c,c),c.clone=function(n){return L(n)?Tn(n)?N(n):T(n,t(n)):n},c.escape=function(n){return(n=Y(n))&&on.test(n)?n.replace(un,i):n},c.every=function(n,t,r){return t=r?rn:t,s(n,m(t))},c.find=kn,c.forEach=J,c.has=function(n,t){return null!=n&&vn.call(n,t)},c.head=C,c.identity=nn,c.indexOf=G,c.isArguments=V,c.isArray=Tn,c.isBoolean=function(n){return true===n||false===n||Q(n)&&"[object Boolean]"==bn.call(n)},c.isDate=function(n){return Q(n)&&"[object Date]"==bn.call(n)},c.isEmpty=function(n){return H(n)&&(Tn(n)||X(n)||K(n.splice)||V(n))?!n.length:!t(n).length;
},c.isEqual=function(n,t){return j(n,t)},c.isFinite=function(n){return typeof n=="number"&&dn(n)},c.isFunction=K,c.isNaN=function(n){return W(n)&&n!=+n},c.isNull=function(n){return null===n},c.isNumber=W,c.isObject=L,c.isRegExp=function(n){return L(n)&&"[object RegExp]"==bn.call(n)},c.isString=X,c.isUndefined=function(n){return n===rn},c.last=function(n){var t=n?n.length:0;return t?n[t-1]:rn},c.max=function(n){return n&&n.length?h(n,nn,_):rn},c.min=function(n){return n&&n.length?h(n,nn,O):rn},c.noConflict=function(){
return pn._===this&&(pn._=gn),this},c.noop=function(){},c.reduce=M,c.result=function(n,t,r){return t=null==n?rn:n[t],t===rn&&(t=r),K(t)?t.call(n):t},c.size=function(n){return null==n?0:(n=H(n)?n:t(n),n.length)},c.some=function(n,t,r){return t=r?rn:t,S(n,m(t))},c.uniqueId=function(n){var t=++yn;return Y(n)+t},c.each=J,c.first=C,tn(c,function(){var n={};return b(c,function(t,r){vn.call(c.prototype,r)||(n[r]=t)}),n}(),{chain:false}),c.VERSION="4.13.1",xn("pop join replace reverse split push shift sort splice unshift".split(" "),function(n){
var t=(/^(?:replace|split)$/.test(n)?String.prototype:sn)[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|join|replace|shift)$/.test(n);c.prototype[n]=function(){var n=arguments;if(e&&!this.__chain__){var u=this.value();return t.apply(Tn(u)?u:[],n)}return this[r](function(r){return t.apply(Tn(r)?r:[],n)})}}),c.prototype.toJSON=c.prototype.valueOf=c.prototype.value=function(){return F(this.__wrapped__,this.__actions__)},(ln||{})._=c,typeof define=="function"&&typeof define.amd=="object"&&define.amd? define(function(){
return c}):an?((an.exports=c)._=c,fn._=c):pn._=c}).call(this);<commit_msg>Update public/libs/bower_components/lodash/dist/lodash.core.min.js<commit_after><|endoftext|>