<commit_before>/**
 * @license
 * Patterns @VERSION@ tooltip - tooltips
 *
 * Copyright 2008-2012 Simplon B.V.
 * Copyright 2011 Humberto Sermeño
 * Copyright 2011 SYSLAB.COM GmbH
 */
define([
    "jquery",
    "../registry",
    "../core/parser",
    "./inject",
    "../core/remove"
], function($, patterns, Parser, inject) {
    var parser = new Parser("tooltip");

    parser.add_argument("position");
    parser.add_argument("click", false);
    parser.add_argument("force", false);
    parser.add_argument("sticky", false);
    parser.add_argument("close", true);
    parser.add_argument("ajax", false);
    parser.add_argument("title", function($el) {
        return $el.attr("title");
    });

    var tooltip = {
        name: "tooltip",
        trigger: ".pat-tooltip",

        count: 0,

        init: function($el, opts) {
            return $el.each(function() {
                var $trigger = $(this),
                    options = parser.parse($trigger, opts);
                $trigger
                    .removeAttr("title")
                    .data("patterns.tooltip", options)
                    .on("destroy", $trigger, tooltip.onDestroy);
                tooltip.setupShowEvents($trigger);
                $trigger.addClass("inactive");
            });
        },

        setupShowEvents: function($trigger) {
            var options = $trigger.data("patterns.tooltip");
            if (options.click) {
                $trigger.on("click.tooltip", $trigger, tooltip.show);
            } else {
                $trigger.on("mouseover.tooltip", $trigger, tooltip.show);
                // Make sure click on the trigger element becomes a NOP
                $trigger.on("click.tooltip", $trigger, tooltip.blockDefault);
            }
        },

        removeShowEvents: function($trigger) {
            $trigger.off(".tooltip");
        },

        setupHideEvents: function($trigger) {
            var $container = tooltip.getContainer($trigger),
                options = $trigger.data("patterns.tooltip");
            if (options.sticky) {
                $container.find(".close-panel")
                    .on("click.tooltip", $trigger, tooltip.hide);
                // Make sure click on the trigger element becomes a NOP
                $trigger.on("click.tooltip", $trigger, tooltip.blockDefault);
            } else {
                if (options.click) {
                    $container.on("click.tooltip", $trigger, function(ev) {
                        ev.stopPropagation();
                    });
                    $(document).on("click.tooltip", $trigger, tooltip.hide);
                    $trigger.on("click.tooltip", tooltip.blockDefault);
                    // close if something inside the tooltip triggered an injection
                    $container.on("patterns-inject-triggered.tooltip",
                                  $trigger, tooltip.hide);
                    $container.on("submit.tooltip", $trigger, tooltip.hide);
                } else {
                    $container.on("click.tooltip", $trigger, tooltip.hide);
                    $trigger.on("mouseleave.tooltip", $trigger, tooltip.hide);
                    $trigger.on("click.tooltip", tooltip.blockDefault);
                }
            }
        },

        removeHideEvents: function($trigger) {
            var $container = tooltip.getContainer($trigger);
            $(document).off(".tooltip");
            $container.off(".tooltip");
            $container.find(".close-panel").off(".tooltip");
            $trigger.off(".tooltip");
        },

        blockDefault: function(event) {
            event.preventDefault();
        },

        show: function(event) {
            event.preventDefault();
            var $trigger = event.data,
                $container = tooltip.getContainer($trigger, true),
                namespace = $container.attr("id"),
                options = $trigger.data("patterns.tooltip");

            tooltip.removeShowEvents($trigger);
            // Wrap in a timeout to make sure this click is not used to
            // trigger a hide as well.
            setTimeout(function() { tooltip.setupHideEvents($trigger); }, 50);

            if (options.ajax) {
                var source = $trigger.attr("href").split("#"),
                    target_id = $container.find("progress").attr("id");
                inject.execute([{
                    url: source[0],
                    source: "#" + source[1],
                    target: "#" + target_id + "::element",
                    dataType: "html"
                }], $trigger);
            }

            tooltip.positionContainer($trigger, $container);
            $container.css("visibility", "visible");

            // reposition tooltip everytime we scroll or resize
            $(window).on("scroll." + namespace + " resize." + namespace, function () {
                 tooltip.positionContainer($trigger, $container);
            });

            $trigger.removeClass("inactive").addClass("active");
        },

        hide: function(event) {
            var $trigger = event.data,
                $container = tooltip.getContainer($trigger),
                namespace = $container.attr("id");
            tooltip.removeHideEvents($trigger);
            $container.css("visibility", "hidden");
            $(window).off("." + namespace);
            tooltip.setupShowEvents($trigger);
            $trigger.removeClass("active").addClass("inactive");
        },

        onDestroy: function(event) {
            var $trigger = event.data,
                $container = $trigger.data("patterns.tooltip.container");
            if ($container!==undefined)
                $container.remove();
        },

        getContainer: function($trigger, create) {
            var $container = $trigger.data("patterns.tooltip.container");

            if (create) {
                if ($container !== undefined) {
                    $container.remove();
                }
                $container = tooltip.createContainer($trigger);
                $trigger.data("patterns.tooltip.container", $container);
            }

            return $container;
        },

        createContainer: function($trigger) {
            var options = $trigger.data("patterns.tooltip"),
                count = ++tooltip.count,
                $content, $container;

            $trigger.data("patterns.tooltip.number", count);
            $container = $("
", {"class": "tooltip-container",
                                     "id": "tooltip" + count});
            $container.css("visibility", "hidden");
            if (options.ajax) {
                $content = $("<progress/>", {"id": "tooltip-load-" + count});
            } else {
                $content = $("
").text(options.title);
            }
            $container.append(
                $("
").css("display", "block").append($content))
                .append($("", {"class": "pointer"}));
            if (options.sticky && options.close) {
                $("<button/>", {"class": "close-panel"})
                    .text("Close")
                    .insertBefore($container.find("*:first"));
            }
            $("body").append($container);
            return $container;
        },

        boundingBox: function($el) {
            var box = $el.offset();
            box.height = $el.height();
            box.width = $el.width();
            box.bottom = box.top + box.height;
            box.right = box.left + box.width;
            return box;
        },

        positionStatus: function($trigger, $container) {
            var trigger_box = tooltip.boundingBox($trigger),
                tooltip_box = tooltip.boundingBox($container),
                $window = $(window),
                window_width = $window.width(),
                window_height = $window.height(),
                trigger_center,
                scroll = {},
                space = {};

            scroll.top = $window.scrollTop();
            scroll.left = $window.scrollLeft();
            trigger_center = {top: trigger_box.top + (trigger_box.height/2),
                              left: trigger_box.left + (trigger_box.width/2)};
            space.top = trigger_box.top - scroll.top;
            space.bottom = window_height - space.top - trigger_box.height;
            space.left = trigger_box.left - scroll.left;
            space.right = window_width - space.left - trigger_box.width;

            return {space: space,
                    trigger_center: trigger_center,
                    trigger_box: trigger_box,
                    tooltip_box: tooltip_box,
                    scroll: scroll,
                    window: {width: window_width, height: window_height}
            };
        },

        // Help function to determine the best position for a tooltip.  Takes
        // the positioning status (as generated by positionStatus) as input
        // and returns a two-character position indiciator.
        findBestPosition: function(status) {
            var space = status.space,
                 cls = "";

            if (space.top > Math.max(space.right, space.bottom, space.left)) {
                cls = "b";
            } else if (space.right > Math.max(space.bottom, space.left, space.top)) {
                cls = "l";
            } else if (space.bottom > Math.max(space.left, space.top, space.right)) {
                cls = "t";
            } else {
                cls = "r";
            }

            switch (cls[0]) {
            case "t":
            case "b":
                if (Math.abs(space.left-space.right) < 20) {
                    cls += "m";
                } else if (space.left > space.right) {
                    cls += "r";
                } else {
                    cls += "l";
                }
                break;
            case "l":
            case "r":
                if (Math.abs(space.top-space.bottom) < 20) {
                    cls += "m";
                } else if (space.top > space.bottom) {
                    cls += "b";
                } else {
                    cls += "t";
                }
            }
            return cls;
        },

        isVisible: function(status, position) {
            var space = status.space,
                tooltip_box = status.tooltip_box;

            switch (position[0]) {
            case "t":
                if (tooltip_box.height > space.bottom) {
                    return false;
                }
                break;
            case "r":
                if (tooltip_box.width > space.left) {
                    return false;
                }
                break;
            case "b":
                if (tooltip_box.height > space.top) {
                    return false;
                }
                break;
            case "l":
                if (tooltip_box.width > space.right) {
                    return false;
                }
                break;
            default:
                return false;
            }

            switch (position[0]) {
            case "t":
            case "b":
                switch (position[1]) {
                    case "l":
                        if ((tooltip_box.width-20)>space.right) {
                            return false;
                        }
                        break;
                    case "m":
                        if ((tooltip_box.width/2)>space.left || (tooltip_box.width/2)>space.right) {
                            return false;
                        }
                        break;
                    case "r":
                        if ((tooltip_box.width-20)>space.left) {
                            return false;
                        }
                        break;
                    default:
                        return false;
                }
                break;
            case "l":
            case "r":
                switch (position[1]) {
                    case "t":
                        if ((tooltip_box.height-20)>space.bottom) {
                            return false;
                        }
                        break;
                    case "m":
                        if ((tooltip_box.height/2)>space.top || (tooltip_box.height/2)>space.bottom) {
                            return false;
                        }
                        break;
                    case "b":
                        if ((tooltip_box.height-20)>space.top) {
                            return false;
                        }
                        break;
                    default:
                        return false;
                }
                break;
            }
            return true;
        },

        VALIDPOSITION: /^([lr][tmb]|[tb][lmr])$/,

        positionContainer: function($trigger, $container) {
            var status = tooltip.positionStatus($trigger, $container),
                options = $trigger.data("patterns.tooltip"),
                container_offset = {},
                tip_offset = {},
                position;

            if (options.position) {
                var positions = options.position.split("-"), i;
                for (i=0; i<positions.length; i++) {
                    if (!tooltip.VALIDPOSITION.test(positions[i])) {
                        continue;
                    }

                    if (options.force || tooltip.isVisible(status, positions[i])) {
                        position = positions[i];
                        break;
                    }
                }
            }

            if (!position) {
                position = tooltip.findBestPosition(status);
            }

            var trigger_box = status.trigger_box,
                tooltip_box = status.tooltip_box,
                trigger_center = status.trigger_center,
                content_css = {"max-height": "", "max-width": ""},
                bottom_row, x;

            switch (position[0]) {
            case "t":
                container_offset.top = trigger_box.bottom + 20;
                tip_offset.top = -23;
                bottom_row = status.scroll.top + status.window.height,
                content_css["max-height"] = (bottom_row - container_offset.top - 30) + "px";
                break;
            case "l":
                container_offset.left = trigger_box.right + 20;
                tip_offset.left = -23;
                x = status.window.width + status.scroll.left;
                content_css["max-width"] = (x - container_offset.left - 30) + "px";
                break;
            case "b":
                container_offset.top = trigger_box.top - tooltip_box.height + 10;
                tip_offset.top = tooltip_box.height;
                x = (status.scroll.top + 10) - container_offset.top;
                if (x>0) {
                    tip_offset.top -= x;
                    content_css["max-height"] = (tooltip_box.height - x) + "px";
                    container_offset.top += x;
                }
                break;
            case "r":
                container_offset.left = trigger_box.left - tooltip_box.width - 20;
                tip_offset.left = tooltip_box.width;
                break;
            }

            switch (position[0]) {
            case "t":
            case "b":
                switch (position[1]) {
                case "l":
                    container_offset.left = trigger_center.left - 20;
                    tip_offset.left = 0;
                    break;
                case "m":
                    container_offset.left = trigger_center.left - (tooltip_box.width/2);
                    tip_offset.left = tooltip_box.width/2 - 10;
                    break;
                case "r":
                    container_offset.left = trigger_center.left + 29 - tooltip_box.width;
                    tip_offset.left = tooltip_box.width - 20;
                    break;
                }
                break;
            case "l":
            case "r":
                switch (position[1]) {
                    case "t":
                        container_offset.top = trigger_center.top - 30;
                        tip_offset.top = 0;
                        break;
                    case "m":
                        container_offset.top = trigger_center.top - (tooltip_box.height/2);
                        tip_offset.top = tooltip_box.height/2 - 10;
                        break;
                    case "b":
                        container_offset.top = trigger_center.top + 20 - tooltip_box.height;
                        tip_offset.top = tooltip_box.height - 20;
                        break;
                }
                break;
            }

            var $body = $("body"),
                body_pos = $body.css("position");

            if (body_pos==="relative" || body_pos==="absolute") {
                var body_offset = $"body".offset();
                container_offset.top-=body_offset.top;
                container_offset.left-=body_offset.left;
            }

            $container.find("> div").css(content_css);
            $container.attr("class", "tooltip-container " + position);
            $container.css({
                top: container_offset.top+"px",
                left: container_offset.left+"px"
            });
            $container.find(".pointer").css({
                top: tip_offset.top+"px",
                left: tip_offset.left+"px"});
        }
    };

    patterns.register(tooltip);
    return tooltip; // XXX Replace for tests
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<commit_msg>Fix typo in tooltip pattern.<commit_after>/**
 * @license
 * Patterns @VERSION@ tooltip - tooltips
 *
 * Copyright 2008-2012 Simplon B.V.
 * Copyright 2011 Humberto Sermeño
 * Copyright 2011 SYSLAB.COM GmbH
 */
define([
    "jquery",
    "../registry",
    "../core/parser",
    "./inject",
    "../core/remove"
], function($, patterns, Parser, inject) {
    var parser = new Parser("tooltip");

    parser.add_argument("position");
    parser.add_argument("click", false);
    parser.add_argument("force", false);
    parser.add_argument("sticky", false);
    parser.add_argument("close", true);
    parser.add_argument("ajax", false);
    parser.add_argument("title", function($el) {
        return $el.attr("title");
    });

    var tooltip = {
        name: "tooltip",
        trigger: ".pat-tooltip",

        count: 0,

        init: function($el, opts) {
            return $el.each(function() {
                var $trigger = $(this),
                    options = parser.parse($trigger, opts);
                $trigger
                    .removeAttr("title")
                    .data("patterns.tooltip", options)
                    .on("destroy", $trigger, tooltip.onDestroy);
                tooltip.setupShowEvents($trigger);
                $trigger.addClass("inactive");
            });
        },

        setupShowEvents: function($trigger) {
            var options = $trigger.data("patterns.tooltip");
            if (options.click) {
                $trigger.on("click.tooltip", $trigger, tooltip.show);
            } else {
                $trigger.on("mouseover.tooltip", $trigger, tooltip.show);
                // Make sure click on the trigger element becomes a NOP
                $trigger.on("click.tooltip", $trigger, tooltip.blockDefault);
            }
        },

        removeShowEvents: function($trigger) {
            $trigger.off(".tooltip");
        },

        setupHideEvents: function($trigger) {
            var $container = tooltip.getContainer($trigger),
                options = $trigger.data("patterns.tooltip");
            if (options.sticky) {
                $container.find(".close-panel")
                    .on("click.tooltip", $trigger, tooltip.hide);
                // Make sure click on the trigger element becomes a NOP
                $trigger.on("click.tooltip", $trigger, tooltip.blockDefault);
            } else {
                if (options.click) {
                    $container.on("click.tooltip", $trigger, function(ev) {
                        ev.stopPropagation();
                    });
                    $(document).on("click.tooltip", $trigger, tooltip.hide);
                    $trigger.on("click.tooltip", tooltip.blockDefault);
                    // close if something inside the tooltip triggered an injection
                    $container.on("patterns-inject-triggered.tooltip",
                                  $trigger, tooltip.hide);
                    $container.on("submit.tooltip", $trigger, tooltip.hide);
                } else {
                    $container.on("click.tooltip", $trigger, tooltip.hide);
                    $trigger.on("mouseleave.tooltip", $trigger, tooltip.hide);
                    $trigger.on("click.tooltip", tooltip.blockDefault);
                }
            }
        },

        removeHideEvents: function($trigger) {
            var $container = tooltip.getContainer($trigger);
            $(document).off(".tooltip");
            $container.off(".tooltip");
            $container.find(".close-panel").off(".tooltip");
            $trigger.off(".tooltip");
        },

        blockDefault: function(event) {
            event.preventDefault();
        },

        show: function(event) {
            event.preventDefault();
            var $trigger = event.data,
                $container = tooltip.getContainer($trigger, true),
                namespace = $container.attr("id"),
                options = $trigger.data("patterns.tooltip");

            tooltip.removeShowEvents($trigger);
            // Wrap in a timeout to make sure this click is not used to
            // trigger a hide as well.
            setTimeout(function() { tooltip.setupHideEvents($trigger); }, 50);

            if (options.ajax) {
                var source = $trigger.attr("href").split("#"),
                    target_id = $container.find("progress").attr("id");
                inject.execute([{
                    url: source[0],
                    source: "#" + source[1],
                    target: "#" + target_id + "::element",
                    dataType: "html"
                }], $trigger);
            }

            tooltip.positionContainer($trigger, $container);
            $container.css("visibility", "visible");

            // reposition tooltip everytime we scroll or resize
            $(window).on("scroll." + namespace + " resize." + namespace, function () {
                 tooltip.positionContainer($trigger, $container);
            });

            $trigger.removeClass("inactive").addClass("active");
        },

        hide: function(event) {
            var $trigger = event.data,
                $container = tooltip.getContainer($trigger),
                namespace = $container.attr("id");
            tooltip.removeHideEvents($trigger);
            $container.css("visibility", "hidden");
            $(window).off("." + namespace);
            tooltip.setupShowEvents($trigger);
            $trigger.removeClass("active").addClass("inactive");
        },

        onDestroy: function(event) {
            var $trigger = event.data,
                $container = $trigger.data("patterns.tooltip.container");
            if ($container!==undefined)
                $container.remove();
        },

        getContainer: function($trigger, create) {
            var $container = $trigger.data("patterns.tooltip.container");

            if (create) {
                if ($container !== undefined) {
                    $container.remove();
                }
                $container = tooltip.createContainer($trigger);
                $trigger.data("patterns.tooltip.container", $container);
            }

            return $container;
        },

        createContainer: function($trigger) {
            var options = $trigger.data("patterns.tooltip"),
                count = ++tooltip.count,
                $content, $container;

            $trigger.data("patterns.tooltip.number", count);
            $container = $("
", {"class": "tooltip-container",
                                     "id": "tooltip" + count});
            $container.css("visibility", "hidden");
            if (options.ajax) {
                $content = $("<progress/>", {"id": "tooltip-load-" + count});
            } else {
                $content = $("
").text(options.title);
            }
            $container.append(
                $("
").css("display", "block").append($content))
                .append($("", {"class": "pointer"}));
            if (options.sticky && options.close) {
                $("<button/>", {"class": "close-panel"})
                    .text("Close")
                    .insertBefore($container.find("*:first"));
            }
            $("body").append($container);
            return $container;
        },

        boundingBox: function($el) {
            var box = $el.offset();
            box.height = $el.height();
            box.width = $el.width();
            box.bottom = box.top + box.height;
            box.right = box.left + box.width;
            return box;
        },

        positionStatus: function($trigger, $container) {
            var trigger_box = tooltip.boundingBox($trigger),
                tooltip_box = tooltip.boundingBox($container),
                $window = $(window),
                window_width = $window.width(),
                window_height = $window.height(),
                trigger_center,
                scroll = {},
                space = {};

            scroll.top = $window.scrollTop();
            scroll.left = $window.scrollLeft();
            trigger_center = {top: trigger_box.top + (trigger_box.height/2),
                              left: trigger_box.left + (trigger_box.width/2)};
            space.top = trigger_box.top - scroll.top;
            space.bottom = window_height - space.top - trigger_box.height;
            space.left = trigger_box.left - scroll.left;
            space.right = window_width - space.left - trigger_box.width;

            return {space: space,
                    trigger_center: trigger_center,
                    trigger_box: trigger_box,
                    tooltip_box: tooltip_box,
                    scroll: scroll,
                    window: {width: window_width, height: window_height}
            };
        },

        // Help function to determine the best position for a tooltip.  Takes
        // the positioning status (as generated by positionStatus) as input
        // and returns a two-character position indiciator.
        findBestPosition: function(status) {
            var space = status.space,
                 cls = "";

            if (space.top > Math.max(space.right, space.bottom, space.left)) {
                cls = "b";
            } else if (space.right > Math.max(space.bottom, space.left, space.top)) {
                cls = "l";
            } else if (space.bottom > Math.max(space.left, space.top, space.right)) {
                cls = "t";
            } else {
                cls = "r";
            }

            switch (cls[0]) {
            case "t":
            case "b":
                if (Math.abs(space.left-space.right) < 20) {
                    cls += "m";
                } else if (space.left > space.right) {
                    cls += "r";
                } else {
                    cls += "l";
                }
                break;
            case "l":
            case "r":
                if (Math.abs(space.top-space.bottom) < 20) {
                    cls += "m";
                } else if (space.top > space.bottom) {
                    cls += "b";
                } else {
                    cls += "t";
                }
            }
            return cls;
        },

        isVisible: function(status, position) {
            var space = status.space,
                tooltip_box = status.tooltip_box;

            switch (position[0]) {
            case "t":
                if (tooltip_box.height > space.bottom) {
                    return false;
                }
                break;
            case "r":
                if (tooltip_box.width > space.left) {
                    return false;
                }
                break;
            case "b":
                if (tooltip_box.height > space.top) {
                    return false;
                }
                break;
            case "l":
                if (tooltip_box.width > space.right) {
                    return false;
                }
                break;
            default:
                return false;
            }

            switch (position[0]) {
            case "t":
            case "b":
                switch (position[1]) {
                    case "l":
                        if ((tooltip_box.width-20)>space.right) {
                            return false;
                        }
                        break;
                    case "m":
                        if ((tooltip_box.width/2)>space.left || (tooltip_box.width/2)>space.right) {
                            return false;
                        }
                        break;
                    case "r":
                        if ((tooltip_box.width-20)>space.left) {
                            return false;
                        }
                        break;
                    default:
                        return false;
                }
                break;
            case "l":
            case "r":
                switch (position[1]) {
                    case "t":
                        if ((tooltip_box.height-20)>space.bottom) {
                            return false;
                        }
                        break;
                    case "m":
                        if ((tooltip_box.height/2)>space.top || (tooltip_box.height/2)>space.bottom) {
                            return false;
                        }
                        break;
                    case "b":
                        if ((tooltip_box.height-20)>space.top) {
                            return false;
                        }
                        break;
                    default:
                        return false;
                }
                break;
            }
            return true;
        },

        VALIDPOSITION: /^([lr][tmb]|[tb][lmr])$/,

        positionContainer: function($trigger, $container) {
            var status = tooltip.positionStatus($trigger, $container),
                options = $trigger.data("patterns.tooltip"),
                container_offset = {},
                tip_offset = {},
                position;

            if (options.position) {
                var positions = options.position.split("-"), i;
                for (i=0; i<positions.length; i++) {
                    if (!tooltip.VALIDPOSITION.test(positions[i])) {
                        continue;
                    }

                    if (options.force || tooltip.isVisible(status, positions[i])) {
                        position = positions[i];
                        break;
                    }
                }
            }

            if (!position) {
                position = tooltip.findBestPosition(status);
            }

            var trigger_box = status.trigger_box,
                tooltip_box = status.tooltip_box,
                trigger_center = status.trigger_center,
                content_css = {"max-height": "", "max-width": ""},
                bottom_row, x;

            switch (position[0]) {
            case "t":
                container_offset.top = trigger_box.bottom + 20;
                tip_offset.top = -23;
                bottom_row = status.scroll.top + status.window.height,
                content_css["max-height"] = (bottom_row - container_offset.top - 30) + "px";
                break;
            case "l":
                container_offset.left = trigger_box.right + 20;
                tip_offset.left = -23;
                x = status.window.width + status.scroll.left;
                content_css["max-width"] = (x - container_offset.left - 30) + "px";
                break;
            case "b":
                container_offset.top = trigger_box.top - tooltip_box.height + 10;
                tip_offset.top = tooltip_box.height;
                x = (status.scroll.top + 10) - container_offset.top;
                if (x>0) {
                    tip_offset.top -= x;
                    content_css["max-height"] = (tooltip_box.height - x) + "px";
                    container_offset.top += x;
                }
                break;
            case "r":
                container_offset.left = trigger_box.left - tooltip_box.width - 20;
                tip_offset.left = tooltip_box.width;
                break;
            }

            switch (position[0]) {
            case "t":
            case "b":
                switch (position[1]) {
                case "l":
                    container_offset.left = trigger_center.left - 20;
                    tip_offset.left = 0;
                    break;
                case "m":
                    container_offset.left = trigger_center.left - (tooltip_box.width/2);
                    tip_offset.left = tooltip_box.width/2 - 10;
                    break;
                case "r":
                    container_offset.left = trigger_center.left + 29 - tooltip_box.width;
                    tip_offset.left = tooltip_box.width - 20;
                    break;
                }
                break;
            case "l":
            case "r":
                switch (position[1]) {
                    case "t":
                        container_offset.top = trigger_center.top - 30;
                        tip_offset.top = 0;
                        break;
                    case "m":
                        container_offset.top = trigger_center.top - (tooltip_box.height/2);
                        tip_offset.top = tooltip_box.height/2 - 10;
                        break;
                    case "b":
                        container_offset.top = trigger_center.top + 20 - tooltip_box.height;
                        tip_offset.top = tooltip_box.height - 20;
                        break;
                }
                break;
            }

            var $body = $("body"),
                body_pos = $body.css("position");

            if (body_pos==="relative" || body_pos==="absolute") {
                var body_offset = $body.offset();
                container_offset.top-=body_offset.top;
                container_offset.left-=body_offset.left;
            }

            $container.find("> div").css(content_css);
            $container.attr("class", "tooltip-container " + position);
            $container.css({
                top: container_offset.top+"px",
                left: container_offset.left+"px"
            });
            $container.find(".pointer").css({
                top: tip_offset.top+"px",
                left: tip_offset.left+"px"});
        }
    };

    patterns.register(tooltip);
    return tooltip; // XXX Replace for tests
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<|endoftext|>


<commit_before>'use strict';

var tape = require('../lib/thaliTape');
var sinon = require('sinon');

var fs = require('fs-extra-promise');
var PouchDB = require('pouchdb')
  .plugin(require('pouchdb-size'))
  .plugin(require('thali/NextGeneration/utils/pouchDBCheckpointsPlugin'))
  .defaults({
     db: require('leveldown-mobile')
   });

// DB directory should be unique among all tests and any instance of this test.
// This is especially required for tape.coordinated.
var db;
var dbName = 'pouchdb-uuid:' + Math.random();
var dbOptions = {
  checkpoint: 900
};
var checkpointPluginDelay = 500;

var test = tape({
  setup: function (t) {
    db = new PouchDB(dbName, dbOptions);
    t.end()
  },
  teardown: function (t) {
    db.destroy()
      .then(function () {
        fs.removeSync(dbName);
        t.end();
      })
      .catch(function (error) {
        t.fail(error);
      });
  }
});

var Doc = function () {
  this._id = Date.now().toString()
};

test('onCheckpointReached callback calling on a single change', function (t) {
  var spy = sinon.spy();

  db.onCheckpointReached(spy);

  db.put(new Doc())
    .then(function () {
      // A small latency is needed to calculate database size after put
      setTimeout(function () {
        t.ok(spy.calledOnce, 'checkpointReached handler should be called once. Called ' + spy.callCount + ' time(s)');
        t.end();
      }, checkpointPluginDelay + 300);
    })
    .catch(function (error) {
      t.fail(error);
    });
});

test('onCheckpointReached callback calling on multiple changes' +
'that are in checkpoints plugin delay interval', function (t) {
    var spy = sinon.spy();

    db.onCheckpointReached(spy);

    db.put(new Doc())
      // put some extra docs for 'change' event emission
      .then(function () {
        return db.put(new Doc());
      })
      .then(function () {
        return db.put(new Doc());
      })
      .then(function () {
        // A small latency is needed to calculate database size after put
        setTimeout(function () {
          t.ok(spy.calledOnce, 'checkpointReached handler should be called once. Called ' + spy.callCount + ' time(s)');
          t.end();
        }, checkpointPluginDelay + 300);
      })
      .catch(function (error) {
        t.fail(error);
      });
    });

//  TODO Investigate how to force PouchDB to shrink database size
//  Atfer that test can be enabled
/*
test('onCheckpointReached callback calling after database shrinks', function (t) {
  var spy = sinon.spy();
  var doc = new Doc();

  db.onCheckpointReached(spy);

  db.put(doc)
    .then(function (res) {
      return db.get(res.id);
    })
    .then(function (doc) {
      return db.remove(doc);
    })
    .then(function () {
      return db.compact();
    })
    .then(function () {
      db.put(new Doc());
    })
    .then(function () {
      // A small latency is needed to calculate database size after put
      setTimeout(function () {
        t.ok(spu.calledTwice, 'checkpointReached reached handler should be called twice');
        t.end();
      }, 200)
    })
    .catch(function (error) {
      t.fail(error);
    });
});
*/
<commit_msg>Added missing return statement<commit_after>'use strict';

var tape = require('../lib/thaliTape');
var sinon = require('sinon');

var fs = require('fs-extra-promise');
var PouchDB = require('pouchdb')
  .plugin(require('pouchdb-size'))
  .plugin(require('thali/NextGeneration/utils/pouchDBCheckpointsPlugin'))
  .defaults({
     db: require('leveldown-mobile')
   });

// DB directory should be unique among all tests and any instance of this test.
// This is especially required for tape.coordinated.
var db;
var dbName = 'pouchdb-uuid:' + Math.random();
var dbOptions = {
  checkpoint: 900
};
var checkpointPluginDelay = 500;

var test = tape({
  setup: function (t) {
    db = new PouchDB(dbName, dbOptions);
    t.end()
  },
  teardown: function (t) {
    db.destroy()
      .then(function () {
        fs.removeSync(dbName);
        t.end();
      })
      .catch(function (error) {
        t.fail(error);
      });
  }
});

var Doc = function () {
  this._id = Date.now().toString()
};

test('onCheckpointReached callback calling on a single change', function (t) {
  var spy = sinon.spy();

  db.onCheckpointReached(spy);

  db.put(new Doc())
    .then(function () {
      // A small latency is needed to calculate database size after put
      setTimeout(function () {
        t.ok(spy.calledOnce, 'checkpointReached handler should be called once. Called ' + spy.callCount + ' time(s)');
        t.end();
      }, checkpointPluginDelay + 300);
    })
    .catch(function (error) {
      t.fail(error);
    });
});

test('onCheckpointReached callback calling on multiple changes' +
'that are in checkpoints plugin delay interval', function (t) {
    var spy = sinon.spy();

    db.onCheckpointReached(spy);

    db.put(new Doc())
      // put some extra docs for 'change' event emission
      .then(function () {
        return db.put(new Doc());
      })
      .then(function () {
        return db.put(new Doc());
      })
      .then(function () {
        // A small latency is needed to calculate database size after put
        setTimeout(function () {
          t.ok(spy.calledOnce, 'checkpointReached handler should be called once. Called ' + spy.callCount + ' time(s)');
          t.end();
        }, checkpointPluginDelay + 300);
      })
      .catch(function (error) {
        t.fail(error);
      });
    });

//  TODO Investigate how to force PouchDB to shrink database size
//  Atfer that test can be enabled
/*
test('onCheckpointReached callback calling after database shrinks', function (t) {
  var spy = sinon.spy();
  var doc = new Doc();

  db.onCheckpointReached(spy);

  db.put(doc)
    .then(function (res) {
      return db.get(res.id);
    })
    .then(function (doc) {
      return db.remove(doc);
    })
    .then(function () {
      return db.compact();
    })
    .then(function () {
      return db.put(new Doc());
    })
    .then(function () {
      // A small latency is needed to calculate database size after put
      setTimeout(function () {
        t.ok(spu.calledTwice, 'checkpointReached reached handler should be called twice');
        t.end();
      }, 200)
    })
    .catch(function (error) {
      t.fail(error);
    });
});
*/
<|endoftext|>


<commit_before>window.showCrosswalkPI = function() {
    var headers = {
        0: "hs_id",
        1: "cnae_id"
    }

    var loadingCrosswalkPI = dataviva.ui.loading('.crosswalk-pi .crosswalk-pi-wrapper');
    loadingCrosswalkPI.text(dataviva.dictionary['loading'] + "...");

    var ProductIndustryTable = function () {
        this.tableId = '#crosswalk-pi-table';

        this.table = $(this.tableId).DataTable({
            dom: 'Bfti',
            "buttons": [
                {
                    extend: 'csvHtml5',
                    text: '',
                    filename: 'dataviva-help-crosswalk-pi'
                }
            ],
            "ajax": {
                "url": "/help/crosswalk/pi",
                "dataSrc": "data",
                "cache": true,
            },
            "order": [],
            "columns": [
                {
                    render: function (data, type, row, meta){
                        return dataviva.hs[row[0]].name.truncate(40) + ' (' + row[0] + ')';
                    }
                },
                {
                    render: function (data, type, row, meta){
                        result = '';
                        for(i=0; i<row[1].length; i++){
                            if(dataviva.cnae[ row[1][i] ])
                                result += (i != 0 ? '
' : '') + dataviva.cnae[row[1][i]].name.truncate(40) + ' (' + row[1][i] + ')';
                        }
                        return result != '' ? result : "-";
                    }
                }
            ],
            "deferRender": true,
            "language": dataviva.datatables.language,
            "scrollY": 500,
            "scrollX": true,
            "scrollCollapse": true,
            "scroller": true,
            initComplete: function () {
                loadingCrosswalkPI.show();
                $('.crosswalk-pi .crosswalk-pi-wrapper .crosswalk-pi-content').show();
                loadingCrosswalkPI.hide();
            }
        });
    };
    window.productIndustry = new ProductIndustryTable(loadingCrosswalkPI.hide());
};

window.showCrosswalkIP = function() {
    var headers = {
        0: "cnae_id",
        1: "hs_id"
    }

    var loadingCrosswalkIP = dataviva.ui.loading('.crosswalk-ip .crosswalk-ip-wrapper');
    loadingCrosswalkIP.text(dataviva.dictionary['loading'] + "...");

    var IndustryProductTable = function () {
        this.tableId = '#crosswalk-ip-table';

        this.table = $(this.tableId).DataTable({
            dom: 'Bfti',
            "buttons": [
                {
                    extend: 'csvHtml5',
                    text: '',
                    filename: 'dataviva-help-crosswalk-ip'
                }
            ],
            "ajax": {
                "url": "/help/crosswalk/ip",
                "dataSrc": "data",
                "cache": true,
            },
            "order": [],
            "columns": [
                {
                    render: function (data, type, row, meta){
                        if (dataviva.cnae[row[0]]){
                            return dataviva.cnae[row[0]].name.truncate(40) + ' (' + row[0] + ')';
                        }
                        else{
                            return '-';
                        }

                    }
                },
                {
                    render: function (data, type, row, meta){
                        result = '';
                        $.each(row[1], function(i, value) {
                            if(dataviva.hs[ value ])
                                result += (i != 0 ? '
' : '') + dataviva.hs[value].name.truncate(40) + ' (' + value + ')';
                        });
                        return result != '' ? result : "-";
                    }
                }
            ],
            "deferRender": true,
            "language": dataviva.datatables.language,
            "scrollY": 500,
            "scrollX": true,
            "scrollCollapse": true,
            "scroller": true,
            initComplete: function () {
                loadingCrosswalkIP.show();
                $('.crosswalk-ip .crosswalk-ip-wrapper .crosswalk-ip-content').show();
                loadingCrosswalkIP.hide();
            }
        });
    };
    window.industryProduct = new IndustryProductTable(loadingCrosswalkIP.hide());
};

window.showCrosswalkOC = function() {
    var headers = {
        0: "cbo_id",
        1: "course_hedu_id"
    }

    var loadingCrosswalkOC = dataviva.ui.loading('.crosswalk-oc .crosswalk-oc-wrapper');
    loadingCrosswalkOC.text(dataviva.dictionary['loading'] + "...");

    var OccupationCourseTable = function () {
        this.tableId = '#crosswalk-oc-table';

        this.table = $(this.tableId).DataTable({
            dom: 'Bfti',
            "buttons": [
                {
                    extend: 'csvHtml5',
                    text: '',
                    filename: 'dataviva-help-crosswalk-oc'
                }
            ],
            "ajax": {
                "url": "/help/crosswalk/oc",
                "dataSrc": "data",
                "cache": true,
            },
            "order": [],
            "columns": [
                {
                    render: function (data, type, row, meta){
                            return dataviva.cbo[row[0]].name.truncate(40) + ' (' + row[0] + ')';
                    }
                },
                {
                    render: function (data, type, row, meta){
                        result = '';
                        $.each(row[1], function(i, value) {
                            if(dataviva.course_hedu[ value ])
                                result += (i != 0 ? '
' : '') + dataviva.course_hedu[value].name.truncate(40) + ' (' + value + ')';
                            else
                                result += (i != 0 ? '
' : '') + dataviva.course_sc[value.substr(1,5)].name.truncate(40) + ' (' + value.substr(1,5) + ')';
                        });

                        return result != '' ? result : "-";
                    }
                }
            ],
            "deferRender": true,
            "language": dataviva.datatables.language,
            "scrollY": 500,
            "scrollX": true,
            "scrollCollapse": true,
            "scroller": true,
            initComplete: function () {
                loadingCrosswalkOC.show();
                $('.crosswalk-oc .crosswalk-oc-wrapper .crosswalk-oc-content').show();
                loadingCrosswalkOC.hide();
            }
        });
    };
    window.occupationCourse = new OccupationCourseTable(loadingCrosswalkOC.hide());
};

window.showCrosswalkCO = function() {
    var headers = {
        0: "course_hedu_id",
        1: "cbo_id"
    }

    var loadingCrosswalkCO = dataviva.ui.loading('.crosswalk-co .crosswalk-co-wrapper');
    loadingCrosswalkCO.text(dataviva.dictionary['loading'] + "...");

    var CourseOccupationTable = function () {
        this.tableId = '#crosswalk-co-table';

        this.table = $(this.tableId).DataTable({
            dom: 'Bfti',
            "buttons": [
                {
                    extend: 'csvHtml5',
                    text: '',
                    filename: 'dataviva-help-crosswalk-co'
                }
            ],
            "ajax": {
                "url": "/help/crosswalk/co",
                "dataSrc": "data",
                "cache": true
            },
            "order": [],
            "columns": [
                {
                    render: function (data, type, row, meta){
                        if(row[0].match(/^[0-9]+$/)){
                           return dataviva.course_sc[row[0].substr(1,5)].name.truncate(40) + ' (' + row[0].substr(1,5) + ')';
                        }
                        else if (dataviva.course_hedu[row[0]]){
                            return dataviva.course_hedu[row[0]].name.truncate(40) + ' (' + row[0] + ')';
                        }
                        else{
                            return row[0];
                        }
                    }
                },
                {
                    render: function (data, type, row, meta){
                        result = '';
                        for(i=0; i<row[1].length; i++){
                            if(dataviva.cbo[ row[1][i] ])
                                result += (i != 0 ? '
' : '') + dataviva.cbo[row[1][i]].name.truncate(40) + ' (' + row[1][i] + ')';
                        }
                        return result != '' ? result : "-";
                    }
                },
            ],
            "deferRender": true,
            "language": dataviva.datatables.language,
            "scrollY": 500,
            "scrollX": true,
            "scrollCollapse": true,
            "scroller": true,
            initComplete: function () {
                loadingCrosswalkCO.show();
                $('.crosswalk-co .crosswalk-co-wrapper .crosswalk-co-content').show();
                loadingCrosswalkCO.hide();
            }
        });
    };
    window.courseOccupation = new CourseOccupationTable(loadingCrosswalkCO.hide());
};

$('.product-industry').on('click', function(){
    dataviva.requireAttrs(['hs', 'cnae'], function() {
        if(!window.productIndustry){
            showCrosswalkPI();
        }
    });
});

$('.industry-product').on('click', function(){
    dataviva.requireAttrs(['hs', 'cnae'], function() {
        if(!window.industryProduct){
            showCrosswalkIP();
        }
    });
});

$('.occupation-course').on('click', function(){

    dataviva.requireAttrs(['course_sc', 'cbo', 'course_hedu'], function() {
        if(!window.occupationCourse){
            showCrosswalkOC();
        }
    });
});

$('.course-occupation').on('click', function(){
    dataviva.requireAttrs(['course_sc', 'cbo', 'course_hedu'], function() {
         if(!window.courseOccupation){
            showCrosswalkCO();
        }
    });
});
<commit_msg>Add new download function to crosswalks.<commit_after>//attr1 and attr2 refers to crosswalk_table, download(pi, hs, cnae)
function download(crosswalk_table, attr1, attr2){
    $.ajax({
        dataType: 'json',
        method: 'GET',
        url: "/help/crosswalk/" + crosswalk_table + "?download=true",
        success: function (response) {
            var csv = dataviva.dictionary[attr1] + " ID," +
                    dataviva.dictionary[attr1] + " Name," +
                    dataviva.dictionary[attr2] + " ID,"+
                    dataviva.dictionary[attr2] + " Name\n";

            response.data.forEach(function(row){
                if(row[0] && row[1]){
                    csv+=row[0] + "," +
                    dataviva[attr1][row[0]].name.replace(/,/g, '') + "," +
                    row[1] + "," +
                    dataviva[attr2][row[1]].name.replace(/,/g, '') + "\n";
                }
            });

            var a = document.createElement('a');
            a.download = "dataviva-help-crosswalk-" + crosswalk_table + ".csv";
            a.href = 'data:text/csv;charset=utf-8,' + escape(csv);
            a.click();

        }
    });
}

window.showCrosswalkPI = function() {
    var headers = {
        0: "hs_id",
        1: "cnae_id"
    }

    var loadingCrosswalkPI = dataviva.ui.loading('.crosswalk-pi .crosswalk-pi-wrapper');
    loadingCrosswalkPI.text(dataviva.dictionary['loading'] + "...");

    var ProductIndustryTable = function () {
        this.tableId = '#crosswalk-pi-table';

        this.table = $(this.tableId).DataTable({
            dom: 'Bfti',
            "buttons": [
                {
                    text: 'save',
                    text: '',
                    action: function ( e, dt, node, config ) {
                        download('pi', 'hs', 'cnae')
                    }
                }
            ],
            "ajax": {
                "url": "/help/crosswalk/pi",
                "dataSrc": "data",
                "cache": true,
            },
            "order": [],
            "columns": [
                {
                    render: function (data, type, row, meta){
                        return dataviva.hs[row[0]].name.truncate(40) + ' (' + row[0] + ')';
                    }
                },
                {
                    render: function (data, type, row, meta){
                        result = '';
                        for(i=0; i<row[1].length; i++){
                            if(dataviva.cnae[ row[1][i] ])
                                result += (i != 0 ? '
' : '') + dataviva.cnae[row[1][i]].name.truncate(40) + ' (' + row[1][i] + ')';
                        }
                        return result != '' ? result : "-";
                    }
                }
            ],
            "deferRender": true,
            "language": dataviva.datatables.language,
            "scrollY": 500,
            "scrollX": true,
            "scrollCollapse": true,
            "scroller": true,
            initComplete: function () {
                loadingCrosswalkPI.show();
                $('.crosswalk-pi .crosswalk-pi-wrapper .crosswalk-pi-content').show();
                loadingCrosswalkPI.hide();
            }
        });
    };
    window.productIndustry = new ProductIndustryTable(loadingCrosswalkPI.hide());
};

window.showCrosswalkIP = function() {
    var headers = {
        0: "cnae_id",
        1: "hs_id"
    }

    var loadingCrosswalkIP = dataviva.ui.loading('.crosswalk-ip .crosswalk-ip-wrapper');
    loadingCrosswalkIP.text(dataviva.dictionary['loading'] + "...");

    var IndustryProductTable = function () {
        this.tableId = '#crosswalk-ip-table';

        this.table = $(this.tableId).DataTable({
            dom: 'Bfti',
            "buttons": [
                {
                    extend: 'csvHtml5',
                    text: '',
                    filename: 'dataviva-help-crosswalk-ip'
                }
            ],
            "ajax": {
                "url": "/help/crosswalk/ip",
                "dataSrc": "data",
                "cache": true,
            },
            "order": [],
            "columns": [
                {
                    render: function (data, type, row, meta){
                        if (dataviva.cnae[row[0]]){
                            return dataviva.cnae[row[0]].name.truncate(40) + ' (' + row[0] + ')';
                        }
                        else{
                            return '-';
                        }

                    }
                },
                {
                    render: function (data, type, row, meta){
                        result = '';
                        $.each(row[1], function(i, value) {
                            if(dataviva.hs[ value ])
                                result += (i != 0 ? '
' : '') + dataviva.hs[value].name.truncate(40) + ' (' + value + ')';
                        });
                        return result != '' ? result : "-";
                    }
                }
            ],
            "deferRender": true,
            "language": dataviva.datatables.language,
            "scrollY": 500,
            "scrollX": true,
            "scrollCollapse": true,
            "scroller": true,
            initComplete: function () {
                loadingCrosswalkIP.show();
                $('.crosswalk-ip .crosswalk-ip-wrapper .crosswalk-ip-content').show();
                loadingCrosswalkIP.hide();
            }
        });
    };
    window.industryProduct = new IndustryProductTable(loadingCrosswalkIP.hide());
};

window.showCrosswalkOC = function() {
    var headers = {
        0: "cbo_id",
        1: "course_hedu_id"
    }

    var loadingCrosswalkOC = dataviva.ui.loading('.crosswalk-oc .crosswalk-oc-wrapper');
    loadingCrosswalkOC.text(dataviva.dictionary['loading'] + "...");

    var OccupationCourseTable = function () {
        this.tableId = '#crosswalk-oc-table';

        this.table = $(this.tableId).DataTable({
            dom: 'Bfti',
            "buttons": [
                {
                    extend: 'csvHtml5',
                    text: '',
                    filename: 'dataviva-help-crosswalk-oc'
                }
            ],
            "ajax": {
                "url": "/help/crosswalk/oc",
                "dataSrc": "data",
                "cache": true,
            },
            "order": [],
            "columns": [
                {
                    render: function (data, type, row, meta){
                            return dataviva.cbo[row[0]].name.truncate(40) + ' (' + row[0] + ')';
                    }
                },
                {
                    render: function (data, type, row, meta){
                        result = '';
                        $.each(row[1], function(i, value) {
                            if(dataviva.course_hedu[ value ])
                                result += (i != 0 ? '
' : '') + dataviva.course_hedu[value].name.truncate(40) + ' (' + value + ')';
                            else
                                result += (i != 0 ? '
' : '') + dataviva.course_sc[value.substr(1,5)].name.truncate(40) + ' (' + value.substr(1,5) + ')';
                        });

                        return result != '' ? result : "-";
                    }
                }
            ],
            "deferRender": true,
            "language": dataviva.datatables.language,
            "scrollY": 500,
            "scrollX": true,
            "scrollCollapse": true,
            "scroller": true,
            initComplete: function () {
                loadingCrosswalkOC.show();
                $('.crosswalk-oc .crosswalk-oc-wrapper .crosswalk-oc-content').show();
                loadingCrosswalkOC.hide();
            }
        });
    };
    window.occupationCourse = new OccupationCourseTable(loadingCrosswalkOC.hide());
};

window.showCrosswalkCO = function() {
    var headers = {
        0: "course_hedu_id",
        1: "cbo_id"
    }

    var loadingCrosswalkCO = dataviva.ui.loading('.crosswalk-co .crosswalk-co-wrapper');
    loadingCrosswalkCO.text(dataviva.dictionary['loading'] + "...");

    var CourseOccupationTable = function () {
        this.tableId = '#crosswalk-co-table';

        this.table = $(this.tableId).DataTable({
            dom: 'Bfti',
            "buttons": [
                {
                    extend: 'csvHtml5',
                    text: '',
                    filename: 'dataviva-help-crosswalk-co'
                }
            ],
            "ajax": {
                "url": "/help/crosswalk/co",
                "dataSrc": "data",
                "cache": true
            },
            "order": [],
            "columns": [
                {
                    render: function (data, type, row, meta){
                        if(row[0].match(/^[0-9]+$/)){
                           return dataviva.course_sc[row[0].substr(1,5)].name.truncate(40) + ' (' + row[0].substr(1,5) + ')';
                        }
                        else if (dataviva.course_hedu[row[0]]){
                            return dataviva.course_hedu[row[0]].name.truncate(40) + ' (' + row[0] + ')';
                        }
                        else{
                            return row[0];
                        }
                    }
                },
                {
                    render: function (data, type, row, meta){
                        result = '';
                        for(i=0; i<row[1].length; i++){
                            if(dataviva.cbo[ row[1][i] ])
                                result += (i != 0 ? '
' : '') + dataviva.cbo[row[1][i]].name.truncate(40) + ' (' + row[1][i] + ')';
                        }
                        return result != '' ? result : "-";
                    }
                },
            ],
            "deferRender": true,
            "language": dataviva.datatables.language,
            "scrollY": 500,
            "scrollX": true,
            "scrollCollapse": true,
            "scroller": true,
            initComplete: function () {
                loadingCrosswalkCO.show();
                $('.crosswalk-co .crosswalk-co-wrapper .crosswalk-co-content').show();
                loadingCrosswalkCO.hide();
            }
        });
    };
    window.courseOccupation = new CourseOccupationTable(loadingCrosswalkCO.hide());
};

$('.product-industry').on('click', function(){
    dataviva.requireAttrs(['hs', 'cnae'], function() {
        if(!window.productIndustry){
            showCrosswalkPI();
        }
    });
});

$('.industry-product').on('click', function(){
    dataviva.requireAttrs(['hs', 'cnae'], function() {
        if(!window.industryProduct){
            showCrosswalkIP();
        }
    });
});

$('.occupation-course').on('click', function(){

    dataviva.requireAttrs(['course_sc', 'cbo', 'course_hedu'], function() {
        if(!window.occupationCourse){
            showCrosswalkOC();
        }
    });
});

$('.course-occupation').on('click', function(){
    dataviva.requireAttrs(['course_sc', 'cbo', 'course_hedu'], function() {
         if(!window.courseOccupation){
            showCrosswalkCO();
        }
    });
});
<|endoftext|>


<commit_before>describe("Test for type EMAIL", function(){

	var User = Backbone.Model.extend({
		validates: {
			email: {
				type: "email"
			}
		}
	}),
	user;

	beforeEach(function(){
		user = new User();
	});

	it("should not allow empty strings", function(){
		user.set({email: ""});
		expect(user.isValid()).toBeFalsy();
	});

	it("should not allow only whitespace strings", function(){
		user.set({email: "    "});
		expect(user.isValid()).toBeFalsy();
	});

	it("should return custom error message", function(){
		user.validates.email.msg = "This is a bogus email";
		user.set({email: ""});
		user.isValid();
		expect(user.validationError.email.type).toEqual("This is a bogus email");
	});
})<commit_msg>Fixed EMAIL validation to allow empty strings<commit_after>describe("Test for type EMAIL", function(){

	var User = Backbone.Model.extend({
		validates: {
			email: {
				type: "email"
			}
		}
	}),
	user;

	beforeEach(function(){
		user = new User();
	});

	it("should allow empty strings", function(){
		user.set({email: ""});
		expect(user.isValid()).toBeTruthy();
	});

	it("should not allow only whitespace strings", function(){
		user.set({email: "    "});
		expect(user.isValid()).toBeFalsy();
	});

	it("should return custom error message", function(){
		user.validates.email.msg = "This is a bogus email";
		user.set({email: "foo"});
		user.isValid();
		expect(user.validationError.email.type).toEqual("This is a bogus email");
	});
})<|endoftext|>


<commit_before>/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is DownThemAll! Anti-Container.
 *
 * The Initial Developer of the Original Code is Nils Maier
 * Portions created by the Initial Developer are Copyright (C) 2009
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Nils Maier <MaierMan@web.de>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

var acPlugins = {
	_plugins: {},
	_init: false,
	_pending: false,
	FilePicker: Components.Constructor('@mozilla.org/filepicker;1', 'nsIFilePicker', 'init'),
	LocalFile: Components.Constructor('@mozilla.org/file/local;1', 'nsILocalFile', 'initWithPath'),
	Process: Components.Constructor('@mozilla.org/process/util;1', 'nsIProcess', 'init'),

	init: function acPL_init() {
		this._pane = document.getElementById('acPane');
		this._pref = document.getElementById('acPrefPlugins');
		this._list = document.getElementById('acListPlugins');

		Components.utils.import('resource://dtaac/plugins.jsm', this._plugins);

		this.reload();
		Preferences.makeObserver(this);
		Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService).addObserver(this, this._plugins.TOPIC_PLUGINSCHANGED, true);
		this.init = function() {};
	},
	reload: function() {
		function zeropad (s, l) {
			s = s.toString(); // force it to a string
			while (s.length < l) {
				s = '0' + s;
			}
			return s;
		}

		while (this._list.childNodes.length) {
			this._list.removeChild(this._list.firstChild);
		}

		let p = eval(this._pref.value);
		if (!(p instanceof Array)) {
			p = [];
		}
		let plugs = [];
		for (let f in this._plugins.enumerate(true)) {
			let date = new Date(f.file.lastModifiedTime);
			date = zeropad(date.getUTCFullYear(), 4)
             + "/" + zeropad(date.getUTCMonth() + 1, 2)
             + "/" + zeropad(date.getUTCDate(), 2);
			plugs.push([f.prefix, f.id, date , p.indexOf(f.id) != -1, f.priority, f.match, f.type, f.managed, f.author, f.file.path]);
		}
		plugs.sort(
			function(a,b) { return a[0] < b[0] ? -1 : (a[0] > b[0] ? 1 : 0);}
		);
		let i = 1;
		for each (let [prefix, plugin, date, disabled, prio, match, ptype, managed, author, file] in plugs) {
			let li = document.createElement('richlistitem');
			if (!author) {
				author = _(managed ? 'ac-syspluginauthor' : 'ac-unkpluginauthor');
			}
			li.setAttribute('id', 'acplugin_' + plugin);
			li.setAttribute('plugin', plugin);
			li.setAttribute('prefix', prefix);
			li.setAttribute('searchlabel', prefix);
			li.setAttribute('date', date);
			li.setAttribute('position', i + ".");
			li.setAttribute('priority', prio);
			li.setAttribute('match', match);
			li.setAttribute('ptype', ptype);
			li.setAttribute('author', author);
			li.setAttribute('activated', !disabled);
			li.setAttribute('managed', managed);
			li.setAttribute('file', file);
			this._list.appendChild(li);
			++i;
		};
		this._list.clearSelection();
	},
	install: function() {
		let fp = new this.FilePicker(window, _('ac-installplugintitle'), Ci.nsIFilePicker.modeOpen);
		fp.appendFilter('JSON Plugin', '*.json');
		fp.defaultExtension = "json";
		fp.filterIndex = 1;

		let rv = fp.show();
		if (rv == Ci.nsIFilePicker.returnOK) {
			let installed = this._plugins.installFromFile(fp.file);
			Prompts.alert(window, _('ac-installplugintitle'), _('ac-installpluginsuccess', [installed.prefix]));
		}
	},
	showNewPlugin: function() {
		this.np_clearErrors();

		$('acNPprefix', 'acNPmatch').forEach(function(e) e.value = '');
		$('acNPns').value = Preferences.getExt('anticontainer.namespace', '');
		$('acNPauthor').value = Preferences.getExt('anticontainer.author', '');

		if (!$('acNPns').value) {
			$('acNPns').value = this._plugins.DEFAULT_NAMESPACE;
		}

		$('acPluginsDeck').selectedIndex = 1;
	},
	showPluginList: function(id) {
		if (id) {
			let p = $('acplugin_' + id);
			if (p) {
				with (this._list) {
					selectedItem = p;
					ensureElementIsVisible(selectedItem);
				}
			}
		}
		$('acPluginsDeck').selectedIndex = 0;
	},
	get editor() {
		let _ed = Preferences.getExt('anticontainer.editor', '');
		if (_ed && !(new this.LocalFile(_ed)).isExecutable()) {
			_ed = '';
		}
		let fp = null;
		while (!_ed) {
			if (!fp) {
				fp = new this.FilePicker(window, _('ac-chooseeditortitle'), Ci.nsIFilePicker.modeOpen);
				fp.appendFilters(Ci.nsIFilePicker.filterApps);
				fp.appendFilters(Ci.nsIFilePicker.filterAll);
				let ds = Cc['@mozilla.org/file/directory_service;1']
		    		.getService(Ci.nsIProperties);
				for each (let d in ['ProgF', 'LocApp', 'CurProcD']) {
					try {
						fp.displayDirectory = ds.get("ProgF", Ci.nsILocalFile);
						break;
					}
					catch (ex) {
						// no op
					}
				}
			}
			let rv = fp.show();
			if (rv == Ci.nsIFilePicker.returnOK) {
				let f = fp.file;
				if (f.isSymlink()) {
					try {
						f = new this.LocalFile(f.target);
					}
					catch (ex) {
						// no op
					}
				}
				if (!f.isExecutable()) {
					alert(_('ac-editornotexec'));
					continue;
				}
				_ed = f.path;
				Preferences.setExt('anticontainer.editor', _ed);
				break;
			}
			// nothing selected;
			return null;
		}

		_ed = new this.LocalFile(_ed);
		_ed.followLinks = true;
		if (!_ed.exists() || !_ed.isExecutable()) {
			Preferences.setExt('anticontainer.editor', '');
			return this.editor; // recursive
		}
		return _ed;
	},
	showInEditor: function(file) {
		let ed = this.editor;
		if (!ed) {
			return;
		}
		if (typeof file == 'string') {
			file = new this.LocalFile(file);
		}
		if (!file) {
			throw new Error("invalid file specified");
		}
		if (!file.exists()) {
			throw new Error("File does not exist");
		}
		// credit to greasemonkey for this
		let args = [file.path];
		try {
			let rt = Cc['@mozilla.org/xre/app-info;1'].getService(Ci.nsIXULRuntime);
			if (rt.OS.match(/Darwin/)) {
				args = ['-a', ed.path, file.path];
				ed = new this.LocalFile('/usr/bin/open');
				ed.followLinks = true;
			}
		}
		catch (ex) {
			Debug.log("Failed to get runtime", ex);
		}
		try {
			let process = new this.Process(ed);
			process.run(false, args, args.length);
		}
		catch (ex) {
			Preferences.setExt('anticontainer.editor', '');
			this.showInEditor(file); // recursive
		}
	},
	np_showError: function(err) {
		let nb = $('acNPErrors');
		nb.appendNotification(err, null, null, nb.PRIORITY_CRITICAL_MEDIUM, null);
	},
	np_clearErrors: function(err) $('acNPErrors').removeAllNotifications(true),

	createNewPlugin: function() {
		let p = {};
		let errs = 0;

		this.np_clearErrors();

		for each (let e in $('acNPtype', 'acNPns', 'acNPauthor', 'acNPprefix', 'acNPmatch', 'acNPstatic')) {
			let n = e.id.substr(4);
			if (!(p[n] = e.value)) {
				this.np_showError(_('ac-npnotset', [$(e.id + 'Label').value]));
				++errs;
			}
		}
		if (p.match) {
			try {
				new RegExp(p.match);
			}
			catch (ex) {
				this.np_showError(_('ac-matchnotregex'));
				++errs;
			}
		}
		p.static = p.static == 'true';

		if (errs) {
			return;
		}

		try {
			let plug = this._plugins.createNewPlugin(p);

			try {
				this.showInEditor(plug.file);
			}
			catch (ex) {
				Debug.log("Failed to launch editor", ex);
			}

			Preferences.setExt('anticontainer.namespace', p.ns);
			Preferences.setExt('anticontainer.author', p.author);
			this.showPluginList(plug.id);
		}
		catch (ex) {
			Debug.log("Failed to install plugin", ex)
		}
	},
	observe: function() {
		this.reload();
	},

	syncFrom: function acPL_syncFrom() {
	},
	syncTo: function acPL_syncTo() {
		try	{
			let p = [];
			for (let i = 0; i < this._list.childNodes.length; ++i) {
				if (!this._list.childNodes[i].activated) {
					p.push(this._list.childNodes[i].getAttribute('plugin'));
				}
			}
			return this._plugins.nsJSON.encode(p);
		}
		catch (ex) {
			alert(ex);
			throw ex;
		}
		return "";
	}
};
addEventListener('load', function() acPlugins.init(), true);<commit_msg>completely remove use of eval()<commit_after>/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is DownThemAll! Anti-Container.
 *
 * The Initial Developer of the Original Code is Nils Maier
 * Portions created by the Initial Developer are Copyright (C) 2009
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Nils Maier <MaierMan@web.de>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

var acPlugins = {
	_plugins: {},
	_init: false,
	_pending: false,
	FilePicker: Components.Constructor('@mozilla.org/filepicker;1', 'nsIFilePicker', 'init'),
	LocalFile: Components.Constructor('@mozilla.org/file/local;1', 'nsILocalFile', 'initWithPath'),
	Process: Components.Constructor('@mozilla.org/process/util;1', 'nsIProcess', 'init'),

	init: function acPL_init() {
		this._pane = document.getElementById('acPane');
		this._pref = document.getElementById('acPrefPlugins');
		this._list = document.getElementById('acListPlugins');

		Components.utils.import('resource://dtaac/plugins.jsm', this._plugins);

		this.reload();
		Preferences.makeObserver(this);
		Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService).addObserver(this, this._plugins.TOPIC_PLUGINSCHANGED, true);
		this.init = function() {};
	},
	reload: function() {
		function zeropad (s, l) {
			s = s.toString(); // force it to a string
			while (s.length < l) {
				s = '0' + s;
			}
			return s;
		}

		while (this._list.childNodes.length) {
			this._list.removeChild(this._list.firstChild);
		}

		let p = [];
		try {
			p = this._plugins.nsJSON.decode(this._pref.value);
		}
		catch (ex) { /* no op */ }

		if (!(p instanceof Array)) {
			p = [];
		}
		let plugs = [];
		for (let f in this._plugins.enumerate(true)) {
			let date = new Date(f.file.lastModifiedTime);
			date = zeropad(date.getUTCFullYear(), 4)
             + "/" + zeropad(date.getUTCMonth() + 1, 2)
             + "/" + zeropad(date.getUTCDate(), 2);
			plugs.push([f.prefix, f.id, date , p.indexOf(f.id) != -1, f.priority, f.match, f.type, f.managed, f.author, f.file.path]);
		}
		plugs.sort(
			function(a,b) { return a[0] < b[0] ? -1 : (a[0] > b[0] ? 1 : 0);}
		);
		let i = 1;
		for each (let [prefix, plugin, date, disabled, prio, match, ptype, managed, author, file] in plugs) {
			let li = document.createElement('richlistitem');
			if (!author) {
				author = _(managed ? 'ac-syspluginauthor' : 'ac-unkpluginauthor');
			}
			li.setAttribute('id', 'acplugin_' + plugin);
			li.setAttribute('plugin', plugin);
			li.setAttribute('prefix', prefix);
			li.setAttribute('searchlabel', prefix);
			li.setAttribute('date', date);
			li.setAttribute('position', i + ".");
			li.setAttribute('priority', prio);
			li.setAttribute('match', match);
			li.setAttribute('ptype', ptype);
			li.setAttribute('author', author);
			li.setAttribute('activated', !disabled);
			li.setAttribute('managed', managed);
			li.setAttribute('file', file);
			this._list.appendChild(li);
			++i;
		};
		this._list.clearSelection();
	},
	install: function() {
		let fp = new this.FilePicker(window, _('ac-installplugintitle'), Ci.nsIFilePicker.modeOpen);
		fp.appendFilter('JSON Plugin', '*.json');
		fp.defaultExtension = "json";
		fp.filterIndex = 1;

		let rv = fp.show();
		if (rv == Ci.nsIFilePicker.returnOK) {
			let installed = this._plugins.installFromFile(fp.file);
			Prompts.alert(window, _('ac-installplugintitle'), _('ac-installpluginsuccess', [installed.prefix]));
		}
	},
	showNewPlugin: function() {
		this.np_clearErrors();

		$('acNPprefix', 'acNPmatch').forEach(function(e) e.value = '');
		$('acNPns').value = Preferences.getExt('anticontainer.namespace', '');
		$('acNPauthor').value = Preferences.getExt('anticontainer.author', '');

		if (!$('acNPns').value) {
			$('acNPns').value = this._plugins.DEFAULT_NAMESPACE;
		}

		$('acPluginsDeck').selectedIndex = 1;
	},
	showPluginList: function(id) {
		if (id) {
			let p = $('acplugin_' + id);
			if (p) {
				with (this._list) {
					selectedItem = p;
					ensureElementIsVisible(selectedItem);
				}
			}
		}
		$('acPluginsDeck').selectedIndex = 0;
	},
	get editor() {
		let _ed = Preferences.getExt('anticontainer.editor', '');
		if (_ed && !(new this.LocalFile(_ed)).isExecutable()) {
			_ed = '';
		}
		let fp = null;
		while (!_ed) {
			if (!fp) {
				fp = new this.FilePicker(window, _('ac-chooseeditortitle'), Ci.nsIFilePicker.modeOpen);
				fp.appendFilters(Ci.nsIFilePicker.filterApps);
				fp.appendFilters(Ci.nsIFilePicker.filterAll);
				let ds = Cc['@mozilla.org/file/directory_service;1']
		    		.getService(Ci.nsIProperties);
				for each (let d in ['ProgF', 'LocApp', 'CurProcD']) {
					try {
						fp.displayDirectory = ds.get("ProgF", Ci.nsILocalFile);
						break;
					}
					catch (ex) {
						// no op
					}
				}
			}
			let rv = fp.show();
			if (rv == Ci.nsIFilePicker.returnOK) {
				let f = fp.file;
				if (f.isSymlink()) {
					try {
						f = new this.LocalFile(f.target);
					}
					catch (ex) {
						// no op
					}
				}
				if (!f.isExecutable()) {
					alert(_('ac-editornotexec'));
					continue;
				}
				_ed = f.path;
				Preferences.setExt('anticontainer.editor', _ed);
				break;
			}
			// nothing selected;
			return null;
		}

		_ed = new this.LocalFile(_ed);
		_ed.followLinks = true;
		if (!_ed.exists() || !_ed.isExecutable()) {
			Preferences.setExt('anticontainer.editor', '');
			return this.editor; // recursive
		}
		return _ed;
	},
	showInEditor: function(file) {
		let ed = this.editor;
		if (!ed) {
			return;
		}
		if (typeof file == 'string') {
			file = new this.LocalFile(file);
		}
		if (!file) {
			throw new Error("invalid file specified");
		}
		if (!file.exists()) {
			throw new Error("File does not exist");
		}
		// credit to greasemonkey for this
		let args = [file.path];
		try {
			let rt = Cc['@mozilla.org/xre/app-info;1'].getService(Ci.nsIXULRuntime);
			if (rt.OS.match(/Darwin/)) {
				args = ['-a', ed.path, file.path];
				ed = new this.LocalFile('/usr/bin/open');
				ed.followLinks = true;
			}
		}
		catch (ex) {
			Debug.log("Failed to get runtime", ex);
		}
		try {
			let process = new this.Process(ed);
			process.run(false, args, args.length);
		}
		catch (ex) {
			Preferences.setExt('anticontainer.editor', '');
			this.showInEditor(file); // recursive
		}
	},
	np_showError: function(err) {
		let nb = $('acNPErrors');
		nb.appendNotification(err, null, null, nb.PRIORITY_CRITICAL_MEDIUM, null);
	},
	np_clearErrors: function(err) $('acNPErrors').removeAllNotifications(true),

	createNewPlugin: function() {
		let p = {};
		let errs = 0;

		this.np_clearErrors();

		for each (let e in $('acNPtype', 'acNPns', 'acNPauthor', 'acNPprefix', 'acNPmatch', 'acNPstatic')) {
			let n = e.id.substr(4);
			if (!(p[n] = e.value)) {
				this.np_showError(_('ac-npnotset', [$(e.id + 'Label').value]));
				++errs;
			}
		}
		if (p.match) {
			try {
				new RegExp(p.match);
			}
			catch (ex) {
				this.np_showError(_('ac-matchnotregex'));
				++errs;
			}
		}
		p.static = p.static == 'true';

		if (errs) {
			return;
		}

		try {
			let plug = this._plugins.createNewPlugin(p);

			try {
				this.showInEditor(plug.file);
			}
			catch (ex) {
				Debug.log("Failed to launch editor", ex);
			}

			Preferences.setExt('anticontainer.namespace', p.ns);
			Preferences.setExt('anticontainer.author', p.author);
			this.showPluginList(plug.id);
		}
		catch (ex) {
			Debug.log("Failed to install plugin", ex)
		}
	},
	observe: function() {
		this.reload();
	},

	syncFrom: function acPL_syncFrom() {
	},
	syncTo: function acPL_syncTo() {
		try	{
			let p = [];
			for (let i = 0; i < this._list.childNodes.length; ++i) {
				if (!this._list.childNodes[i].activated) {
					p.push(this._list.childNodes[i].getAttribute('plugin'));
				}
			}
			return this._plugins.nsJSON.encode(p);
		}
		catch (ex) {
			alert(ex);
			throw ex;
		}
		return "";
	}
};
addEventListener('load', function() acPlugins.init(), true);<|endoftext|>


<commit_before>/**
 * @file
 * Define the base routes
 */

// Libraries
const Router = require('koa-router');

// Init router
const router = new Router();

// Routes
router.get('/', ctx => {
  ctx.body = `
    <!DOCTYPE html>

        <title>Tanterne</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" type="text/css" href="/css/main.css"/>

  `;
});

module.exports = {
  router
};
<commit_msg>Setting pro html class when in a pro context<commit_after>/**
 * @file
 * Define the base routes
 */

// Libraries
const Router = require('koa-router');

// Init router
const router = new Router();

// Routes
router.get('/', ctx => {
  const proClass = ctx.pro ? 'main pro' : 'main';

  ctx.body = `
    <!DOCTYPE html>

        <title>Tanterne</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" type="text/css" href="/css/main.css"/>

  `;
});

module.exports = {
  router
};
<|endoftext|>


<commit_before>/*global describe, it, beforeEach */
/**
 * observe-plus.js - https://github.com/podefr/observe-plus
 * Copyright(c) 2014-2015 Olivier Scherrer <pode.fr@gmail.com>
 * MIT Licensed
 */
"use strict";

var chai = require("chai");
var expect = chai.expect;
var asap = require("asap");
var sinon = require("sinon");

var observe = require("../src/observe-plus").observe;

describe("GIVEN an observed array", function () {
    var array, observer;

    beforeEach(function () {
        array = [];
        observer = observe(array);
    });

    describe("WHEN observing addedCount", function () {
        var spy;

        beforeEach(function () {
            spy = sinon.spy();
            observer.addListener("addedCount", 2, spy);
        });

        describe("WHEN items are added", function () {
            beforeEach(function () {
                array.push(1, 2);
            });

            it("THEN triggers an event", function (done) {
                asap(function () {
                    expect(spy.firstCall.args[0]).to.eql({
                        type: "splice",
                        object: array,
                        index: "0",
                        removed: [],
                        addedCount: 2
                    });
                    done();
                });
            });
        });
    });
});

describe("GIVEN a very complex data structure", function () {
    var dataStructure, observer;

    beforeEach(function () {
        dataStructure = [
            {
                arrayProperty: [
                    ["value1", "value2"],
                    ["value3", "value4"],
                    [{ property: ["deeply", "nested", "array"]}]
                ],
                objectProperty: {
                    property1: true,
                    property2: null,
                    property3: {
                        nestedArrayProperty: ["", function () {}, undefined, 0, 147, false, {}]
                    },
                    property4: {
                        deeplyNestedObject: {
                            anotherArray: [
                                0, 1, 2, 3
                            ]
                        }
                    }
                }
            }
        ];
        observer = observe(dataStructure);
    });

    describe("WHEN pushing an item to a deeply nested array", function () {
        var arr = ['value'], spliceSpy;
        beforeEach(function () {
            spliceSpy = sinon.spy();
            observer.observe("splice", spliceSpy);
            dataStructure[0].arrayProperty[2][0].property.push(arr);
        });

        it("THEN publishes a splice event", function (done) {
            asap(function () {
                expect(spliceSpy.firstCall.args[0]).to.eql({
                    type: "splice",
                    object: dataStructure,
                    index: "0.arrayProperty.2.0.property.3",
                    removed: [],
                    addedCount: 1
                });
                done();
            })
        });

        describe("WHEN adding another! nested array to the newly added one", function () {
            beforeEach(function () {
                dataStructure[0].arrayProperty[2][0].property[3].push("very nested!");
            });

            it("THEN publishes a very nested event", function (done) {
                asap(function () {
                    expect(spliceSpy.secondCall.args[0]).to.eql({
                        type: "splice",
                        object: dataStructure,
                        index: "0.arrayProperty.2.0.property.3.1",
                        removed: [],
                        addedCount: 1
                    });
                    done();
                });
            });

            describe("WHEN modifying the nested array", function () {
                var updateSpy;

                beforeEach(function () {
                    updateSpy = sinon.spy();
                    observer.observe("update", updateSpy);
                    dataStructure[0].arrayProperty[2][0].property[3][1] = "updated very nested!";
                });

                it("THEN publishes an update event", function (done) {
                    asap(function () {
                        expect(updateSpy.firstCall.args[0]).to.eql({
                            type: "update",
                            object: dataStructure,
                            name: "0.arrayProperty.2.0.property.3.1",
                            oldValue: "very nested!"
                        });
                        done();
                    });
                });
            });
        });
    });
});<commit_msg>add delete test<commit_after>/*global describe, it, beforeEach */
/**
 * observe-plus.js - https://github.com/podefr/observe-plus
 * Copyright(c) 2014-2015 Olivier Scherrer <pode.fr@gmail.com>
 * MIT Licensed
 */
"use strict";

var chai = require("chai");
var expect = chai.expect;
var asap = require("asap");
var sinon = require("sinon");

var observe = require("../src/observe-plus").observe;

describe("GIVEN an observed array", function () {
    var array, observer;

    beforeEach(function () {
        array = [];
        observer = observe(array);
    });

    describe("WHEN observing addedCount", function () {
        var spy;

        beforeEach(function () {
            spy = sinon.spy();
            observer.addListener("addedCount", 2, spy);
        });

        describe("WHEN items are added", function () {
            beforeEach(function () {
                array.push(1, 2);
            });

            it("THEN triggers an event", function (done) {
                asap(function () {
                    expect(spy.firstCall.args[0]).to.eql({
                        type: "splice",
                        object: array,
                        index: "0",
                        removed: [],
                        addedCount: 2
                    });
                    done();
                });
            });
        });
    });
});

describe("GIVEN a very complex data structure", function () {
    var dataStructure, observer;

    beforeEach(function () {
        dataStructure = [
            {
                arrayProperty: [
                    ["value1", "value2"],
                    ["value3", "value4"],
                    [{ property: ["deeply", "nested", "array"]}]
                ],
                objectProperty: {
                    property1: true,
                    property2: null,
                    property3: {
                        nestedArrayProperty: ["", function () {}, undefined, 0, 147, false, {}]
                    },
                    property4: {
                        deeplyNestedObject: {
                            anotherArray: [
                                0, 1, 2, 3
                            ]
                        }
                    }
                }
            }
        ];
        observer = observe(dataStructure);
    });

    describe("WHEN pushing an item to a deeply nested array", function () {
        var arr = ['value'], spliceSpy;
        beforeEach(function () {
            spliceSpy = sinon.spy();
            observer.observe("splice", spliceSpy);
            dataStructure[0].arrayProperty[2][0].property.push(arr);
        });

        it("THEN publishes a splice event", function (done) {
            asap(function () {
                expect(spliceSpy.firstCall.args[0]).to.eql({
                    type: "splice",
                    object: dataStructure,
                    index: "0.arrayProperty.2.0.property.3",
                    removed: [],
                    addedCount: 1
                });
                done();
            })
        });

        describe("WHEN adding another! nested array to the newly added one", function () {
            beforeEach(function () {
                dataStructure[0].arrayProperty[2][0].property[3].push("very nested!");
            });

            it("THEN publishes a very nested event", function (done) {
                asap(function () {
                    expect(spliceSpy.secondCall.args[0]).to.eql({
                        type: "splice",
                        object: dataStructure,
                        index: "0.arrayProperty.2.0.property.3.1",
                        removed: [],
                        addedCount: 1
                    });
                    done();
                });
            });

            describe("WHEN modifying the nested array", function () {
                var updateSpy;

                beforeEach(function () {
                    updateSpy = sinon.spy();
                    observer.observe("update", updateSpy);
                    dataStructure[0].arrayProperty[2][0].property[3][1] = "updated very nested!";
                });

                it("THEN publishes an update event", function (done) {
                    asap(function () {
                        expect(updateSpy.firstCall.args[0]).to.eql({
                            type: "update",
                            object: dataStructure,
                            name: "0.arrayProperty.2.0.property.3.1",
                            oldValue: "very nested!"
                        });
                        done();
                    });
                });

                describe("WHEN deleting an item", function () {
                    var deleteSpy;

                    beforeEach(function () {
                        deleteSpy = sinon.spy();
                        observer.observe("delete", deleteSpy);
                        delete dataStructure[0].arrayProperty[2][0].property[3][0];
                    });

                    it("THEN publishes a delete event", function (done) {
                        asap(function () {
                            expect(deleteSpy.firstCall.args[0]).to.eql({
                                type: "delete",
                                object: dataStructure,
                                name: "0.arrayProperty.2.0.property.3.0",
                                oldValue: "value"
                            });
                            done();
                        });
                    });
                });
            });
        });
    });
});<|endoftext|>