<commit_before>define(function(require, exports, module) {
    plugin.consumes = ["eventbus", "history", "token_store", "fs", "editor", "config", "background", "menu"];
    plugin.provides = ["open_ui"];
    return plugin;

    function plugin(opts, imports, register) {
        var eventbus = imports.eventbus;
        var history = imports.history;
        var tokenStore = imports.token_store;
        var fs = imports.fs;
        var editor = imports.editor;
        var config = imports.config;
        var background = imports.background;
        var menu = imports.menu;

        var options = require("./lib/options");
        var icons = require("./lib/icons");
        var filterList = require("./lib/filter_list");
        var dropbox = require("./lib/dropbox");
        var githubUi = require("./open/github");

        var defaultConfig = JSON.parse(require("text!../config/default/preferences.json"));

        eventbus.declare("urlchanged");

        var builtinProjects;

        if (window.isNodeWebkit) {
            builtinProjects = [{
                name: "Local Folder",
                url: "node:"
            }, {
                name: "Remote Zedrem Folder",
                url: "zedrem:"
            }, {
                name: "Github Repository",
                url: "gh:"
            }, {
                name: "Configuration",
                html: "Configuration ",
                url: "nwconfig:"
            }, {
                name: "Manual",
                url: "manual:"
            }];
        } else {
            builtinProjects = [{
                name: "Local Folder",
                url: "local:"
            }, {
                name: "Remote Zedrem Folder",
                url: "zedrem:"
            }, {
                name: "Github Repository",
                url: "gh:"
            }, {
                name: "Dropbox Folder",
                url: "dropbox:"
            }, {
                name: "Notes",
                url: "syncfs:",
            }, {
                name: "Configuration",
                html: "Configuration ",
                url: "config:"
            }, {
                name: "Manual",
                url: "manual:"
            }];
        }

        var viewEl, headerEl, phraseEl, listEl;

        var closed = false;

        var api = {
            openInNewWindow: false,
            boot: function() {
                config.loadConfiguration().then(function() {
                    if (closed) {
                        return;
                    }
                    api.showOpenUi();
                    var enable = config.getPreference("enableAnalytics");
                    var showMenus = config.getPreference("showMenus");
                    if (enable === undefined || showMenus === undefined) {
                        api.firstRun();
                    }
                });
            },
            showOpenUi: function() {
                menu.disabled = true;
                viewEl = $("

<input type='text' id='phrase' placeholder='Filter list'>

");
                $("body").append(viewEl);
                headerEl = viewEl.find("h1");
                phraseEl = viewEl.find("#phrase");
                listEl = viewEl.find("#item-list");
                api.fadeOutBackground();
                eventbus.once("editorloaded", function() {
                    api.fadeOutBackground();
                });
                api.projectList();
            },
            close: function() {
                menu.disabled = false;
                closed = true;
                api.fadeInBackground();
                viewEl && viewEl.remove();
            },
            fadeOutBackground: function() {
                $(".ace_editor").css("opacity", 0.3);
                $(".pathbar").css("opacity", 0.3);
            },
            fadeInBackground: function() {
                $(".ace_editor").css("opacity", "");
                $(".pathbar").css("opacity", "");
            },
            projectList: function() {
                headerEl.text("Open in Zed");
                history.getProjects().then(function(projects) {
                    if (projects.length > 0) {
                        projects.splice(0, 0, {
                            section: "Recently Opened"
                        });
                    }
                    projects.push({
                        section: "Other"
                    });
                    projects = projects.concat(builtinProjects);

                    var items = projects.map(function(project) {
                        if (project.section) {
                            return project;
                        }
                        return {
                            name: project.name,
                            url: project.url,
                            html: "" + (project.html ? project.html : project.name)
                        };
                    });

                    phraseEl.val("");
                    phraseEl.focus();
                    filterList({
                        inputEl: phraseEl,
                        resultsEl: listEl,
                        list: items,
                        onSelect: function(b) {
                            if (b === "set-config-dir") {
                                api.close();
                                zed.getService("configfs").storeLocalFolder().then(function() {
                                    api.showOpenUi();
                                });
                                return;
                            }
                            switch (b.url) {
                                case "gh:":
                                    api.github().then(function(repo) {
                                        if (repo) {
                                            api.open(repo.repo + " [" + repo.branch + "]", "gh:" + repo.repo + ":" + repo.branch);
                                        } else {
                                            api.showOpenUi();
                                        }
                                    });
                                    break;
                                case "dropbox:":
                                    api.dropbox().then(function(url) {
                                        if (url) {
                                            api.open(url.slice("dropbox:".length), url);
                                        } else {
                                            api.showOpenUi();
                                        }
                                    });
                                    break;
                                case "local:":
                                    api.localChrome().then(function(data) {
                                        console.log("Picked a folder", data);
                                        if (data) {
                                            api.open(data.title, data.url);
                                        } else {
                                            api.showOpenUi();
                                        }
                                    });
                                    break;
                                case "zedrem:":
                                    api.zedrem().then(function(url) {
                                        if (url) {
                                            api.open("Zedrem Project", url);
                                        } else {
                                            api.showOpenUi();
                                        }
                                    });
                                    break;
                                case "manual:":
                                    background.openProject("Manual", "manual:");
                                    // Using return instead of break to avoid closing
                                    return api.projectList();
                                default:
                                    api.open(b.name, b.url);
                            }
                            api.close();
                        },
                        onCancel: function() {
                            if (!fs.isEmpty) {
                                viewEl.remove();
                                api.fadeInBackground();
                                editor.getActiveEditor().focus();
                            }
                        },
                        onDelete: function(b) {
                            items.splice(items.indexOf(b), 1);
                            history.removeProject(b.url);
                        }
                    });
                }).
                catch (function(err) {
                    console.error("Error", err);
                });
            },
            open: function(title, url) {
                if (api.openInNewWindow) {
                    background.openProject(title, url);
                } else {
                    options.set("title", title);
                    options.set("url", url);
                    eventbus.emit("urlchanged");
                }
            },
            firstRun: function() {
                return new Promise(function(resolve, reject) {
                    var el = $("

");
                    $("body").append(el);
                    $.get("/firstrun.html", function(html) {
                        el.html(html);
                        $("#enable").change(function() {
                            config.setPreference("enableAnalytics", $("#enable").is(":checked"));
                        });

                        $("#menubar").change(function() {
                            config.setPreference("showMenus", $("#menubar").is(":checked"));
                        });

                        $("#done").click(function() {
                            el.remove();
                            resolve();
                        });

                        $("td").click(function(event) {
                            var target = $(event.target).parents("td");
                            $("td").removeClass("selected");
                            $(target).addClass("selected");
                            var mode = target.data("mode");
                            console.log("Mode selected", mode);
                            switch (mode) {
                                case "traditional":
                                    config.setPreference("showMenus", true);
                                    config.setPreference("persistentTree", true);
                                    break;
                                case "chromeless":
                                    config.setPreference("showMenus", $("#menubar").is(":checked"));
                                    config.setPreference("persistentTree", false);
                                    break;
                                default:
                                    console.log("Unknown mode", mode)
                            }
                        });

                        setTimeout(function() {
                            config.setPreference("enableAnalytics", true);
                            config.setPreference("showMenus", false);
                            config.setPreference("persistentTree", false);
                        }, 1000);
                    });
                });
            },
            githubAuth: function(githubToken) {
                return new Promise(function(resolve, reject) {
                    var el = $("

");
                    $("body").append(el);
                    $.get("/open/github_token.html", function(html) {
                        el.html(html);
                        $("#token-form").submit(function(event) {
                            event.preventDefault();
                            verifyToken($("#token").val());
                        });
                        $("#cancel").click(function() {
                            close();
                            resolve();
                        });

                        $("#token").val(githubToken);

                        function close() {
                            el.remove();
                            resolve();
                        }

                        function verifyToken(token) {
                            $.ajax({
                                type: "GET",
                                url: "https://api.github.com/user?access_token=" + token,
                                dataType: "json",
                                processData: false,
                                success: function() {
                                    tokenStore.set("githubToken", token);
                                    resolve(token);
                                    close();
                                },
                                error: function() {
                                    $("#hint").text("Invalid token");
                                }
                            });
                        }
                    });

                });
            },
            github: function() {
                return tokenStore.get("githubToken").then(function(githubToken) {
                    if (!githubToken) {
                        return api.githubAuth().then(function(githubToken) {
                            if (githubToken) {
                                return pick(githubToken);
                            } else {
                                console.log("Shoing project list again");
                                api.projectList();
                                return;
                            }
                        });
                    } else {
                        return pick(githubToken);
                    }
                });

                function pick(githubToken) {
                    return githubUi(githubToken)(headerEl, phraseEl, listEl);
                }
            },
            dropbox: function() {
                return new Promise(function(resolve) {
                    var el = $("

Pick a Dropbox Folder

Authenticating...
<button id='logout'>Logout</button>
");
                    $("body").append(el);

                    dropbox.authenticate(function(err, dropbox) {
                        if (err) {
                            close();
                            return api.projectList();
                        }

                        var treeEl = $("#dropbox-tree");
                        treeEl.focus();
                        $("#logout").click(function() {
                            dropbox.signOut(close);
                        });

                        function open(path) {
                            resolve("dropbox:" + path);
                        }

                        function readDir(path, callback) {
                            dropbox.readdir(path, function(err, resultStrings, dirState, entries) {
                                if (err) {
                                    return callback(err);
                                }
                                var dirs = [];
                                entries.forEach(function(entry) {
                                    if (entry.isFolder) {
                                        dirs.push({
                                            title: entry.name,
                                            key: entry.path,
                                            isFolder: true,
                                            isLazy: true
                                        });
                                    }
                                });
                                callback(null, dirs);
                            });
                        }

                        function renderInitialTree(err, children) {
                            treeEl.dynatree({
                                onActivate: function(node) {
                                    open(node.data.key);
                                    close();
                                },
                                onLazyRead: function(node) {
                                    readDir(node.data.key, function(err, dirs) {
                                        if (err) {
                                            return console.error(err);
                                        }
                                        dirs.forEach(function(dir) {
                                            node.addChild(dir);
                                        });
                                        node.setLazyNodeStatus(DTNodeStatus_Ok);
                                    });
                                },
                                onKeydown: function(node, event) {
                                    if (event.keyCode === 27) {
                                        close();
                                    }
                                },
                                keyboard: true,
                                autoFocus: true,
                                debugLevel: 0,
                                children: children
                            });
                        }

                        readDir("/", renderInitialTree);
                    });

                    function close() {
                        el.remove();
                    }
                });
            },
            localChrome: function() {
                return new Promise(function(resolve) {
                    chrome.fileSystem.chooseEntry({
                        type: "openDirectory"
                    }, function(dir) {
                        if (!dir) {
                            return resolve();
                        }
                        var id = chrome.fileSystem.retainEntry(dir);
                        var title = dir.fullPath.slice(1);
                        resolve({
                            title: title,
                            url: "local:" + id
                        });
                    });
                });
            },
            zedrem: function() {
                return new Promise(function(resolve, reject) {
                    var sockOptions = background.getSocketOptions();
                    var el = $("

");
                    $("body").append(el);
                    $.get("/open/zedrem.html", function(html) {
                        el.html(html);
                        $("#zedrem-url").focus();
                        $("#cancel").click(function() {
                            close();
                            resolve();
                        });

                        $("#zedrem-form").submit(function(event) {
                            var url = $("#zedrem-url").val();
                            check(url).then(function() {
                                resolve(url);
                            }, function() {
                                $("#hint").text("Invalid Zedrem URL");
                            });
                            event.preventDefault();
                        });

                        if (sockOptions.status === "connected") {
                            $("#zedrem-command").text("$ ./zedrem -key " + sockOptions.userKey + (sockOptions.server !== defaultConfig.preferences.zedremServer ? (" -u " + sockOptions.server) : "") + " .");
                            $("#zedrem-explanation").text("After running this command, a Zed window should automatically pop up with your project loaded.");
                        }
                    });

                    function close() {
                        el.remove();
                    }

                    function check(url) {
                        return new Promise(function(resolve, reject) {
                            // Only check http(s) links
                            if (url.indexOf("http") !== 0) {
                                return reject();
                            }
                            $.ajax({
                                type: "POST",
                                url: url,
                                data: {
                                    action: 'version'
                                },
                                success: function() {
                                    resolve();
                                },
                                error: function() {
                                    reject();
                                },
                                dataType: "text"
                            });
                        });
                    }
                });
            }
        };

        register(null, {
            open_ui: api
        });
    }
});
<commit_msg>Rename 'Remote Zedrem Folder' to just 'Remote Folder'<commit_after>define(function(require, exports, module) {
    plugin.consumes = ["eventbus", "history", "token_store", "fs", "editor", "config", "background", "menu"];
    plugin.provides = ["open_ui"];
    return plugin;

    function plugin(opts, imports, register) {
        var eventbus = imports.eventbus;
        var history = imports.history;
        var tokenStore = imports.token_store;
        var fs = imports.fs;
        var editor = imports.editor;
        var config = imports.config;
        var background = imports.background;
        var menu = imports.menu;

        var options = require("./lib/options");
        var icons = require("./lib/icons");
        var filterList = require("./lib/filter_list");
        var dropbox = require("./lib/dropbox");
        var githubUi = require("./open/github");

        var defaultConfig = JSON.parse(require("text!../config/default/preferences.json"));

        eventbus.declare("urlchanged");

        var builtinProjects;

        if (window.isNodeWebkit) {
            builtinProjects = [{
                name: "Local Folder",
                url: "node:"
            }, {
                name: "Remote Folder",
                url: "zedrem:"
            }, {
                name: "Github Repository",
                url: "gh:"
            }, {
                name: "Configuration",
                html: "Configuration ",
                url: "nwconfig:"
            }, {
                name: "Manual",
                url: "manual:"
            }];
        } else {
            builtinProjects = [{
                name: "Local Folder",
                url: "local:"
            }, {
                name: "Remote Folder",
                url: "zedrem:"
            }, {
                name: "Github Repository",
                url: "gh:"
            }, {
                name: "Dropbox Folder",
                url: "dropbox:"
            }, {
                name: "Notes",
                url: "syncfs:",
            }, {
                name: "Configuration",
                html: "Configuration ",
                url: "config:"
            }, {
                name: "Manual",
                url: "manual:"
            }];
        }

        var viewEl, headerEl, phraseEl, listEl;

        var closed = false;

        var api = {
            openInNewWindow: false,
            boot: function() {
                config.loadConfiguration().then(function() {
                    if (closed) {
                        return;
                    }
                    api.showOpenUi();
                    var enable = config.getPreference("enableAnalytics");
                    var showMenus = config.getPreference("showMenus");
                    if (enable === undefined || showMenus === undefined) {
                        api.firstRun();
                    }
                });
            },
            showOpenUi: function() {
                menu.disabled = true;
                viewEl = $("

<input type='text' id='phrase' placeholder='Filter list'>

");
                $("body").append(viewEl);
                headerEl = viewEl.find("h1");
                phraseEl = viewEl.find("#phrase");
                listEl = viewEl.find("#item-list");
                api.fadeOutBackground();
                eventbus.once("editorloaded", function() {
                    api.fadeOutBackground();
                });
                api.projectList();
            },
            close: function() {
                menu.disabled = false;
                closed = true;
                api.fadeInBackground();
                viewEl && viewEl.remove();
            },
            fadeOutBackground: function() {
                $(".ace_editor").css("opacity", 0.3);
                $(".pathbar").css("opacity", 0.3);
            },
            fadeInBackground: function() {
                $(".ace_editor").css("opacity", "");
                $(".pathbar").css("opacity", "");
            },
            projectList: function() {
                headerEl.text("Open in Zed");
                history.getProjects().then(function(projects) {
                    if (projects.length > 0) {
                        projects.splice(0, 0, {
                            section: "Recently Opened"
                        });
                    }
                    projects.push({
                        section: "Other"
                    });
                    projects = projects.concat(builtinProjects);

                    var items = projects.map(function(project) {
                        if (project.section) {
                            return project;
                        }
                        return {
                            name: project.name,
                            url: project.url,
                            html: "" + (project.html ? project.html : project.name)
                        };
                    });

                    phraseEl.val("");
                    phraseEl.focus();
                    filterList({
                        inputEl: phraseEl,
                        resultsEl: listEl,
                        list: items,
                        onSelect: function(b) {
                            if (b === "set-config-dir") {
                                api.close();
                                zed.getService("configfs").storeLocalFolder().then(function() {
                                    api.showOpenUi();
                                });
                                return;
                            }
                            switch (b.url) {
                                case "gh:":
                                    api.github().then(function(repo) {
                                        if (repo) {
                                            api.open(repo.repo + " [" + repo.branch + "]", "gh:" + repo.repo + ":" + repo.branch);
                                        } else {
                                            api.showOpenUi();
                                        }
                                    });
                                    break;
                                case "dropbox:":
                                    api.dropbox().then(function(url) {
                                        if (url) {
                                            api.open(url.slice("dropbox:".length), url);
                                        } else {
                                            api.showOpenUi();
                                        }
                                    });
                                    break;
                                case "local:":
                                    api.localChrome().then(function(data) {
                                        console.log("Picked a folder", data);
                                        if (data) {
                                            api.open(data.title, data.url);
                                        } else {
                                            api.showOpenUi();
                                        }
                                    });
                                    break;
                                case "zedrem:":
                                    api.zedrem().then(function(url) {
                                        if (url) {
                                            api.open("Zedrem Project", url);
                                        } else {
                                            api.showOpenUi();
                                        }
                                    });
                                    break;
                                case "manual:":
                                    background.openProject("Manual", "manual:");
                                    // Using return instead of break to avoid closing
                                    return api.projectList();
                                default:
                                    api.open(b.name, b.url);
                            }
                            api.close();
                        },
                        onCancel: function() {
                            if (!fs.isEmpty) {
                                viewEl.remove();
                                api.fadeInBackground();
                                editor.getActiveEditor().focus();
                            }
                        },
                        onDelete: function(b) {
                            items.splice(items.indexOf(b), 1);
                            history.removeProject(b.url);
                        }
                    });
                }).
                catch (function(err) {
                    console.error("Error", err);
                });
            },
            open: function(title, url) {
                if (api.openInNewWindow) {
                    background.openProject(title, url);
                } else {
                    options.set("title", title);
                    options.set("url", url);
                    eventbus.emit("urlchanged");
                }
            },
            firstRun: function() {
                return new Promise(function(resolve, reject) {
                    var el = $("

");
                    $("body").append(el);
                    $.get("/firstrun.html", function(html) {
                        el.html(html);
                        $("#enable").change(function() {
                            config.setPreference("enableAnalytics", $("#enable").is(":checked"));
                        });

                        $("#menubar").change(function() {
                            config.setPreference("showMenus", $("#menubar").is(":checked"));
                        });

                        $("#done").click(function() {
                            el.remove();
                            resolve();
                        });

                        $("td").click(function(event) {
                            var target = $(event.target).parents("td");
                            $("td").removeClass("selected");
                            $(target).addClass("selected");
                            var mode = target.data("mode");
                            console.log("Mode selected", mode);
                            switch (mode) {
                                case "traditional":
                                    config.setPreference("showMenus", true);
                                    config.setPreference("persistentTree", true);
                                    break;
                                case "chromeless":
                                    config.setPreference("showMenus", $("#menubar").is(":checked"));
                                    config.setPreference("persistentTree", false);
                                    break;
                                default:
                                    console.log("Unknown mode", mode)
                            }
                        });

                        setTimeout(function() {
                            config.setPreference("enableAnalytics", true);
                            config.setPreference("showMenus", false);
                            config.setPreference("persistentTree", false);
                        }, 1000);
                    });
                });
            },
            githubAuth: function(githubToken) {
                return new Promise(function(resolve, reject) {
                    var el = $("

");
                    $("body").append(el);
                    $.get("/open/github_token.html", function(html) {
                        el.html(html);
                        $("#token-form").submit(function(event) {
                            event.preventDefault();
                            verifyToken($("#token").val());
                        });
                        $("#cancel").click(function() {
                            close();
                            resolve();
                        });

                        $("#token").val(githubToken);

                        function close() {
                            el.remove();
                            resolve();
                        }

                        function verifyToken(token) {
                            $.ajax({
                                type: "GET",
                                url: "https://api.github.com/user?access_token=" + token,
                                dataType: "json",
                                processData: false,
                                success: function() {
                                    tokenStore.set("githubToken", token);
                                    resolve(token);
                                    close();
                                },
                                error: function() {
                                    $("#hint").text("Invalid token");
                                }
                            });
                        }
                    });

                });
            },
            github: function() {
                return tokenStore.get("githubToken").then(function(githubToken) {
                    if (!githubToken) {
                        return api.githubAuth().then(function(githubToken) {
                            if (githubToken) {
                                return pick(githubToken);
                            } else {
                                console.log("Shoing project list again");
                                api.projectList();
                                return;
                            }
                        });
                    } else {
                        return pick(githubToken);
                    }
                });

                function pick(githubToken) {
                    return githubUi(githubToken)(headerEl, phraseEl, listEl);
                }
            },
            dropbox: function() {
                return new Promise(function(resolve) {
                    var el = $("

Pick a Dropbox Folder

Authenticating...
<button id='logout'>Logout</button>
");
                    $("body").append(el);

                    dropbox.authenticate(function(err, dropbox) {
                        if (err) {
                            close();
                            return api.projectList();
                        }

                        var treeEl = $("#dropbox-tree");
                        treeEl.focus();
                        $("#logout").click(function() {
                            dropbox.signOut(close);
                        });

                        function open(path) {
                            resolve("dropbox:" + path);
                        }

                        function readDir(path, callback) {
                            dropbox.readdir(path, function(err, resultStrings, dirState, entries) {
                                if (err) {
                                    return callback(err);
                                }
                                var dirs = [];
                                entries.forEach(function(entry) {
                                    if (entry.isFolder) {
                                        dirs.push({
                                            title: entry.name,
                                            key: entry.path,
                                            isFolder: true,
                                            isLazy: true
                                        });
                                    }
                                });
                                callback(null, dirs);
                            });
                        }

                        function renderInitialTree(err, children) {
                            treeEl.dynatree({
                                onActivate: function(node) {
                                    open(node.data.key);
                                    close();
                                },
                                onLazyRead: function(node) {
                                    readDir(node.data.key, function(err, dirs) {
                                        if (err) {
                                            return console.error(err);
                                        }
                                        dirs.forEach(function(dir) {
                                            node.addChild(dir);
                                        });
                                        node.setLazyNodeStatus(DTNodeStatus_Ok);
                                    });
                                },
                                onKeydown: function(node, event) {
                                    if (event.keyCode === 27) {
                                        close();
                                    }
                                },
                                keyboard: true,
                                autoFocus: true,
                                debugLevel: 0,
                                children: children
                            });
                        }

                        readDir("/", renderInitialTree);
                    });

                    function close() {
                        el.remove();
                    }
                });
            },
            localChrome: function() {
                return new Promise(function(resolve) {
                    chrome.fileSystem.chooseEntry({
                        type: "openDirectory"
                    }, function(dir) {
                        if (!dir) {
                            return resolve();
                        }
                        var id = chrome.fileSystem.retainEntry(dir);
                        var title = dir.fullPath.slice(1);
                        resolve({
                            title: title,
                            url: "local:" + id
                        });
                    });
                });
            },
            zedrem: function() {
                return new Promise(function(resolve, reject) {
                    var sockOptions = background.getSocketOptions();
                    var el = $("

");
                    $("body").append(el);
                    $.get("/open/zedrem.html", function(html) {
                        el.html(html);
                        $("#zedrem-url").focus();
                        $("#cancel").click(function() {
                            close();
                            resolve();
                        });

                        $("#zedrem-form").submit(function(event) {
                            var url = $("#zedrem-url").val();
                            check(url).then(function() {
                                resolve(url);
                            }, function() {
                                $("#hint").text("Invalid Zedrem URL");
                            });
                            event.preventDefault();
                        });

                        if (sockOptions.status === "connected") {
                            $("#zedrem-command").text("$ ./zedrem -key " + sockOptions.userKey + (sockOptions.server !== defaultConfig.preferences.zedremServer ? (" -u " + sockOptions.server) : "") + " .");
                            $("#zedrem-explanation").text("After running this command, a Zed window should automatically pop up with your project loaded.");
                        }
                    });

                    function close() {
                        el.remove();
                    }

                    function check(url) {
                        return new Promise(function(resolve, reject) {
                            // Only check http(s) links
                            if (url.indexOf("http") !== 0) {
                                return reject();
                            }
                            $.ajax({
                                type: "POST",
                                url: url,
                                data: {
                                    action: 'version'
                                },
                                success: function() {
                                    resolve();
                                },
                                error: function() {
                                    reject();
                                },
                                dataType: "text"
                            });
                        });
                    }
                });
            }
        };

        register(null, {
            open_ui: api
        });
    }
});
<|endoftext|>


<commit_before>/* ©Copyright Utrecht University (Department of Information and Computing Sciences) */

var Clipboard;

(function()
{
    Clipboard =
    {
        copyElement: copyElement,
        cutElement: cutElement,
        pasteElement: pasteElement
    };

    var copiedElement = null,
        copiedElements = [],
        copiedTrees = false;

    $(document).ready(function()
    {
        $("#copyNode").on('click', function()
        {
            copyElement();
        });
        $("#cutNode").on('click', function ()
        {
            cutElement();
        });
        $("#pasteNode").on('click', function()
        {
            pasteElement();
        });
    });

    function copyElement()
    {
        //Check if we're saving tree(s) or node(s)
        copiedTrees = !Zoom.isZoomed();

        //Save element(s) in memory
        if (Main.selectedElement !== null && Main.selectedElement !==
            undefined)
        {
            if (copiedTrees)
            {
                copiedElement = copyTree(Main.selectedElement);
            }
            else
            {
                copiedElement = copyNode(Main.selectedElement);
            }
            copiedElements = null;
        }
        else if (Main.selectedElements !== null && Main.selectedElements !==
            undefined)
        {
            copiedElements = [];
            if (copiedTrees)
            {
                $.each(Main.selectedElements, function(index, treeId)
                {
                    copiedElements.push(copyTree(treeId));
                });
            }
            else
            {
                $.each(Main.selectedElements, function(index, nodeId)
                {
                    copiedElements.push(copyNode(nodeId));
                });
            }
            copiedElement = null;
        }
    }

    function copyTree(treeId)
    {
        //Save tree data
        var toCopy = Utils.clone(Main.trees[treeId]),
        nodes = [];
        //Save all node data in tree
        $.each(Main.trees[treeId].nodes, function(index, nodeId)
        {
            nodes.push(copyNode(nodeId));
        });
        toCopy.nodes = nodes;

        return toCopy;
    }

    function copyNode(nodeID)
    {
        // Delete the properties from node that are used for arranging all nodes within a tree
        // This is done here, because doing it after an arrange operation will make it even slower
        delete Main.nodes[nodeID].topologicalChildren;
        delete Main.nodes[nodeID].topologicalOrderingVisited;
        delete Main.nodes[nodeID].topologicalParent;

        toCopy = Utils.clone(Main.nodes[nodeID]);
        var plumbInstance = Main.getPlumbInstanceByNodeID(nodeID);

        //Get node connections
        var connections = plumbInstance.getConnections(
                    {
                        target: nodeID
                    });
        //Get node position
        var position = $('#' + nodeID).position();

        //Save extra node info
        toCopy.connections = connections;
        toCopy.position = position;

        return toCopy;
    }

    function cutElement()
    {
        copyElement();
        Main.deleteAllSelected();
    }

    function pasteElement()
    {
        if (copiedElement !== null && copiedElement !== undefined)
        {
            if (copiedTrees && !Zoom.isZoomed())
            {
                pasteTree(copiedElement, 0, 0);
            }
            else if (Zoom.isZoomed() && !copiedTrees)
            {
                var newNode = pasteNode(copiedElement);
                Main.selectElement(newNode.id);
            }
        }
        else if (copiedElements !== null && copiedElements !== undefined)
        {
            if (copiedTrees && !Zoom.isZoomed())
            {
                // In grid positions
                var minY = Number.MAX_VALUE;
                var minX = Number.MAX_VALUE;
                var offSetY = [];
                var offSetX = [];

                $.each(copiedElements, function(index, tree)
                {
                    if(tree.leftPos < minX)
                        minX = tree.leftPos;
                    if(tree.topPos < minY)
                        minY = tree.topPos;
                });

                $.each(copiedElements, function(index, tree)
                {
                    offSetY[index] = tree.topPos-minY;
                    offSetX[index] = tree.leftPos-minX;
                });

                // Paste trees relative to top left of smallest bounding box
                $.each(copiedElements, function(index, tree)
                {
                    pasteTree(tree, offSetX[index], offSetY[index]);
                });
            }
            else if (Zoom.isZoomed() && !copiedTrees)
            {
                //Needed to save jsPlumb connections
                var idMappings = {};
                $.each(copiedElements, function(index, node)
                {
                    newNode = pasteNode(node);
                    idMappings[node.id] = newNode.id;
                });

                var plumbInstance = Zoom.getZoomed().plumbInstance;
                //Copy jsPlumb connections
                $.each(copiedElements, function(index, node)
                {
                    if (!node) //due to deleting from arrays in js leaving values undefined
                        return true;

                    var connections = node.connections;

                    $.each(connections, function(index,
                        connection)
                    {
                        var target = idMappings[
                            connection.targetId]; //map original target to copied target
                        if (!target)
                            return true;
                        var source = idMappings[
                            connection.sourceId]; //map original source to copied source
                        if (!source)
                            return true;
                        plumbInstance.connect(
                        {
                            "source": source,
                            "target": target
                        });
                    });
                });
                // select all nodes just copied
                for (var key in idMappings)
                {
                    // function that allows for more than one selected node at a time
                    KeyControl.selectExtraElement(idMappings[key]);
                }
            }
        }
    }

    function pasteNode(copiedNode)
    {
        var node = Utils.clone(copiedNode); //no dom action just yet. this just copies the object in the nodes object
        var newNode = Main.addNewNode(node.type); //to do dom manipulations and create the id. no data now present in nodes[newNode.id] is kept

        Main.selectElement(null);

        node.id = newNode.id;
        node.parent = newNode.parent;
        delete node.position;
        delete node.connections;

        Main.nodes[newNode.id] = node;

        // set nodeposition relatively to the positions off the original node(s)
        var left = copiedNode.position.left + 50;
        var top = copiedNode.position.top + 50;

        var nodeElem = $('#' + newNode.id);
        //Set position
        nodeElem.css(
        {
            "top": top,
            "left": left
        });
        //Save node text
        nodeElem.find("textarea.nodestatement").val(copiedNode.text);

        Main.changeNodeText(newNode.id);

        return node;
    }

    function pasteTree(toCopy, offSetX, offSetY)
    {
        var idMappings = {}; //record wich original node id was copied to which id
        //idmappings[originalID] = copyID
        //all other information like dom elements and position should not be copied

        var newTree = Main.addNewTree(null, true, offSetX, offSetY);

        newTree.subject = LanguageManager.fLang("edt_clipboard_copy_of", [toCopy.subject]);
        newTree.optional = toCopy.optional;

        var treeDiv = $("#" + newTree.id);
        treeDiv.find(".subjectName").text(newTree.subject);
        treeDiv.find(".subjectNameInput").val(newTree.subject);

        Main.selectElement(newTree.id); //tree needs to be selected when copied nodes are created

        $.each(toCopy.nodes, function(index, node)
        {
            if (!node) //due to deleting from arrays in js leaving values undefined
                return true; //$.each version of continue

            var newNode = pasteNode(node);

            Main.selectElement(newTree.id); //after creation a new node is immediately selected. so we need to reselect the tree

            idMappings[node.id] = newNode.id; //needed to also copy over jsplumb connectors.

            var newNodeDiv = $("#" + newNode.id);

            newNodeDiv.css(
            {
                "top": node.position.top,
                "left": node.position.left
            }); //position is relative to dom parent, so can be copied directly
        });

        //all nodes have been created. now copy connectors
        $.each(toCopy.nodes, function(index, node)
        {
            if (!node) //due to deleting from arrays in js leaving values undefined
                return true;

            var connections = node.connections;

            $.each(connections, function(index, connection)
            {
                var target = idMappings[connection.targetId]; //map original target to copied target
                var source = idMappings[connection.sourceId]; //map original source to copied source
                newTree.plumbInstance.connect(
                {
                    "source": source,
                    "target": target
                });
            });
        });
    }

}());
<commit_msg>Fixed undeclared variable<commit_after>/* ©Copyright Utrecht University (Department of Information and Computing Sciences) */

var Clipboard;

(function()
{
    "use strict";

    Clipboard =
    {
        copyElement: copyElement,
        cutElement: cutElement,
        pasteElement: pasteElement
    };

    var copiedElement = null,
        copiedElements = [],
        copiedTrees = false;

    $(document).ready(function()
    {
        $("#copyNode").on('click', function()
        {
            copyElement();
        });
        $("#cutNode").on('click', function ()
        {
            cutElement();
        });
        $("#pasteNode").on('click', function()
        {
            pasteElement();
        });
    });

    function copyElement()
    {
        //Check if we're saving tree(s) or node(s)
        copiedTrees = !Zoom.isZoomed();

        //Save element(s) in memory
        if (Main.selectedElement !== null && Main.selectedElement !==
            undefined)
        {
            if (copiedTrees)
            {
                copiedElement = copyTree(Main.selectedElement);
            }
            else
            {
                copiedElement = copyNode(Main.selectedElement);
            }
            copiedElements = null;
        }
        else if (Main.selectedElements !== null && Main.selectedElements !==
            undefined)
        {
            copiedElements = [];
            if (copiedTrees)
            {
                $.each(Main.selectedElements, function(index, treeId)
                {
                    copiedElements.push(copyTree(treeId));
                });
            }
            else
            {
                $.each(Main.selectedElements, function(index, nodeId)
                {
                    copiedElements.push(copyNode(nodeId));
                });
            }
            copiedElement = null;
        }
    }

    function copyTree(treeId)
    {
        //Save tree data
        var toCopy = Utils.clone(Main.trees[treeId]),
        nodes = [];
        //Save all node data in tree
        $.each(Main.trees[treeId].nodes, function(index, nodeId)
        {
            nodes.push(copyNode(nodeId));
        });
        toCopy.nodes = nodes;

        return toCopy;
    }

    function copyNode(nodeID)
    {
        // Delete the properties from node that are used for arranging all nodes within a tree
        // This is done here, because doing it after an arrange operation will make it even slower
        delete Main.nodes[nodeID].topologicalChildren;
        delete Main.nodes[nodeID].topologicalOrderingVisited;
        delete Main.nodes[nodeID].topologicalParent;

        var toCopy = Utils.clone(Main.nodes[nodeID]);
        var plumbInstance = Main.getPlumbInstanceByNodeID(nodeID);

        //Get node connections
        var connections = plumbInstance.getConnections(
                    {
                        target: nodeID
                    });
        //Get node position
        var position = $('#' + nodeID).position();

        //Save extra node info
        toCopy.connections = connections;
        toCopy.position = position;

        return toCopy;
    }

    function cutElement()
    {
        copyElement();
        Main.deleteAllSelected();
    }

    function pasteElement()
    {
        if (copiedElement !== null && copiedElement !== undefined)
        {
            if (copiedTrees && !Zoom.isZoomed())
            {
                pasteTree(copiedElement, 0, 0);
            }
            else if (Zoom.isZoomed() && !copiedTrees)
            {
                var newNode = pasteNode(copiedElement);
                Main.selectElement(newNode.id);
            }
        }
        else if (copiedElements !== null && copiedElements !== undefined)
        {
            if (copiedTrees && !Zoom.isZoomed())
            {
                // In grid positions
                var minY = Number.MAX_VALUE;
                var minX = Number.MAX_VALUE;
                var offSetY = [];
                var offSetX = [];

                $.each(copiedElements, function(index, tree)
                {
                    if(tree.leftPos < minX)
                        minX = tree.leftPos;
                    if(tree.topPos < minY)
                        minY = tree.topPos;
                });

                $.each(copiedElements, function(index, tree)
                {
                    offSetY[index] = tree.topPos-minY;
                    offSetX[index] = tree.leftPos-minX;
                });

                // Paste trees relative to top left of smallest bounding box
                $.each(copiedElements, function(index, tree)
                {
                    pasteTree(tree, offSetX[index], offSetY[index]);
                });
            }
            else if (Zoom.isZoomed() && !copiedTrees)
            {
                //Needed to save jsPlumb connections
                var idMappings = {};
                $.each(copiedElements, function(index, node)
                {
                    newNode = pasteNode(node);
                    idMappings[node.id] = newNode.id;
                });

                var plumbInstance = Zoom.getZoomed().plumbInstance;
                //Copy jsPlumb connections
                $.each(copiedElements, function(index, node)
                {
                    if (!node) //due to deleting from arrays in js leaving values undefined
                        return true;

                    var connections = node.connections;

                    $.each(connections, function(index,
                        connection)
                    {
                        var target = idMappings[
                            connection.targetId]; //map original target to copied target
                        if (!target)
                            return true;
                        var source = idMappings[
                            connection.sourceId]; //map original source to copied source
                        if (!source)
                            return true;
                        plumbInstance.connect(
                        {
                            "source": source,
                            "target": target
                        });
                    });
                });
                // select all nodes just copied
                for (var key in idMappings)
                {
                    // function that allows for more than one selected node at a time
                    KeyControl.selectExtraElement(idMappings[key]);
                }
            }
        }
    }

    function pasteNode(copiedNode)
    {
        var node = Utils.clone(copiedNode); //no dom action just yet. this just copies the object in the nodes object
        var newNode = Main.addNewNode(node.type); //to do dom manipulations and create the id. no data now present in nodes[newNode.id] is kept

        Main.selectElement(null);

        node.id = newNode.id;
        node.parent = newNode.parent;
        delete node.position;
        delete node.connections;

        Main.nodes[newNode.id] = node;

        // set nodeposition relatively to the positions off the original node(s)
        var left = copiedNode.position.left + 50;
        var top = copiedNode.position.top + 50;

        var nodeElem = $('#' + newNode.id);
        //Set position
        nodeElem.css(
        {
            "top": top,
            "left": left
        });
        //Save node text
        nodeElem.find("textarea.nodestatement").val(copiedNode.text);

        Main.changeNodeText(newNode.id);

        return node;
    }

    function pasteTree(toCopy, offSetX, offSetY)
    {
        var idMappings = {}; //record wich original node id was copied to which id
        //idmappings[originalID] = copyID
        //all other information like dom elements and position should not be copied

        var newTree = Main.addNewTree(null, true, offSetX, offSetY);

        newTree.subject = LanguageManager.fLang("edt_clipboard_copy_of", [toCopy.subject]);
        newTree.optional = toCopy.optional;

        var treeDiv = $("#" + newTree.id);
        treeDiv.find(".subjectName").text(newTree.subject);
        treeDiv.find(".subjectNameInput").val(newTree.subject);

        Main.selectElement(newTree.id); //tree needs to be selected when copied nodes are created

        $.each(toCopy.nodes, function(index, node)
        {
            if (!node) //due to deleting from arrays in js leaving values undefined
                return true; //$.each version of continue

            var newNode = pasteNode(node);

            Main.selectElement(newTree.id); //after creation a new node is immediately selected. so we need to reselect the tree

            idMappings[node.id] = newNode.id; //needed to also copy over jsplumb connectors.

            var newNodeDiv = $("#" + newNode.id);

            newNodeDiv.css(
            {
                "top": node.position.top,
                "left": node.position.left
            }); //position is relative to dom parent, so can be copied directly
        });

        //all nodes have been created. now copy connectors
        $.each(toCopy.nodes, function(index, node)
        {
            if (!node) //due to deleting from arrays in js leaving values undefined
                return true;

            var connections = node.connections;

            $.each(connections, function(index, connection)
            {
                var target = idMappings[connection.targetId]; //map original target to copied target
                var source = idMappings[connection.sourceId]; //map original source to copied source
                newTree.plumbInstance.connect(
                {
                    "source": source,
                    "target": target
                });
            });
        });
    }

}());
<|endoftext|>


<commit_before>var MongoClient = require('mongodb').MongoClient;
var projector = require("nodetiles-core").projector;
var __ = require("lodash");

var MongoSource = function(options) {
  this._projection = projector.util.cleanProjString(options.projection || 'EPSG:4326');
  // this._connectionString = options.connectionString; // required
  this._db = options.db;
  this._collectionName = options.collectionName;     // required
  this._geoKey = options.key;                        // required - name of the geodata field
  this._query =   options.query;                     // required - a query to get started with
  this._select = options.select;                     // required - fields to select
  this._filter = options.filter;                     // optional - key to filter data
  this.sourceName = options.name || 'localdata';
  return this;
};

MongoSource.prototype = {
  constructor: MongoSource,

  getShapes: function(minX, minY, maxX, maxY, mapProjection, callback) {

    // First, we need to turn the coordinates into a bounds query for Mongo
    var min = [minX, minY];
    var max = [maxX, maxY];

    // project request coordinates into data coordinates
    if (mapProjection !== this._projection) {
      min = projector.project.Point(mapProjection, this._projection, min);
      max = projector.project.Point(mapProjection, this._projection, max);
    }

    var query = this._query || {};
    var parsedBbox = [[min[0], min[1]], [max[0],  max[1]]];
    query[this._geoKey] = { '$within': { '$box': parsedBbox } };

    // TODO: set autoreconnect
    //MongoClient.connect(this._connectionString, {
    //}, function(err, db) {
      //if(err) {
      //  console.log("Mongo error:", err);
      //  return;
      //}

      start = Date.now();
      // var stream = this._db.collection(this._collectionName)
      //   .find(this._query, this._select)
      //   .stream();

      var cursor = this._db.collection(this._collectionName)
        .find(this._query, this._select);

      // console.log("Query %j %j", this._query, this._select);

      var features = [];

      var self = this;

      /**
       * Turn stored a stored parcel result into geoJSON
       * TODO: Can save time and memory by not creating a new object here.
       * @param  {Object} item  A single response
       * @return {Object}       A single response structured as geoJSON
       */
      function resultToGeoJSON(item, filter) {
        item.type = 'Feature';

        // Get the geo info
        if (item.geo_info.geometry !== undefined) {
          item.id = item.object_id;
          item.geometry = item.geo_info.geometry;
        }else {

          // Or if there isn't one, use the centroid.
          item.id = item._id;
          item.geometry = {};
          item.geometry.type = 'Point';
          item.geometry.coordinates = item.geo_info.centroid;
        }

        item.properties = {
          geometry: __cloneDeep(item.geo_info.geometry),
          name: item.geo_info.humanReadableName
        };

        // Clean up a bit
        delete item.geo_info.centroid;
        delete item.geo_info.geometry;
        delete item.responses;

        // If there is a filter, we also want the key easily accessible.
        if(filter) {
          // TODO: Handle the undefined condition
          if(item.hasOwnProperty("responses")) {
            if(item.responses.hasOwnProperty(filter.key)) {
              item.properties[filter.key] = item.responses[filter.key];
            }
          }
        }

        return item;
      }

      function addFeature(doc) {
        features.push(resultToGeoJSON(doc));
      }

      // ----------------------------------------------------------
      // Get the data
      // Set to true to try streaming
      // Streaming is both broken and not optimized
      if(false) {
        stream.on('data', addFeature);

        stream.on('close', function() {
          console.log("Fetched and processed " + features.length + " responses in " + (Date.now() - start) + "ms");

          callback(null, {
            type: 'FeatureCollection',
            features: features
          });
        }.bind(this));
      }else {

        // The same thing as above, except using toArray
        // NB -- conversion to a format that the renderer wants is broken
        cursor.toArray(function(error, results) {
          if(error) {
            console.log("Error fetching results: ", error);
          }

          if(results) {
            console.log("Fetched " + results.length + " responses in " + (Date.now() - start) + "ms");
          }

          start = Date.now();
          var len = results.length;

          // Convert the results to geojson
          for (var i = 0; i < len; i++) {
            results[i] = resultToGeoJSON(results[i]);
          }

          var fc = {
            type: 'FeatureCollection',
            features: results
          };

          if (self._projection !== mapProjection) {
            fc = projector.project.FeatureCollection(self._projection, mapProjection, fc);
          }

          // console.log("FC");
          // console.log(JSON.stringify(fc, null, 4));

          console.log("Processed " + results.length + " responses in " + (Date.now() - start) + "ms");

          callback(null, fc);

        }.bind(this));

      }

      // Going to skip reprojecting
      // features.push(projectFeature(mapProjection, geoJSONDoc));
    //}.bind(this));
  }
};

module.exports = MongoSource;
<commit_msg>Fix clone deep<commit_after>var MongoClient = require('mongodb').MongoClient;
var projector = require("nodetiles-core").projector;
var __ = require("lodash");

var MongoSource = function(options) {
  this._projection = projector.util.cleanProjString(options.projection || 'EPSG:4326');
  // this._connectionString = options.connectionString; // required
  this._db = options.db;
  this._collectionName = options.collectionName;     // required
  this._geoKey = options.key;                        // required - name of the geodata field
  this._query =   options.query;                     // required - a query to get started with
  this._select = options.select;                     // required - fields to select
  this._filter = options.filter;                     // optional - key to filter data
  this.sourceName = options.name || 'localdata';
  return this;
};

MongoSource.prototype = {
  constructor: MongoSource,

  getShapes: function(minX, minY, maxX, maxY, mapProjection, callback) {

    // First, we need to turn the coordinates into a bounds query for Mongo
    var min = [minX, minY];
    var max = [maxX, maxY];

    // project request coordinates into data coordinates
    if (mapProjection !== this._projection) {
      min = projector.project.Point(mapProjection, this._projection, min);
      max = projector.project.Point(mapProjection, this._projection, max);
    }

    var query = this._query || {};
    var parsedBbox = [[min[0], min[1]], [max[0],  max[1]]];
    query[this._geoKey] = { '$within': { '$box': parsedBbox } };

    // TODO: set autoreconnect
    //MongoClient.connect(this._connectionString, {
    //}, function(err, db) {
      //if(err) {
      //  console.log("Mongo error:", err);
      //  return;
      //}

      start = Date.now();
      // var stream = this._db.collection(this._collectionName)
      //   .find(this._query, this._select)
      //   .stream();

      var cursor = this._db.collection(this._collectionName)
        .find(this._query, this._select);

      // console.log("Query %j %j", this._query, this._select);

      var features = [];

      var self = this;

      /**
       * Turn stored a stored parcel result into geoJSON
       * TODO: Can save time and memory by not creating a new object here.
       * @param  {Object} item  A single response
       * @return {Object}       A single response structured as geoJSON
       */
      function resultToGeoJSON(item, filter) {
        item.type = 'Feature';

        // Get the geo info
        if (item.geo_info.geometry !== undefined) {
          item.id = item.object_id;
          item.geometry = item.geo_info.geometry;
        }else {

          // Or if there isn't one, use the centroid.
          item.id = item._id;
          item.geometry = {};
          item.geometry.type = 'Point';
          item.geometry.coordinates = item.geo_info.centroid;
        }

        item.properties = {
          geometry: __.cloneDeep(item.geo_info.geometry),
          name: item.geo_info.humanReadableName
        };

        // Clean up a bit
        delete item.geo_info.centroid;
        delete item.geo_info.geometry;
        delete item.responses;

        // If there is a filter, we also want the key easily accessible.
        if(filter) {
          // TODO: Handle the undefined condition
          if(item.hasOwnProperty("responses")) {
            if(item.responses.hasOwnProperty(filter.key)) {
              item.properties[filter.key] = item.responses[filter.key];
            }
          }
        }

        return item;
      }

      function addFeature(doc) {
        features.push(resultToGeoJSON(doc));
      }

      // ----------------------------------------------------------
      // Get the data
      // Set to true to try streaming
      // Streaming is both broken and not optimized
      if(false) {
        stream.on('data', addFeature);

        stream.on('close', function() {
          console.log("Fetched and processed " + features.length + " responses in " + (Date.now() - start) + "ms");

          callback(null, {
            type: 'FeatureCollection',
            features: features
          });
        }.bind(this));
      }else {

        // The same thing as above, except using toArray
        // NB -- conversion to a format that the renderer wants is broken
        cursor.toArray(function(error, results) {
          if(error) {
            console.log("Error fetching results: ", error);
          }

          if(results) {
            console.log("Fetched " + results.length + " responses in " + (Date.now() - start) + "ms");
          }

          start = Date.now();
          var len = results.length;

          // Convert the results to geojson
          for (var i = 0; i < len; i++) {
            results[i] = resultToGeoJSON(results[i]);
          }

          var fc = {
            type: 'FeatureCollection',
            features: results
          };

          if (self._projection !== mapProjection) {
            fc = projector.project.FeatureCollection(self._projection, mapProjection, fc);
          }

          // console.log("FC");
          // console.log(JSON.stringify(fc, null, 4));

          console.log("Processed " + results.length + " responses in " + (Date.now() - start) + "ms");

          callback(null, fc);

        }.bind(this));

      }

      // Going to skip reprojecting
      // features.push(projectFeature(mapProjection, geoJSONDoc));
    //}.bind(this));
  }
};

module.exports = MongoSource;
<|endoftext|>


<commit_before>'use strict';

if (!Error.captureStackTrace) throw new Error('Error.captureStackTrace does not exist!');

var util = require('./util');
var BaseError = require('./base_error');
var v = require('./validator').v;
var check = require('./validator').check;

/**
 * This is a module which exports some APIs, the BaseError class, and your defined Error classes.
 *
 * @class Errors
 * @singleton
 */
var Errors = {
    template: null,
    BaseError: BaseError,
};
exports = module.exports = Errors;

/**
 * Set the separator for multi error stacks.
 *
 * Default to "\n==== Pre-Error-Stack ====\n"
 *
 * @method setErrorStackSeparator
 * @param  {String} separator
 * @return {undefined}
 */
exports.setErrorStackSeparator = function(separator) {
    BaseError.prototype.ERROR_STACK_SEPARATOR = separator;
};

/**
 * Set the connector for multi error messages. Default to " && "
 *
 * @method setMessageConnector
 * @param  {String} connector
 * @return {undefined}
 */
exports.setMessageConnector = function(connector) {
    BaseError.prototype.MESSAGE_CONNECTOR = connector;
};

/**
 * Define a subclass of BaseError
 *
 * @method defineError
 * @param  {Object} definition
 * @param  {String} name  the name of Error Class
 * @return {Function}  Error Class
 */
exports.defineError = function(definition, name) {
    if (!Errors.template) throw new Error('The error template should be defined firstly!');
    if (util.isObject(definition) === false) throw new Error('definition should be an object! Current error name=' + name);

    var E = function() {
        BaseError.apply(this, arguments);
    };
    util.inherits(E, BaseError);

    util.each(Errors.template, function(opts, key) {
        var value = definition[key];
        if (value !== undefined) {
            E.prototype[key] = value;
        } else {
            if (opts.required === true) {
                throw new Error('Missing the key "' + key + '", which is required. Current error name=' + name);
            } else {
                E.prototype[key] = opts.default;
            }
        }
    });

    E.prototype.name = name;

    Errors[name] = E;

    return E;
};

/**
 * To determine whether it is your custom error.
 *
 * If the error is an instance of the native Error, return `false`.
 *
 * @method isCustomError
 * @param  {*}  error
 * @return {Boolean}
 */
exports.isCustomError = function(err) {
    return err instanceof BaseError;
};
/**
 * @alias #isCustomError
 * @method isError
 */
exports.isError = Errors.isCustomError;

/**
 * @method setTemplate
 * @param  {Object} template
 * @return {undefined}
 */
exports.setTemplate = function(template) {
    if (util.isObject(template) === false) {
        throw new Error('template should be an object!');
    }

    var t = {};
    util.each(template, function(params, key) {
        if (util.isString(params)) {
            t[key] = {
                message: params,
                required: true,
            };
        } else if (util.isObject(params)) {
            t[key] = check(params, v.templateProp());
        } else {
            throw new Error('The value of template item should be an object or a string. Actual key=' + key + ' and value=' + JSON.stringify(params));
        }
    });
    Errors.template = t;
};

/**
 * Assigns own enumerable properties of meta to the err.meta.
 *
 * If the err.meta is undefined before assigning, it will be assigned a new object,
 * and then the own enumerable properties of second parameter will be assigned to err.meta.
 * If the err.meta is not undefined, it should be a plain object.
 *
 * The properties of meta will overwrite the properties of err.meta, if they have same name.
 *
 * @side_effect  err, err.meta
 * @method addMeta
 * @param  {Error}  err  the instance of Error class or Error subclass
 * @param  {Object} meta
 * @return {undefined}
 */
exports.addMeta = function(err, meta) {
    if (!err.meta) err.meta = {};
    util.extend(err.meta, meta);
};

/**
 * Initialize module. Set your error template and error definitions.
 *
 * @method init
 * @param  {Object} params
 * @param  {Object} params.template  a template for all error sub-classes
 * @param  {Object[]} params.definitions the definitions of error sub-classes
 * @return {Object}  a map of Error classes
 */
exports.init = function(params) {
    Errors.setTemplate(params.template);
    var _Errors = {};
    util.each(params.definitions, function(definition, name) {
        var E = Errors.defineError(definition, name);
        _Errors[name] = E;
    });

    return _Errors;
};
<commit_msg>docs: add more code comments for documenting<commit_after>'use strict';

if (!Error.captureStackTrace) throw new Error('Error.captureStackTrace does not exist!');

var util = require('./util');
var BaseError = require('./base_error');
var v = require('./validator').v;
var check = require('./validator').check;

/**
 * This is a module which exports some APIs, the BaseError class, and your defined Error classes.
 *
 * @class Errors
 * @singleton
 */
var Errors = {
    /**
     * The parsed error template.
     * @property {Object}
     */
    template: null,
    /**
     * The BaseError class
     * @property {BaseError}
     */
    BaseError: BaseError,
};
exports = module.exports = Errors;

/**
 * Set the separator for multi error stacks.
 *
 * Default to "\n==== Pre-Error-Stack ====\n"
 *
 * @method setErrorStackSeparator
 * @param  {String} separator
 * @return {undefined}
 */
exports.setErrorStackSeparator = function(separator) {
    BaseError.prototype.ERROR_STACK_SEPARATOR = separator;
};

/**
 * Set the connector for multi error messages. Default to " && "
 *
 * @method setMessageConnector
 * @param  {String} connector
 * @return {undefined}
 */
exports.setMessageConnector = function(connector) {
    BaseError.prototype.MESSAGE_CONNECTOR = connector;
};

/**
 * Define a subclass of BaseError
 *
 * @method defineError
 * @param  {Object} definition
 * @param  {String} name  the name of Error Class
 * @return {Function}  Error Class
 */
exports.defineError = function(definition, name) {
    if (!Errors.template) throw new Error('The error template should be defined firstly!');
    if (util.isObject(definition) === false) throw new Error('definition should be an object! Current error name=' + name);

    var E = function() {
        BaseError.apply(this, arguments);
    };
    util.inherits(E, BaseError);

    util.each(Errors.template, function(opts, key) {
        var value = definition[key];
        if (value !== undefined) {
            E.prototype[key] = value;
        } else {
            if (opts.required === true) {
                throw new Error('Missing the key "' + key + '", which is required. Current error name=' + name);
            } else {
                E.prototype[key] = opts.default;
            }
        }
    });

    E.prototype.name = name;

    Errors[name] = E;

    return E;
};

/**
 * To determine whether it is your custom error.
 *
 * If the error is an instance of the native Error, return `false`.
 *
 * @method isCustomError
 * @param  {*}  error
 * @return {Boolean}
 */
exports.isCustomError = function(err) {
    return err instanceof BaseError;
};
/**
 * @alias #isCustomError
 * @method isError
 */
exports.isError = Errors.isCustomError;

/**
 * @method setTemplate
 * @param  {Object} template
 * @return {undefined}
 */
exports.setTemplate = function(template) {
    if (util.isObject(template) === false) {
        throw new Error('template should be an object!');
    }

    var t = {};
    util.each(template, function(params, key) {
        if (util.isString(params)) {
            t[key] = {
                message: params,
                required: true,
            };
        } else if (util.isObject(params)) {
            t[key] = check(params, v.templateProp());
        } else {
            throw new Error('The value of template item should be an object or a string. Actual key=' + key + ' and value=' + JSON.stringify(params));
        }
    });
    Errors.template = t;
};

/**
 * Assigns own enumerable properties of meta to the err.meta.
 *
 * If the err.meta is undefined before assigning, it will be assigned a new object,
 * and then the own enumerable properties of second parameter will be assigned to err.meta.
 * If the err.meta is not undefined, it should be a plain object.
 *
 * The properties of meta will overwrite the properties of err.meta, if they have same name.
 *
 * @side_effect  err, err.meta
 * @method addMeta
 * @param  {Error}  err  the instance of Error class or Error subclass
 * @param  {Object} meta
 * @return {undefined}
 */
exports.addMeta = function(err, meta) {
    if (!err.meta) err.meta = {};
    util.extend(err.meta, meta);
};

/**
 * Initialize module. Set your error template and error definitions.
 *
 * @method init
 * @param  {Object} params
 * @param  {Object} params.template  a template for all error sub-classes
 * @param  {Object[]} params.definitions the definitions of error sub-classes
 * @return {Object}  a map of Error classes
 */
exports.init = function(params) {
    Errors.setTemplate(params.template);
    var _Errors = {};
    util.each(params.definitions, function(definition, name) {
        var E = Errors.defineError(definition, name);
        _Errors[name] = E;
    });

    return _Errors;
};
<|endoftext|>