<commit_before>(function($) {
    var app_name = '';
    var blog_base = '';
    //当前请求的markdown文件
    var cur_md_path = '';
    /*是否是http:// 如果是，那么这是资源文件,如果否，说明这是要处理的a标签*/
    function isAbsolute(url) {
            return url.indexOf('//') !== -1;
        }
        /*获得相对目录*/
    function getPageBase(url) {
            return url.slice(0, url.lastIndexOf('/') + 1);
        }
        /*判断加载的路径是否是markdown文件*/
    function isMarkdownFile(url) {
            return url.toLowerCase().indexOf('.md') !== -1 || url.toLowerCase().indexOf('.markdown') !== -1;
        }
        //获得markdown的文件名,用作标题
    function getMarkdownTitle(file_path) {
            if (!isMarkdownFile(file_path)) {
                return app_name;
            } else {
                var real_file_name = file_path;
                if (hasFolder(file_path)) {
                    real_file_name = file_path.slice(file_path.lastIndexOf('/') + 1, file_path.length);
                }
                return real_file_name.split('.')[0];
            }
        }
        /**
         * @param selector 选择器
         * @param  file_path 文件路径
         * @param  isSidebar 是否是左边导航栏
         * @param  baseUrl 基准url
         */
    function load(selector, file_path, isSidebar, baseUrl) {
        baseUrl = baseUrl || blog_base;
        isSidebar = isSidebar || false;

        var p_url = baseUrl + file_path;

        console.log("load-->" + p_url);
        console.log(blog_base);
        console.log(app_name);
        $.get(p_url, function(data) {
            marked.setOptions({
                highlight: function(code) {
                    return hljs.highlightAuto(code).value;
                }
            });
            $(selector).html(marked(data));

            //处理所有scr
            $(selector).find('[href]').each(function() {
                var $element = $(this);
                var url = $element.attr('href');

                if (isAbsolute(url)) {
                    $element.attr('target', '_blank');
                }

                // sidebar
                if (isSidebar && isMarkdownFile(url)) {
                    $element.attr('href', '?' + url);

                }

                //main page
                if (!isAbsolute(url) && !isSidebar && isMarkdownFile(url) ) {
                    $element.attr('href', '?' + getPageBase(cur_md_path) + url);
                }
            });
            //title
            if (!isSidebar) {
                var mainTitle = $('#main-page').find('h1, h2, h3, h4, h5, h6').first().text();
                $('title').text(mainTitle);
            }

        }).fail(function(err) {
            if (err.status === 404) {
                console.log('404-->' + '/' + app_name + '/');
                console.log($._c);
                load('#main-page', '404.md', false, '/' + app_name + '/');
            }
        });
    }

    function read_config(callback) {
        $.getJSON('config.json', {}, function(data) {
            app_name = data.app_name || app_name;
            blog_base = '/' + app_name + '/p/';
            console.log('---read config');
            console.log(app_name + ' : ' + blog_base);
            callback();
        }).fail(function(err) {
            alert('读取配置有误');
        });
    }

    function main() {

        read_config(function() {
            //加载侧边菜单栏
            load('#sidebar-page', 'sidebar.md', true);
            //加载主内容页
            cur_md_path = location.search.slice(1,  location.search.indexOf('&'));
            if (cur_md_path === '') {
                load('#main-page', 'home.md');
                console.log("load main~");
                //多说评论,若想不在首页显示评论框 那么：取消这一句注释
                //$('.ds-thread').removeClass('ds-thread');
            } else {
                load('#main-page', cur_md_path);
            }
        });
    }

    main();

})(jQuery);
<commit_msg>fix #4<commit_after>(function($) {
    var app_name = '';
    var blog_base = '';
    //当前请求的markdown文件
    var cur_md_path = '';
    /*是否是http:// 如果是，那么这是资源文件,如果否，说明这是要处理的a标签*/
    function isAbsolute(url) {
            return url.indexOf('//') !== -1;
        }
        /*获得相对目录*/
    function getPageBase(url) {
            return url.slice(0, url.lastIndexOf('/') + 1);
        }
        /*判断加载的路径是否是markdown文件*/
    function isMarkdownFile(url) {
            return url.toLowerCase().indexOf('.md') !== -1 || url.toLowerCase().indexOf('.markdown') !== -1;
        }
        //获得markdown的文件名,用作标题
    function getMarkdownTitle(file_path) {
            if (!isMarkdownFile(file_path)) {
                return app_name;
            } else {
                var real_file_name = file_path;
                if (hasFolder(file_path)) {
                    real_file_name = file_path.slice(file_path.lastIndexOf('/') + 1, file_path.length);
                }
                return real_file_name.split('.')[0];
            }
        }
        /**
         * @param selector 选择器
         * @param  file_path 文件路径
         * @param  isSidebar 是否是左边导航栏
         * @param  baseUrl 基准url
         */
    function load(selector, file_path, isSidebar, baseUrl) {
        baseUrl = baseUrl || blog_base;
        isSidebar = isSidebar || false;

        var p_url = baseUrl + file_path;

        console.log("load-->" + p_url);
        console.log(blog_base);
        console.log(app_name);
        $.get(p_url, function(data) {
            marked.setOptions({
                highlight: function(code) {
                    return hljs.highlightAuto(code).value;
                }
            });
            $(selector).html(marked(data));

            //处理所有scr
            $(selector).find('[href]').each(function() {
                var $element = $(this);
                var url = $element.attr('href');

                if (isAbsolute(url)) {
                    $element.attr('target', '_blank');
                }

                // sidebar
                if (isSidebar && isMarkdownFile(url)) {
                    $element.attr('href', '?' + url);

                }

                //main page
                if (!isAbsolute(url) && !isSidebar && isMarkdownFile(url) ) {
                    $element.attr('href', '?' + getPageBase(cur_md_path) + url);
                }
            });
            //title
            if (!isSidebar) {
                var mainTitle = $('#main-page').find('h1, h2, h3, h4, h5, h6').first().text();
                $('title').text(mainTitle);
            }

        }).fail(function(err) {
            if (err.status === 404) {
                console.log('404-->' + '/' + app_name + '/');
                console.log($._c);
                load('#main-page', '404.md', false, '/' + app_name + '/');
            }
        });
    }

    function read_config(callback) {
        $.getJSON('config.json', {}, function(data) {
            app_name = data.app_name || app_name;
            blog_base = '/' + app_name + '/p/';
            console.log('---read config');
            console.log(app_name + ' : ' + blog_base);
            callback();
        }).fail(function(err) {
            alert('读取配置有误');
        });
    }

    function main() {

        read_config(function() {
            //加载侧边菜单栏
            load('#sidebar-page', 'sidebar.md', true);
            //加载主内容页
            if(location.search.indexOf('&') !== -1){
                 cur_md_path = location.search.slice(1,  location.search.indexOf('&'));
             }else{
                 cur_md_path = location.search.slice(1,  location.search.length);
             }
            if (cur_md_path === '') {
                load('#main-page', 'home.md');
                console.log("load main~");
                //多说评论,若想不在首页显示评论框 那么：取消这一句注释
                //$('.ds-thread').removeClass('ds-thread');
            } else {
                load('#main-page', cur_md_path);
            }
        });
    }

    main();

})(jQuery);
<|endoftext|>


<commit_before>
var fbutil = require('./fbutil');
var DynamicPathMonitor = require('./DynamicPathMonitor');

function PathMonitor(esc, firebaseUrl, path) {
   this.ref = fbutil.fbRef(firebaseUrl, path.path);
   console.log('Indexing %s/%s using path "%s"'.grey, path.index, path.type, fbutil.pathName(this.ref));
   this.esc = esc;

   this.index = path.index;
   this.type  = path.type;
   this.filter = path.filter || function() { return true; };
   this.parse  = path.parser || function(data) { return extractKeys(data, path.fields) };

   this._init();
}

PathMonitor.prototype = {
   _init: function() {
      this.addMonitor = this.ref.on('child_added', this._process.bind(this, this._childAdded));
      this.changeMonitor = this.ref.on('child_changed', this._process.bind(this, this._childChanged));
      this.removeMonitor = this.ref.on('child_removed', this._process.bind(this, this._childRemoved));
   },

   _stop: function() {
      this.ref.off('child_added', this.addMonitor);
      this.ref.off('child_changed', this.changeMonitor);
      this.ref.off('child_removed', this.removeMonitor);
   },

   _process: function(fn, snap) {
      var dat = snap.val();
      if( this.filter(dat) ) {
         fn.call(this, snap.name(), this.parse(dat));
      }
   },

   _childAdded: function(key, data) {
      var name = nameFor(this, key);
      this.esc.index(this.index, this.type, data, key)
         .on('data', function(data) {
            console.log('indexed'.green, name);
         })
         .on('error', function(err) {
            console.error('failed to index %s: %s'.red, name, err);
         })
         .exec();
   },

   _childChanged: function(key, data) {
      var name = nameFor(this, key);
      this.esc.index(this.index, this.type, data, key)
         .on('data', function(data) {
            console.log('updated'.cyan, name);
         })
         .on('error', function(err) {
            console.error('failed to update %s: %s'.red, name, err);
         })
         .exec();
   },

   _childRemoved: function(key, data) {
      var name = nameFor(this, key);
      this.esc.deleteDocument(this.index, this.type, key, function(error, data) {
         if( error ) {
            console.error('failed to delete %s: %s'.red, name, error);
         }
         else {
            console.log('deleted'.cyan, name);
         }
      })
   }
};

function nameFor(path, key) {
   return path.index + '/' + path.type + '/' + key;
}

function extractKeys(data, fields) {
  var out = data;
  if( Array.isArray(fields) && fields.length && data && typeof(data) === 'object' ) {
    out = {};
    fields.forEach(function(f) {
      if( data.hasOwnProperty(f) ) {
        out[f] = data[f];
      }
    })
  }
  return out;
}

exports.process = function(esc, firebaseUrl, paths, dynamicPathUrl) {
   paths && paths.forEach(function(pathProps) {
      new PathMonitor(esc, firebaseUrl, pathProps);
   });
   if (dynamicPathUrl) {
      new DynamicPathMonitor(fbutil.fbRef(firebaseUrl, dynamicPathUrl), function(pathProps) {
        return new PathMonitor(esc, firebaseUrl, pathProps);
      });
   }
};
<commit_msg>Added omit fields to parser<commit_after>
var fbutil = require('./fbutil');
var DynamicPathMonitor = require('./DynamicPathMonitor');

function PathMonitor(esc, firebaseUrl, path) {
   this.ref = fbutil.fbRef(firebaseUrl, path.path);
   console.log('Indexing %s/%s using path "%s"'.grey, path.index, path.type, fbutil.pathName(this.ref));
   this.esc = esc;

   this.index = path.index;
   this.type  = path.type;
   this.filter = path.filter || function() { return true; };
   this.parse  = path.parser || function(data) { return parseKeys(data, path.fields, path.omit) };

   this._init();
}

PathMonitor.prototype = {
   _init: function() {
      this.addMonitor = this.ref.on('child_added', this._process.bind(this, this._childAdded));
      this.changeMonitor = this.ref.on('child_changed', this._process.bind(this, this._childChanged));
      this.removeMonitor = this.ref.on('child_removed', this._process.bind(this, this._childRemoved));
   },

   _stop: function() {
      this.ref.off('child_added', this.addMonitor);
      this.ref.off('child_changed', this.changeMonitor);
      this.ref.off('child_removed', this.removeMonitor);
   },

   _process: function(fn, snap) {
      var dat = snap.val();
      if( this.filter(dat) ) {
         fn.call(this, snap.name(), this.parse(dat));
      }
   },

   _childAdded: function(key, data) {
      var name = nameFor(this, key);
      this.esc.index(this.index, this.type, data, key)
         .on('data', function(data) {
            console.log('indexed'.green, name);
         })
         .on('error', function(err) {
            console.error('failed to index %s: %s'.red, name, err);
         })
         .exec();
   },

   _childChanged: function(key, data) {
      var name = nameFor(this, key);
      this.esc.index(this.index, this.type, data, key)
         .on('data', function(data) {
            console.log('updated'.cyan, name);
         })
         .on('error', function(err) {
            console.error('failed to update %s: %s'.red, name, err);
         })
         .exec();
   },

   _childRemoved: function(key, data) {
      var name = nameFor(this, key);
      this.esc.deleteDocument(this.index, this.type, key, function(error, data) {
         if( error ) {
            console.error('failed to delete %s: %s'.red, name, error);
         }
         else {
            console.log('deleted'.cyan, name);
         }
      })
   }
};

function nameFor(path, key) {
   return path.index + '/' + path.type + '/' + key;
}

function parseKeys(data, fields, omit) {
  if (!data || typeof(data)!=='object') {
    return data;
  }
  var out = data;
  // restrict to specified fields list
  if( Array.isArray(fields) && fields.length) {
    out = {};
    fields.forEach(function(f) {
      if( data.hasOwnProperty(f) ) {
        out[f] = data[f];
      }
    })
  }
  // remove omitted fields
  if( Array.isArray(omit) && omit.length) {
    omit.forEach(function(f) {
      if( out.hasOwnProperty(f) ) {
        delete out[f];
      }
    })
  }
  return out;
}

exports.process = function(esc, firebaseUrl, paths, dynamicPathUrl) {
   paths && paths.forEach(function(pathProps) {
      new PathMonitor(esc, firebaseUrl, pathProps);
   });
   if (dynamicPathUrl) {
      new DynamicPathMonitor(fbutil.fbRef(firebaseUrl, dynamicPathUrl), function(pathProps) {
        return new PathMonitor(esc, firebaseUrl, pathProps);
      });
   }
};
<|endoftext|>


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

define([
    "firebug/lib/object",
    "firebug/firebug",
    "firebug/lib/domplate",
    "firebug/chrome/reps",
    "firebug/lib/locale",
    "firebug/lib/events",
    "firebug/lib/css",
    "firebug/lib/dom",
    "firebug/lib/string",
    "firebug/lib/options",
],
function(Obj, Firebug, Domplate, FirebugReps, Locale, Events, Css, Dom, Str, Options) {

with (Domplate) {

// ********************************************************************************************* //
// Constants

var TraceError = FBTrace.to("DBG_ERRORS");
var Trace = FBTrace.to("DBG_BREAKNOTIFICATION");

// ********************************************************************************************* //
// Breakpoint Notification

/**
 * Construct a break notification popup
 * @param doc the document to contain the notification
 * @param cause info object for the popup, with these optional fields:
 *   strings: title, message, attrName
 *   elements: target, relatedTarget: element
 *   objects: prevValue, newValue
 */
function BreakNotification(cause)
{
    this.cause = cause;
}

BreakNotification.prototype = domplate(Firebug.Rep,
/** @lends Firebug.ScriptPanel.Notification */
{
    tag:
        DIV({"class": "notificationBox"},
            TABLE({"class": "notificationTable", onclick: "$onHide",
                onmouseover: "$onMouseOver", onmouseout: "$onMouseOut"},
                TBODY(
                    TR(
                        TD({"class": "imageCol"},
                            IMG({"class": "notificationImage",
                                src: "chrome://firebug/skin/breakpoint.png"})
                        ),
                        TD({"class": "descCol"},
                            SPAN({"class": "notificationDesc"}, "$cause|getDescription"),
                            SPAN(" "),
                            SPAN({"class": "diff"}, "$cause|getDiff"),
                            SPAN({"class": "targets"}),
                            DIV({"class": "noNotificationDesc"})
                        ),
                        TD({"class": "buttonsCol"},
                            BUTTON({"class": "notificationButton copyButton",
                                onclick: "$onCopyAction",
                                $collapsed: "$cause|hideCopyAction"},
                                Locale.$STR("Copy")
                            ),
                            BUTTON({"class": "notificationButton skipButton",
                                onclick: "$onSkipAction",
                                $collapsed: "$cause|hideSkipAction"},
                                Locale.$STR("script.balloon.Disable")
                            ),
                            BUTTON({"class": "notificationButton okButton",
                                onclick: "$onOkAction",
                                $collapsed: "$cause|hideOkAction"},
                                Locale.$STR("script.balloon.Continue")
                            )
                        ),
                        TD(
                            DIV({"class": "notificationClose", onclick: "$onHide"})
                        )
                    )
                )
            )
        ),

    targets:
        SPAN(
            SPAN(" "),
            TAG("$cause|getTargetTag", {object: "$cause.target"}),
            SPAN(" "),
            TAG("$cause|getRelatedTargetTag", {object: "$cause.relatedNode"})
        ),

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

    onMouseOver: function(event)
    {
        var target = event.target;
        var box = Dom.getAncestorByClass(target, "notificationBox");
        var close = box.querySelector(".notificationClose");

        // The close button is "active" (red) if the mouse hovers over the notification
        // area except when it hovers over a button or link.
        var localName = target.localName ? target.localName.toLowerCase() : "";
        if (Css.hasClass(target, "notificationButton") || localName == "a")
            close.removeAttribute("active");
        else
            close.setAttribute("active", true);
    },

    onMouseOut: function(event)
    {
        var box = Dom.getAncestorByClass(event.target, "notificationBox");
        var close = box.querySelector(".notificationClose");
        close.removeAttribute("active");
    },

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

    onHide: function(event)
    {
        var notify = this.getNotifyObject(event.target);
        notify.hide();
    },

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

    getDescription: function(cause)
    {
        var str = cause.message + (cause.attrName ? (" '" + cause.attrName + "'") : "");
        if (this.getDiff(cause))
            str += ":";

        return str;
    },

    getTargetTag: function(cause)
    {
        return this.getElementTag(cause.target) || null;
    },

    getRelatedTargetTag: function(cause)
    {
        return this.getElementTag(cause.relatedNode) || null;
    },

    getElementTag: function(node)
    {
        if (node)
        {
            var rep = Firebug.getRep(node);
            if (rep)
                return rep.shortTag || rep.tag;
        }
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Button Handlers

    hideCopyAction: function(cause)
    {
        return !cause.copyAction;
    },

    hideSkipAction: function(cause)
    {
        return !cause.skipAction;
    },

    hideOkAction: function(cause)
    {
        return !cause.okAction;
    },

    onCopyAction: function(event)
    {
        var notify = this.getNotifyObject(event.target);
        if (notify.cause.copyAction)
            notify.cause.copyAction();
    },

    onSkipAction: function(event)
    {
        var notify = this.getNotifyObject(event.target);
        if (notify.cause.skipAction)
            notify.cause.skipAction();
    },

    onOkAction: function(event)
    {
        var notify = this.getNotifyObject(event.target);
        if (notify.cause.okAction)
            notify.cause.okAction();
    },

    onCloseAction: function(event)
    {
        var notify = this.getNotifyObject(event.target);
        if (notify.cause.onCloseAction)
            notify.cause.onCloseAction();
        else
            notify.hide(event); // same as click on notify body
    },

    getNotifyObject: function(target)
    {
        var parentNode = Dom.getAncestorByClass(target, "notificationBox");
        return parentNode.repObject;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Action handlers from "do not show again" description

    onClickLink: function(event)
    {
        this.showTabMenu(event);
    },

    disableNotifications: function(event)
    {
        Firebug.setPref(Firebug.prefDomain, "showBreakNotification", false);

        // Hide the notification, but default processing of this event would hide it anyway.
        this.onHide(event);
    },

    showTabMenu: function(event)
    {
        // Open panel's tab menu to show the "Show Break Notifications" option
        // to teach the user where to enable it again.
        var panelBar = Firebug.chrome.$("fbPanelBar1");
        var tab = panelBar.getTab("script");
        tab.tabMenu.showMenu();

        // Avoid default processing that hides the notification popup.
        Events.cancelEvent(event);
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Helpers

    getDiff: function(cause)
    {
        var str = "";

        if (cause.prevValue)
            str += Str.cropString(cause.prevValue, 40) + " -> ";

        if (cause.newValue)
            str += Str.cropString(cause.newValue, 40);

        if (!str.length)
            return "";

        if (!cause.target)
            return str;

        return str;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Public

    show: function(parentNode)
    {
        Trace.sysout("breakNotification.show;");

        // Reneder the entire notification box.
        this.box = this.tag.append(this.cause, parentNode, this);
        this.box.repObject = this;

        // Appends the HTML targets dynamically. In case they are null, it breaks
        // click events.
        // xxxHonza: this problem would deserve clarification.
        if (this.cause.target || this.cause.relatedNode)
        {
            var targetsNode = this.box.querySelector(".targets");
            this.targets.replace(this.cause, targetsNode, this);
        }

        // Render "do not show again" text
        var descNode = this.box.querySelector(".noNotificationDesc");
        FirebugReps.Description.render(Locale.$STR("firebug.breakpoint.doNotShowBreakNotification2"),
            descNode, Obj.bind(this.onClickLink, this));

        // Tooltips
        if (this.cause.skipActionTooltip)
            this.box.querySelector(".skipButton").setAttribute("title", this.cause.skipActionTooltip);
        if (this.cause.okActionTooltip)
            this.box.querySelector(".okButton").setAttribute("title", this.cause.okActionTooltip);
        if (this.cause.copyActionTooltip)
            this.box.querySelector(".copyButton").setAttribute("title", this.cause.copyActionTooltip);

        // xxxHonza: disable the animation, the interval seems to be frozen during debugger break.
        this.box.style.top = "0";
        return;

        // Animation
        var self = this;
        var delta = Math.max(3, Math.floor(this.box.clientHeight/5));
        var clientHeight = this.box.clientHeight;

        this.box.style.top = -clientHeight + "px";
        var interval = setInterval(function slide(event)
        {
            var top = parseInt(self.box.style.top, 10);
            if (top >= 0)
            {
                clearInterval(interval);
            }
            else
            {
                var newTop = (top + delta) > 0 ? 0 : (top + delta);
                self.box.style.top = newTop + "px";
            }
        }, 15);

        return this.box;
    },

    hide: function()
    {
        Trace.sysout("breakNotification.hide; " + this.box);

        // xxxHonza: disable the animation, the interval seems to be frozen during debugger break.
        if (this.box.parentNode)
            this.box.parentNode.removeChild(this.box);
        return;

        // Animation
        var self = this;
        var delta = Math.max(3, Math.floor(this.box.clientHeight/5));
        var clientHeight = this.box.clientHeight;
        var top = 0;

        var interval = setInterval(function slide(event)
        {
            top = top - delta;
            if (top < -clientHeight)
            {
                clearInterval(interval);

                if (self.box.parentNode)
                    self.box.parentNode.removeChild(self.box);
            }
            else
            {
                self.box.style.top = top + "px";
            }
        }, 15);
    }
});

// ********************************************************************************************* //
// Public API

BreakNotification.show = function(context, parentNode, breakType)
{
    Trace.sysout("BreakNotification.show");

    // There is a global option that can be used to swith off the break notification
    // (it can be annoying sometimes)
    if (!Options.get("showBreakNotification"))
        return;

    // If there is no breaking cause object, there is nothing to display so, bail out.
    if (!context.breakingCause)
        return;

    var box = new BreakNotification(context.breakingCause);
    box.show(parentNode);

    // Remember the box, we need to hide it when the debugger is resumed.
    context.breakingCauseBox = box;

    delete context.breakingCause;

    return box;
}

BreakNotification.hide = function(context)
{
    var box = context.breakingCauseBox;
    if (box)
        box.hide();

    delete context.breakingCauseBox;
}

// ********************************************************************************************* //
// Registration

return BreakNotification;

// ********************************************************************************************* //
}});
<commit_msg>Fix typos + use strict<commit_after>/* See license.txt for terms of usage */

define([
    "firebug/lib/object",
    "firebug/firebug",
    "firebug/lib/domplate",
    "firebug/chrome/reps",
    "firebug/lib/locale",
    "firebug/lib/events",
    "firebug/lib/css",
    "firebug/lib/dom",
    "firebug/lib/string",
    "firebug/lib/options",
],
function(Obj, Firebug, Domplate, FirebugReps, Locale, Events, Css, Dom, Str, Options) {

"use strict";

// ********************************************************************************************* //
// Constants

var {domplate, DIV, TABLE, TBODY, TR, TD, IMG, SPAN, BUTTON, TAG} = Domplate;

var TraceError = FBTrace.to("DBG_ERRORS");
var Trace = FBTrace.to("DBG_BREAKNOTIFICATION");

// ********************************************************************************************* //
// Breakpoint Notification

/**
 * @domplate Construct a break notification popup
 *
 * @param doc the document to contain the notification
 * @param cause info object for the popup, with these optional fields:
 *   strings: title, message, attrName
 *   elements: target, relatedTarget: element
 *   objects: prevValue, newValue
 */
function BreakNotification(cause)
{
    this.cause = cause;
}

BreakNotification.prototype = domplate(Firebug.Rep,
/** @lends BreakNotification */
{
    tag:
        DIV({"class": "notificationBox"},
            TABLE({"class": "notificationTable", onclick: "$onHide",
                onmouseover: "$onMouseOver", onmouseout: "$onMouseOut"},
                TBODY(
                    TR(
                        TD({"class": "imageCol"},
                            IMG({"class": "notificationImage",
                                src: "chrome://firebug/skin/breakpoint.png"})
                        ),
                        TD({"class": "descCol"},
                            SPAN({"class": "notificationDesc"}, "$cause|getDescription"),
                            SPAN(" "),
                            SPAN({"class": "diff"}, "$cause|getDiff"),
                            SPAN({"class": "targets"}),
                            DIV({"class": "noNotificationDesc"})
                        ),
                        TD({"class": "buttonsCol"},
                            BUTTON({"class": "notificationButton copyButton",
                                onclick: "$onCopyAction",
                                $collapsed: "$cause|hideCopyAction"},
                                Locale.$STR("Copy")
                            ),
                            BUTTON({"class": "notificationButton skipButton",
                                onclick: "$onSkipAction",
                                $collapsed: "$cause|hideSkipAction"},
                                Locale.$STR("script.balloon.Disable")
                            ),
                            BUTTON({"class": "notificationButton okButton",
                                onclick: "$onOkAction",
                                $collapsed: "$cause|hideOkAction"},
                                Locale.$STR("script.balloon.Continue")
                            )
                        ),
                        TD(
                            DIV({"class": "notificationClose", onclick: "$onHide"})
                        )
                    )
                )
            )
        ),

    targets:
        SPAN(
            SPAN(" "),
            TAG("$cause|getTargetTag", {object: "$cause.target"}),
            SPAN(" "),
            TAG("$cause|getRelatedTargetTag", {object: "$cause.relatedNode"})
        ),

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

    onMouseOver: function(event)
    {
        var target = event.target;
        var box = Dom.getAncestorByClass(target, "notificationBox");
        var close = box.querySelector(".notificationClose");

        // The close button is "active" (red) if the mouse hovers over the notification
        // area except when it hovers over a button or link.
        var localName = target.localName ? target.localName.toLowerCase() : "";
        if (Css.hasClass(target, "notificationButton") || localName == "a")
            close.removeAttribute("active");
        else
            close.setAttribute("active", true);
    },

    onMouseOut: function(event)
    {
        var box = Dom.getAncestorByClass(event.target, "notificationBox");
        var close = box.querySelector(".notificationClose");
        close.removeAttribute("active");
    },

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

    onHide: function(event)
    {
        var notify = this.getNotifyObject(event.target);
        notify.hide();
    },

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

    getDescription: function(cause)
    {
        var str = cause.message + (cause.attrName ? (" '" + cause.attrName + "'") : "");
        if (this.getDiff(cause))
            str += ":";

        return str;
    },

    getTargetTag: function(cause)
    {
        return this.getElementTag(cause.target) || null;
    },

    getRelatedTargetTag: function(cause)
    {
        return this.getElementTag(cause.relatedNode) || null;
    },

    getElementTag: function(node)
    {
        if (node)
        {
            var rep = Firebug.getRep(node);
            if (rep)
                return rep.shortTag || rep.tag;
        }
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Button Handlers

    hideCopyAction: function(cause)
    {
        return !cause.copyAction;
    },

    hideSkipAction: function(cause)
    {
        return !cause.skipAction;
    },

    hideOkAction: function(cause)
    {
        return !cause.okAction;
    },

    onCopyAction: function(event)
    {
        var notify = this.getNotifyObject(event.target);
        if (notify.cause.copyAction)
            notify.cause.copyAction();
    },

    onSkipAction: function(event)
    {
        var notify = this.getNotifyObject(event.target);
        if (notify.cause.skipAction)
            notify.cause.skipAction();
    },

    onOkAction: function(event)
    {
        var notify = this.getNotifyObject(event.target);
        if (notify.cause.okAction)
            notify.cause.okAction();
    },

    onCloseAction: function(event)
    {
        var notify = this.getNotifyObject(event.target);
        if (notify.cause.onCloseAction)
            notify.cause.onCloseAction();
        else
            notify.hide(event); // same as click on notify body
    },

    getNotifyObject: function(target)
    {
        var parentNode = Dom.getAncestorByClass(target, "notificationBox");
        return parentNode.repObject;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Action handlers from "do not show again" description

    onClickLink: function(event)
    {
        this.showTabMenu(event);
    },

    disableNotifications: function(event)
    {
        Firebug.setPref(Firebug.prefDomain, "showBreakNotification", false);

        // Hide the notification, but default processing of this event would hide it anyway.
        this.onHide(event);
    },

    showTabMenu: function(event)
    {
        // Open panel's tab menu to show the "Show Break Notifications" option
        // to teach the user where to enable it again.
        var panelBar = Firebug.chrome.$("fbPanelBar1");
        var tab = panelBar.getTab("script");
        tab.tabMenu.showMenu();

        // Avoid default processing that hides the notification popup.
        Events.cancelEvent(event);
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Helpers

    getDiff: function(cause)
    {
        var str = "";

        if (cause.prevValue)
            str += Str.cropString(cause.prevValue, 40) + " -> ";

        if (cause.newValue)
            str += Str.cropString(cause.newValue, 40);

        if (!str.length)
            return "";

        if (!cause.target)
            return str;

        return str;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    // Public

    show: function(parentNode)
    {
        Trace.sysout("breakNotification.show;");

        // Render the entire notification box.
        this.box = this.tag.append(this.cause, parentNode, this);
        this.box.repObject = this;

        // Appends the HTML targets dynamically. In case they are null, it breaks
        // click events.
        // xxxHonza: this problem would deserve clarification.
        if (this.cause.target || this.cause.relatedNode)
        {
            var targetsNode = this.box.querySelector(".targets");
            this.targets.replace(this.cause, targetsNode, this);
        }

        // Render "do not show again" text
        var descNode = this.box.querySelector(".noNotificationDesc");
        FirebugReps.Description.render(Locale.$STR("firebug.breakpoint.doNotShowBreakNotification2"),
            descNode, Obj.bind(this.onClickLink, this));

        // Tooltips
        if (this.cause.skipActionTooltip)
            this.box.querySelector(".skipButton").setAttribute("title", this.cause.skipActionTooltip);
        if (this.cause.okActionTooltip)
            this.box.querySelector(".okButton").setAttribute("title", this.cause.okActionTooltip);
        if (this.cause.copyActionTooltip)
            this.box.querySelector(".copyButton").setAttribute("title", this.cause.copyActionTooltip);

        // xxxHonza: disable the animation, the interval seems to be frozen during debugger break.
        this.box.style.top = "0";
        return;

        // Animation
        var self = this;
        var delta = Math.max(3, Math.floor(this.box.clientHeight/5));
        var clientHeight = this.box.clientHeight;

        this.box.style.top = -clientHeight + "px";
        var interval = setInterval(function slide(event)
        {
            var top = parseInt(self.box.style.top, 10);
            if (top >= 0)
            {
                clearInterval(interval);
            }
            else
            {
                var newTop = (top + delta) > 0 ? 0 : (top + delta);
                self.box.style.top = newTop + "px";
            }
        }, 15);

        return this.box;
    },

    hide: function()
    {
        Trace.sysout("breakNotification.hide; " + this.box);

        // xxxHonza: disable the animation, the interval seems to be frozen during debugger break.
        if (this.box.parentNode)
            this.box.parentNode.removeChild(this.box);
        return;

        // Animation
        var self = this;
        var delta = Math.max(3, Math.floor(this.box.clientHeight/5));
        var clientHeight = this.box.clientHeight;
        var top = 0;

        var interval = setInterval(function slide(event)
        {
            top = top - delta;
            if (top < -clientHeight)
            {
                clearInterval(interval);

                if (self.box.parentNode)
                    self.box.parentNode.removeChild(self.box);
            }
            else
            {
                self.box.style.top = top + "px";
            }
        }, 15);
    }
});

// ********************************************************************************************* //
// Public API

BreakNotification.show = function(context, parentNode, breakType)
{
    Trace.sysout("BreakNotification.show");

    // There is a global option that can be used to switch off the break notification
    // (it can be annoying sometimes)
    if (!Options.get("showBreakNotification"))
        return;

    // If there is no breaking cause object, there is nothing to display so, bail out.
    if (!context.breakingCause)
        return;

    var box = new BreakNotification(context.breakingCause);
    box.show(parentNode);

    // Remember the box, we need to hide it when the debugger is resumed.
    context.breakingCauseBox = box;

    delete context.breakingCause;

    return box;
}

BreakNotification.hide = function(context)
{
    var box = context.breakingCauseBox;
    if (box)
        box.hide();

    delete context.breakingCauseBox;
}

// ********************************************************************************************* //
// Registration

return BreakNotification;

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


<commit_before>angular.module('PaperUI', [
  'PaperUI.controllers',
  'PaperUI.controllers.control',
  'PaperUI.controllers.setup',
  'PaperUI.controllers.configuration',
  'PaperUI.controllers.extension',
  'PaperUI.controllers.rules',
  'PaperUI.services',
  'PaperUI.services.rest',
  'PaperUI.services.repositories',
  'PaperUI.extensions',
  'ngRoute',
  'ngResource',
  'ngMaterial',
  'ngMessages'
]).config(['$routeProvider', '$httpProvider', 'globalConfig', function($routeProvider, httpProvider, globalConfig) {
  $routeProvider.
	when('/control', {templateUrl: 'partials/control.html', controller: 'ControlPageController', title: 'Control', simpleHeader: true}).
	when('/setup', {redirectTo: '/inbox/search'}).
	when('/inbox', {redirectTo: '/inbox/search'}).
	when('/inbox/search', {templateUrl: 'partials/setup.html', controller: 'InboxController', title: 'Inbox'}).
	when('/inbox/manual-setup/choose', {templateUrl: 'partials/setup.html', controller: 'ManualSetupChooseController', title: 'Inbox'}).
	when('/inbox/manual-setup/configure/:thingTypeUID', {templateUrl: 'partials/setup.html', controller: 'ManualSetupConfigureController', title: 'Inbox'}).
	when('/inbox/setup', {templateUrl: 'partials/setup.html', controller: 'SetupWizardController', title: 'Inbox'}).
	when('/inbox/setup/bindings', {templateUrl: 'partials/setup.html', controller: 'SetupWizardController', title: 'Inbox'}).
	when('/inbox/setup/search/:bindingId', {templateUrl: 'partials/setup.html', controller: 'SetupWizardController', title: 'Inbox'}).
	when('/inbox/setup/thing-types/:bindingId', {templateUrl: 'partials/setup.html', controller: 'SetupWizardController', title: 'Inbox'}).
	when('/inbox/setup/add/:thingTypeUID', {templateUrl: 'partials/setup.html', controller: 'SetupWizardController', title: 'Inbox'}).
	when('/configuration', {redirectTo: '/configuration/bindings'}).
	when('/configuration/bindings', {templateUrl: 'partials/configuration.html', controller: 'ConfigurationPageController', title: 'Configuration'}).
	when('/configuration/services', {templateUrl: 'partials/configuration.html', controller: 'ConfigurationPageController', title: 'Configuration'}).
	when('/configuration/groups', {templateUrl: 'partials/configuration.html', controller: 'ConfigurationPageController', title: 'Configuration'}).
	when('/configuration/things', {templateUrl: 'partials/configuration.html', controller: 'ConfigurationPageController', title: 'Configuration'}).
	when('/configuration/things/view/:thingUID', {templateUrl: 'partials/configuration.html', controller: 'ConfigurationPageController', title: 'Configuration'}).
	when('/configuration/things/edit/:thingUID', {templateUrl: 'partials/configuration.html', controller: 'ConfigurationPageController', title: 'Configuration'}).
	when('/extensions', {templateUrl: 'partials/extensions.html', controller: 'ExtensionPageController', title: 'Extensions'}).
	when('/rules', {templateUrl: 'partials/rules.html', controller: 'RulesPageController', title: 'Rules'}).
	when('/rules/new', {templateUrl: 'partials/rules.html', controller: 'RulesPageController', title: 'Rules'}).
	when('/rules/view/:ruleUID', {templateUrl: 'partials/rules.html', controller: 'RulesPageController', title: 'Rules'}).
	when('/rules/configure/:ruleUID', {templateUrl: 'partials/rules.html', controller: 'RulesPageController', title: 'Rules'}).
	when('/preferences', {templateUrl: 'partials/preferences.html', controller: 'PreferencesPageController', title: 'Preferences'});
    if(globalConfig.defaultRoute) {
        $routeProvider.otherwise({redirectTo: globalConfig.defaultRoute});
    } else {
        $routeProvider.otherwise({redirectTo: '/control'});
    }
}]).directive('editableitemstate', function(){
    return function($scope, $element) {
        $element.context.addEventListener('focusout', function(e){
            $scope.sendCommand($($element).html());
        });
    };
}).directive('onFinishRender', function ($timeout) {
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            if (scope.$last === true) {
                $timeout(function () {
                    scope.$emit('ngRepeatFinished');
                });
            }
        }
    }
}).directive('isrequired', function(){
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attrs,ngModel){

        	 element[0].addEventListener('click', function(){
        		 scope.$watch(attrs.ngModel, function(value) {
         			if((value===undefined || value=="") && attrs.isrequired)
         			element.addClass('border-invalid');
         			else
         				element.removeClass('border-invalid');
         	});             });

        }
    };
}).run(['$location', '$rootScope', 'globalConfig', function($location, $rootScope, globalConfig) {
	var original = $location.path;
	$rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
	 	if (current.hasOwnProperty('$$route')) {
        	$rootScope.title = current.$$route.title;
        	$rootScope.simpleHeader = current.$$route.simpleHeader;
        }
        $rootScope.path = $location.path().split('/');
        $rootScope.section = $rootScope.path[1];
        $rootScope.page = $rootScope.path[2];
    });
    $rootScope.asArray = function (object) {
        return $.isArray(object) ? object : object ? [ object ] : [] ;
    }
    $rootScope.itemUpdates = {};
    $rootScope.data = [];
    $rootScope.navigateToRoot = function() {
        $location.path('');
    }
    $rootScope.$location = $location;
    var advancedMode = localStorage.getItem('paperui.advancedMode');
    if(advancedMode !== 'true' && advancedMode !== 'false') {
        $rootScope.advancedMode = globalConfig.advancedDefault;
    } else {
        $rootScope.advancedMode = advancedMode === 'true';
    }

}]);<commit_msg>fixed link from Conigurations->Things->+ to Inbox<commit_after>angular.module('PaperUI', [
  'PaperUI.controllers',
  'PaperUI.controllers.control',
  'PaperUI.controllers.setup',
  'PaperUI.controllers.configuration',
  'PaperUI.controllers.extension',
  'PaperUI.controllers.rules',
  'PaperUI.services',
  'PaperUI.services.rest',
  'PaperUI.services.repositories',
  'PaperUI.extensions',
  'ngRoute',
  'ngResource',
  'ngMaterial',
  'ngMessages'
]).config(['$routeProvider', '$httpProvider', 'globalConfig', function($routeProvider, httpProvider, globalConfig) {
  $routeProvider.
	when('/control', {templateUrl: 'partials/control.html', controller: 'ControlPageController', title: 'Control', simpleHeader: true}).
	when('/setup', {redirectTo: '/inbox/search'}).
	when('/inbox', {redirectTo: '/inbox/search'}).
	when('/inbox/setup', {redirectTo : '/inbox/setup/bindings'}).
	when('/inbox/search', {templateUrl: 'partials/setup.html', controller: 'InboxController', title: 'Inbox'}).
	when('/inbox/manual-setup/choose', {templateUrl: 'partials/setup.html', controller: 'ManualSetupChooseController', title: 'Inbox'}).
	when('/inbox/manual-setup/configure/:thingTypeUID', {templateUrl: 'partials/setup.html', controller: 'ManualSetupConfigureController', title: 'Inbox'}).
	when('/inbox/setup/bindings', {templateUrl: 'partials/setup.html', controller: 'SetupWizardController', title: 'Inbox'}).
	when('/inbox/setup/search/:bindingId', {templateUrl: 'partials/setup.html', controller: 'SetupWizardController', title: 'Inbox'}).
	when('/inbox/setup/thing-types/:bindingId', {templateUrl: 'partials/setup.html', controller: 'SetupWizardController', title: 'Inbox'}).
	when('/inbox/setup/add/:thingTypeUID', {templateUrl: 'partials/setup.html', controller: 'SetupWizardController', title: 'Inbox'}).
	when('/configuration', {redirectTo: '/configuration/bindings'}).
	when('/configuration/bindings', {templateUrl: 'partials/configuration.html', controller: 'ConfigurationPageController', title: 'Configuration'}).
	when('/configuration/services', {templateUrl: 'partials/configuration.html', controller: 'ConfigurationPageController', title: 'Configuration'}).
	when('/configuration/groups', {templateUrl: 'partials/configuration.html', controller: 'ConfigurationPageController', title: 'Configuration'}).
	when('/configuration/things', {templateUrl: 'partials/configuration.html', controller: 'ConfigurationPageController', title: 'Configuration'}).
	when('/configuration/things/view/:thingUID', {templateUrl: 'partials/configuration.html', controller: 'ConfigurationPageController', title: 'Configuration'}).
	when('/configuration/things/edit/:thingUID', {templateUrl: 'partials/configuration.html', controller: 'ConfigurationPageController', title: 'Configuration'}).
	when('/extensions', {templateUrl: 'partials/extensions.html', controller: 'ExtensionPageController', title: 'Extensions'}).
	when('/rules', {templateUrl: 'partials/rules.html', controller: 'RulesPageController', title: 'Rules'}).
	when('/rules/new', {templateUrl: 'partials/rules.html', controller: 'RulesPageController', title: 'Rules'}).
	when('/rules/view/:ruleUID', {templateUrl: 'partials/rules.html', controller: 'RulesPageController', title: 'Rules'}).
	when('/rules/configure/:ruleUID', {templateUrl: 'partials/rules.html', controller: 'RulesPageController', title: 'Rules'}).
	when('/preferences', {templateUrl: 'partials/preferences.html', controller: 'PreferencesPageController', title: 'Preferences'});
    if(globalConfig.defaultRoute) {
        $routeProvider.otherwise({redirectTo: globalConfig.defaultRoute});
    } else {
        $routeProvider.otherwise({redirectTo: '/control'});
    }
}]).directive('editableitemstate', function(){
    return function($scope, $element) {
        $element.context.addEventListener('focusout', function(e){
            $scope.sendCommand($($element).html());
        });
    };
}).directive('onFinishRender', function ($timeout) {
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            if (scope.$last === true) {
                $timeout(function () {
                    scope.$emit('ngRepeatFinished');
                });
            }
        }
    }
}).directive('isrequired', function(){
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attrs,ngModel){

        	 element[0].addEventListener('click', function(){
        		 scope.$watch(attrs.ngModel, function(value) {
         			if((value===undefined || value=="") && attrs.isrequired)
         			element.addClass('border-invalid');
         			else
         				element.removeClass('border-invalid');
         	});             });

        }
    };
}).run(['$location', '$rootScope', 'globalConfig', function($location, $rootScope, globalConfig) {
	var original = $location.path;
	$rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
	 	if (current.hasOwnProperty('$$route')) {
        	$rootScope.title = current.$$route.title;
        	$rootScope.simpleHeader = current.$$route.simpleHeader;
        }
        $rootScope.path = $location.path().split('/');
        $rootScope.section = $rootScope.path[1];
        $rootScope.page = $rootScope.path[2];
    });
    $rootScope.asArray = function (object) {
        return $.isArray(object) ? object : object ? [ object ] : [] ;
    }
    $rootScope.itemUpdates = {};
    $rootScope.data = [];
    $rootScope.navigateToRoot = function() {
        $location.path('');
    }
    $rootScope.$location = $location;
    var advancedMode = localStorage.getItem('paperui.advancedMode');
    if(advancedMode !== 'true' && advancedMode !== 'false') {
        $rootScope.advancedMode = globalConfig.advancedDefault;
    } else {
        $rootScope.advancedMode = advancedMode === 'true';
    }

}]);<|endoftext|>


<commit_before>import test from 'ava'
import sleep from 'sleep-promise'

import { SpacebroClient } from '../src/spacebro-client'

const SB_TEST_ADDRESS = process.env.SB_TEST_ADDRESS || 'spacebro.space'
const SB_TEST_PORT = process.env.SB_TEST_PORT || 3333

test('connect', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-connect',
    client: {name: 'connect1'},
    verbose: false
  })

  client.on('connect', () => {
    t.pass('Connected')
  })
  await sleep(5000)
})

test('connect - Wrong address', async (t) => {
  const client = new SpacebroClient({
    host: 'a.wrong.address',
    port: 12345,
    channelName: 'spacebro-client-test-connect',
    client: {name: 'connect2'},
    verbose: false
  })

  client.on('connect_error', (err) => {
    t.pass('Connection error')
    t.skip.is(err, 'Cannot find server at address "a.wrong.address:12345"')
  })
  await sleep(5000)
})

test('connect - Wrong port', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: 12345,
    channelName: 'spacebro-client-test-connect',
    client: {name: 'connect3'},
    verbose: false
  })

  client.on('connect_error', (err) => {
    t.pass('Connection error')
    t.skip.is(err, 'Cannot connect to server - wrong port')
  })
  await sleep(5000)
})

test('connect - Delayed', async (t) => {
  const client = new SpacebroClient({
    host: 'whatever',
    port: 12345,
    channelName: 'spacebro-client-test-connect-delayed',
    client: {name: 'connect'},
    verbose: false
  }, false)

  client.connect(SB_TEST_ADDRESS, SB_TEST_PORT)
  client.on('connect', () => {
    t.pass('Connected')
  })
  await sleep(5000)
})

test('connect - Without host', (t) => {
  const consoleWarn = console.warn
  const warnings = []
  console.warn = (message) => warnings.push(message)

  /* eslint-disable no-new */
  new SpacebroClient({
    port: 12345,
    verbose: false
  })

  console.warn = consoleWarn
  t.deepEqual(warnings, ['Cannot connect without host address and port'])
})

test('connect - Without port', (t) => {
  const consoleWarn = console.warn
  const warnings = []
  console.warn = (message) => warnings.push(message)

  /* eslint-disable no-new */
  new SpacebroClient({
    host: SB_TEST_ADDRESS,
    verbose: false
  })

  console.warn = consoleWarn
  t.deepEqual(warnings, ['Cannot connect without host address and port'])
})

test.serial('disconnect', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-disconnect',
    client: {name: 'connect4'},
    verbose: false
  })

  t.plan(2)

  client.on('connect', async () => {
    const consoleError = console.error
    const errors = []

    console.error = (err) => {
      errors.push(err)
    }

    client.on('disconnect', () => t.pass('Disconnected'))
    client.disconnect()
    client.emit('what', () => 'ever')

    t.deepEqual(errors, [
      'Error: "connect4" is disconnected and cannot emit "what"'
    ])
    console.error = consoleError
  })
  await sleep(5000)
})

test('connect with connection', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-connect-connection',
    client: {name: 'connect-connections'},
    verbose: false,
    connection: 'chokibro/outMedia => etna/inMedia'
  })

  client.on('connections', (data) => {
    t.deepEqual(data, [{
      src: {
        clientName: 'chokibro',
        eventName: 'outMedia'
      },
      tgt: {
        clientName: 'etna',
        eventName: 'inMedia'
      }
    }])
  })
  await sleep(5000)
})

test('receive data with connection', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-receive-data-connection',
    client: {name: 'connect-connections'},
    verbose: false,
    connection: 'connect-connections/outMedia => connect-connections/inMedia'
  })

  client.on('connect', () => {
    client.emit('outMedia', {
      that: 'message'
    })
  })

  client.on('inMedia', (data) => {
    t.deepEqual(data, {
      that: 'message',
      _to: null,
      _from: 'connect-connections'
    })
  })
  await sleep(5000)
})

test('receive two data with connection', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-receive-two-data-connection',
    client: {name: 'connect-connections'},
    verbose: false,
    connection: 'connect-connections/outMedia => connect-connections/inMedia'
  })

  client.on('connect', () => {
    client.emit('outMedia', {
      that: 'message'
    }, {
      this: 'message'
    })
  })

  client.on('inMedia', (data1, data2) => {
    t.deepEqual(data1, {
      that: 'message',
      _to: null,
      _from: 'connect-connections'
    })
    t.deepEqual(data2, {
      this: 'message'
    })
  })
  await sleep(5000)
})

test('receive one string and one data with connection', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-receive-string-data-connection',
    client: {name: 'connect-connections'},
    verbose: false,
    connection: 'connect-connections/outMedia => connect-connections/inMedia'
  })

  client.on('connect', () => {
    client.emit('outMedia', 'create', {
      this: 'message'
    })
  })

  client.on('inMedia', (data1, data2) => {
    t.is(data1, 'create')
    t.deepEqual(data2, {
      this: 'message'
    })
  })
  await sleep(5000)
})

test('connect with connections', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-connect-connections',
    client: {name: 'connect-connections'},
    verbose: false,
    connection: [
      'chokibro/outMedia => etna/inMedia',
      'foo/outMedia => bar/inMedia'
    ]
  })

  client.on('connections', (data) => {
    t.deepEqual(data, [
      {
        src: {
          clientName: 'chokibro',
          eventName: 'outMedia'
        },
        tgt: {
          clientName: 'etna',
          eventName: 'inMedia'
        }
      }, {
        src: {
          clientName: 'foo',
          eventName: 'outMedia'
        },
        tgt: {
          clientName: 'bar',
          eventName: 'inMedia'
        }
      }
    ])
  })
  await sleep(5000)
})
<commit_msg>test socket.io acknowledgments<commit_after>import test from 'ava'
import sleep from 'sleep-promise'

import { SpacebroClient } from '../src/spacebro-client'

const SB_TEST_ADDRESS = process.env.SB_TEST_ADDRESS || 'spacebro.space'
const SB_TEST_PORT = process.env.SB_TEST_PORT || 3333

test('connect', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-connect',
    client: {name: 'connect1'},
    verbose: false
  })

  client.on('connect', () => {
    t.pass('Connected')
  })
  await sleep(5000)
})

test('connect - Wrong address', async (t) => {
  const client = new SpacebroClient({
    host: 'a.wrong.address',
    port: 12345,
    channelName: 'spacebro-client-test-connect',
    client: {name: 'connect2'},
    verbose: false
  })

  client.on('connect_error', (err) => {
    t.pass('Connection error')
    t.skip.is(err, 'Cannot find server at address "a.wrong.address:12345"')
  })
  await sleep(5000)
})

test('connect - Wrong port', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: 12345,
    channelName: 'spacebro-client-test-connect',
    client: {name: 'connect3'},
    verbose: false
  })

  client.on('connect_error', (err) => {
    t.pass('Connection error')
    t.skip.is(err, 'Cannot connect to server - wrong port')
  })
  await sleep(5000)
})

test('connect - Delayed', async (t) => {
  const client = new SpacebroClient({
    host: 'whatever',
    port: 12345,
    channelName: 'spacebro-client-test-connect-delayed',
    client: {name: 'connect'},
    verbose: false
  }, false)

  client.connect(SB_TEST_ADDRESS, SB_TEST_PORT)
  client.on('connect', () => {
    t.pass('Connected')
  })
  await sleep(5000)
})

test('connect - Without host', (t) => {
  const consoleWarn = console.warn
  const warnings = []
  console.warn = (message) => warnings.push(message)

  /* eslint-disable no-new */
  new SpacebroClient({
    port: 12345,
    verbose: false
  })

  console.warn = consoleWarn
  t.deepEqual(warnings, ['Cannot connect without host address and port'])
})

test('connect - Without port', (t) => {
  const consoleWarn = console.warn
  const warnings = []
  console.warn = (message) => warnings.push(message)

  /* eslint-disable no-new */
  new SpacebroClient({
    host: SB_TEST_ADDRESS,
    verbose: false
  })

  console.warn = consoleWarn
  t.deepEqual(warnings, ['Cannot connect without host address and port'])
})

test.serial('disconnect', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-disconnect',
    client: {name: 'connect4'},
    verbose: false
  })

  t.plan(2)

  client.on('connect', async () => {
    const consoleError = console.error
    const errors = []

    console.error = (err) => {
      errors.push(err)
    }

    client.on('disconnect', () => t.pass('Disconnected'))
    client.disconnect()
    client.emit('what', () => 'ever')

    t.deepEqual(errors, [
      'Error: "connect4" is disconnected and cannot emit "what"'
    ])
    console.error = consoleError
  })
  await sleep(5000)
})

test('connect with connection', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-connect-connection',
    client: {name: 'connect-connections'},
    verbose: false,
    connection: 'chokibro/outMedia => etna/inMedia'
  })

  client.on('connections', (data) => {
    t.deepEqual(data, [{
      src: {
        clientName: 'chokibro',
        eventName: 'outMedia'
      },
      tgt: {
        clientName: 'etna',
        eventName: 'inMedia'
      }
    }])
  })
  await sleep(5000)
})

test('receive data with connection', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-receive-data-connection',
    client: {name: 'connect-connections'},
    verbose: false,
    connection: 'connect-connections/outMedia => connect-connections/inMedia'
  })

  client.on('connect', () => {
    client.emit('outMedia', {
      that: 'message'
    })
  })

  client.on('inMedia', (data) => {
    t.deepEqual(data, {
      that: 'message',
      _to: null,
      _from: 'connect-connections'
    })
  })
  await sleep(5000)
})

test('receive two data with connection', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-receive-two-data-connection',
    client: {name: 'connect-connections'},
    verbose: false,
    connection: 'connect-connections/outMedia => connect-connections/inMedia'
  })

  client.on('connect', () => {
    client.emit('outMedia', {
      that: 'message'
    }, {
      this: 'message'
    })
  })

  client.on('inMedia', (data1, data2) => {
    t.deepEqual(data1, {
      that: 'message',
      _to: null,
      _from: 'connect-connections'
    })
    t.deepEqual(data2, {
      this: 'message'
    })
  })
  await sleep(5000)
})

test('receive one string and one data with connection', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-receive-string-data-connection',
    client: {name: 'connect-connections'},
    verbose: false,
    connection: 'connect-connections/outMedia => connect-connections/inMedia'
  })

  client.on('connect', () => {
    client.emit('outMedia', 'create', {
      this: 'message'
    })
  })

  client.on('inMedia', (data1, data2) => {
    t.is(data1, 'create')
    t.deepEqual(data2, {
      this: 'message'
    })
  })
  await sleep(5000)
})

test('receive ack with connection', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-receive-ack-connection',
    client: {name: 'connect-connections'},
    verbose: false,
    connection: 'connect-connections/outMedia => connect-connections/inMedia'
  })

  client.on('connect', () => {
    client.emit('outMedia', {
      that: 'message'
    }, function (data) {
      t.is(data, '_pong')
    })
  })

  client.on('inMedia', (data, fn) => {
    fn('_pong')
  })
  await sleep(5000)
})

test('connect with connections', async (t) => {
  const client = new SpacebroClient({
    host: SB_TEST_ADDRESS,
    port: SB_TEST_PORT,
    channelName: 'spacebro-client-test-connect-connections',
    client: {name: 'connect-connections'},
    verbose: false,
    connection: [
      'chokibro/outMedia => etna/inMedia',
      'foo/outMedia => bar/inMedia'
    ]
  })

  client.on('connections', (data) => {
    t.deepEqual(data, [
      {
        src: {
          clientName: 'chokibro',
          eventName: 'outMedia'
        },
        tgt: {
          clientName: 'etna',
          eventName: 'inMedia'
        }
      }, {
        src: {
          clientName: 'foo',
          eventName: 'outMedia'
        },
        tgt: {
          clientName: 'bar',
          eventName: 'inMedia'
        }
      }
    ])
  })
  await sleep(5000)
})
<|endoftext|>


<commit_before>module('Segment');
test('new Segment(point)', function() {
	var segment = new Segment(new Point(10, 10));
	var expected = { point: { x: 10, y: 10 } };
	compareSegments(segment, expected);
});

test('new Segment(x, y)', function() {
	var segment = new Segment(10, 10);
	var expected = { point: { x: 10, y: 10 } };
	compareSegments(segment, expected);
});

test('new Segment(object)', function() {
	var segment = new Segment({ point: { x: 10, y: 10 }, handleIn: { x: 5, y: 5 }, handleOut: { x: 15, y: 15 } });
	var expected = { point: { x: 10, y: 10 }, handleIn: { x: 5, y: 5 }, handleOut: { x: 15, y: 15 } };
	compareSegments(segment, expected);
});

test('new Segment(point, handleIn, handleOut)', function() {
	var segment = new Segment(new Point(10, 10), new Point(5, 5), new Point(15, 15));
	var expected = { point: { x: 10, y: 10 }, handleIn: { x: 5, y: 5 }, handleOut: { x: 15, y: 15 } };
	compareSegments(segment, expected);
});

test('new Segment(x, y, inX, inY, outX, outY)', function() {
	var segment = new Segment(10, 10, 5, 5, 15, 15);
	var expected = { point: { x: 10, y: 10 }, handleIn: { x: 5, y: 5 }, handleOut: { x: 15, y: 15 } };
	compareSegments(segment, expected);
});

test('segment.reverse()', function() {
	var segment = new Segment(new Point(10, 10), new Point(5, 5), new Point(15, 15));
	segment = segment.reverse();
	var expected = { point: { x: 10, y: 10 }, handleIn: { x: 15, y: 15 }, handleOut: { x: 5, y: 5 } };
	compareSegments(segment, expected);
});

test('segment.clone()', function() {
	var segment = new Segment(new Point(10, 10), new Point(5, 5), new Point(15, 15));
	var clone = segment.clone();
	equals(segment == clone, false);
	compareSegments(segment, clone);
});

test('segment.remove()', function() {
	var doc = new Document();
	var path = new Path([10, 10], [5, 5], [10, 10]);
	path.segments[1].remove();
	equals(path.segments.length, 2);
});<commit_msg>Segment tests: add a test for segment selection.<commit_after>module('Segment');
test('new Segment(point)', function() {
	var segment = new Segment(new Point(10, 10));
	var expected = { point: { x: 10, y: 10 } };
	compareSegments(segment, expected);
});

test('new Segment(x, y)', function() {
	var segment = new Segment(10, 10);
	var expected = { point: { x: 10, y: 10 } };
	compareSegments(segment, expected);
});

test('new Segment(object)', function() {
	var segment = new Segment({ point: { x: 10, y: 10 }, handleIn: { x: 5, y: 5 }, handleOut: { x: 15, y: 15 } });
	var expected = { point: { x: 10, y: 10 }, handleIn: { x: 5, y: 5 }, handleOut: { x: 15, y: 15 } };
	compareSegments(segment, expected);
});

test('new Segment(point, handleIn, handleOut)', function() {
	var segment = new Segment(new Point(10, 10), new Point(5, 5), new Point(15, 15));
	var expected = { point: { x: 10, y: 10 }, handleIn: { x: 5, y: 5 }, handleOut: { x: 15, y: 15 } };
	compareSegments(segment, expected);
});

test('new Segment(x, y, inX, inY, outX, outY)', function() {
	var segment = new Segment(10, 10, 5, 5, 15, 15);
	var expected = { point: { x: 10, y: 10 }, handleIn: { x: 5, y: 5 }, handleOut: { x: 15, y: 15 } };
	compareSegments(segment, expected);
});

test('segment.reverse()', function() {
	var segment = new Segment(new Point(10, 10), new Point(5, 5), new Point(15, 15));
	segment = segment.reverse();
	var expected = { point: { x: 10, y: 10 }, handleIn: { x: 15, y: 15 }, handleOut: { x: 5, y: 5 } };
	compareSegments(segment, expected);
});

test('segment.clone()', function() {
	var segment = new Segment(new Point(10, 10), new Point(5, 5), new Point(15, 15));
	var clone = segment.clone();
	equals(segment == clone, false);
	compareSegments(segment, clone);
});

test('segment.remove()', function() {
	var doc = new Document();
	var path = new Path([10, 10], [5, 5], [10, 10]);
	path.segments[1].remove();
	equals(path.segments.length, 2);
});

test('segment.selected', function() {
	var doc = new Document();
	var path = new Path([10, 20], [50, 100]);
	path.segments[0].point.selected = true;
	equals(path.segments[0].point.selected, true);

	path.segments[0].point.selected = false;
	equals(path.segments[0].point.selected, false);
});<|endoftext|>


<commit_before>var path = require('path'),
    _ = require('underscore'),
    seq = require('seq'),
    urlTools = require('url-tools'),
    AssetGraph = require('../');

module.exports = function (queryObj) {
    var stylus;
    try {
        stylus = require('stylus');
    } catch (e) {
        throw new Error('transforms.compileStylusToCss: The "stylus" module is required. Please run "npm install stylus" and try again (tested with version 0.23.0).');
    }

    return function compileStylusToCss(assetGraph, cb) {
        seq(assetGraph.findAssets(_.extend({type: 'Stylus'}, queryObj)))
            .parEach(function (stylusAsset) {
                var stylusOptions = {},
                    nonInlineAncestor = stylusAsset.nonInlineAncestor,
                    stylusRenderer = stylus(stylusAsset.text);
                // If the Stylus asset has a file:// url, tell the renderer so relative urls in @import statements work:
                if (/^file:/.test(nonInlineAncestor.url)) {
                    stylusRenderer.set('paths', [path.dirname(urlTools.fileUrlToFsPath(nonInlineAncestor.url))]);
                }
                stylusRenderer.render(this.into(stylusAsset.id));
            })
            .parEach(function (stylusAsset) {
                var cssAsset = new AssetGraph.Css({
                    text: this.vars[stylusAsset.id]
                });
                if (stylusAsset.url) {
                    cssAsset.url = stylusAsset.url.replace(/\.styl$|$/, cssAsset.defaultExtension);
                }
                stylusAsset.replaceWith(cssAsset);
                this();
            })
            .seq(function () {
                cb();
            })
            ['catch'](cb);
    };
};
<commit_msg>compileStylusToCss.js<commit_after>var path = require('path'),
    _ = require('underscore'),
    seq = require('seq'),
    urlTools = require('url-tools'),
    AssetGraph = require('../');

module.exports = function (queryObj) {
    var stylus;
    try {
        stylus = require('stylus');
    } catch (e) {
        throw new Error('transforms.compileStylusToCss: The "stylus" module is required. Please run "npm install stylus" and try again (tested with version 0.23.0).');
    }

    return function compileStylusToCss(assetGraph, cb) {
        seq(assetGraph.findAssets(_.extend({type: 'Stylus'}, queryObj)))
            .parEach(function (stylusAsset) {
                var nonInlineAncestor = stylusAsset.nonInlineAncestor,
                    stylusRenderer = stylus(stylusAsset.text);
                // If the Stylus asset has a file:// url, tell the renderer so relative urls in @import statements work:
                if (/^file:/.test(nonInlineAncestor.url)) {
                    stylusRenderer.set('paths', [path.dirname(urlTools.fileUrlToFsPath(nonInlineAncestor.url))]);
                }
                stylusRenderer.render(this.into(stylusAsset.id));
            })
            .parEach(function (stylusAsset) {
                var cssAsset = new AssetGraph.Css({
                    text: this.vars[stylusAsset.id]
                });
                if (stylusAsset.url) {
                    cssAsset.url = stylusAsset.url.replace(/\.styl$|$/, cssAsset.defaultExtension);
                }
                stylusAsset.replaceWith(cssAsset);
                this();
            })
            .seq(function () {
                cb();
            })['catch'](cb);
    };
};
<|endoftext|>


<commit_before>var _ = require('underscore'),
    seq = require('seq'),
    uglifyJs = require('uglify-js-papandreou'),
    passError = require('passerror'),
    compressorsByName = {};

compressorsByName.uglifyJs = function (assetGraph, javaScript, compressorOptions, cb) {
    compressorOptions = _.extend({no_warnings: true}, compressorOptions);
    process.nextTick(function () {
        cb(null, new assetGraph.JavaScript({
            parseTree: uglifyJs.uglify.ast_squeeze(uglifyJs.uglify.ast_mangle(javaScript.parseTree, compressorOptions), compressorOptions)
        }));
    });
};

compressorsByName.yuicompressor = function (assetGraph, javaScript, compressorOptions, cb) {
    var yuicompressor;
    try {
        yuicompressor = require('yui-compressor');
    } catch (e) {
        return cb(new Error("transforms.compressJavaScript: node-yui-compressor not found. Please run 'npm install yui-compressor' and try again (tested with version 0.1.3)."));
    }
    compressorOptions = compressorOptions || {};
    yuicompressor.compile(javaScript.text, compressorOptions, passError(cb, function (compressedText) {
        cb(null, new assetGraph.JavaScript({
            text: compressedText
        }));
    }));
};

compressorsByName.closurecompiler = function (assetGraph, javaScript, compressorOptions, cb) {
    var closurecompiler;
    try {
        closurecompiler = require('closure-compiler');
    } catch (e) {
        return cb(new Error("transforms.compressJavaScript: node-closure-compiler not found. Please run 'npm install closure-compiler' and try again (tested with version 0.1.1)."));
    }
    compressorOptions = compressorOptions || {};
    closurecompiler.compile(javaScript.text, compressorOptions, passError(cb, function (compressedText) {
        cb(null, new assetGraph.JavaScript({
            text: compressedText
        }));
    }));
};

module.exports = function (queryObj, compressorName, compressorOptions) {
    if (!compressorName) {
        compressorName = 'uglifyJs';
    }
    if (!(compressorName in compressorsByName)) {
        throw new Error("transforms.compressJavaScript: Unknown compressor: " + compressorName);
    }
    return function compressJavaScript(assetGraph, cb) {
        seq(assetGraph.findAssets(_.extend({type: 'JavaScript'}, queryObj)))
            .parEach(function (javaScript) {
                compressorsByName[compressorName](assetGraph, javaScript, compressorOptions, this.into(javaScript.id));
            })
            .parEach(function (javaScript) {
                var compressedJavaScript = this.vars[javaScript.id];
                javaScript.replaceWith(compressedJavaScript);
                // FIXME: These belong elsewhere:
                compressedJavaScript.quoteChar = javaScript.quoteChar;
                compressedJavaScript.initialComments = javaScript.initialComments;
                this();
            })
            .seq(function () {
                cb();
            })
            ['catch'](cb);
    };
};
<commit_msg>compressJavaScript transform: Preserve the copyright notice comments of the original asset.<commit_after>var _ = require('underscore'),
    seq = require('seq'),
    uglifyJs = require('uglify-js-papandreou'),
    passError = require('passerror'),
    compressorsByName = {};

compressorsByName.uglifyJs = function (assetGraph, javaScript, compressorOptions, cb) {
    compressorOptions = _.extend({no_warnings: true}, compressorOptions);
    process.nextTick(function () {
        cb(null, new assetGraph.JavaScript({
            copyrightNoticeComments: javaScript.copyrightNoticeComments,
            parseTree: uglifyJs.uglify.ast_squeeze(uglifyJs.uglify.ast_mangle(javaScript.parseTree, compressorOptions), compressorOptions)
        }));
    });
};

compressorsByName.yuicompressor = function (assetGraph, javaScript, compressorOptions, cb) {
    var yuicompressor;
    try {
        yuicompressor = require('yui-compressor');
    } catch (e) {
        return cb(new Error("transforms.compressJavaScript: node-yui-compressor not found. Please run 'npm install yui-compressor' and try again (tested with version 0.1.3)."));
    }
    compressorOptions = compressorOptions || {};
    yuicompressor.compile(javaScript.text, compressorOptions, passError(cb, function (compressedText) {
        cb(null, new assetGraph.JavaScript({
            copyrightNoticeComments: javaScript.copyrightNoticeComments,
            text: compressedText
        }));
    }));
};

compressorsByName.closurecompiler = function (assetGraph, javaScript, compressorOptions, cb) {
    var closurecompiler;
    try {
        closurecompiler = require('closure-compiler');
    } catch (e) {
        return cb(new Error("transforms.compressJavaScript: node-closure-compiler not found. Please run 'npm install closure-compiler' and try again (tested with version 0.1.1)."));
    }
    compressorOptions = compressorOptions || {};
    closurecompiler.compile(javaScript.text, compressorOptions, passError(cb, function (compressedText) {
        cb(null, new assetGraph.JavaScript({
            copyrightNoticeComments: javaScript.copyrightNoticeComments,
            text: compressedText
        }));
    }));
};

module.exports = function (queryObj, compressorName, compressorOptions) {
    if (!compressorName) {
        compressorName = 'uglifyJs';
    }
    if (!(compressorName in compressorsByName)) {
        throw new Error("transforms.compressJavaScript: Unknown compressor: " + compressorName);
    }
    return function compressJavaScript(assetGraph, cb) {
        seq(assetGraph.findAssets(_.extend({type: 'JavaScript'}, queryObj)))
            .parEach(function (javaScript) {
                compressorsByName[compressorName](assetGraph, javaScript, compressorOptions, this.into(javaScript.id));
            })
            .parEach(function (javaScript) {
                var compressedJavaScript = this.vars[javaScript.id];
                javaScript.replaceWith(compressedJavaScript);
                // FIXME: These belong elsewhere:
                compressedJavaScript.quoteChar = javaScript.quoteChar;
                compressedJavaScript.initialComments = javaScript.initialComments;
                this();
            })
            .seq(function () {
                cb();
            })
            ['catch'](cb);
    };
};
<|endoftext|>


<commit_before>import { LOCATION_CHANGE } from 'react-router-redux';
import { uniq, keys } from 'lodash';

import {
  UPDATE_CONFIGURATION,
  ENTITY_HOLD,
  RELEASE_HOLD,
  ENTITY_HOVER_START,
  ENTITY_HOVER_END,
  RELEASE_SYNC_LOCK,
  TOP_LEVEL_ENTITY_CREATE,
  CANCEL_TOP_LEVEL_ENTITY_CREATE,
} from 'store/actions/sector.actions';
import {
  SAVE_SECTOR,
  UPDATE_ENTITIES,
  DELETE_ENTITIES,
  UPDATE_ID_MAPPING,
} from 'store/actions/entity.actions';
import { INITIALIZE, LOGGED_IN, LOGGED_OUT } from 'store/actions/user.actions';

import { generateSectorName } from 'utils/name-generator';
import { ROWS, COLUMNS } from 'constants/defaults';
import Entities from 'constants/entities';

const initialState = {
  renderSector: false,
  currentSector: null,
  currentEntityType: null,
  currentEntity: null,
  saved: [],
  shared: [],
  holdKey: null,
  hoverKey: null,
  topLevelKey: null,
  syncLock: false,
  configuration: {
    name: generateSectorName(),
    isBuilder: false,
    columns: COLUMNS,
    rows: ROWS,
  },
};

export default function sector(state = initialState, action) {
  switch (action.type) {
    case LOCATION_CHANGE: {
      const { pathname } = action.payload;
      if (['/', '/configure'].indexOf(pathname) >= 0) {
        return {
          ...initialState,
          renderSector: false,
          saved: state.saved,
          shared: state.shared,
          configuration: {
            ...initialState.configuration,
            name: generateSectorName(),
          },
        };
      }
      if (pathname.startsWith('/sector/')) {
        return {
          ...state,
          renderSector: true,
          currentSector: pathname.split('/')[2],
          currentEntityType: pathname.split('/')[3],
          currentEntity: pathname.split('/')[4],
        };
      }
      return {
        ...state,
        renderSector: false,
      };
    }
    case SAVE_SECTOR:
    case UPDATE_ENTITIES:
      return {
        ...state,
        saved: uniq([...state.saved, state.currentSector]).filter(s => s),
        holdKey: null,
        hoverKey: null,
        topLevelKey: null,
        syncLock: true,
      };
    case DELETE_ENTITIES: {
      const deletedSectorIds = action.entities[Entities.sector.key] || [];
      return {
        ...state,
        saved: state.saved.filter(
          saveId => deletedSectorIds.indexOf(saveId) < 0,
        ),
        holdKey: null,
        hoverKey: null,
        topLevelKey: null,
        syncLock: true,
      };
    }
    case LOGGED_IN:
      return {
        ...state,
        saved: keys(action.entities[Entities.sector.key] || {}),
      };
    case LOGGED_OUT:
      return {
        ...state,
        saved: [],
      };
    case UPDATE_ID_MAPPING:
      return {
        ...state,
        saved: state.saved.map(saveId => action.mapping[saveId] || saveId),
      };
    case UPDATE_CONFIGURATION:
      return {
        ...state,
        configuration: {
          ...state.configuration,
          [action.key]: action.value,
        },
      };
    case ENTITY_HOLD:
      return { ...state, holdKey: action.key };
    case RELEASE_HOLD:
      return { ...state, holdKey: null };
    case ENTITY_HOVER_START:
      return { ...state, hoverKey: action.key };
    case ENTITY_HOVER_END:
      return { ...state, hoverKey: null };
    case RELEASE_SYNC_LOCK:
      return { ...state, syncLock: false };
    case INITIALIZE:
      return { ...state, saved: action.saved, shared: action.shared };
    case TOP_LEVEL_ENTITY_CREATE:
      return { ...state, topLevelKey: action.key };
    case CANCEL_TOP_LEVEL_ENTITY_CREATE:
      return { ...state, topLevelKey: null };
    default:
      return state;
  }
}
<commit_msg>Protect the changelog from rendering the last sector<commit_after>import { LOCATION_CHANGE } from 'react-router-redux';
import { uniq, keys } from 'lodash';

import {
  UPDATE_CONFIGURATION,
  ENTITY_HOLD,
  RELEASE_HOLD,
  ENTITY_HOVER_START,
  ENTITY_HOVER_END,
  RELEASE_SYNC_LOCK,
  TOP_LEVEL_ENTITY_CREATE,
  CANCEL_TOP_LEVEL_ENTITY_CREATE,
} from 'store/actions/sector.actions';
import {
  SAVE_SECTOR,
  UPDATE_ENTITIES,
  DELETE_ENTITIES,
  UPDATE_ID_MAPPING,
} from 'store/actions/entity.actions';
import { INITIALIZE, LOGGED_IN, LOGGED_OUT } from 'store/actions/user.actions';

import { generateSectorName } from 'utils/name-generator';
import { ROWS, COLUMNS } from 'constants/defaults';
import Entities from 'constants/entities';

const initialState = {
  renderSector: false,
  currentSector: null,
  currentEntityType: null,
  currentEntity: null,
  saved: [],
  shared: [],
  holdKey: null,
  hoverKey: null,
  topLevelKey: null,
  syncLock: false,
  configuration: {
    name: generateSectorName(),
    isBuilder: false,
    columns: COLUMNS,
    rows: ROWS,
  },
};

export default function sector(state = initialState, action) {
  switch (action.type) {
    case LOCATION_CHANGE: {
      const { pathname } = action.payload;
      if (['/', '/configure', '/changelog'].indexOf(pathname) >= 0) {
        return {
          ...initialState,
          renderSector: false,
          saved: state.saved,
          shared: state.shared,
          configuration: {
            ...initialState.configuration,
            name: generateSectorName(),
          },
        };
      }
      if (pathname.startsWith('/sector/')) {
        return {
          ...state,
          renderSector: true,
          currentSector: pathname.split('/')[2],
          currentEntityType: pathname.split('/')[3],
          currentEntity: pathname.split('/')[4],
        };
      }
      return {
        ...state,
        renderSector: false,
      };
    }
    case SAVE_SECTOR:
    case UPDATE_ENTITIES:
      return {
        ...state,
        saved: uniq([...state.saved, state.currentSector]).filter(s => s),
        holdKey: null,
        hoverKey: null,
        topLevelKey: null,
        syncLock: true,
      };
    case DELETE_ENTITIES: {
      const deletedSectorIds = action.entities[Entities.sector.key] || [];
      return {
        ...state,
        saved: state.saved.filter(
          saveId => deletedSectorIds.indexOf(saveId) < 0,
        ),
        holdKey: null,
        hoverKey: null,
        topLevelKey: null,
        syncLock: true,
      };
    }
    case LOGGED_IN:
      return {
        ...state,
        saved: keys(action.entities[Entities.sector.key] || {}),
      };
    case LOGGED_OUT:
      return {
        ...state,
        saved: [],
      };
    case UPDATE_ID_MAPPING:
      return {
        ...state,
        saved: state.saved.map(saveId => action.mapping[saveId] || saveId),
      };
    case UPDATE_CONFIGURATION:
      return {
        ...state,
        configuration: {
          ...state.configuration,
          [action.key]: action.value,
        },
      };
    case ENTITY_HOLD:
      return { ...state, holdKey: action.key };
    case RELEASE_HOLD:
      return { ...state, holdKey: null };
    case ENTITY_HOVER_START:
      return { ...state, hoverKey: action.key };
    case ENTITY_HOVER_END:
      return { ...state, hoverKey: null };
    case RELEASE_SYNC_LOCK:
      return { ...state, syncLock: false };
    case INITIALIZE:
      return { ...state, saved: action.saved, shared: action.shared };
    case TOP_LEVEL_ENTITY_CREATE:
      return { ...state, topLevelKey: action.key };
    case CANCEL_TOP_LEVEL_ENTITY_CREATE:
      return { ...state, topLevelKey: null };
    default:
      return state;
  }
}
<|endoftext|>