<commit_before>/* See license.txt for terms of usage */

define([
    "lib/domplate",
    "lib/lib",
    "lib/trace"
],
function(Domplate, Lib, FBTrace) { with (Domplate) {

// ********************************************************************************************* //
// Controller

var Controller =
{
    controllers: [],
    controllerContext: {label: "controller context"},

    initialize: function(context)
    {
        this.controllers = [];
        this.controllerContext = context || this.controllerContext;
    },

    shutdown: function()
    {
        this.removeControllers();
    },

    addController: function()
    {
        for (var i=0, arg; arg=arguments[i]; i++)
        {
            // If the first argument is a string, make a selector query
            // within the controller node context
            if (typeof arg[0] == "string")
            {
                arg[0] = $$(arg[0], this.controllerContext);
            }

            // bind the handler to the proper context
            var handler = arg[2];
            arg[2] = Lib.bind(handler, this);
            // save the original handler as an extra-argument, so we can
            // look for it later, when removing a particular controller
            arg[3] = handler;

            this.controllers.push(arg);
            Lib.addEventListener.apply(this, arg);
        }
    },

    removeController: function()
    {
        for (var i=0, arg; arg=arguments[i]; i++)
        {
            for (var j=0, c; c=this.controllers[j]; j++)
            {
                if (arg[0] == c[0] && arg[1] == c[1] && arg[2] == c[3])
                    Lib.removeEventListener.apply(this, c);
            }
        }
    },

    removeControllers: function()
    {
        for (var i=0, c; c=this.controllers[i]; i++)
        {
            Lib.removeEventListener.apply(this, c);
        }
    }
};

// ********************************************************************************************* //
// Menu

var menuItemProps = {
    "class": "$item.className",
    type: "$item.type",
    value: "$item.value",
    _command: "$item.command"
};

if (Lib.isIE6)
    menuItemProps.href = "javascript:void(0)";

var MenuPlate = domplate(
{
    tag:
        DIV({"class": "popupMenu popupMenuShadow"},
            DIV({"class": "popupMenuContent popupMenuShadowContent"},
                FOR("item", "$object.items|memberIterator",
                    TAG("$item.tag", {item: "$item"})
                )
            )
        ),

    itemTag:
        A(menuItemProps,
            "$item.label"
        ),

    checkBoxTag:
        A(Lib.extend(menuItemProps, {checked : "$item.checked"}),
            "$item.label"
        ),

    radioButtonTag:
        A(Lib.extend(menuItemProps, {selected : "$item.selected"}),
            "$item.label"
        ),

    groupTag:
        A(Lib.extend(menuItemProps, {child: "$item.child"}),
            "$item.label"
        ),

    shortcutTag:
        A(menuItemProps,
            "$item.label",
            SPAN({"class": "popupMenuShortcutKey"},
                "$item.key"
            )
        ),

    separatorTag:
        SPAN({"class": "popupMenuSeparator"}),

    memberIterator: function(items)
    {
        var result = [];
        for (var i=0, length=items.length; i<length; i++)
        {
            var item = items[i];

            // separator representation
            if (typeof item == "string" && item.indexOf("-") == 0)
            {
                result.push({tag: this.separatorTag});
                continue;
            }

            item = Lib.extend(item, {});
            item.type = item.type || "";
            item.value = item.value || "";

            var type = item.type;

            // default item representation
            item.tag = this.itemTag;

            var className = item.className || "";
            className += "popupMenuOption ";

            // specific representations
            if (type == "checkbox")
            {
                className += "popupMenuCheckBox ";
                item.tag = this.checkBoxTag;
            }
            else if (type == "radio")
            {
                className += "popupMenuRadioButton ";
                item.tag = this.radioButtonTag;
            }
            else if (type == "group")
            {
                className += "popupMenuGroup ";
                item.tag = this.groupTag;
            }
            else if (type == "shortcut")
            {
                className += "popupMenuShortcut ";
                item.tag = this.shortcutTag;
            }

            if (item.checked)
                className += "popupMenuChecked ";
            else if (item.selected)
                className += "popupMenuRadioSelected ";

            if (item.disabled)
                className += "popupMenuDisabled ";

            item.className = className;
            item.label = item.label;
            result.push(item);
        }

        return result;
    }
});

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

function Menu(options)
{
    // if element is not pre-rendered, we must render it now
    if (!options.element)
    {
        if (options.getItems)
            options.items = options.getItems();

        // Trim separators
        if (options.items[0] == "-")
            options.items.shift();
        if (options.items[options.items.length - 1] == "-")
            options.items.pop();

        var body = Lib.getBody(document);
        options.element = MenuPlate.tag.append({object: options}, body, MenuPlate);
    }

    // extend itself with the provided options
    Lib.append(this, options);

    if (typeof this.element == "string")
    {
        this.id = this.element;
        this.element = $(this.id);
    }
    else if (this.id)
    {
        this.element.id = this.id;
    }

    this.elementStyle = this.element.style;
    this.isVisible = false;

    this.handleMouseDown = Lib.bind(this.handleMouseDown, this);
    this.handleMouseOver = Lib.bind(this.handleMouseOver, this);
    this.handleMouseOut = Lib.bind(this.handleMouseOut, this);
    this.handleWindowMouseDown = Lib.bind(this.handleWindowMouseDown, this);
};

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

var menuMap = {};

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

Menu.prototype = Lib.extend(Controller,
{
    initialize: function()
    {
        Controller.initialize.call(this);

        this.addController(
            [this.element, "mousedown", this.handleMouseDown],
            [this.element, "mouseover", this.handleMouseOver]
        );
    },

    destroy: function()
    {
        this.hide();

        // if it is a childMenu, remove its reference from the parentMenu
        if (this.parentMenu)
            this.parentMenu.childMenu = null;

        // remove the element from the document
        this.element.parentNode.removeChild(this.element);

        // clear references
        this.element = null;
        this.elementStyle = null;
        this.parentMenu = null;
        this.parentTarget = null;
    },

    shutdown: function()
    {
        Controller.shutdown.call(this);
    },

    showPopup: function(target)
    {
        var offsetLeft = Lib.isIE6 ? 1 : -4;  // IE6 problem with fixed position
        var box = Lib.getElementBox(target);
        var offset = {top: 0, left: 0};

        this.show(
            box.left + offsetLeft - offset.left,
            box.top + box.height - 5 - offset.top
        );
    },

    show: function(x, y)
    {
        this.initialize();

        if (this.isVisible)
            return;

        x = x || 0;
        y = y || 0;

        if (this.parentMenu)
        {
            var oldChildMenu = this.parentMenu.childMenu;
            if (oldChildMenu && oldChildMenu != this)
            {
                oldChildMenu.destroy();
            }

            this.parentMenu.childMenu = this;
        }
        else
        {
            Lib.addEventListener(document, "mousedown", this.handleWindowMouseDown);
        }

        this.elementStyle.display = "block";
        this.elementStyle.visibility = "hidden";

        var size = Lib.getWindowSize();

        x = Math.min(x, size.width - this.element.clientWidth - 30);
        x = Math.max(x, 0);

        y = Math.min(y, size.height - this.element.clientHeight - 10);
        y = Math.max(y, 0);

        this.elementStyle.left = x + "px";
        this.elementStyle.top = y + "px";
        this.elementStyle.visibility = "visible";
        this.isVisible = true;

        if (Lib.isFunction(this.onShow))
            this.onShow.apply(this, arguments);
    },

    hide: function()
    {
        this.clearHideTimeout();
        this.clearShowChildTimeout();

        if (!this.isVisible)
            return;

        this.elementStyle.display = "none";

        if (this.childMenu)
        {
            this.childMenu.destroy();
            this.childMenu = null;
        }

        if (this.parentTarget)
            Lib.removeClass(this.parentTarget, "popupMenuGroupSelected");

        this.isVisible = false;
        this.shutdown();

        if (Lib.isFunction(this.onHide))
            this.onHide.apply(this, arguments);
    },

    showChildMenu: function(target)
    {
        var id = target.getAttribute("child");
        var parent = this;
        var target = target;

        this.showChildTimeout = window.setTimeout(function()
        {
            //if (!parent.isVisible) return;
            var box = Lib.getElementBox(target);
            var childMenuObject = menuMap.hasOwnProperty(id) ? menuMap[id] : {element: $(id)};

            var childMenu = new Menu(Lib.extend(childMenuObject,
            {
                parentMenu: parent,
                parentTarget: target
            }));

            var offsetLeft = Lib.isIE6 ? -1 : -6; // IE6 problem with fixed position
            childMenu.show(box.left + box.width + offsetLeft, box.top -6);
            Lib.setClass(target, "popupMenuGroupSelected");
        },350);
    },

    clearHideTimeout: function()
    {
        if (this.hideTimeout)
        {
            window.clearTimeout(this.hideTimeout);
            delete this.hideTimeout;
        }
    },

    clearShowChildTimeout: function()
    {
        if(this.showChildTimeout)
        {
            window.clearTimeout(this.showChildTimeout);
            this.showChildTimeout = null;
        }
    },

    handleMouseDown: function(event)
    {
        Lib.cancelEvent(event, true);

        var topParent = this;
        while (topParent.parentMenu)
            topParent = topParent.parentMenu;

        var target = event.target || event.srcElement;

        target = Lib.getAncestorByClass(target, "popupMenuOption");

        if(!target || Lib.hasClass(target, "popupMenuGroup"))
            return false;

        if (target && !Lib.hasClass(target, "popupMenuDisabled"))
        {
            var type = target.getAttribute("type");

            if (type == "checkbox")
            {
                var checked = target.getAttribute("checked");
                var value = target.getAttribute("value");
                var wasChecked = Lib.hasClass(target, "popupMenuChecked");

                if (wasChecked)
                {
                    Lib.removeClass(target, "popupMenuChecked");
                    target.setAttribute("checked", "");
                }
                else
                {
                    Lib.setClass(target, "popupMenuChecked");
                    target.setAttribute("checked", "true");
                }

                if (Lib.isFunction(this.onCheck))
                    this.onCheck.call(this, target, value, !wasChecked)
            }

            if (type == "radiobutton")
            {
                var selectedRadios = Lib.getElementsByClass(target.parentNode, "popupMenuRadioSelected");
                var group = target.getAttribute("group");

                for (var i = 0, length = selectedRadios.length; i < length; i++)
                {
                    radio = selectedRadios[i];

                    if (radio.getAttribute("group") == group)
                    {
                        Lib.removeClass(radio, "popupMenuRadioSelected");
                        radio.setAttribute("selected", "");
                    }
                }

                Lib.setClass(target, "popupMenuRadioSelected");
                target.setAttribute("selected", "true");
            }

            var handler = null;

            // target.command can be a function or a string.
            var cmd = target.command;

            // If it is a function it will be used as the handler
            // If it is a string, tha handler is the property of the current menu object
            // will be used as the handler
            if (Lib.isFunction(cmd))
                handler = cmd;
            else if (typeof cmd == "string")
                handler = this[cmd];

            var closeMenu = true;
            if (handler)
                closeMenu = handler.call(this, target) !== false;

            if (closeMenu)
                topParent.hide();
        }

        return false;
    },

    handleWindowMouseDown: function(event)
    {
        var target = event.target || event.srcElement;
        target = Lib.getAncestorByClass(target, "popupMenu");
        if (!target)
        {
            Lib.removeEventListener(document, "mousedown", this.handleWindowMouseDown);
            this.destroy();
        }
    },

    handleMouseOver: function(event)
    {
        this.clearHideTimeout();
        this.clearShowChildTimeout();

        var target = event.target || event.srcElement;

        target = Lib.getAncestorByClass(target, "popupMenuOption");

        if (!target)
            return;

        var childMenu = this.childMenu;
        if (childMenu)
        {
            Lib.removeClass(childMenu.parentTarget, "popupMenuGroupSelected");

            if (childMenu.parentTarget != target && childMenu.isVisible)
            {
                childMenu.clearHideTimeout();
                childMenu.hideTimeout = window.setTimeout(function(){
                    childMenu.destroy();
                },300);
            }
        }

        if (Lib.hasClass(target, "popupMenuGroup"))
        {
            this.showChildMenu(target);
        }
    }
});

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Lib.append(Menu,
{
    register: function(object)
    {
        menuMap[object.id] = object;
    },

    check: function(element)
    {
        Lib.setClass(element, "popupMenuChecked");
        element.setAttribute("checked", "true");
    },

    uncheck: function(element)
    {
        Lib.removeClass(element, "popupMenuChecked");
        element.setAttribute("checked", "");
    },

    disable: function(element)
    {
        Lib.setClass(element, "popupMenuDisabled");
    },

    enable: function(element)
    {
        Lib.removeClass(element, "popupMenuDisabled");
    }
});

// ********************************************************************************************* //

return Menu;

// ********************************************************************************************* //
}});
<commit_msg>Fix context menu position (needs further improvement)<commit_after>/* See license.txt for terms of usage */

define([
    "lib/domplate",
    "lib/lib",
    "lib/trace"
],
function(Domplate, Lib, FBTrace) { with (Domplate) {

// ********************************************************************************************* //
// Controller

var Controller =
{
    controllers: [],
    controllerContext: {label: "controller context"},

    initialize: function(context)
    {
        this.controllers = [];
        this.controllerContext = context || this.controllerContext;
    },

    shutdown: function()
    {
        this.removeControllers();
    },

    addController: function()
    {
        for (var i=0, arg; arg=arguments[i]; i++)
        {
            // If the first argument is a string, make a selector query
            // within the controller node context
            if (typeof arg[0] == "string")
            {
                arg[0] = $$(arg[0], this.controllerContext);
            }

            // bind the handler to the proper context
            var handler = arg[2];
            arg[2] = Lib.bind(handler, this);
            // save the original handler as an extra-argument, so we can
            // look for it later, when removing a particular controller
            arg[3] = handler;

            this.controllers.push(arg);
            Lib.addEventListener.apply(this, arg);
        }
    },

    removeController: function()
    {
        for (var i=0, arg; arg=arguments[i]; i++)
        {
            for (var j=0, c; c=this.controllers[j]; j++)
            {
                if (arg[0] == c[0] && arg[1] == c[1] && arg[2] == c[3])
                    Lib.removeEventListener.apply(this, c);
            }
        }
    },

    removeControllers: function()
    {
        for (var i=0, c; c=this.controllers[i]; i++)
        {
            Lib.removeEventListener.apply(this, c);
        }
    }
};

// ********************************************************************************************* //
// Menu

var menuItemProps = {
    "class": "$item.className",
    type: "$item.type",
    value: "$item.value",
    _command: "$item.command"
};

if (Lib.isIE6)
    menuItemProps.href = "javascript:void(0)";

var MenuPlate = domplate(
{
    tag:
        DIV({"class": "popupMenu popupMenuShadow"},
            DIV({"class": "popupMenuContent popupMenuShadowContent"},
                FOR("item", "$object.items|memberIterator",
                    TAG("$item.tag", {item: "$item"})
                )
            )
        ),

    itemTag:
        A(menuItemProps,
            "$item.label"
        ),

    checkBoxTag:
        A(Lib.extend(menuItemProps, {checked : "$item.checked"}),
            "$item.label"
        ),

    radioButtonTag:
        A(Lib.extend(menuItemProps, {selected : "$item.selected"}),
            "$item.label"
        ),

    groupTag:
        A(Lib.extend(menuItemProps, {child: "$item.child"}),
            "$item.label"
        ),

    shortcutTag:
        A(menuItemProps,
            "$item.label",
            SPAN({"class": "popupMenuShortcutKey"},
                "$item.key"
            )
        ),

    separatorTag:
        SPAN({"class": "popupMenuSeparator"}),

    memberIterator: function(items)
    {
        var result = [];
        for (var i=0, length=items.length; i<length; i++)
        {
            var item = items[i];

            // separator representation
            if (typeof item == "string" && item.indexOf("-") == 0)
            {
                result.push({tag: this.separatorTag});
                continue;
            }

            item = Lib.extend(item, {});
            item.type = item.type || "";
            item.value = item.value || "";

            var type = item.type;

            // default item representation
            item.tag = this.itemTag;

            var className = item.className || "";
            className += "popupMenuOption ";

            // specific representations
            if (type == "checkbox")
            {
                className += "popupMenuCheckBox ";
                item.tag = this.checkBoxTag;
            }
            else if (type == "radio")
            {
                className += "popupMenuRadioButton ";
                item.tag = this.radioButtonTag;
            }
            else if (type == "group")
            {
                className += "popupMenuGroup ";
                item.tag = this.groupTag;
            }
            else if (type == "shortcut")
            {
                className += "popupMenuShortcut ";
                item.tag = this.shortcutTag;
            }

            if (item.checked)
                className += "popupMenuChecked ";
            else if (item.selected)
                className += "popupMenuRadioSelected ";

            if (item.disabled)
                className += "popupMenuDisabled ";

            item.className = className;
            item.label = item.label;
            result.push(item);
        }

        return result;
    }
});

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

function Menu(options)
{
    // if element is not pre-rendered, we must render it now
    if (!options.element)
    {
        if (options.getItems)
            options.items = options.getItems();

        // Trim separators
        if (options.items[0] == "-")
            options.items.shift();
        if (options.items[options.items.length - 1] == "-")
            options.items.pop();

        var body = Lib.getBody(document);
        options.element = MenuPlate.tag.append({object: options}, body, MenuPlate);
    }

    // extend itself with the provided options
    Lib.append(this, options);

    if (typeof this.element == "string")
    {
        this.id = this.element;
        this.element = $(this.id);
    }
    else if (this.id)
    {
        this.element.id = this.id;
    }

    this.elementStyle = this.element.style;
    this.isVisible = false;

    this.handleMouseDown = Lib.bind(this.handleMouseDown, this);
    this.handleMouseOver = Lib.bind(this.handleMouseOver, this);
    this.handleMouseOut = Lib.bind(this.handleMouseOut, this);
    this.handleWindowMouseDown = Lib.bind(this.handleWindowMouseDown, this);
};

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

var menuMap = {};

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

Menu.prototype = Lib.extend(Controller,
{
    initialize: function()
    {
        Controller.initialize.call(this);

        this.addController(
            [this.element, "mousedown", this.handleMouseDown],
            [this.element, "mouseover", this.handleMouseOver]
        );
    },

    destroy: function()
    {
        this.hide();

        // if it is a childMenu, remove its reference from the parentMenu
        if (this.parentMenu)
            this.parentMenu.childMenu = null;

        // remove the element from the document
        this.element.parentNode.removeChild(this.element);

        // clear references
        this.element = null;
        this.elementStyle = null;
        this.parentMenu = null;
        this.parentTarget = null;
    },

    shutdown: function()
    {
        Controller.shutdown.call(this);
    },

    showPopup: function(target)
    {
        var offsetLeft = Lib.isIE6 ? 1 : -4;  // IE6 problem with fixed position
        var box = Lib.getElementBox(target);
        var offset = {top: 0, left: 0};

        this.show(
            box.left + offsetLeft - offset.left,
            box.top + box.height - 5 - offset.top
        );
    },

    show: function(x, y)
    {
        this.initialize();

        if (this.isVisible)
            return;

        x = x || 0;
        y = y || 0;

        if (this.parentMenu)
        {
            var oldChildMenu = this.parentMenu.childMenu;
            if (oldChildMenu && oldChildMenu != this)
            {
                oldChildMenu.destroy();
            }

            this.parentMenu.childMenu = this;
        }
        else
        {
            Lib.addEventListener(document, "mousedown", this.handleWindowMouseDown);
        }

        this.elementStyle.display = "block";
        this.elementStyle.visibility = "hidden";

        var size = Lib.getWindowSize();

        x = Math.min(x, size.width - this.element.clientWidth - 30);
        x = Math.max(x, 0);

        //y = Math.min(y, size.height - this.element.clientHeight - 10);
        //y = Math.max(y, 0);

        this.elementStyle.left = x + "px";
        this.elementStyle.top = y + "px";
        this.elementStyle.visibility = "visible";
        this.isVisible = true;

        if (Lib.isFunction(this.onShow))
            this.onShow.apply(this, arguments);
    },

    hide: function()
    {
        this.clearHideTimeout();
        this.clearShowChildTimeout();

        if (!this.isVisible)
            return;

        this.elementStyle.display = "none";

        if (this.childMenu)
        {
            this.childMenu.destroy();
            this.childMenu = null;
        }

        if (this.parentTarget)
            Lib.removeClass(this.parentTarget, "popupMenuGroupSelected");

        this.isVisible = false;
        this.shutdown();

        if (Lib.isFunction(this.onHide))
            this.onHide.apply(this, arguments);
    },

    showChildMenu: function(target)
    {
        var id = target.getAttribute("child");
        var parent = this;
        var target = target;

        this.showChildTimeout = window.setTimeout(function()
        {
            //if (!parent.isVisible) return;
            var box = Lib.getElementBox(target);
            var childMenuObject = menuMap.hasOwnProperty(id) ? menuMap[id] : {element: $(id)};

            var childMenu = new Menu(Lib.extend(childMenuObject,
            {
                parentMenu: parent,
                parentTarget: target
            }));

            var offsetLeft = Lib.isIE6 ? -1 : -6; // IE6 problem with fixed position
            childMenu.show(box.left + box.width + offsetLeft, box.top -6);
            Lib.setClass(target, "popupMenuGroupSelected");
        },350);
    },

    clearHideTimeout: function()
    {
        if (this.hideTimeout)
        {
            window.clearTimeout(this.hideTimeout);
            delete this.hideTimeout;
        }
    },

    clearShowChildTimeout: function()
    {
        if(this.showChildTimeout)
        {
            window.clearTimeout(this.showChildTimeout);
            this.showChildTimeout = null;
        }
    },

    handleMouseDown: function(event)
    {
        Lib.cancelEvent(event, true);

        var topParent = this;
        while (topParent.parentMenu)
            topParent = topParent.parentMenu;

        var target = event.target || event.srcElement;

        target = Lib.getAncestorByClass(target, "popupMenuOption");

        if(!target || Lib.hasClass(target, "popupMenuGroup"))
            return false;

        if (target && !Lib.hasClass(target, "popupMenuDisabled"))
        {
            var type = target.getAttribute("type");

            if (type == "checkbox")
            {
                var checked = target.getAttribute("checked");
                var value = target.getAttribute("value");
                var wasChecked = Lib.hasClass(target, "popupMenuChecked");

                if (wasChecked)
                {
                    Lib.removeClass(target, "popupMenuChecked");
                    target.setAttribute("checked", "");
                }
                else
                {
                    Lib.setClass(target, "popupMenuChecked");
                    target.setAttribute("checked", "true");
                }

                if (Lib.isFunction(this.onCheck))
                    this.onCheck.call(this, target, value, !wasChecked)
            }

            if (type == "radiobutton")
            {
                var selectedRadios = Lib.getElementsByClass(target.parentNode, "popupMenuRadioSelected");
                var group = target.getAttribute("group");

                for (var i = 0, length = selectedRadios.length; i < length; i++)
                {
                    radio = selectedRadios[i];

                    if (radio.getAttribute("group") == group)
                    {
                        Lib.removeClass(radio, "popupMenuRadioSelected");
                        radio.setAttribute("selected", "");
                    }
                }

                Lib.setClass(target, "popupMenuRadioSelected");
                target.setAttribute("selected", "true");
            }

            var handler = null;

            // target.command can be a function or a string.
            var cmd = target.command;

            // If it is a function it will be used as the handler
            // If it is a string, tha handler is the property of the current menu object
            // will be used as the handler
            if (Lib.isFunction(cmd))
                handler = cmd;
            else if (typeof cmd == "string")
                handler = this[cmd];

            var closeMenu = true;
            if (handler)
                closeMenu = handler.call(this, target) !== false;

            if (closeMenu)
                topParent.hide();
        }

        return false;
    },

    handleWindowMouseDown: function(event)
    {
        var target = event.target || event.srcElement;
        target = Lib.getAncestorByClass(target, "popupMenu");
        if (!target)
        {
            Lib.removeEventListener(document, "mousedown", this.handleWindowMouseDown);
            this.destroy();
        }
    },

    handleMouseOver: function(event)
    {
        this.clearHideTimeout();
        this.clearShowChildTimeout();

        var target = event.target || event.srcElement;

        target = Lib.getAncestorByClass(target, "popupMenuOption");

        if (!target)
            return;

        var childMenu = this.childMenu;
        if (childMenu)
        {
            Lib.removeClass(childMenu.parentTarget, "popupMenuGroupSelected");

            if (childMenu.parentTarget != target && childMenu.isVisible)
            {
                childMenu.clearHideTimeout();
                childMenu.hideTimeout = window.setTimeout(function(){
                    childMenu.destroy();
                },300);
            }
        }

        if (Lib.hasClass(target, "popupMenuGroup"))
        {
            this.showChildMenu(target);
        }
    }
});

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Lib.append(Menu,
{
    register: function(object)
    {
        menuMap[object.id] = object;
    },

    check: function(element)
    {
        Lib.setClass(element, "popupMenuChecked");
        element.setAttribute("checked", "true");
    },

    uncheck: function(element)
    {
        Lib.removeClass(element, "popupMenuChecked");
        element.setAttribute("checked", "");
    },

    disable: function(element)
    {
        Lib.setClass(element, "popupMenuDisabled");
    },

    enable: function(element)
    {
        Lib.removeClass(element, "popupMenuDisabled");
    }
});

// ********************************************************************************************* //

return Menu;

// ********************************************************************************************* //
}});
<|endoftext|>


<commit_before>user_pref("beacon.enabled", false);
user_pref("browser.contentblocking.enabled", false);
user_pref("browser.library.activity-stream.enabled", false);
user_pref("browser.safebrowsing.downloads.enabled", false);
user_pref("browser.safebrowsing.malware.enabled", false);
user_pref("browser.safebrowsing.phishing.enabled", false);
user_pref("browser.tabs.drawInTitlebar", true);
user_pref("dom.battery.enabled", false);
user_pref("extensions.pocket.enabled", false);
user_pref("general.autoScroll", true);
user_pref("gfx.canvas.azure.accelerated", true);
user_pref("javascript.options.asyncstack", false);
user_pref("layers.acceleration.force-enabled", true);
user_pref("layers.omtp.paint-workers", 4);
user_pref("media.eme.enabled", false);
user_pref("media.navigator.enabled", false);
user_pref("media.peerconnection.enabled", false);
user_pref("network.IDN_show_punycode", true);
user_pref("privacy.donottrackheader.enabled", true);
<commit_msg>Change URL bar result ordering<commit_after>user_pref("beacon.enabled", false);
user_pref("browser.contentblocking.enabled", false);
user_pref("browser.library.activity-stream.enabled", false);
user_pref("browser.safebrowsing.downloads.enabled", false);
user_pref("browser.safebrowsing.malware.enabled", false);
user_pref("browser.safebrowsing.phishing.enabled", false);
user_pref("browser.tabs.drawInTitlebar", true);
user_pref("browser.urlbar.matchBuckets", "general:5,suggestion:Infinity");
user_pref("dom.battery.enabled", false);
user_pref("extensions.pocket.enabled", false);
user_pref("general.autoScroll", true);
user_pref("gfx.canvas.azure.accelerated", true);
user_pref("javascript.options.asyncstack", false);
user_pref("layers.acceleration.force-enabled", true);
user_pref("layers.omtp.paint-workers", 4);
user_pref("media.eme.enabled", false);
user_pref("media.navigator.enabled", false);
user_pref("media.peerconnection.enabled", false);
user_pref("network.IDN_show_punycode", true);
user_pref("privacy.donottrackheader.enabled", true);
<|endoftext|>


<commit_before>
/*global browser:true*/

let IS_AUTO_UPDATE = true;
let INTERVAL_ID;
const CHECK_INTERVAL = 15000;

if(typeof browser === 'undefined') {
  window.browser = window.chrome;
}

const updatePageAction = function() {
  browser.runtime.sendMessage({task:'setIcon', icon: IS_AUTO_UPDATE});
};

/*
clickUpdateButton():
* click update button.
*/
const clickUpdateButton = function() {
  const wk_elm = document.getElementsByClassName('new-tweets-bar');
  if(wk_elm && wk_elm.length > 0) {
    wk_elm[0].click();
  }
};

const parseTweetTime = function(milsec_txt) {
  const wk = new Date(parseInt(milsec_txt));
  const result = {};
  result.year = wk.getFullYear();
  result.month = ('00' + (wk.getMonth() + 1)).slice(-2);
  result.day = ('00' + wk.getDate()).slice(-2);
  result.hour = ('00' + wk.getHours()).slice(-2);
  result.minute = ('00' + wk.getMinutes()).slice(-2);
  return result;
};

const getQuoteTweetText = function(tgt_elm) {
  let ret = '';
  let wk_elm;
  wk_elm = tgt_elm.getElementsByClassName('QuoteTweet-link');
  if(wk_elm && wk_elm.length > 0) {
    console.log('scrape1');
    let wk = ` <div class="quotedTweet"><a href="${wk_elm[0].href}">`;
    wk_elm = tgt_elm.getElementsByClassName('QuoteTweet-fullname');
    if(wk_elm && wk_elm.length > 0) {
      wk += wk_elm[0].textContent.trim() + ': ';
    }
    wk_elm = tgt_elm.getElementsByClassName('QuoteTweet-text');
    if(wk_elm && wk_elm.length > 0) {
      wk += wk_elm[0].textContent.trim() + '
';
    }
    ret += wk;
  }
  return ret;
};

const copyFromOverlay= function(tgt_elm) {
  const result = {};
  let wk_elm;
  wk_elm = tgt_elm.getElementsByClassName('tweet-timestamp');
  if(wk_elm && wk_elm.length > 0) {
    console.log(1);
    result.href = wk_elm[0].href.trim();
  }
  wk_elm = tgt_elm.getElementsByClassName('_timestamp');
  if(wk_elm && wk_elm.length > 0) {
    console.log(2);
    result.time = parseTweetTime(wk_elm[0].getAttribute('data-time-ms').trim());
  }
  wk_elm = tgt_elm.getElementsByClassName('fullname');
  if(wk_elm && wk_elm.length > 0) {
    console.log(3);
    result.fullname = wk_elm[0].textContent.trim();
  }
  wk_elm = tgt_elm.getElementsByClassName('tweet-text');
  if(wk_elm && wk_elm.length > 0) {
    console.log(4);
    result.text = wk_elm[0].textContent.trim();
    const quoteTweetText = getQuoteTweetText(tgt_elm);
    if(quoteTweetText !== '') {
      console.log('add quote');
      //result.text = result.text.replace(/(.+)(https:\/\/twitter\.com\/ … )$/, '$1');
      result.text = result.text.replace(/(.+)(https:\/\/twitter\.com\/.+)$/, '$1');
      result.text += quoteTweetText;
    }
  }
  //console.log(result);
  const result_text = '
' +
    result.time['year'] + '-' +
    result.time['month'] + '-' +
    result.time['day'] + ' ' +
    result.time['hour'] + ':' +
    result.time['minute'] + ' ' +
    result.fullname + ': ' +
    result.text + '
';
  return result_text;
};

const setTextForCopy = function() {
  console.log('setTextForCopy');
  let ret = '';
  let wk_elm;
  wk_elm = document.getElementById('permalink-overlay');
  console.log('setTextForCopy1');
  if(wk_elm &&
    (wk_elm.style === undefined
      || (wk_elm.style !== undefined && wk_elm.style.display === undefined)
      || wk_elm.style.display === 'block'
      || wk_elm.style.opacity === 1)) {
    console.log('go permalink0');
    wk_elm = wk_elm.getElementsByClassName('permalink-tweet-container');
    if(wk_elm && wk_elm.length > 0) {
      console.log('go permalink1');
      ret = copyFromOverlay(wk_elm[0]);
    }
    return ret;
  }
  console.log('setTextForCopy2');
  wk_elm = document.getElementsByClassName('selected-stream-item');
  console.log('setTextForCopy3');
  if(wk_elm && wk_elm.length > 0) {
    console.log('go stream-item');
    ret = copyFromOverlay(wk_elm[0]);
    return ret;
  }
  return ret;
};

const onCopy = function(ev) {
  console.log('onCopy start');
  if(window.getSelection().toString() === '') {
    const outputText = setTextForCopy();
    console.log(outputText);
    if(outputText !== '') {
      ev.preventDefault();
      const transfer = ev.clipboardData;
      console.log('onCopy transfer');
      transfer.setData('text/plain', outputText);
    }
  }
};

const preventKeydown = function(evt) {
  if(evt.target.isContentEditable
    || evt.target.nodeName.toUpperCase() === 'INPUT'
    || evt.target.nodeName.toUpperCase() === 'TEXTAREA') {
    return;
  }
  evt.preventDefault();
};

const handleKeydown = function(evt) {
  switch(evt.key) {
    case 'a':
      if(IS_AUTO_UPDATE === false) {
        INTERVAL_ID = setInterval(clickUpdateButton, CHECK_INTERVAL);
        IS_AUTO_UPDATE = true;
        updatePageAction();
      }
      break;
    case 'b':
      preventKeydown(evt);
      break;
    case 'q':
      if(IS_AUTO_UPDATE) {
        clearInterval(INTERVAL_ID);
        IS_AUTO_UPDATE = false;
        updatePageAction();
      }
      break;
    case 'u':
      preventKeydown(evt);
      break;
  }
};

const start = function() {
  console.debug(window.location.href);
  updatePageAction();
  //DOMContentLoaded and load Event can be listend on capturing phase. not bubbling phase.
  document.addEventListener('keydown', handleKeydown);
  document.addEventListener('copy', onCopy);
  INTERVAL_ID = setInterval(clickUpdateButton, CHECK_INTERVAL);
};

start();

<commit_msg>doc: add jsdoc<commit_after>
/*global browser:true*/

let IS_AUTO_UPDATE = true;
let INTERVAL_ID;
const CHECK_INTERVAL = 15000;

if(typeof browser === 'undefined') {
  window.browser = window.chrome;
}

const updatePageAction = function() {
  browser.runtime.sendMessage({task:'setIcon', icon: IS_AUTO_UPDATE});
};

/*
clickUpdateButton():
* click update button.
*/
const clickUpdateButton = function() {
  const wk_elm = document.getElementsByClassName('new-tweets-bar');
  if(wk_elm && wk_elm.length > 0) {
    wk_elm[0].click();
  }
};

/**
 * make and return Object contains each datetime infos as string, made from mill seconds string.
 * @param {string} milsec_txt - string
 * @returns {?result} - Object
 */
const parseTweetTime = function(milsec_txt) {
  const wk = new Date(parseInt(milsec_txt));
  const result = {};
  result.year = wk.getFullYear();
  result.month = ('00' + (wk.getMonth() + 1)).slice(-2);
  result.day = ('00' + wk.getDate()).slice(-2);
  result.hour = ('00' + wk.getHours()).slice(-2);
  result.minute = ('00' + wk.getMinutes()).slice(-2);
  return result;
};

const getQuoteTweetText = function(tgt_elm) {
  let ret = '';
  let wk_elm;
  wk_elm = tgt_elm.getElementsByClassName('QuoteTweet-link');
  if(wk_elm && wk_elm.length > 0) {
    console.log('scrape1');
    let wk = ` <div class="quotedTweet"><a href="${wk_elm[0].href}">`;
    wk_elm = tgt_elm.getElementsByClassName('QuoteTweet-fullname');
    if(wk_elm && wk_elm.length > 0) {
      wk += wk_elm[0].textContent.trim() + ': ';
    }
    wk_elm = tgt_elm.getElementsByClassName('QuoteTweet-text');
    if(wk_elm && wk_elm.length > 0) {
      wk += wk_elm[0].textContent.trim() + '
';
    }
    ret += wk;
  }
  return ret;
};

const copyFromOverlay= function(tgt_elm) {
  const result = {};
  let wk_elm;
  wk_elm = tgt_elm.getElementsByClassName('tweet-timestamp');
  if(wk_elm && wk_elm.length > 0) {
    console.log(1);
    result.href = wk_elm[0].href.trim();
  }
  wk_elm = tgt_elm.getElementsByClassName('_timestamp');
  if(wk_elm && wk_elm.length > 0) {
    console.log(2);
    result.time = parseTweetTime(wk_elm[0].getAttribute('data-time-ms').trim());
  }
  wk_elm = tgt_elm.getElementsByClassName('fullname');
  if(wk_elm && wk_elm.length > 0) {
    console.log(3);
    result.fullname = wk_elm[0].textContent.trim();
  }
  wk_elm = tgt_elm.getElementsByClassName('tweet-text');
  if(wk_elm && wk_elm.length > 0) {
    console.log(4);
    result.text = wk_elm[0].textContent.trim();
    const quoteTweetText = getQuoteTweetText(tgt_elm);
    if(quoteTweetText !== '') {
      console.log('add quote');
      //result.text = result.text.replace(/(.+)(https:\/\/twitter\.com\/ … )$/, '$1');
      result.text = result.text.replace(/(.+)(https:\/\/twitter\.com\/.+)$/, '$1');
      result.text += quoteTweetText;
    }
  }
  //console.log(result);
  const result_text = '
' +
    result.time['year'] + '-' +
    result.time['month'] + '-' +
    result.time['day'] + ' ' +
    result.time['hour'] + ':' +
    result.time['minute'] + ' ' +
    result.fullname + ': ' +
    result.text + '
';
  return result_text;
};

const setTextForCopy = function() {
  console.log('setTextForCopy');
  let ret = '';
  let wk_elm;
  wk_elm = document.getElementById('permalink-overlay');
  console.log('setTextForCopy1');
  if(wk_elm &&
    (wk_elm.style === undefined
      || (wk_elm.style !== undefined && wk_elm.style.display === undefined)
      || wk_elm.style.display === 'block'
      || wk_elm.style.opacity === 1)) {
    console.log('go permalink0');
    wk_elm = wk_elm.getElementsByClassName('permalink-tweet-container');
    if(wk_elm && wk_elm.length > 0) {
      console.log('go permalink1');
      ret = copyFromOverlay(wk_elm[0]);
    }
    return ret;
  }
  console.log('setTextForCopy2');
  wk_elm = document.getElementsByClassName('selected-stream-item');
  console.log('setTextForCopy3');
  if(wk_elm && wk_elm.length > 0) {
    console.log('go stream-item');
    ret = copyFromOverlay(wk_elm[0]);
    return ret;
  }
  return ret;
};

const onCopy = function(ev) {
  console.log('onCopy start');
  if(window.getSelection().toString() === '') {
    const outputText = setTextForCopy();
    console.log(outputText);
    if(outputText !== '') {
      ev.preventDefault();
      const transfer = ev.clipboardData;
      console.log('onCopy transfer');
      transfer.setData('text/plain', outputText);
    }
  }
};

const preventKeydown = function(evt) {
  if(evt.target.isContentEditable
    || evt.target.nodeName.toUpperCase() === 'INPUT'
    || evt.target.nodeName.toUpperCase() === 'TEXTAREA') {
    return;
  }
  evt.preventDefault();
};

const handleKeydown = function(evt) {
  switch(evt.key) {
    case 'a':
      if(IS_AUTO_UPDATE === false) {
        INTERVAL_ID = setInterval(clickUpdateButton, CHECK_INTERVAL);
        IS_AUTO_UPDATE = true;
        updatePageAction();
      }
      break;
    case 'b':
      preventKeydown(evt);
      break;
    case 'q':
      if(IS_AUTO_UPDATE) {
        clearInterval(INTERVAL_ID);
        IS_AUTO_UPDATE = false;
        updatePageAction();
      }
      break;
    case 'u':
      preventKeydown(evt);
      break;
  }
};

const start = function() {
  console.debug(window.location.href);
  updatePageAction();
  //DOMContentLoaded and load Event can be listend on capturing phase. not bubbling phase.
  document.addEventListener('keydown', handleKeydown);
  document.addEventListener('copy', onCopy);
  INTERVAL_ID = setInterval(clickUpdateButton, CHECK_INTERVAL);
};

start();

<|endoftext|>


<commit_before>angular.module('argus.controllers.alerts.detail', ['ngResource'])
.controller('AlertsDetail', ['$scope', '$routeParams', '$location', 'growl', 'Alerts', 'Triggers', 'Notifications', 'History', 'TriggersMap', 'JobExecutionDetails',
    function ($scope, $routeParams, $location, growl, Alerts, Triggers, Notifications, History, TriggersMap, JobExecutionDetails) {

        $scope.isAlertDirty = function () {
            return !angular.equals($scope.alert, $scope.unmodifiedAlert);
        };

        $scope.isTriggerDirty = function () {
            return !angular.equals($scope.triggers, $scope.unmodifiedTriggers);
        };

        $scope.isNotificationDirty = function () {
            return !angular.equals($scope.notifications, $scope.unmodifiedNotifications);
        };

        $scope.updateAlert = function () {
            if ($scope.isAlertDirty()) {
                var alert = $scope.alert;

                Alerts.update({alertId: alert.id}, alert, function (result) {
                    $scope.unmodifiedAlert = angular.copy(alert);
                    growl.success(('Updated "') + alert.name + '"');
                    $scope.fetchHistory();
                    $scope.fetchJobExecutionDetails();
                }, function (error) {
                    growl.error('Failed to update "' + alert.name + '"');
                });
            }
        };

        $scope.updateTriggers = function () {
            if ($scope.isTriggerDirty()) {
                var triggers = $scope.triggers;
                for (var i = 0; i < triggers.length; i++) {
                    $scope.updateTrigger(triggers[i]);
                }
                $scope.fetchHistory();
                $scope.fetchJobExecutionDetails();
            }
        };

        $scope.updateTrigger = function (trigger) {
            var toUpdate = $scope.unmodifiedTriggers.filter(function (element) {
                return element.id === trigger.id;
            });

            if (toUpdate.length === 1 && !angular.equals(toUpdate[0], trigger)) {
                Triggers.update({alertId: trigger.alertId, triggerId: trigger.id}, trigger, function (result) {
                    $scope.unmodifiedTriggers.filter(function (element) {
                        if (element.id === trigger.id) {
                            angular.copy(trigger, element);
                            growl.success('Updated trigger "' + trigger.id + '".');
                        }
                    });
                }, function (error) {
                    growl.error('Failed to update "' + trigger.name + '"');
                });
            }
        };

        $scope.updateNotifications = function () {
            if ($scope.isNotificationDirty()) {
                var notifications = $scope.notifications;
                for (var i = 0; i < notifications.length; i++) {
                    $scope.updateNotification(notifications[i]);
                }
                $scope.fetchHistory();
                $scope.fetchJobExecutionDetails();
            }
        };

        $scope.updateNotification = function (notification) {
            var toUpdate = $scope.unmodifiedNotifications.filter(function (element) {
                return element.id === notification.id;
            });

            if (toUpdate.length === 1 && !angular.equals(toUpdate[0], notification)) {
                Notifications.update({alertId: notification.alertId, notificationId: notification.id}, notification, function (result) {
                    $scope.unmodifiedNotifications.filter(function (element) {
                        if (element.id === notification.id) {
                            angular.copy(notification, element);
                            growl.success('Updated notification "' + notification.id + '".');
                        }
                    });
                    $scope.mapTriggers(notification);
                }, function (error) {
                    growl.error('Failed to update "' + notification.name + '"');
                });
            }
        };

        // Restore the unmodified version.
        $scope.resetTriggers = function () {
            $scope.triggers = angular.copy($scope.unmodifiedTriggers);
        };

        $scope.resetAlert = function () {
            $scope.alert = angular.copy($scope.unmodifiedAlert);
        };

        // Restore the unmodified version.
        $scope.resetNotifications = function () {
            $scope.notifications = angular.copy($scope.unmodifiedNotifications);
        };

        $scope.addTrigger = function () {
            var trigger = {
                name: 'new-trigger-' + Date.now(),
                type: "GREATER_THAN",
                threshold: 0,
                secondaryThreshold: 0,
                inertia: 0,
                alertId: $scope.alert.id
            };

            Triggers.save({alertId: $scope.alert.id}, trigger, function (result) {
                angular.copy(result, $scope.triggers);
                $scope.unmodifiedTriggers = angular.copy($scope.triggers);
                $scope.fetchHistory();
                $scope.fetchJobExecutionDetails();
                growl.success('Created "' + trigger.name + '"');
            }, function (error) {
                growl.error('Failed to create "' + trigger.name + '"');
            });
        };

        $scope.addNotification = function () {
            var notification = {
                name: 'new-notification-' + Date.now(),
                notifierName: "com.salesforce.dva.argus.service.alert.notifier.EmailNotifier",
                subscriptions: [],
                metricsToAnnotate: [],
                cooldownPeriod: 3600000,
                alertId: $scope.alert.id
            };

            Notifications.save({alertId: $scope.alert.id}, notification, function (result) {
                angular.copy(result, $scope.notifications);
                $scope.unmodifiedNotifications = angular.copy($scope.notifications);
                $scope.fetchHistory();
                $scope.fetchJobExecutionDetails();
                growl.success('Created "' + notification.name + '"');
            }, function (error) {
                growl.error('Failed to create "' + notification.name + '"');
            });
        };

        $scope.removeTrigger = function (trigger) {
            Triggers.delete({alertId: trigger.alertId, triggerId: trigger.id}, function (result) {
                $scope.triggers = $scope.triggers.filter(function (element) {
                    return element.id !== trigger.id;
                });
                $scope.unmodifiedTriggers = angular.copy($scope.triggers);
                $scope.fetchHistory();
                $scope.fetchJobExecutionDetails();
                growl.success('Deleted "' + trigger.name + '"');
            }, function (error) {
                growl.error('Failed to delete "' + trigger.name + '"');
            });
        };

        $scope.removeNotification = function (notification) {
            Notifications.delete({alertId: notification.alertId, notificationId: notification.id}, function (result) {
                $scope.notifications = $scope.notifications.filter(function (element) {
                    return element.id !== notification.id;
                });
                $scope.unmodifiedNotifications = angular.copy($scope.notifications);
                $scope.fetchHistory();
                $scope.fetchJobExecutionDetails();
                growl.success('Deleted "' + notification.name + '"');
            }, function (error) {
                growl.error('Failed to delete "' + notification.name + '"');
            });
        };

        $scope.mapTriggers = function (notification) {
            for (var i = 0; i < $scope.unmodifiedTriggers.length; i++) {
                var trigger = $scope.unmodifiedTriggers[i];
                TriggerMap.unmap({alertId: notification.alertId, notificationId: notification.id, triggerId: trigger.id});
            }
            for (var i = 0; i < notification.triggersIds.length; i++) {
                var trigger = notification.triggersIds[i];
                TriggerMap.map({alertId: notification.alertId, notificationId: notification.id, triggerId: trigger}, null);
            }
            $scope.fetchHistory();
            $scope.fetchJobExecutionDetails();
        };

        $scope.isTabSelected = function (tab) {
            return $scope.selectedTab === tab;
        };

        $scope.selectTab = function (tab) {
            $scope.selectedTab = tab;
        };

        $scope.fetchHistory = function() {
            History.query({id: $scope.alertId}, function (history) {
                $scope.history = history;
            }, function (error) {
                growl.error('Failed to get history for alert "' + $scope.alertId + '"');
            });
        };

        $scope.fetchJobExecutionDetails = function() {
            JobExecutionDetails.query({id: $scope.alertId}, function (jobExecutionDetails) {
                $scope.jobExecutionDetails = jobExecutionDetails;
                $scope.jobExecutionDetailsError='';
            }, function (error) {
                if(error.status==404){
                    $scope.jobExecutionDetailsError = ' No alert evaluation details found.';
                }else if(error.status==403){
                    $scope.jobExecutionDetailsError = 'You are not authorized to view this data.';
                }
                else {
                    $scope.jobExecutionDetailsError = error.statusText;
                    growl.error('Failed to get the job execution details "' + $scope.jobId + '"');
                }
            });
        };

        $scope.triggerTypes = [
            {label: '=', value: 'EQUAL'},
            {label: '!=', value: 'NOT_EQUAL'},
            {label: '>', value: 'GREATER_THAN'},
            {label: '<', value: 'LESS_THAN'},
            {label: '>=', value: 'GREATER_THAN_OR_EQ'},
            {label: '<=', value: 'LESS_THAN_OR_EQ'},
            {label: '<>', value: 'BETWEEN'},
            {label: '><', value: 'NOT_BETWEEN'}
        ];

        $scope.notificationTypes = [
            {label: 'Audit', value: 'com.salesforce.dva.argus.service.alert.notifier.AuditNotifier'},
            {label: 'Mail', value: 'com.salesforce.dva.argus.service.alert.notifier.EmailNotifier'},
            {label: 'GOC++', value: 'com.salesforce.dva.argus.service.alert.notifier.GOCNotifier'},
            {label: 'Gus', value: 'com.salesforce.dva.argus.service.alert.notifier.GusNotifier'}
        ];

        $scope.getTriggerIds = function () {
            var ids = [];
            var triggers = $scope.unmodifiedTriggers;
            for (var i = 0; i < triggers.length; i++) {
                ids.push(triggers[i].id);
            }
            return ids;
        };

        $scope.alertId = $routeParams.alertId;
        $scope.triggers = [];
        $scope.notifications = [];
        $scope.unmodifiedTriggers = [];
        $scope.unmodifiedNotifications = [];

        if ($scope.alertId > 0) {
            Alerts.get({alertId: $scope.alertId}, function (alert) {
                $scope.alert = alert;
                $scope.unmodifiedAlert = angular.copy(alert);
            }, function (error) {
                growl.error('Failed to get alert "' + $scope.alertId + '"');
                $location.path('/alerts');
            });

            Triggers.query({alertId: $scope.alertId}, function (triggers) {
                $scope.triggers = triggers;
                $scope.unmodifiedTriggers = angular.copy(triggers);
            }, function (error) {
                growl.error('Failed to get triggers for alert "' + $scope.alertId + '"');
            });

            Notifications.query({alertId: $scope.alertId}, function (notifications) {
                $scope.notifications = notifications;
                $scope.unmodifiedNotifications = angular.copy(notifications);
            }, function (error) {
                growl.error('Failed to get notifications for alert "' + $scope.alertId + '"');
            });
            $scope.fetchHistory();
            $scope.fetchJobExecutionDetails();
        } else {
            growl.error('Failed to get alert "' + $routeParams.alertId + '"');
            $location.path('alerts');
        }
        $scope.selectedTab = 1;

        $scope.resetAlert();
        $scope.resetTriggers();
        $scope.resetNotifications();
    }]);
<commit_msg>fix typo for TriggersMap.<commit_after>angular.module('argus.controllers.alerts.detail', ['ngResource'])
.controller('AlertsDetail', ['$scope', '$routeParams', '$location', 'growl', 'Alerts', 'Triggers', 'Notifications', 'History', 'TriggersMap', 'JobExecutionDetails',
    function ($scope, $routeParams, $location, growl, Alerts, Triggers, Notifications, History, TriggersMap, JobExecutionDetails) {

        $scope.isAlertDirty = function () {
            return !angular.equals($scope.alert, $scope.unmodifiedAlert);
        };

        $scope.isTriggerDirty = function () {
            return !angular.equals($scope.triggers, $scope.unmodifiedTriggers);
        };

        $scope.isNotificationDirty = function () {
            return !angular.equals($scope.notifications, $scope.unmodifiedNotifications);
        };

        $scope.updateAlert = function () {
            if ($scope.isAlertDirty()) {
                var alert = $scope.alert;

                Alerts.update({alertId: alert.id}, alert, function (result) {
                    $scope.unmodifiedAlert = angular.copy(alert);
                    growl.success(('Updated "') + alert.name + '"');
                    $scope.fetchHistory();
                    $scope.fetchJobExecutionDetails();
                }, function (error) {
                    growl.error('Failed to update "' + alert.name + '"');
                });
            }
        };

        $scope.updateTriggers = function () {
            if ($scope.isTriggerDirty()) {
                var triggers = $scope.triggers;
                for (var i = 0; i < triggers.length; i++) {
                    $scope.updateTrigger(triggers[i]);
                }
                $scope.fetchHistory();
                $scope.fetchJobExecutionDetails();
            }
        };

        $scope.updateTrigger = function (trigger) {
            var toUpdate = $scope.unmodifiedTriggers.filter(function (element) {
                return element.id === trigger.id;
            });

            if (toUpdate.length === 1 && !angular.equals(toUpdate[0], trigger)) {
                Triggers.update({alertId: trigger.alertId, triggerId: trigger.id}, trigger, function (result) {
                    $scope.unmodifiedTriggers.filter(function (element) {
                        if (element.id === trigger.id) {
                            angular.copy(trigger, element);
                            growl.success('Updated trigger "' + trigger.id + '".');
                        }
                    });
                }, function (error) {
                    growl.error('Failed to update "' + trigger.name + '"');
                });
            }
        };

        $scope.updateNotifications = function () {
            if ($scope.isNotificationDirty()) {
                var notifications = $scope.notifications;
                for (var i = 0; i < notifications.length; i++) {
                    $scope.updateNotification(notifications[i]);
                }
                $scope.fetchHistory();
                $scope.fetchJobExecutionDetails();
            }
        };

        $scope.updateNotification = function (notification) {
            var toUpdate = $scope.unmodifiedNotifications.filter(function (element) {
                return element.id === notification.id;
            });

            if (toUpdate.length === 1 && !angular.equals(toUpdate[0], notification)) {
                Notifications.update({alertId: notification.alertId, notificationId: notification.id}, notification, function (result) {
                    $scope.unmodifiedNotifications.filter(function (element) {
                        if (element.id === notification.id) {
                            angular.copy(notification, element);
                            growl.success('Updated notification "' + notification.id + '".');
                        }
                    });
                    $scope.mapTriggers(notification);
                }, function (error) {
                    growl.error('Failed to update "' + notification.name + '"');
                });
            }
        };

        // Restore the unmodified version.
        $scope.resetTriggers = function () {
            $scope.triggers = angular.copy($scope.unmodifiedTriggers);
        };

        $scope.resetAlert = function () {
            $scope.alert = angular.copy($scope.unmodifiedAlert);
        };

        // Restore the unmodified version.
        $scope.resetNotifications = function () {
            $scope.notifications = angular.copy($scope.unmodifiedNotifications);
        };

        $scope.addTrigger = function () {
            var trigger = {
                name: 'new-trigger-' + Date.now(),
                type: "GREATER_THAN",
                threshold: 0,
                secondaryThreshold: 0,
                inertia: 0,
                alertId: $scope.alert.id
            };

            Triggers.save({alertId: $scope.alert.id}, trigger, function (result) {
                angular.copy(result, $scope.triggers);
                $scope.unmodifiedTriggers = angular.copy($scope.triggers);
                $scope.fetchHistory();
                $scope.fetchJobExecutionDetails();
                growl.success('Created "' + trigger.name + '"');
            }, function (error) {
                growl.error('Failed to create "' + trigger.name + '"');
            });
        };

        $scope.addNotification = function () {
            var notification = {
                name: 'new-notification-' + Date.now(),
                notifierName: "com.salesforce.dva.argus.service.alert.notifier.EmailNotifier",
                subscriptions: [],
                metricsToAnnotate: [],
                cooldownPeriod: 3600000,
                alertId: $scope.alert.id
            };

            Notifications.save({alertId: $scope.alert.id}, notification, function (result) {
                angular.copy(result, $scope.notifications);
                $scope.unmodifiedNotifications = angular.copy($scope.notifications);
                $scope.fetchHistory();
                $scope.fetchJobExecutionDetails();
                growl.success('Created "' + notification.name + '"');
            }, function (error) {
                growl.error('Failed to create "' + notification.name + '"');
            });
        };

        $scope.removeTrigger = function (trigger) {
            Triggers.delete({alertId: trigger.alertId, triggerId: trigger.id}, function (result) {
                $scope.triggers = $scope.triggers.filter(function (element) {
                    return element.id !== trigger.id;
                });
                $scope.unmodifiedTriggers = angular.copy($scope.triggers);
                $scope.fetchHistory();
                $scope.fetchJobExecutionDetails();
                growl.success('Deleted "' + trigger.name + '"');
            }, function (error) {
                growl.error('Failed to delete "' + trigger.name + '"');
            });
        };

        $scope.removeNotification = function (notification) {
            Notifications.delete({alertId: notification.alertId, notificationId: notification.id}, function (result) {
                $scope.notifications = $scope.notifications.filter(function (element) {
                    return element.id !== notification.id;
                });
                $scope.unmodifiedNotifications = angular.copy($scope.notifications);
                $scope.fetchHistory();
                $scope.fetchJobExecutionDetails();
                growl.success('Deleted "' + notification.name + '"');
            }, function (error) {
                growl.error('Failed to delete "' + notification.name + '"');
            });
        };

        $scope.mapTriggers = function (notification) {
            for (var i = 0; i < $scope.unmodifiedTriggers.length; i++) {
                var trigger = $scope.unmodifiedTriggers[i];
                TriggersMap.unmap({alertId: notification.alertId, notificationId: notification.id, triggerId: trigger.id});
            }
            for (var i = 0; i < notification.triggersIds.length; i++) {
                var trigger = notification.triggersIds[i];
                TriggersMap.map({alertId: notification.alertId, notificationId: notification.id, triggerId: trigger}, null);
            }
            $scope.fetchHistory();
            $scope.fetchJobExecutionDetails();
        };

        $scope.isTabSelected = function (tab) {
            return $scope.selectedTab === tab;
        };

        $scope.selectTab = function (tab) {
            $scope.selectedTab = tab;
        };

        $scope.fetchHistory = function() {
            History.query({id: $scope.alertId}, function (history) {
                $scope.history = history;
            }, function (error) {
                growl.error('Failed to get history for alert "' + $scope.alertId + '"');
            });
        };

        $scope.fetchJobExecutionDetails = function() {
            JobExecutionDetails.query({id: $scope.alertId}, function (jobExecutionDetails) {
                $scope.jobExecutionDetails = jobExecutionDetails;
                $scope.jobExecutionDetailsError='';
            }, function (error) {
                if(error.status==404){
                    $scope.jobExecutionDetailsError = ' No alert evaluation details found.';
                }else if(error.status==403){
                    $scope.jobExecutionDetailsError = 'You are not authorized to view this data.';
                }
                else {
                    $scope.jobExecutionDetailsError = error.statusText;
                    growl.error('Failed to get the job execution details "' + $scope.jobId + '"');
                }
            });
        };

        $scope.triggerTypes = [
            {label: '=', value: 'EQUAL'},
            {label: '!=', value: 'NOT_EQUAL'},
            {label: '>', value: 'GREATER_THAN'},
            {label: '<', value: 'LESS_THAN'},
            {label: '>=', value: 'GREATER_THAN_OR_EQ'},
            {label: '<=', value: 'LESS_THAN_OR_EQ'},
            {label: '<>', value: 'BETWEEN'},
            {label: '><', value: 'NOT_BETWEEN'}
        ];

        $scope.notificationTypes = [
            {label: 'Audit', value: 'com.salesforce.dva.argus.service.alert.notifier.AuditNotifier'},
            {label: 'Mail', value: 'com.salesforce.dva.argus.service.alert.notifier.EmailNotifier'},
            {label: 'GOC++', value: 'com.salesforce.dva.argus.service.alert.notifier.GOCNotifier'},
            {label: 'Gus', value: 'com.salesforce.dva.argus.service.alert.notifier.GusNotifier'}
        ];

        $scope.getTriggerIds = function () {
            var ids = [];
            var triggers = $scope.unmodifiedTriggers;
            for (var i = 0; i < triggers.length; i++) {
                ids.push(triggers[i].id);
            }
            return ids;
        };

        $scope.alertId = $routeParams.alertId;
        $scope.triggers = [];
        $scope.notifications = [];
        $scope.unmodifiedTriggers = [];
        $scope.unmodifiedNotifications = [];

        if ($scope.alertId > 0) {
            Alerts.get({alertId: $scope.alertId}, function (alert) {
                $scope.alert = alert;
                $scope.unmodifiedAlert = angular.copy(alert);
            }, function (error) {
                growl.error('Failed to get alert "' + $scope.alertId + '"');
                $location.path('/alerts');
            });

            Triggers.query({alertId: $scope.alertId}, function (triggers) {
                $scope.triggers = triggers;
                $scope.unmodifiedTriggers = angular.copy(triggers);
            }, function (error) {
                growl.error('Failed to get triggers for alert "' + $scope.alertId + '"');
            });

            Notifications.query({alertId: $scope.alertId}, function (notifications) {
                $scope.notifications = notifications;
                $scope.unmodifiedNotifications = angular.copy(notifications);
            }, function (error) {
                growl.error('Failed to get notifications for alert "' + $scope.alertId + '"');
            });
            $scope.fetchHistory();
            $scope.fetchJobExecutionDetails();
        } else {
            growl.error('Failed to get alert "' + $routeParams.alertId + '"');
            $location.path('alerts');
        }
        $scope.selectedTab = 1;

        $scope.resetAlert();
        $scope.resetTriggers();
        $scope.resetNotifications();
    }]);
<|endoftext|>


<commit_before>const config = {
  siteTitle: "Thada W.", // Site title.
  siteTitleShort: "Thada W", // Short site title for homescreen (PWA). Preferably should be under 12 characters to prevent truncation.
  siteTitleAlt: "Thada W.", // Alternative site title for SEO.
  siteLogo: "/logos/android-chrome-512x512.png", // Logo used for SEO and manifest.
  siteUrl: "https://thadaw.com", // Domain of your website without pathPrefix.
  pathPrefix: "/", // Prefixes all links. For cases when deployed to example.github.io/gatsby-advanced-starter/.
  nodePrefix: "/b", // Prefixes for only post created by createNodeField from `gastby-node.js`
  siteDescription: "You can find almost stuff about me: sharing ideas, programming techniques, web technology and others.", // Website description used for RSS feeds/meta description tag.
  siteRss: "/rss.xml", // Path to the RSS file.
  siteRssTitle: "Thadaw.com RSS feed", // Title of the RSS feed
  siteFBAppID: "xxxxx", // FB Application ID for using app insights
  googleAnalyticsID: "UA-62565035-1", // GA tracking ID.
  disqusShortname: "https-vagr9k-github-io-gatsby-advanced-starter", // Disqus shortname.
  dateFromFormat: "YYYY-MM-DD", // Date format used in the frontmatter.
  dateFormat: "DD/MM/YYYY", // Date format for display.
  // postsPerPage: 4, // Amount of posts displayed per listing page.
  userName: "Thada Wangthammang", // Username to display in the author segment.
  userEmail: "thada.wth@gmail.com", // Email used for RSS feed's author segment
  userTwitter: "mildronize", // Optionally renders "Follow Me" in the UserInfo segment.
  userGithub: "mildronize",
  userLocation: "Songkhla, Thailand", // User location to display in the author segment.
  userAvatar: "https://avatars.githubusercontent.com/u/3647850?v=4", // User avatar to display in the author segment.
  userDescription:
    "Yeah, I like animals better than people sometimes... Especially dogs. Dogs are the best. Every time you come home, they act like they haven't seen you in a year. And the good thing about dogs... is they got different dogs for different people.", // User description to display in the author segment.
  // Links to social profiles/projects you want to display in the author segment/navigation bar.
  userLinks: [
    {
      label: "GitHub",
      url: "https://github.com/mildronize",
      iconClassName: "fab fa-github",
    },
    {
      label: "Twitter",
      url: "https://twitter.com/mildronize",
      iconClassName: "fab fa-twitter",
    },
    {
      label: "Email",
      url: "mailto:thada.wth@gmail.com",
      iconClassName: "fas fa-envelope",
    },
    {
      label: "Linkedin",
      url: "https://www.linkedin.com/in/thada-wangthammang-281894a6/",
      iconClassName: "fab fa-linkedin",
    },
    {
      label: "Medium",
      url: "https://thadaw.medium.com/",
      iconClassName: "fab fa-medium",
    },
    {
      label: "RSS",
      url: "/rss.xml",
      iconClassName: "fas fa-rss",
    }
  ],
  copyright: "Copyright © 2021. Thada W.", // Copyright string for the footer of the website and RSS feed.
  themeColor: "#c62828", // Used for setting manifest and progress theme colors.
  backgroundColor: "#e0e0e0", // Used for setting manifest background color.
};

// Validate

// Make sure pathPrefix is empty if not needed
if (config.pathPrefix === "/") {
  config.pathPrefix = "";
} else {
  // Make sure pathPrefix only contains the first forward slash
  config.pathPrefix = `/${config.pathPrefix.replace(/^\/|\/$/g, "")}`;
}

// Make sure siteUrl doesn't have an ending forward slash
if (config.siteUrl.substr(-1) === "/")
  config.siteUrl = config.siteUrl.slice(0, -1);

// Make sure nodePrefix doesn't have an ending forward slash
if (config.nodePrefix.substr(-1) === "/")
  config.nodePrefix = config.nodePrefix.slice(0, -1);

// Make sure siteRss has a starting forward slash
if (config.siteRss && config.siteRss[0] !== "/")
  config.siteRss = `/${config.siteRss}`;

module.exports = config;
<commit_msg>feat: add FB app Id<commit_after>const config = {
  siteTitle: "Thada W.", // Site title.
  siteTitleShort: "Thada W", // Short site title for homescreen (PWA). Preferably should be under 12 characters to prevent truncation.
  siteTitleAlt: "Thada W.", // Alternative site title for SEO.
  siteLogo: "/logos/android-chrome-512x512.png", // Logo used for SEO and manifest.
  siteUrl: "https://thadaw.com", // Domain of your website without pathPrefix.
  pathPrefix: "/", // Prefixes all links. For cases when deployed to example.github.io/gatsby-advanced-starter/.
  nodePrefix: "/b", // Prefixes for only post created by createNodeField from `gastby-node.js`
  siteDescription: "You can find almost stuff about me: sharing ideas, programming techniques, web technology and others.", // Website description used for RSS feeds/meta description tag.
  siteRss: "/rss.xml", // Path to the RSS file.
  siteRssTitle: "Thadaw.com RSS feed", // Title of the RSS feed
  siteFBAppID: "487836291329244", // FB Application ID for using app insights
  googleAnalyticsID: "UA-62565035-1", // GA tracking ID.
  disqusShortname: "https-vagr9k-github-io-gatsby-advanced-starter", // Disqus shortname.
  dateFromFormat: "YYYY-MM-DD", // Date format used in the frontmatter.
  dateFormat: "DD/MM/YYYY", // Date format for display.
  // postsPerPage: 4, // Amount of posts displayed per listing page.
  userName: "Thada Wangthammang", // Username to display in the author segment.
  userEmail: "thada.wth@gmail.com", // Email used for RSS feed's author segment
  userTwitter: "mildronize", // Optionally renders "Follow Me" in the UserInfo segment.
  userGithub: "mildronize",
  userLocation: "Songkhla, Thailand", // User location to display in the author segment.
  userAvatar: "https://avatars.githubusercontent.com/u/3647850?v=4", // User avatar to display in the author segment.
  userDescription:
    "Yeah, I like animals better than people sometimes... Especially dogs. Dogs are the best. Every time you come home, they act like they haven't seen you in a year. And the good thing about dogs... is they got different dogs for different people.", // User description to display in the author segment.
  // Links to social profiles/projects you want to display in the author segment/navigation bar.
  userLinks: [
    {
      label: "GitHub",
      url: "https://github.com/mildronize",
      iconClassName: "fab fa-github",
    },
    {
      label: "Twitter",
      url: "https://twitter.com/mildronize",
      iconClassName: "fab fa-twitter",
    },
    {
      label: "Email",
      url: "mailto:thada.wth@gmail.com",
      iconClassName: "fas fa-envelope",
    },
    {
      label: "Linkedin",
      url: "https://www.linkedin.com/in/thada-wangthammang-281894a6/",
      iconClassName: "fab fa-linkedin",
    },
    {
      label: "Medium",
      url: "https://thadaw.medium.com/",
      iconClassName: "fab fa-medium",
    },
    {
      label: "RSS",
      url: "/rss.xml",
      iconClassName: "fas fa-rss",
    }
  ],
  copyright: "Copyright © 2021. Thada W.", // Copyright string for the footer of the website and RSS feed.
  themeColor: "#c62828", // Used for setting manifest and progress theme colors.
  backgroundColor: "#e0e0e0", // Used for setting manifest background color.
};

// Validate

// Make sure pathPrefix is empty if not needed
if (config.pathPrefix === "/") {
  config.pathPrefix = "";
} else {
  // Make sure pathPrefix only contains the first forward slash
  config.pathPrefix = `/${config.pathPrefix.replace(/^\/|\/$/g, "")}`;
}

// Make sure siteUrl doesn't have an ending forward slash
if (config.siteUrl.substr(-1) === "/")
  config.siteUrl = config.siteUrl.slice(0, -1);

// Make sure nodePrefix doesn't have an ending forward slash
if (config.nodePrefix.substr(-1) === "/")
  config.nodePrefix = config.nodePrefix.slice(0, -1);

// Make sure siteRss has a starting forward slash
if (config.siteRss && config.siteRss[0] !== "/")
  config.siteRss = `/${config.siteRss}`;

module.exports = config;
<|endoftext|>


<commit_before>'use strict';
var bunyan = require('bunyan');
var MongoLogStream = require('bunyan-mongodb-stream');
var EmailStream = require('bunyan-emailstream').EmailStream;
var BunyanSlack = require('bunyan-slack');

module.exports = bunyan.createLogger({
    name: 'taskmaster',
    streams: [{
        level: 'info',
        stream: process.stdout
    }, {
        level: 'info',
        type: 'rotating-file',
        path: './logs/taskmaster-info.log',
        period: '1d',
        count: 90
    }, {
        level: 'warn',
        stream: MongoLogStream({model: require('./models/logs')})
    }, {
        type: 'raw',
        level: 'warn',
        stream: new BunyanSlack({
            webhook_url: '',
            channel: '',
            username: 'Task Master'
        })
    }, {
        type: 'raw',
        level: 'error',
        stream: new EmailStream({
            from: '',
            to: '',
            subject: 'Task Master Error',
            message: 'Something is wrong'
        }, {
            type: 'SMTP',
            host: "smtp.gmail.com",
            secureConnection: true,
            port: 465,
            auth: {
                user: '',
                pass: ''
            }
        })
    }]
});
<commit_msg>update the logger.example<commit_after>'use strict';
var bunyan = require('bunyan');
var MongoLogStream = require('bunyan-mongodb-stream');
var EmailStream = require('bunyan-emailstream').EmailStream;
var BunyanSlack = require('bunyan-slack');

module.exports = bunyan.createLogger({
    name: 'taskmaster',
    streams: [{
        level: 'info',
        stream: process.stdout
    }, {
        level: 'info',
        type: 'rotating-file',
        path: './logs/taskmaster-info.log',
        period: '1d',
        count: 90
    }, {
        level: 'warn',
        stream: MongoLogStream({model: require('./models/logs')})
    }, {
        type: 'raw',
        level: 'warn',
        stream: new BunyanSlack({
            webhook_url: '',
            channel: '',
            username: '',
            icon_emoji: '',
            customFormatter: function (record, levelName) {
                var fields = [];
                for (var field in record.err) {
                    fields.push({title: field, value: '```' + record.err[field] + '```', short: false});
                }
                return {
                    attachments: [{
                        fallback: record.msg,
                        pretext: '',
                        color: (levelName == 'error' || levelName == 'fatal') ? 'danger' : (levelName == 'warn') ? 'warning' : '#aaa',
                        author_name: record.name + '@' + record.hostname,
                        author_icon: '',
                        title: '[' + levelName.toUpperCase() + '] ' + record.msg,
                        text: (levelName == 'error' || levelName == 'fatal') ? 'Attn: <!channel>' : '',
                        fields: fields,
                        'mrkdwn_in': ["pretext", "text", "fields"]
                    }]
                }
            }
        })
    }, {
        type: 'raw',
        level: 'error',
        stream: new EmailStream({
            from: '',
            to: '',
            subject: 'Task Master Error',
            message: 'Something is wrong'
        }, {
            type: 'SMTP',
            host: "smtp.gmail.com",
            secureConnection: true,
            port: 465,
            auth: {
                user: '',
                pass: ''
            }
        })
    }]
});
<|endoftext|>


<commit_before>/*
 * backbone-krankshaft.js 0.1
 *
 * Copyright 2013 Dan LaMotte <lamotte85@gmail.com>
 *
 * This software may be used and distributed according to the terms of the
 * MIT License.
 */
(function($, bb, _, undefined) {
  'use strict';

  bb.ks = {
    authn: {
      secret: '',
      username: ''
    },
    authn_header: 'Authorization',
    authn_method: 'APIToken',
    authn_method_value: function(method, username, secret) {
      return method + ' ' + username + ':' + secret;
    },
    authn_update: function(opts) {
      var authn = _.defaults({}, bb.ks.authn, opts.authn);

      if (authn.username && authn.secret) {
        var headers = {};
        headers[bb.ks.authn_header] = bb.ks.authn_method_value(
          bb.ks.authn_method,
          authn.username,
          authn.secret
        );

        opts.headers = _.extend(headers, opts.headers);
      }

      return opts;
    }
  };

  bb.ks_old_sync = bb.sync;
  bb.sync = function(method, model, opts) {
    opts = bb.ks.authn_update(opts);

    return bb.ks_old_sync(method, model, opts);
  };
}(jQuery, Backbone, _));
<commit_msg>js/bb: improve noconflict support<commit_after>/*
 * backbone-krankshaft.js 0.1
 *
 * Copyright 2013 Dan LaMotte <lamotte85@gmail.com>
 *
 * This software may be used and distributed according to the terms of the
 * MIT License.
 */
(function($, bb, _, undefined) {
  'use strict';

  bb.ks = {
    authn: {
      secret: '',
      username: ''
    },
    authn_header: 'Authorization',
    authn_method: 'APIToken',
    authn_method_value: function(method, username, secret) {
      return method + ' ' + username + ':' + secret;
    },
    authn_update: function(opts) {
      var authn = _.defaults({}, bb.ks.authn, opts.authn);

      if (authn.username && authn.secret) {
        var headers = {};
        headers[bb.ks.authn_header] = bb.ks.authn_method_value(
          bb.ks.authn_method,
          authn.username,
          authn.secret
        );

        opts.headers = _.extend(headers, opts.headers);
      }

      return opts;
    }
  };

  bb.sync_ks_old = bb.sync;
  bb.sync_ks = bb.sync = function(method, model, opts) {
    opts = bb.ks.authn_update(opts);

    return bb.ks_old_sync(method, model, opts);
  };
}(jQuery, Backbone, _));
<|endoftext|>


<commit_before>l.touches = new Object() // Group the touch-related functions

l.touches.database = new Array() // Keep track of where we're touching on the screen

l.touches.enable = function()
{
    document.addEventListener('touchstart', function(event) { l.touches.touches(event) })
    document.addEventListener('touchmove', function(event) { l.touches.touches(event) })
    document.addEventListener('touchend', function() { l.touches.cancel() })
    document.addEventListener('touchcancel', function() { l.touches.cancel() })
}

l.touches.touches = function(event)
{
    if (event)
    {
        l.touches.database = event.touches
        l.touches.debug()
    }
}

l.touches.cancel = function(event)
{
    l.touches.database.length = 0
    l.touches.debug()
}

l.touches.touched = function(name)
{
    if (l.touches.database.length > 0)
    {
        for (var i = 0; i < l.touches.database.length; i++)
        {
            if (l.touches.database[i].pageX < l.entities[name].bounding.x + l.entities[name].bounding.width && l.touches.database[i].pageX > l.entities[name].bounding.x &&
            l.touches.database[i].pageY < l.entities[name].bounding.y + l.entities[name].bounding.height && l.touches.database[i].pageY > l.entities[name].bounding.y)
            {
                if (l.debug.all || l.debug.touches)
                {
                    console.log(name + ' was touched')
                }
                return true
                break
            }
            else
            {
                return false
            }
        }
    }
}

l.touches.debug = function()
{
    if (l.debug.all || l.debug.touches && l.touches.database.length > 0)
    {
        for (var i = 0; i < l.touches.database.length; i++)
        {
            console.log('X' + i + ': ' + l.touches.database[i].pageX + ' Y' + i + ': ' + l.touches.database[i].pageY)
        }
    }
}<commit_msg>Made touches more intuitive and less buggy.<commit_after>l.touches = new Object() // Group the touch-related functions

l.touches.database = new Array() // Keep track of where we're touching on the screen

l.touches.enable = function()
{
    document.addEventListener('touchstart', function(event) { l.touches.touches(event) })
    document.addEventListener('touchmove', function(event) { l.touches.touches(event) })
    document.addEventListener('touchend', function(event) { l.touches.touches(event) })
    document.addEventListener('touchcancel', function(event) { l.touches.touches(event) })
}

l.touches.touches = function(event)
{
    if (event)
    {
        l.touches.database = event.touches
        l.touches.debug()
    }
    else
    {
        l.touches.database.length = 0
    }
}

l.touches.touched = function(name)
{
    if (l.touches.database.length > 0)
    {
        for (var i = 0; i < l.touches.database.length; i++)
        {
            if (l.touches.database[i].pageX < l.entities[name].bounding.x + l.entities[name].bounding.width && l.touches.database[i].pageX > l.entities[name].bounding.x &&
            l.touches.database[i].pageY < l.entities[name].bounding.y + l.entities[name].bounding.height && l.touches.database[i].pageY > l.entities[name].bounding.y)
            {
                if (l.debug.all || l.debug.touches)
                {
                    console.log(name + ' was touched')
                }
                return true
                break
            }
            else
            {
                if (i == l.touches.database.length - 1)
                {
                    return false
                }
            }
        }
    }
}

l.touches.debug = function()
{
    if (l.debug.all || l.debug.touches && l.touches.database.length > 0)
    {
        for (var i = 0; i < l.touches.database.length; i++)
        {
            console.log('X' + i + ': ' + l.touches.database[i].pageX + ' Y' + i + ': ' + l.touches.database[i].pageY)
        }
    }
}<|endoftext|>


<commit_before>(function (global, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module unless amdModuleId is set
    define([], function () {
      return (global['lrStickyHeader'] = factory(global));
    });
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory(global);
  } else {
    global['lrStickyHeader'] = factory(global);
  }
})(window, function factory (window) {
  'use strict';
  function getOffset (element, property) {
    var offset = element[property];
    var parent = element;
    while ((parent = parent.offsetParent) !== null) {
      offset += parent[property];
    }
    return offset;
  }

  var sticky = {
    //todo some memoize stuff
    setWidth: function setWidth () {
      var firstRow = this.tbody.getElementsByTagName('TR')[0];
      var trh = this.thead.getElementsByTagName('TR')[0];
      var firstTds;
      var firstThs;

      function setCellWidth (cell) {
        cell.style.width = cell.offsetWidth + 'px';
      }

      if (firstRow && trh) {
        firstTds = firstRow.getElementsByTagName('TD');
        firstThs = trh.getElementsByTagName('TH');

        [].forEach.call(firstTds, setCellWidth);
        [].forEach.call(firstThs, setCellWidth);
      }
    },
    eventListener: function eventListener () {
      var offsetTop = getOffset(this.thead, 'offsetTop') - Number(this.headerHeight);
      var offsetLeft = getOffset(this.thead, 'offsetLeft');
      var parentOffsetTop = this.parentIsWindow ? 0 : getOffset(this.parent, 'offsetTop');
      var parentScrollTop = this.parentIsWindow ? parent.scrollY : parentOffsetTop + this.parent.scrollTop;
      var classes = this.thead.className.split(' ');

      if (this.stick !== true && (offsetTop - parentScrollTop < 0) &&
          (offsetTop + this.tbody.offsetHeight - parentScrollTop > 0)) {
        this.stick = true;
        this.treshold = offsetTop;
        this.windowScrollY = this.parentIsWindow ? 0 : window.scrollY;
        this.setWidth();
        this.thead.style.left = offsetLeft + 'px';
        this.thead.style.top = Number(this.headerHeight + parentOffsetTop - this.windowScrollY) + 'px';
        setTimeout(function () {
          classes.push('lr-sticky-header');
          this.thead.style.position = 'fixed';
          this.thead.className = classes.join(' ');
          this.element.style.marginTop = Number(this.thead.offsetHeight) + 'px';
        }.bind(this), 0);
      }

      if (this.stick === true && !this.parentIsWindow && this.windowScrollY !== window.scrollY) {
        this.windowScrollY = window.scrollY;
        this.thead.style.top = Number(this.headerHeight + parentOffsetTop - this.windowScrollY) + 'px';
      }

      if (this.stick === true && (
                  (this.treshold - parentScrollTop > 0) ||
                  (this.treshold + this.element.offsetHeight - parentScrollTop < 0))) {
        this.stick = false;
        this.thead.style.position = 'initial';
        classes.splice(classes.indexOf('lr-sticky-header'), 1);
        this.thead.className = (classes).join(' ');
        this.element.style.marginTop = '0';
      }
    }
  };

  return function lrStickyHeader (tableElement, options) {
    var headerHeight = 0;
    if (options&&options.headerHeight)
      headerHeight=options.headerHeight;
    var parent = window;
    if (options && options.parent) {
      parent = options.parent;
    }

    var thead;
    var tbody;

    if (tableElement.tagName !== 'TABLE') {
      throw new Error('lrStickyHeader only works on table element');
    }
    tbody = tableElement.getElementsByTagName('TBODY');
    thead = tableElement.getElementsByTagName('THEAD');

    if (!thead.length) {
      throw new Error('could not find the thead group element');
    }

    if (!tbody.length) {
      throw new Error('could not find the tbody group element');
    }

    thead = thead[0];
    tbody = tbody[0];

    var stickyTable = Object.create(sticky, {
      element: {value: tableElement},
      parent: {
        get: function () {
          return parent;
        }
      },
      parentIsWindow: {value: parent === window},
      headerHeight: {
        get: function () {
          return headerHeight;
        }
      },
      thead: {
        get: function () {
          return thead;
        }
      },
      tbody: {
        get: function () {
          return tbody;
        }
      }
    });

    var listener = stickyTable.eventListener.bind(stickyTable);
    parent.addEventListener('scroll', listener);
    if (parent !== window) {
      window.addEventListener('scroll', listener);
    }
    stickyTable.clean = function clean () {
      parent.removeEventListener('scroll', listener);
      if (parent !== window) {
        window.removeEventListener('scroll', listener);
      }
    };

    return stickyTable;
  };
});

<commit_msg>Fixes putting thead back in scrollable panel<commit_after>(function (global, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module unless amdModuleId is set
    define([], function () {
      return (global['lrStickyHeader'] = factory(global));
    });
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory(global);
  } else {
    global['lrStickyHeader'] = factory(global);
  }
})(window, function factory (window) {
  'use strict';
  function getOffset (element, property) {
    var offset = element[property];
    var parent = element;
    while ((parent = parent.offsetParent) !== null) {
      offset += parent[property];
    }
    return offset;
  }

  var sticky = {
    //todo some memoize stuff
    setWidth: function setWidth () {
      var firstRow = this.tbody.getElementsByTagName('TR')[0];
      var trh = this.thead.getElementsByTagName('TR')[0];
      var firstTds;
      var firstThs;

      function setCellWidth (cell) {
        cell.style.width = cell.offsetWidth + 'px';
      }

      if (firstRow && trh) {
        firstTds = firstRow.getElementsByTagName('TD');
        firstThs = trh.getElementsByTagName('TH');

        [].forEach.call(firstTds, setCellWidth);
        [].forEach.call(firstThs, setCellWidth);
      }
    },
    eventListener: function eventListener () {
      var offsetTop = getOffset(this.thead, 'offsetTop') - Number(this.headerHeight);
      var offsetLeft = getOffset(this.thead, 'offsetLeft');
      var parentOffsetTop = this.parentIsWindow ? 0 : getOffset(this.parent, 'offsetTop');
      var parentScrollTop = this.parentIsWindow ? parent.scrollY : this.parent.scrollTop;
      var classes = this.thead.className.split(' ');

      if (this.stick !== true && (offsetTop - (parentOffsetTop + parentScrollTop) < 0) &&
          (offsetTop + this.tbody.offsetHeight - (parentOffsetTop + parentScrollTop) > 0)) {
        this.stick = true;
        this.treshold = offsetTop;
        this.windowScrollY = this.parentIsWindow ? 0 : window.scrollY;
        this.setWidth();
        this.thead.style.left = offsetLeft + 'px';
        this.thead.style.top = Number(this.headerHeight + parentOffsetTop - this.windowScrollY) + 'px';
        setTimeout(function () {
          classes.push('lr-sticky-header');
          this.thead.style.position = 'fixed';
          this.thead.className = classes.join(' ');
          this.element.style.marginTop = Number(this.thead.offsetHeight) + 'px';
        }.bind(this), 0);
      }

      if (this.stick === true && !this.parentIsWindow && this.windowScrollY !== window.scrollY) {
        this.windowScrollY = window.scrollY;
        this.thead.style.top = Number(this.headerHeight + parentOffsetTop - this.windowScrollY) + 'px';
      }

      if (this.stick === true && (
                 (this.parentIsWindow && (this.treshold - parentScrollTop > 0)) ||
                 (parentScrollTop <= 0))) {
        this.stick = false;
        this.thead.style.position = 'initial';
        classes.splice(classes.indexOf('lr-sticky-header'), 1);
        this.thead.className = (classes).join(' ');
        this.element.style.marginTop = '0';
      }
    }
  };

  return function lrStickyHeader (tableElement, options) {
    var headerHeight = 0;
    if (options&&options.headerHeight)
      headerHeight=options.headerHeight;
    var parent = window;
    if (options && options.parent) {
      parent = options.parent;
    }

    var thead;
    var tbody;

    if (tableElement.tagName !== 'TABLE') {
      throw new Error('lrStickyHeader only works on table element');
    }
    tbody = tableElement.getElementsByTagName('TBODY');
    thead = tableElement.getElementsByTagName('THEAD');

    if (!thead.length) {
      throw new Error('could not find the thead group element');
    }

    if (!tbody.length) {
      throw new Error('could not find the tbody group element');
    }

    thead = thead[0];
    tbody = tbody[0];

    var stickyTable = Object.create(sticky, {
      element: {value: tableElement},
      parent: {
        get: function () {
          return parent;
        }
      },
      parentIsWindow: {value: parent === window},
      headerHeight: {
        get: function () {
          return headerHeight;
        }
      },
      thead: {
        get: function () {
          return thead;
        }
      },
      tbody: {
        get: function () {
          return tbody;
        }
      }
    });

    var listener = stickyTable.eventListener.bind(stickyTable);
    parent.addEventListener('scroll', listener);
    if (parent !== window) {
      window.addEventListener('scroll', listener);
    }
    stickyTable.clean = function clean () {
      parent.removeEventListener('scroll', listener);
      if (parent !== window) {
        window.removeEventListener('scroll', listener);
      }
    };

    return stickyTable;
  };
});

<|endoftext|>