<commit_before>define(function(require, module, exports) {
    main.consumes = ["Plugin", "settings", "fs", "c9", "preferences", "run", "util"];
    main.provides = ["build"];
    return main;

    function main(options, imports, register) {
        var Plugin      = imports.Plugin;
        var settings    = imports.settings;
        var prefs       = imports.preferences;
        var run         = imports.run;
        var fs          = imports.fs;
        var c9          = imports.c9;
        var util        = imports.util;

        /***** Initialization *****/

        var plugin  = new Plugin("Ajax.org", main.consumes);
        var emit    = plugin.getEmitter();

        var builders    = util.cloneObject(options.builders);
        var processes   = [];
        var base        = options.base;
        var builderPath = options.builderPath || "/.c9/builders"

        var loaded = false;
        function load(){
            if (loaded) return false;
            loaded = true;

            // Settings
            settings.on("read", function(e){
                // Defaults
                settings.setDefaults("project/build", [
                    ["path", builderPath]
                ]);

                // @todo Could consider adding a watcher to ~/.c9/runners
                listBuilders(function(err, files){
                    files.forEach(function(file){
                        if (!builders[file]) {
                            getBuilder(file, false, function(err, builder){
                                if (!err)
                                    builders[file] = builder;
                            });
                        }
                    });
                });
            }, plugin);

            settings.on("write", function(e){

            }, plugin);

            // Preferences
            prefs.add({
                "Project" : {
                    "Build" : {
                        position : 400,
                        "Builder Path in Workspace" : {
                           type     : "textbox",
                           path     : "project/build/@path",
                           position : 1000
                        }
                    }
                }
            }, plugin);

            prefs.add({
                "Run" : {
                    "Build" : {
                        position : 400,
                        "Automatically Build Supported Files" : {
                           type     : "checkbox",
                           path     : "user/build/@autobuild",
                           position : 100
                        }
                    }
                }
            }, plugin);

            // Check after state.change
            c9.on("stateChange", function(e){

            }, plugin);
        }

        /***** Methods *****/

        function listBuilders(callback){
            var builders = Object.keys(options.builders || {});
            fs.readdir(settings.get("project/build/@path"), function(err, files){
//                if (err && err.code == "ENOENT")
//                    return callback(err);

                if (files) {
                    files.forEach(function(file) {
                        var basename = file.name.replace(/\.build$/, "");
                        if (builders.indexOf(basename) < 0 && file.name !== basename)
                            builders.push(basename);
                    });
                }

                callback(null, builders);
            });
        }

        function detectBuilder(options, callback){
            listBuilders(function(err, names){
                if (err) return callback(err);

                var count = 0;
                names.forEach(function(name){
                    if (!builders[name]) {
                        count++;
                        getBuilder(name, false, function(){
                            if (--count === 0)
                                done();
                        });
                    }
                })
                if (count === 0) done();
            });

            function done(){
                for (var name in builders) {
                    var builder = builders[name];
                    if (run.matchSelector(builder.selector, options.path))
                        return callback(null, builder);
                }

                var err = new Error("Could not find Builder");
                err.code = "EBUILDERNOTFOUND";
                callback(err);
            }
        }

        function getBuilder(name, refresh, callback){
            var path = settings.get("project/build/@path") + "/" + name + ".build";
            fs.exists(path, function(exists) {
                if (!exists) {
                    if (options.builders[name])
                        return callback(null, options.builders[name]);
                    callback("Builder does not exist");
                }
                else if (builders[name] && !refresh && (!exists || options.builders[name] === builders[name])) {
                    callback(null, builders[name]);
                }
                else {
                    fs.readFile(path, "utf8", function(err, data){
                        if (err)
                            return callback(err);

                        // Remove comments
                        data = data.replace(/\/\/.*/g, "");

                        var builder;
                        try{ builder = JSON.parse(data); }
                        catch(e){ return callback(e); }

                        builder.caption = name.replace(/\.build$/, "");
                        builders[builder.caption] = builder;
                        callback(null, builder);
                    })
                }
            });
        }

        function build(builder, options, name, callback){
            options.builder = true;

            if (builder == "auto") {
                return detectBuilder(options, function(err, detected){
                    if (err) return callback(err);

                    build(detected, options, name, callback);
                });
            }

            var proc = run.run(builder, options, name, callback);
            processes.push(proc);

            var event = { process: proc };

            proc.on("starting", function(){ emit("starting", event); })
            proc.on("started", function(){ emit("started", event); })
            proc.on("stopping", function(){ emit("stopping", event); })
            proc.on("stopped", function(){
                emit("stopped", event);
                processes.remove(proc);
            });

            return proc;
        }

        /***** Lifecycle *****/

        plugin.on("load", function(){
            load();
        });
        plugin.on("enable", function(){

        });
        plugin.on("disable", function(){

        });
        plugin.on("unload", function(){
            loaded = false;
        });

        /***** Register and define API *****/

        /**
         * Builds arbitrary code from within Cloud9 based on a builder.
         *
         * *NB.: The build plugin works almost identical to the run plugin. The
         * builder format is a subset of the runner format. The major difference
         * is that builders are used to build code into executables or
         * deployables and that the runner is used to run executables.*
         *
         * Example:
         *
         *     build.getBuilder("coffee", false, function(err, builder){
         *         if (err) throw err.message;
         *
         *         var process = build.build(builder, {
         *             path: "/helloworld.coffee"
         *         }, function(err, pid){
         *             if (err) throw err.message;
         *
         *             console.log("The PID is ", pid);
         *         });
         *     });
         *
         * You can also ask for auto-detection of the builder based on the file
         * extension:
         *
         *     var process = build.build("auto", {
         *         path: "/helloworld.coffee"
         *     }, function(err, pid){
         *         if (err) throw err.message;
         *
         *         console.log("The PID is ", pid);
         *     });
         *
         * A builder is a simple struct that describes how to build a
         * certain subset of files. For instance a builder describing how to run
         * Coffeescript files looks like this:
         *
         *     {
         *         "caption" : "Coffee",
         *         "cmd": [coffee, "-c", "$file"],
         *         "selector": "source.coffee"
         *     }
         *
         * The concept of builders is based on the
         * [Sublime Text(tm) Build Systems](http://docs.sublimetext.info/en/sublime-text-3/file_processing/build_systems.html),
         * and is compatible with that format. There are a several
         * built-in builders, and external plugins can add new builders as well.
         * Users can also add builders to their .c9/builders directory in
         * the workspace. We recommend users to commit these builders to their
         * repository.
         *
         * The {@link run run plugin} also uses a compatible
         * format for the cloud9 runners.
         *
         * It is possible to combine builders and runners, therefore it is
         * often not needed to describe the build and run step in the same
         * definition.
         *
         * A process is always started in a [TMUX](http://en.wikipedia.org/wiki/Tmux)
         * session. TMUX is a PTY multi-plexer which has several advantages;
         * multiple clients can connect to the same session and the sessions are
         * kept even if no user is connected.
         *
         * You can connect an {@link output} pane to the started process to
         * see the output of your running process. The name passed to
         * {@link build#build} should be the same as the name of the output pane
         * you open:
         *
         *     tabManager.open({
         *         editorType : "output",
         *         active     : true,
         *         document   : {
         *             title  : "My Process Name",
         *             output : {
         *                 id : "name_of_process"
         *             }
         *         }
         *     }, function(){});
         *
         * Note that by default the process name is "output" and is shown in the
         * default output panel (available via the View menu).
         *
         * @singleton
         */
        plugin.freezePublicAPI({
            /**
             * Indicates the process is being killed. To be tested against
             * the `running` property.
             * @property {-1} STOPPING
             */
            STOPPING : run.STOPPING,
            /**
             * Indicates the process is not running. To be tested against
             * the `running` property.
             * @property {0}  STOPPED
             */
            STOPPED  : run.STOPPED,
            /**
             * Indicates the process is getting started. To be tested against
             * the `running` property.
             * @property {1}  STARTING
             */
            STARTING : run.STARTING,
            /**
             * Indicates the process is running. To be tested against
             * the `running` property.
             * @property {2}  STARTED
             */
            STARTED  : run.STARTED,

            /**
             * @property {run.Process[]}  processes  List of running processes
             */
            get processes(){ return processes; },
            /**
             * @property {Object[]}  builders  List of available builders
             */
            get builders(){ return builders; },
            /**
             * @ignore
             */
            get base(){ return base; },

            _events : [
                /**
                 * Fires when the process is going to be killed
                 * @event stopping
                 * @param {Object} e
                 * @param {run.Process} e.process the process that is stopping
                 */
                "stopping",
                /**
                 * Fires when the process stopped running
                 * @event stopped
                 * @param {Object} e
                 * @param {run.Process} e.process the process that is stopped
                 */
                "stopped",
                /**
                 * Fires when the process is being started
                 * @event starting
                 * @param {Object} e
                 * @param {run.Process} e.process the process that is starting
                 */
                "starting",
                /**
                 * Fires when the process is started. This event also fires
                 * during startup if there's a PID file present.
                 * @event started
                 * @param {Object} e
                 * @param {run.Process} e.process the process that is started
                 */
                "started"
            ],

            /**
             * Retrieves an array of names of builders available to the system.
             * A builder is a JSON file that describes how a certain file can
             * be executed. The JSON file format is based on and compatible with
             * the sublime build scripts. Besides the build in builders, the
             * user can store builders in ~/.c9/builders. This list will contain
             * both the user's builders as well as the build-in builders.
             * @param {Function} callback           Called when the builders are retrieved
             * @param {Error}    callback.err       The error object if an error occurred.
             * @param {String[]} callback.builders  A list of names of builders.
             */
            listBuilders : listBuilders,

            /**
             * Retrieves an individual builder's JSON object based on it's name.
             * The names of available builders can be retrieved using `listBuilders`.
             * @param {Function} callback         Called when the runner is retrieved
             * @param {Function} callback.err     The error object if an error occurred.
             * @param {Function} callback.runner  A builder object. See {@link run#run} for more information.
             */
            getBuilder : getBuilder,

            /**
             * Builds a file. See `run.run()` for the full documentation
             * @param {Object/"auto"} builder   Object describing how to build a process.
             * @param {Object}        options
             * @param {String}        options.path        The path to the file to build
             * @param {String}        [options.cwd]       The current working directory
             * @param {Boolean}       [options.debug]     Specifies whether to start the process in debug mode
             * @param {String}        [name]              The unique name of the output buffer. Defaults to "output".
             * @param {Function}      callback            Called when the process is started
             * @param {Error}         callback.err        The error object if an error occurred.
             * @returns {run.Process} the process object
             */
            build : build
        });

        register(null, {
            build : plugin
        });
    }
});<commit_msg>Warn about legacy runners/builders<commit_after>define(function(require, module, exports) {
    main.consumes = ["Plugin", "settings", "fs", "c9", "preferences", "run", "util"];
    main.provides = ["build"];
    return main;

    function main(options, imports, register) {
        var Plugin      = imports.Plugin;
        var settings    = imports.settings;
        var prefs       = imports.preferences;
        var run         = imports.run;
        var fs          = imports.fs;
        var c9          = imports.c9;
        var util        = imports.util;

        /***** Initialization *****/

        var plugin  = new Plugin("Ajax.org", main.consumes);
        var emit    = plugin.getEmitter();

        var builders    = util.cloneObject(options.builders);
        var processes   = [];
        var base        = options.base;
        var builderPath = options.builderPath || "/.c9/builders"

        var loaded = false;
        function load(){
            if (loaded) return false;
            loaded = true;

            // Settings
            settings.on("read", function(e){
                // Defaults
                settings.setDefaults("project/build", [
                    ["path", builderPath]
                ]);

                // @todo Could consider adding a watcher to ~/.c9/runners
                listBuilders(function(err, files){
                    files.forEach(function(file){
                        if (!builders[file]) {
                            getBuilder(file, false, function(err, builder){
                                if (!err)
                                    builders[file] = builder;
                            });
                        }
                    });
                });
            }, plugin);

            settings.on("write", function(e){

            }, plugin);

            // Preferences
            prefs.add({
                "Project" : {
                    "Build" : {
                        position : 400,
                        "Builder Path in Workspace" : {
                           type     : "textbox",
                           path     : "project/build/@path",
                           position : 1000
                        }
                    }
                }
            }, plugin);

            prefs.add({
                "Run" : {
                    "Build" : {
                        position : 400,
                        "Automatically Build Supported Files" : {
                           type     : "checkbox",
                           path     : "user/build/@autobuild",
                           position : 100
                        }
                    }
                }
            }, plugin);

            // Check after state.change
            c9.on("stateChange", function(e){

            }, plugin);
        }

        /***** Methods *****/

        function listBuilders(callback){
            var builders = Object.keys(options.builders || {});
            fs.readdir(settings.get("project/build/@path"), function(err, files){
//                if (err && err.code == "ENOENT")
//                    return callback(err);

                if (files) {
                    files.forEach(function(file) {
                        var name = file.name.match(/(.*)\.build$/);
                        if (!name)
                            return console.warn("Builder ignored, doesn't have .build extension: " + file.name)
                        if (builders.indexOf(name[1]) < 0)
                            builders.push(name[1]);
                    });
                }

                callback(null, builders);
            });
        }

        function detectBuilder(options, callback){
            listBuilders(function(err, names){
                if (err) return callback(err);

                var count = 0;
                names.forEach(function(name){
                    if (!builders[name]) {
                        count++;
                        getBuilder(name, false, function(){
                            if (--count === 0)
                                done();
                        });
                    }
                })
                if (count === 0) done();
            });

            function done(){
                for (var name in builders) {
                    var builder = builders[name];
                    if (run.matchSelector(builder.selector, options.path))
                        return callback(null, builder);
                }

                var err = new Error("Could not find Builder");
                err.code = "EBUILDERNOTFOUND";
                callback(err);
            }
        }

        function getBuilder(name, refresh, callback){
            var path = settings.get("project/build/@path") + "/" + name + ".build";
            fs.exists(path, function(exists) {
                if (!exists) {
                    if (options.builders[name])
                        return callback(null, options.builders[name]);
                    callback("Builder does not exist");
                }
                else if (builders[name] && !refresh && (!exists || options.builders[name] === builders[name])) {
                    callback(null, builders[name]);
                }
                else {
                    fs.readFile(path, "utf8", function(err, data){
                        if (err)
                            return callback(err);

                        // Remove comments
                        data = data.replace(/\/\/.*/g, "");

                        var builder;
                        try{ builder = JSON.parse(data); }
                        catch(e){ return callback(e); }

                        builder.caption = name.replace(/\.build$/, "");
                        builders[builder.caption] = builder;
                        callback(null, builder);
                    })
                }
            });
        }

        function build(builder, options, name, callback){
            options.builder = true;

            if (builder == "auto") {
                return detectBuilder(options, function(err, detected){
                    if (err) return callback(err);

                    build(detected, options, name, callback);
                });
            }

            var proc = run.run(builder, options, name, callback);
            processes.push(proc);

            var event = { process: proc };

            proc.on("starting", function(){ emit("starting", event); })
            proc.on("started", function(){ emit("started", event); })
            proc.on("stopping", function(){ emit("stopping", event); })
            proc.on("stopped", function(){
                emit("stopped", event);
                processes.remove(proc);
            });

            return proc;
        }

        /***** Lifecycle *****/

        plugin.on("load", function(){
            load();
        });
        plugin.on("enable", function(){

        });
        plugin.on("disable", function(){

        });
        plugin.on("unload", function(){
            loaded = false;
        });

        /***** Register and define API *****/

        /**
         * Builds arbitrary code from within Cloud9 based on a builder.
         *
         * *NB.: The build plugin works almost identical to the run plugin. The
         * builder format is a subset of the runner format. The major difference
         * is that builders are used to build code into executables or
         * deployables and that the runner is used to run executables.*
         *
         * Example:
         *
         *     build.getBuilder("coffee", false, function(err, builder){
         *         if (err) throw err.message;
         *
         *         var process = build.build(builder, {
         *             path: "/helloworld.coffee"
         *         }, function(err, pid){
         *             if (err) throw err.message;
         *
         *             console.log("The PID is ", pid);
         *         });
         *     });
         *
         * You can also ask for auto-detection of the builder based on the file
         * extension:
         *
         *     var process = build.build("auto", {
         *         path: "/helloworld.coffee"
         *     }, function(err, pid){
         *         if (err) throw err.message;
         *
         *         console.log("The PID is ", pid);
         *     });
         *
         * A builder is a simple struct that describes how to build a
         * certain subset of files. For instance a builder describing how to run
         * Coffeescript files looks like this:
         *
         *     {
         *         "caption" : "Coffee",
         *         "cmd": [coffee, "-c", "$file"],
         *         "selector": "source.coffee"
         *     }
         *
         * The concept of builders is based on the
         * [Sublime Text(tm) Build Systems](http://docs.sublimetext.info/en/sublime-text-3/file_processing/build_systems.html),
         * and is compatible with that format. There are a several
         * built-in builders, and external plugins can add new builders as well.
         * Users can also add builders to their .c9/builders directory in
         * the workspace. We recommend users to commit these builders to their
         * repository.
         *
         * The {@link run run plugin} also uses a compatible
         * format for the cloud9 runners.
         *
         * It is possible to combine builders and runners, therefore it is
         * often not needed to describe the build and run step in the same
         * definition.
         *
         * A process is always started in a [TMUX](http://en.wikipedia.org/wiki/Tmux)
         * session. TMUX is a PTY multi-plexer which has several advantages;
         * multiple clients can connect to the same session and the sessions are
         * kept even if no user is connected.
         *
         * You can connect an {@link output} pane to the started process to
         * see the output of your running process. The name passed to
         * {@link build#build} should be the same as the name of the output pane
         * you open:
         *
         *     tabManager.open({
         *         editorType : "output",
         *         active     : true,
         *         document   : {
         *             title  : "My Process Name",
         *             output : {
         *                 id : "name_of_process"
         *             }
         *         }
         *     }, function(){});
         *
         * Note that by default the process name is "output" and is shown in the
         * default output panel (available via the View menu).
         *
         * @singleton
         */
        plugin.freezePublicAPI({
            /**
             * Indicates the process is being killed. To be tested against
             * the `running` property.
             * @property {-1} STOPPING
             */
            STOPPING : run.STOPPING,
            /**
             * Indicates the process is not running. To be tested against
             * the `running` property.
             * @property {0}  STOPPED
             */
            STOPPED  : run.STOPPED,
            /**
             * Indicates the process is getting started. To be tested against
             * the `running` property.
             * @property {1}  STARTING
             */
            STARTING : run.STARTING,
            /**
             * Indicates the process is running. To be tested against
             * the `running` property.
             * @property {2}  STARTED
             */
            STARTED  : run.STARTED,

            /**
             * @property {run.Process[]}  processes  List of running processes
             */
            get processes(){ return processes; },
            /**
             * @property {Object[]}  builders  List of available builders
             */
            get builders(){ return builders; },
            /**
             * @ignore
             */
            get base(){ return base; },

            _events : [
                /**
                 * Fires when the process is going to be killed
                 * @event stopping
                 * @param {Object} e
                 * @param {run.Process} e.process the process that is stopping
                 */
                "stopping",
                /**
                 * Fires when the process stopped running
                 * @event stopped
                 * @param {Object} e
                 * @param {run.Process} e.process the process that is stopped
                 */
                "stopped",
                /**
                 * Fires when the process is being started
                 * @event starting
                 * @param {Object} e
                 * @param {run.Process} e.process the process that is starting
                 */
                "starting",
                /**
                 * Fires when the process is started. This event also fires
                 * during startup if there's a PID file present.
                 * @event started
                 * @param {Object} e
                 * @param {run.Process} e.process the process that is started
                 */
                "started"
            ],

            /**
             * Retrieves an array of names of builders available to the system.
             * A builder is a JSON file that describes how a certain file can
             * be executed. The JSON file format is based on and compatible with
             * the sublime build scripts. Besides the build in builders, the
             * user can store builders in ~/.c9/builders. This list will contain
             * both the user's builders as well as the build-in builders.
             * @param {Function} callback           Called when the builders are retrieved
             * @param {Error}    callback.err       The error object if an error occurred.
             * @param {String[]} callback.builders  A list of names of builders.
             */
            listBuilders : listBuilders,

            /**
             * Retrieves an individual builder's JSON object based on it's name.
             * The names of available builders can be retrieved using `listBuilders`.
             * @param {Function} callback         Called when the runner is retrieved
             * @param {Function} callback.err     The error object if an error occurred.
             * @param {Function} callback.runner  A builder object. See {@link run#run} for more information.
             */
            getBuilder : getBuilder,

            /**
             * Builds a file. See `run.run()` for the full documentation
             * @param {Object/"auto"} builder   Object describing how to build a process.
             * @param {Object}        options
             * @param {String}        options.path        The path to the file to build
             * @param {String}        [options.cwd]       The current working directory
             * @param {Boolean}       [options.debug]     Specifies whether to start the process in debug mode
             * @param {String}        [name]              The unique name of the output buffer. Defaults to "output".
             * @param {Function}      callback            Called when the process is started
             * @param {Error}         callback.err        The error object if an error occurred.
             * @returns {run.Process} the process object
             */
            build : build
        });

        register(null, {
            build : plugin
        });
    }
});<|endoftext|>


<commit_before>"use strict";

var assert = require("@sinonjs/referee").assert;

// in order for `is-element.js` to correctly detect the DOM being set up
// in the previous line, we need to reload it, as other tests will have
// loaded `is-element.js`, most likely without a DOM in place
function requireWithDOM(file) {
    require("jsdom-global")();

    delete require.cache[require.resolve(file)];

    return require("./is-element");
}

describe("isElement", function() {
    var isElement;

    before(function() {
        isElement = requireWithDOM("./is-element");
    });

    it("returns true if DOM element node", function() {
        var element = document.createElement("div");
        var checkElement = isElement(element);
        assert.isTrue(checkElement);
    });

    it("returns false if DOM text node", function() {
        var element = document.createTextNode("Hello");
        var checkElement = isElement(element);
        assert.isFalse(checkElement);
    });

    it("returns false if node like object", function() {
        var nodeLike = { nodeType: 1 };
        var checkElement = isElement(nodeLike);
        assert.isFalse(checkElement);
    });

    it("returns false if number", function() {
        var checkElement = isElement(42);
        assert.isFalse(checkElement);
    });

    it("returns false if object", function() {
        var checkElement = isElement({});
        assert.isFalse(checkElement);
    });
});
<commit_msg>Improve readability of is-element.test.js<commit_after>"use strict";

var assert = require("@sinonjs/referee").assert;

// in order for `is-element.js` to correctly detect the DOM being set up
// in the previous line, we need to reload it, as other tests will have
// loaded `is-element.js`, most likely without a DOM in place
function requireWithDOM(file) {
    require("jsdom-global")();

    delete require.cache[require.resolve(file)];

    return require("./is-element");
}

describe("isElement", function() {
    var isElement;

    before(function() {
        isElement = requireWithDOM("./is-element");
    });

    it("returns true if DOM element node", function() {
        var element = document.createElement("div");
        var result = isElement(element);

        assert.isTrue(result);
    });

    it("returns false if DOM text node", function() {
        var element = document.createTextNode("Hello");
        var result = isElement(element);

        assert.isFalse(result);
    });

    it("returns false if node like object", function() {
        var nodeLike = { nodeType: 1 };
        var result = isElement(nodeLike);

        assert.isFalse(result);
    });

    it("returns false if number", function() {
        var result = isElement(42);

        assert.isFalse(result);
    });

    it("returns false if object", function() {
        var result = isElement({});

        assert.isFalse(result);
    });
});
<|endoftext|>


<commit_before>require('module-alias/register')

const fs = require('fs')
const path = require('path')
const glob = require('glob')
const esbuild = require('esbuild')
const sassPlugin = require('esbuild-plugin-sass')

const { makePromise } = require('@/cjs/promises')
const { composePaths } = require('@/cjs/compose-paths')
const { loadTextFile, fileOnly } = require('@/cjs/files')

const paths = composePaths(`
  ${__dirname}
    /src                 = SRC
      /plugins           = SRC_PLUGINS
      /ui
        /index.js        = SRC_UI
        /styles/statements-browser/
          /all.scss      = SRC_CSS

      /bookmarklet.js    = SRC_BOOKMARKLET
      /main.js           = SRC_MAIN

      /_mock-server
        /index.js        = SERVER_SCRIPT

    /dist                = DIST
      /plugins           = DIST_PLUGINS
      /ui.js             = DIST_UI
      /bookmarklet.js    = DIST_BOOKMARKLET
      /main.js           = DIST_MAIN
      /statement.css     = DIST_CSS
`)

// Require plugins folder before moving on...

if (!fs.statSync(paths.DIST_PLUGINS).isDirectory()) {
  process.exit(255)
}

const RUN_MOCK_SERVER = process.argv.some(arg => arg === '--mock-server')
const IS_LOCAL = (process.env.NODE_ENV || 'local') === 'local'
const BUILD_REPLACEMENTS = {
  'process.env.NODE_ENV': `"${process.env.NODE_ENV}"`,
  'process.env.HYDRATE': `"${process.env.HYDRATE}"`
}

console.log('IS_LOCAL', IS_LOCAL)

function main() {
  return buildBookmarklet()
    .then(buildMain)
    .then(buildPlugins)
    .then(buildUi)
    .then(buildCss)
    .then(maybeRunMockServer)
}

function maybeRunMockServer() {
  if (RUN_MOCK_SERVER) {
    const nodemon = require('nodemon')
    nodemon({ script: paths.SERVER_SCRIPT, ext: 'js,jsx,json,scss' })
      .on('start', () => {
        console.log('nodemon started')
      })
      .on('crash', error => {
        console.log('script crashed for some reason')
        console.error(error)
      })

    process.on('SIGINT', function () {
      console.log('Caught interrupt signal')
      nodemon.emit('quit')
      process.exit()
    })
  }
}

//
// Builders
//

function buildBookmarklet() {
  return esbuild
    .build({
      define: BUILD_REPLACEMENTS,
      entryPoints: [paths.SRC_BOOKMARKLET],
      bundle: true,
      minify: true,
      platform: 'browser',
      sourcemap: IS_LOCAL,
      banner: 'javascript:',
      outfile: paths.DIST_BOOKMARKLET
    })
    .then(() => loadTextFile(paths.DIST_BOOKMARKLET))
    .then(bookmarkletContent =>
      fs.writeFileSync(
        paths.DIST_BOOKMARKLET,
        bookmarkletContent.toString().replace('\n', '')
      )
    )
}

function buildMain() {
  return esbuild.build({
    define: BUILD_REPLACEMENTS,
    entryPoints: [paths.SRC_MAIN],
    bundle: true,
    minify: true,
    platform: 'browser',
    sourcemap: IS_LOCAL,
    outfile: paths.DIST_MAIN
  })
}

function buildUi() {
  return esbuild.build({
    define: BUILD_REPLACEMENTS,
    entryPoints: [paths.SRC_UI],
    bundle: true,
    minify: true,
    platform: 'browser',
    jsxFactory: 'm',
    jsxFragment: 'm.Fragment',
    plugins: [sassPlugin()],
    sourcemap: IS_LOCAL,
    outfile: paths.DIST_UI
  })
}

function buildCss() {
  return esbuild.build({
    entryPoints: [paths.SRC_CSS],
    bundle: true,
    minify: true,
    loader: { '.scss': 'css' },
    plugins: [sassPlugin()],
    sourcemap: IS_LOCAL,
    outfile: paths.DIST_CSS
  })
}

function buildPlugins() {
  return (
    allPluginFileNames()
      // Load all plugins
      .then(pluginsFiles =>
        Promise.allSettled(
          pluginsFiles.map(fileName =>
            loadTextFile(fileName).then(src => ({ fileName, src }))
          )
        )
      )
      // Build plugins.js output (but don't write it yet)
      .then(results =>
        results
          .filter(result => result.status === 'fulfilled')
          .map(result => result.value)
          .map(details => {
            const { fileName, src } = details
            const { name, description, urls } = JSON.parse(src)
            const { dir } = path.parse(fileName)
            const srcJs = path.join(dir, 'plugin.js')
            const distJs = path.join(paths.DIST_PLUGINS, `${name}.js`)
            return {
              src: srcJs,
              dist: distJs,
              name,
              description,
              urls
            }
          })
      )
      // Bundle/minify plugins
      .then(pluginInfo =>
        Promise.allSettled(
          pluginInfo.map(info => {
            const { src, dist } = info
            return esbuild
              .build({
                define: BUILD_REPLACEMENTS,
                entryPoints: [src],
                bundle: true,
                minify: true,
                platform: 'browser',
                sourcemap: IS_LOCAL,
                outfile: dist
              })
              .then(() => info)
          })
        )
      )
      // Plugins built successfully, so write-out plugins.js now
      .then(results => {
        const pluginInfo = results
          .filter(result => result.status === 'fulfilled')
          .map(result => {
            // eslint-disable-next-line no-unused-vars
            const { src, dist, ...restValue } = result.value
            return restValue
          })

        const [promise, resolve, reject] = makePromise()

        fs.writeFile(
          'dist/plugins.js',
          `obis.registerPlugins(${JSON.stringify(pluginInfo, null, 2)})`,
          err => (err ? reject(err) : resolve())
        )
        return promise
      })
      .catch(err => console.log('err = ', err))
  )
}

function allPluginFileNames() {
  const [promise, resolve, reject] = makePromise()

  glob(path.join(paths.SRC_PLUGINS, '**/plugin.json'), {}, (err, files) => {
    if (err) {
      return reject(err)
    }

    Promise.all(files.map(fileOnly)).then(resolve, reject)
  })

  return promise
}

main()
<commit_msg>No need for esbuild banner option to do this<commit_after>require('module-alias/register')

const fs = require('fs')
const path = require('path')
const glob = require('glob')
const esbuild = require('esbuild')
const sassPlugin = require('esbuild-plugin-sass')

const { makePromise } = require('@/cjs/promises')
const { composePaths } = require('@/cjs/compose-paths')
const { loadTextFile, fileOnly } = require('@/cjs/files')

const paths = composePaths(`
  ${__dirname}
    /src                 = SRC
      /plugins           = SRC_PLUGINS
      /ui
        /index.js        = SRC_UI
        /styles/statements-browser/
          /all.scss      = SRC_CSS

      /bookmarklet.js    = SRC_BOOKMARKLET
      /main.js           = SRC_MAIN

      /_mock-server
        /index.js        = SERVER_SCRIPT

    /dist                = DIST
      /plugins           = DIST_PLUGINS
      /ui.js             = DIST_UI
      /bookmarklet.js    = DIST_BOOKMARKLET
      /main.js           = DIST_MAIN
      /statement.css     = DIST_CSS
`)

// Require plugins folder before moving on...

if (!fs.statSync(paths.DIST_PLUGINS).isDirectory()) {
  process.exit(255)
}

const RUN_MOCK_SERVER = process.argv.some(arg => arg === '--mock-server')
const IS_LOCAL = (process.env.NODE_ENV || 'local') === 'local'
const BUILD_REPLACEMENTS = {
  'process.env.NODE_ENV': `"${process.env.NODE_ENV}"`,
  'process.env.HYDRATE': `"${process.env.HYDRATE}"`
}

console.log('IS_LOCAL', IS_LOCAL)

function main() {
  return buildBookmarklet()
    .then(buildMain)
    .then(buildPlugins)
    .then(buildUi)
    .then(buildCss)
    .then(maybeRunMockServer)
}

function maybeRunMockServer() {
  if (RUN_MOCK_SERVER) {
    const nodemon = require('nodemon')
    nodemon({ script: paths.SERVER_SCRIPT, ext: 'js,jsx,json,scss' })
      .on('start', () => {
        console.log('nodemon started')
      })
      .on('crash', error => {
        console.log('script crashed for some reason')
        console.error(error)
      })

    process.on('SIGINT', function () {
      console.log('Caught interrupt signal')
      nodemon.emit('quit')
      process.exit()
    })
  }
}

//
// Builders
//

function buildBookmarklet() {
  return esbuild
    .build({
      define: BUILD_REPLACEMENTS,
      entryPoints: [paths.SRC_BOOKMARKLET],
      bundle: true,
      minify: true,
      platform: 'browser',
      sourcemap: IS_LOCAL,
      outfile: paths.DIST_BOOKMARKLET
    })
    .then(() => loadTextFile(paths.DIST_BOOKMARKLET))
    .then(bookmarkletContent =>
      fs.writeFileSync(
        paths.DIST_BOOKMARKLET,
        'javascript:' + bookmarkletContent.toString()
      )
    )
}

function buildMain() {
  return esbuild.build({
    define: BUILD_REPLACEMENTS,
    entryPoints: [paths.SRC_MAIN],
    bundle: true,
    minify: true,
    platform: 'browser',
    sourcemap: IS_LOCAL,
    outfile: paths.DIST_MAIN
  })
}

function buildUi() {
  return esbuild.build({
    define: BUILD_REPLACEMENTS,
    entryPoints: [paths.SRC_UI],
    bundle: true,
    minify: true,
    platform: 'browser',
    jsxFactory: 'm',
    jsxFragment: 'm.Fragment',
    plugins: [sassPlugin()],
    sourcemap: IS_LOCAL,
    outfile: paths.DIST_UI
  })
}

function buildCss() {
  return esbuild.build({
    entryPoints: [paths.SRC_CSS],
    bundle: true,
    minify: true,
    loader: { '.scss': 'css' },
    plugins: [sassPlugin()],
    sourcemap: IS_LOCAL,
    outfile: paths.DIST_CSS
  })
}

function buildPlugins() {
  return (
    allPluginFileNames()
      // Load all plugins
      .then(pluginsFiles =>
        Promise.allSettled(
          pluginsFiles.map(fileName =>
            loadTextFile(fileName).then(src => ({ fileName, src }))
          )
        )
      )
      // Build plugins.js output (but don't write it yet)
      .then(results =>
        results
          .filter(result => result.status === 'fulfilled')
          .map(result => result.value)
          .map(details => {
            const { fileName, src } = details
            const { name, description, urls } = JSON.parse(src)
            const { dir } = path.parse(fileName)
            const srcJs = path.join(dir, 'plugin.js')
            const distJs = path.join(paths.DIST_PLUGINS, `${name}.js`)
            return {
              src: srcJs,
              dist: distJs,
              name,
              description,
              urls
            }
          })
      )
      // Bundle/minify plugins
      .then(pluginInfo =>
        Promise.allSettled(
          pluginInfo.map(info => {
            const { src, dist } = info
            return esbuild
              .build({
                define: BUILD_REPLACEMENTS,
                entryPoints: [src],
                bundle: true,
                minify: true,
                platform: 'browser',
                sourcemap: IS_LOCAL,
                outfile: dist
              })
              .then(() => info)
          })
        )
      )
      // Plugins built successfully, so write-out plugins.js now
      .then(results => {
        const pluginInfo = results
          .filter(result => result.status === 'fulfilled')
          .map(result => {
            // eslint-disable-next-line no-unused-vars
            const { src, dist, ...restValue } = result.value
            return restValue
          })

        const [promise, resolve, reject] = makePromise()

        fs.writeFile(
          'dist/plugins.js',
          `obis.registerPlugins(${JSON.stringify(pluginInfo, null, 2)})`,
          err => (err ? reject(err) : resolve())
        )
        return promise
      })
      .catch(err => console.log('err = ', err))
  )
}

function allPluginFileNames() {
  const [promise, resolve, reject] = makePromise()

  glob(path.join(paths.SRC_PLUGINS, '**/plugin.json'), {}, (err, files) => {
    if (err) {
      return reject(err)
    }

    Promise.all(files.map(fileOnly)).then(resolve, reject)
  })

  return promise
}

main()
<|endoftext|>


<commit_before>var crypto = require('crypto'),
    path = require('path'),
    fs = require('fs');

var uuid = require('node-uuid');

var db = require('../db.js'),
    util = require('../util'),
    defaults = require('../defaults.js'),
    settings = require('../settings');

function create_update(req, res, next) {
  settings.set(req.body);
  var error = settings.save();

  if(error) next(error);
  else res.json(201, settings.toJSON());
}
exports.create = exports.update = util.loginRequired(create_update);

function show(req, res) {
  res.json(settings.toJSON());
}
exports.show = util.loginRequired(show);

function connectionTest(req, res, next) {
  settings.set('DB', req.body.uri);

  db.query('SELECT NOW();', function(err) {
    if(err) {
      if(err.code == 'ENOTFOUND') {
        err.message = 'Failure: Address not found!';
      }
      next(err);
    } else {
      res.json(200, {ok: true});
    }
  });
}
exports.connectionTest = connectionTest;

function tableCreation(req, res, next) {
  res.set('Content-Type','text/event-stream');

  db.syncDB({
    oncomplete: function(err) {
      if(err) return next(err);
      res.end('data: ' + JSON.stringify({done: true}) + '\n\n');
    },

    onprogress: function(script) {
      res.write('data: ' + JSON.stringify({script: script}) + '\n\n');
    },

    forceDrop: false
  });
}
exports.tableCreation = tableCreation;

function commit(req, res, next) {
  var obj = {
      DB: settings.get('DB'),
      SITE_ID: uuid.v4(),
      SECRET_KEY: crypto.randomBytes(64).toString('base64')
    };

  var err = settings.save(obj, settings.DEFAULT_FILENAME);
  if(err) {
    if(err.code == 'EACCES') {
      err.message = 'You don\'t have permission to write to `' + err.path + '`';
    }
    next(err);
  } else {
    res.json(201, {ok: true});
  }
}
exports.commit = commit;

function userCreation(req, res, next) {
  var body = req.body;

  db.users.create(body, function(err) {
    if(err) return next(err);
    res.json(201, {ok: true});
  });
}
exports.userCreation = userCreation;<commit_msg>Pass in a fully qualified path<commit_after>var crypto = require('crypto'),
    path = require('path'),
    fs = require('fs');

var uuid = require('node-uuid');

var db = require('../db.js'),
    util = require('../util'),
    defaults = require('../defaults.js'),
    settings = require('../settings');

function create_update(req, res, next) {
  settings.set(req.body);
  var error = settings.save();

  if(error) next(error);
  else res.json(201, settings.toJSON());
}
exports.create = exports.update = util.loginRequired(create_update);

function show(req, res) {
  res.json(settings.toJSON());
}
exports.show = util.loginRequired(show);

function connectionTest(req, res, next) {
  settings.set('DB', req.body.uri);

  db.query('SELECT NOW();', function(err) {
    if(err) {
      if(err.code == 'ENOTFOUND') {
        err.message = 'Failure: Address not found!';
      }
      next(err);
    } else {
      res.json(200, {ok: true});
    }
  });
}
exports.connectionTest = connectionTest;

function tableCreation(req, res, next) {
  res.set('Content-Type','text/event-stream');

  db.syncDB({
    oncomplete: function(err) {
      if(err) return next(err);
      res.end('data: ' + JSON.stringify({done: true}) + '\n\n');
    },

    onprogress: function(script) {
      res.write('data: ' + JSON.stringify({script: script}) + '\n\n');
    },

    forceDrop: false
  });
}
exports.tableCreation = tableCreation;

function commit(req, res, next) {
  var obj = {
      DB: settings.get('DB'),
      SITE_ID: uuid.v4(),
      SECRET_KEY: crypto.randomBytes(64).toString('base64')
    };

  var err = settings.save(obj, path.join(process.cwd(), settings.DEFAULT_FILENAME));
  if(err) {
    if(err.code == 'EACCES') {
      err.message = 'You don\'t have permission to write to `' + err.path + '`';
    }
    next(err);
  } else {
    res.json(201, {ok: true});
  }
}
exports.commit = commit;

function userCreation(req, res, next) {
  var body = req.body;

  db.users.create(body, function(err) {
    if(err) return next(err);
    res.json(201, {ok: true});
  });
}
exports.userCreation = userCreation;<|endoftext|>


<commit_before>//Require Module
var log4js = require('log4js');
var logger = log4js.getLogger('Logging');
var moment = require('moment-timezone');
var fs = require('fs');

function checkTimeFormat(time){

/*
 * Check time format "hh:mm"
 * Receive a string of time,
 * If the time format is wrong, throw error,
 * else retun true.
 * */

    var checking = time.match(/^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/);

    if(!checking){

        throw new Error('TIME_FORMAT_ERROR');
    }

    return true;
}

function getTimeMs(time){

/*
 * Convert time to ms
 * Receive a string of time,and call checkTimeFormat to make sure the format is right.
 *
 * After that, split the time and convert it to a int,
 * then convert it again to ms, add them together, and return it.
 *
 * */

    checkTimeFormat(time);

    var splitedTime = time.split(':');

    var hour = splitedTime[0];

    var minute = splitedTime[1];

    var hourMs = hour * 60 * 60 * 1000;

    var minMs = minute * 60 *1000;

    var totalMs = hourMs + minMs;

    return totalMs;

}

function getInitTime(timeZone){

    if(timeZone == '' || timeZone == null){

        var currentDate = new Date();

        currentDate.setHours(0);
        currentDate.setMinutes(0);
        currentDate.setSeconds(0);
        currentDate.setMilliseconds(0);

        return currentDate;

    }

    var currentDate = new Date();

    var currentDateTz = new moment.tz(new Date(),timeZone);

    currentDateTz.month(currentDate.getMonth());
    currentDateTz.date(currentDate.getDate());
    currentDateTz.hours(0);
    currentDateTz.minutes(0);
    currentDateTz.seconds(0);
    currentDateTz.milliseconds(0);

    var currentDateMs = currentDateTz.valueOf();

    var newCurrentDate = new Date(currentDateMs)

    return newCurrentDate;
}

function checkKeepAliveTime(keepAliveTimes,lastAliveTime,lastSuccessTime,timeZone){

    var currentDateInited = getInitTime(timeZone).getTime();

    for(var i =0; i < keepAliveTimes.length; i++){
        var lastSuccessTimeMs = lastSuccessTime.getTime();
        var lastAliveTimeMs = null;

        try{
            lastAliveTimeMs = lastAliveTime.getTime();
        }catch(err){}
        var keepAliveTimeMs1 = keepAliveTimes[i];
        var keepAliveTimeMs2 = keepAliveTimes[i+1];

        var totalKeepAliveTimeMs1 = keepAliveTimeMs1 + currentDateInited;
        var totalKeepAliveTimeMs2 = keepAliveTimeMs2 + currentDateInited;

        logger.debug('keepAliveTimes: ', new Date(totalKeepAliveTimeMs1));
        logger.debug('lastSuccessTime: ', new Date(lastSuccessTimeMs));

        if(isNaN(keepAliveTimeMs2) && lastSuccessTimeMs >= totalKeepAliveTimeMs1){

            if(lastAliveTime == null){

                return new Date(totalKeepAliveTimeMs1);
            }

            if(lastAliveTimeMs >= totalKeepAliveTimeMs1){

                return undefined;

            }

            return new Date(totalKeepAliveTimeMs1);
        }

        if(lastSuccessTimeMs >= totalKeepAliveTimeMs1 && lastSuccessTimeMs < totalKeepAliveTimeMs2){
            if(lastAliveTime == null){

                return new Date(totalKeepAliveTimeMs1);

            }

            if(lastAliveTimeMs >= totalKeepAliveTimeMs1){

                continue;
            }

            return new Date(totalKeepAliveTimeMs1);
        }
    }
}

module.exports = {
    checkTimeFormat:checkTimeFormat,
    getTimeMs:getTimeMs,
    getInitTime:getInitTime,
    checkKeepAliveTime:checkKeepAliveTime
}
<commit_msg>Add comment with jsdoc style<commit_after>//Require Module
var log4js = require('log4js');
var logger = log4js.getLogger('Logging');
var moment = require('moment-timezone');
var fs = require('fs');

function checkTimeFormat(time){

/*
 * Check time format "hh:mm"
 * Receive a string of time,
 * If the time format is wrong, throw error,
 * else retun true.
 * */

    var checking = time.match(/^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/);

    if(!checking){

        throw new Error('TIME_FORMAT_ERROR');
    }

    return true;
}

function getTimeMs(time){

/*
 * Convert time to ms
 * Receive a string of time,and call checkTimeFormat to make sure the format is right.
 *
 * After that, split the time and convert it to a int,
 * then convert it again to ms, add them together, and return it.
 *
 * */

    checkTimeFormat(time);

    var splitedTime = time.split(':');

    var hour = splitedTime[0];

    var minute = splitedTime[1];

    var hourMs = hour * 60 * 60 * 1000;

    var minMs = minute * 60 *1000;

    var totalMs = hourMs + minMs;

    return totalMs;

}

function getInitTime(timeZone){

/*
 * Get init time of today
 * Receive a string of timeZone, if it is '' or null,
 * get new Date and set the time to all zero.
 *
 * If it is not null, get new date by moment with the time zone,
 * and convert it to a normal date object.
 *
 * */

    if(timeZone == '' || timeZone == null){

        var currentDate = new Date();

        currentDate.setHours(0);
        currentDate.setMinutes(0);
        currentDate.setSeconds(0);
        currentDate.setMilliseconds(0);

        return currentDate;

    }

    var currentDate = new Date();

    var currentDateTz = new moment.tz(new Date(),timeZone);

    currentDateTz.month(currentDate.getMonth());
    currentDateTz.date(currentDate.getDate());
    currentDateTz.hours(0);
    currentDateTz.minutes(0);
    currentDateTz.seconds(0);
    currentDateTz.milliseconds(0);

    var currentDateMs = currentDateTz.valueOf();

    var newCurrentDate = new Date(currentDateMs)

    return newCurrentDate;
}

function checkKeepAliveTime(keepAliveTimes,lastAliveTime,lastSuccessTime,timeZone){

    /*
     * Check the last success time is match the keepAliveTime and lastAliveTime.
     * Receive a array of keepAliveTimes,a date object of lastAliveTime,
     * a date object of lastSuccess Time and a string of timeZone.
     *
     * It will get a initDate by calling the getInitTime function,
     * then convert lastSuccessTime,lastAliveTime(If it is not null) and keepAliveTime to ms.
     *
     * If the keepAliveTimeMs2 is NaN, lastSuccessTimeMs is bigger than totalKeepAliveTimeMs1,
     * it will return a date object of totalKeepAliveTime.
     * Otherwise, it will return undefined.
     *
     * If the keepAliveTimeMs2 is NaN, lastSuccessTimeMs is bigger than totalKeepAliveTimeMs1,
     * but lastAliveTimeMs is bigger than totalKeepAliveTimeMs1,
     * it will return undefined.
     *
     * If the keepAliveTimeMs2 is not NaN,
     * lastSuccessTimeMs is bigger than totalKeepAliveTimeMs1
     * and smaller than totalKeepAliveTimeMs2,
     * it will return a date object of totalKeepAliveTime.
     * Otherwise, it will return undefined.
     *
     * If the keepAliveTimeMs2 is not NaN,
     * lastSuccessTimeMs is bigger than totalKeepAliveTimeMs1,
     * but lastAliveTimeMs is bigger than totalKeepAliveTimeMs1,
     * it will return undefined.
     * Otherwise, it will return a date object of totalKeepAliveTime.
     *
     *
     * */

    var currentDateInited = getInitTime(timeZone).getTime();

    for(var i =0; i < keepAliveTimes.length; i++){
        var lastSuccessTimeMs = lastSuccessTime.getTime();
        var lastAliveTimeMs = null;

        try{
            lastAliveTimeMs = lastAliveTime.getTime();
        }catch(err){}
        var keepAliveTimeMs1 = keepAliveTimes[i];
        var keepAliveTimeMs2 = keepAliveTimes[i+1];

        //Convert the KeepAliveTime to be a timestamp of current Date.

        var totalKeepAliveTimeMs1 = keepAliveTimeMs1 + currentDateInited;
        var totalKeepAliveTimeMs2 = keepAliveTimeMs2 + currentDateInited;

        logger.debug('keepAliveTimes: ', new Date(totalKeepAliveTimeMs1));
        logger.debug('lastSuccessTime: ', new Date(lastSuccessTimeMs));

        if(isNaN(keepAliveTimeMs2) && lastSuccessTimeMs >= totalKeepAliveTimeMs1){

            if(lastAliveTime == null){

                return new Date(totalKeepAliveTimeMs1);
            }

            if(lastAliveTimeMs >= totalKeepAliveTimeMs1){

                return undefined;

            }

            return new Date(totalKeepAliveTimeMs1);
        }

        if(lastSuccessTimeMs >= totalKeepAliveTimeMs1 && lastSuccessTimeMs < totalKeepAliveTimeMs2){
            if(lastAliveTime == null){

                return new Date(totalKeepAliveTimeMs1);

            }

            if(lastAliveTimeMs >= totalKeepAliveTimeMs1){

                continue;
            }

            return new Date(totalKeepAliveTimeMs1);
        }
    }
}

module.exports = {
    checkTimeFormat:checkTimeFormat,
    getTimeMs:getTimeMs,
    getInitTime:getInitTime,
    checkKeepAliveTime:checkKeepAliveTime
}
<|endoftext|>


<commit_before>var Handlebars = require('handlebars');
var lessc = require('less');
var Promise = require('bluebird');
var path = require('path');
var fs = Promise.promisifyAll(require('fs'));
var browserify = require('browserify');
var moment = require('moment');
var _ = require('lodash');

Handlebars.registerHelper('lowercase', function (str) {
  return str.toLowerCase();
});

Handlebars.registerHelper('date', function (val) {
  return moment(val).format('MMM GGGG');
});

function identity (val) { return val; }

module.exports = {
  __dirname: __dirname,
  DEFAULT_OPTS: {
    paths: {
      hbs: path.resolve(__dirname, 'index.hbs'),
      less: path.resolve(__dirname, 'index.less'),
      js: path.resolve(__dirname, 'index.js')
    },
    hbs: {},
    less: {append: ''},
    js: {append: ''},
    prerender: identity
  },
  render: Promise.method(function (resume, opts) {
    opts = _.merge({}, module.exports.DEFAULT_OPTS, opts);
    return Promise
      .props({
        render: fs.readFileAsync(opts.paths.hbs, 'utf8')
          .then(function (hbs) { return Handlebars.compile(hbs, opts.hbs.opts); }),

        css: fs.readFileAsync(opts.paths.less, 'utf8')
          .then(function (less) {
            return lessc.render(less + opts.less.append, _.merge({
              filename: opts.paths.less,
              compress: true,
              rootpath: path.relative(process.cwd(), __dirname)
            }, opts.less.opts));
          })
          .get('css'),

        js: Promise.promisifyAll(browserify(_.merge({
          entries: opts.paths.js,
          transform: [[require('uglifyify'), {global: true}]]
        }, opts.js.opts))).bundleAsync()
      })
      .then(opts.prerender)
      .then(function (result) {
        var phone = (resume.basics || {}).phone;
        if (phone) resume.basics.cleanedPhone = phone.replace(/[^\d]/g, '');

        return result.render({
          resume: resume,
          css: result.css,
          js: result.js
        });
      });
  })
};
<commit_msg>fix(unused): remove unused code<commit_after>var Handlebars = require('handlebars');
var lessc = require('less');
var Promise = require('bluebird');
var path = require('path');
var fs = Promise.promisifyAll(require('fs'));
var browserify = require('browserify');
var moment = require('moment');
var _ = require('lodash');

Handlebars.registerHelper('lowercase', function (str) {
  return str.toLowerCase();
});

Handlebars.registerHelper('date', function (val) {
  return moment(val).format('MMM GGGG');
});

module.exports = {
  __dirname: __dirname,
  DEFAULT_OPTS: {
    paths: {
      hbs: path.resolve(__dirname, 'index.hbs'),
      less: path.resolve(__dirname, 'index.less'),
      js: path.resolve(__dirname, 'index.js')
    },
    hbs: {},
    less: {append: ''},
    js: {}
  },
  render: Promise.method(function (resume, opts) {
    opts = _.merge({}, module.exports.DEFAULT_OPTS, opts);
    return Promise
      .props({
        render: fs.readFileAsync(opts.paths.hbs, 'utf8')
          .then(function (hbs) { return Handlebars.compile(hbs, opts.hbs.opts); }),

        css: fs.readFileAsync(opts.paths.less, 'utf8')
          .then(function (less) {
            return lessc.render(less + opts.less.append, _.merge({
              filename: opts.paths.less,
              compress: true,
              rootpath: path.relative(process.cwd(), __dirname)
            }, opts.less.opts));
          })
          .get('css'),

        js: Promise.promisifyAll(browserify(_.merge({
          entries: opts.paths.js,
          transform: [[require('uglifyify'), {global: true}]]
        }, opts.js.opts))).bundleAsync()
      })
      .then(opts.prerender)
      .then(function (result) {
        var phone = (resume.basics || {}).phone;
        if (phone) resume.basics.cleanedPhone = phone.replace(/[^\d]/g, '');

        return result.render({
          resume: resume,
          css: result.css,
          js: result.js
        });
      });
  })
};
<|endoftext|>


<commit_before>
import {
    InsertTransactionDispatcher,
    UpdateTransactionDispatcher,
    DeleteTransactionDispatcher,
    LoginTransactionDispatcher,
    RegisterTransactionDispatcher } from './transaction';

import {
    ViewDispatcher } from './view';

class ApiDispatcher {

    constructor(api) {
        this._api = api;
        this._insertTransactionDispatcher = this._createInsertTransactionDispatcher();
        this._updateTransactionDispatcher = this._createUpdateTransactionDispatcher();
        this._deleteTransactionDispatcher = this._createDeleteTransactionDispatcher();
        this._loginTransactionDispatcher = this._createLoginTransactionDispatcher();
        this._registerTransactionDispatcher = this._createRegisterTransactionDispatcher();
        this._viewDispatcher = this._createViewTransactionDispatcher();
    }

    _createInsertTransactionDispatcher() {
        return new InsertTransactionDispatcher();
    }

    _createUpdateTransactionDispatcher() {
        return new UpdateTransactionDispatcher();
    }

    _createDeleteTransactionDispatcher() {
        return new DeleteTransactionDispatcher();
    }

    _createLoginTransactionDispatcher() {
        return new LoginTransactionDispatcher();
    }

    _createRegisterTransactionDispatcher() {
        return new RegisterTransactionDispatcher();
    }

    _createViewDispatcher() {
        return new ViewDispatcher();
    }

    dispatch(action) {

    }
}<commit_msg>implemented ApiDispatcher.js<commit_after>
import {
    InsertTransactionDispatcher,
    UpdateTransactionDispatcher,
    DeleteTransactionDispatcher,
    LoginTransactionDispatcher,
    RegisterTransactionDispatcher } from './transaction';

import {
    ViewDispatcher } from './view';

class ApiDispatcher {

    constructor(api) {
        this._api = api;
        this._cacheDispatchers = this._createCacheDispatchers();
        this._transactionDispatchers = this._createTransactionDispatchers();
        this._viewDispatcher = this._createViewTransactionDispatcher();
    }

    _createCacheDispatchers() {
        const cacheDispatchers = {};
        return cacheDispatchers;
    }

    _getCacheDispatcher($itemType) {
        return this._cacheDispatchers[$itemType];
    }

    _createTransactionDispatchers() {
        const transactionDispatchers = {
            'insert': this.__createInsertTransactionDispatcher(),
            'update': this._createUpdateTransactionDispatcher(),
            'delete': this._createDeleteTransactionDispatcher(),
            'login': this._createLoginTransactionDispatcher(),
            'register': this._createRegisterTransactionDispatcher()
        };
        return transactionDispatchers;
    }

    _getTransactionDispatcher($type) {
        return this._transactionDispatchers[$type];
    }

    _createInsertTransactionDispatcher() {
        return new InsertTransactionDispatcher();
    }

    _createUpdateTransactionDispatcher() {
        return new UpdateTransactionDispatcher();
    }

    _createDeleteTransactionDispatcher() {
        return new DeleteTransactionDispatcher();
    }

    _createLoginTransactionDispatcher() {
        return new LoginTransactionDispatcher();
    }

    _createRegisterTransactionDispatcher() {
        return new RegisterTransactionDispatcher();
    }

    _createViewDispatcher() {
        return new ViewDispatcher();
    }

    dispatch(action) {
        const actionTypeFrags = action.type.split('_');
        if (actionTypeFrags.length >= 2) {
            if (actionTypeFrags[1] === 'TRANSACTION') {
                const transactionType = actionTypeFrags[2].toLowerCase();
                const transactionDispatcher = this._getTransactionDispatcher(transactionType);
                transactionDispatcher.dispatch(api.transactions, action);
            }
            else if (actionTypeFrags[1] === 'VIEW') {
                const viewDispatcher = this._getViewDispatcher();
                viewDispatcher.dispatch(api.views, action);
            }
            else if (actionTypeFrags[1] === 'CACHE') {
                const itemType = actionTypeFrags[2].toLowerCase();
                const cacheDispatcher = this._getCacheDispatcher(itemType);
                cacheDispatcher.dispatch(api.cache(itemType), action);
            }
        }
    }
}<|endoftext|>


<commit_before>/*
 *
 * (c) Copyright Ascensio System SIA 2010-2019
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
 * street, Riga, Latvia, EU, LV-1050.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

/**
 *  EditParagraph.js
 *  Document Editor
 *
 *  Created by Alexander Yuzhin on 10/14/16
 *  Copyright (c) 2018 Ascensio System SIA. All rights reserved.
 *
 */

define([
    'core',
    'documenteditor/mobile/app/view/edit/EditParagraph',
    'jquery',
    'underscore',
    'backbone'
], function (core, view, $, _, Backbone) {
    'use strict';

    DE.Controllers.EditParagraph = Backbone.Controller.extend(_.extend((function() {
        // Private
        var _stack = [],
            _paragraphInfo = {},
            _paragraphObject = undefined,
            _paragraphProperty = undefined,
            _styles = [],
            _styleThumbSize,
            _styleName,
            metricText = Common.Utils.Metric.getCurrentMetricName();

        return {
            models: [],
            collections: [],
            views: [
                'EditParagraph'
            ],

            initialize: function () {
                Common.NotificationCenter.on('editcontainer:show', _.bind(this.initEvents, this));
                Common.NotificationCenter.on('editcategory:show',  _.bind(this.categoryShow, this));

                this.addListeners({
                    'EditParagraph': {
                        'page:show'     : this.onPageShow,
                        'style:click'   : this.onStyleClick
                    }
                });
            },

            setApi: function (api) {
                var me = this;
                me.api = api;

                me.api.asc_setParagraphStylesSizes(330, 38);

                me.api.asc_registerCallback('asc_onInitEditorStyles',   _.bind(me.onApiInitEditorStyles, me));
                me.api.asc_registerCallback('asc_onFocusObject',        _.bind(me.onApiFocusObject, me));
                me.api.asc_registerCallback('asc_onParaStyleName',      _.bind(me.onApiParagraphStyleChange, me));
            },

            onLaunch: function () {
                this.createView('EditParagraph').render();
            },

            initEvents: function () {
                var me = this;

                me.initSettings();
            },

            categoryShow: function (e) {
                var $target = $(e.currentTarget);

                if ($target && $target.prop('id') === 'edit-paragraph') {
                    this.initSettings();
                }
            },

            onPageShow: function () {
                var me = this,
                    paletteBackgroundColor = me.getView('EditParagraph').paletteBackgroundColor;

                $('#paragraph-distance-before .button').single('click',          _.bind(me.onDistanceBefore, me));
                $('#paragraph-distance-after .button').single('click',           _.bind(me.onDistanceAfter, me));
                $('#paragraph-spin-first-line .button').single('click',          _.bind(me.onSpinFirstLine, me));
                $('#paragraph-space input:checkbox').single('change',            _.bind(me.onSpaceBetween, me));
                $('#paragraph-page-break input:checkbox').single('change',       _.bind(me.onBreakBefore, me));
                $('#paragraph-page-orphan input:checkbox').single('change',      _.bind(me.onOrphan, me));
                $('#paragraph-page-keeptogether input:checkbox').single('change',_.bind(me.onKeepTogether, me));
                $('#paragraph-page-keepnext input:checkbox').single('change',    _.bind(me.onKeepNext, me));

                paletteBackgroundColor && paletteBackgroundColor.on('select',    _.bind(me.onBackgroundColor, me));

                me.initSettings();
            },

            initSettings: function () {
                var me = this;

                var selectedElements = me.api.getSelectedElements();
                if (selectedElements && _.isArray(selectedElements)) {
                    for (var i = selectedElements.length - 1; i >= 0; i--) {
                        if (Asc.c_oAscTypeSelectElement.Paragraph == selectedElements[i].get_ObjectType()) {
                            _paragraphProperty = selectedElements[i].get_ObjectValue();
                            break;
                        }
                    }
                }

                if (_paragraphProperty) {
                    if (_paragraphProperty.get_Ind()===null || _paragraphProperty.get_Ind()===undefined) {
                        _paragraphProperty.get_Ind().put_FirstLine(0);
                    }
                    $('#paragraph-spin-first-line .item-after label').text(_paragraphProperty.get_Ind().get_FirstLine() + ' ' + metricText);
                }

                if (_paragraphObject) {
                    _paragraphInfo.spaceBefore = _paragraphObject.get_Spacing().get_Before() < 0 ? _paragraphObject.get_Spacing().get_Before() : Common.Utils.Metric.fnRecalcFromMM(_paragraphObject.get_Spacing().get_Before());
                    _paragraphInfo.spaceAfter  = _paragraphObject.get_Spacing().get_After() < 0 ? _paragraphObject.get_Spacing().get_After() : Common.Utils.Metric.fnRecalcFromMM(_paragraphObject.get_Spacing().get_After());
                    $('#paragraph-distance-before .item-after label').text(_paragraphInfo.spaceBefore < 0 ? 'Auto' : _paragraphInfo.spaceBefore + ' ' + metricText);
                    $('#paragraph-distance-after .item-after label').text(_paragraphInfo.spaceAfter < 0 ? 'Auto' : _paragraphInfo.spaceAfter + ' ' + metricText);

                    $('#paragraph-space input:checkbox').prop('checked', _paragraphObject.get_ContextualSpacing());
                    $('#paragraph-page-break input:checkbox').prop('checked', _paragraphObject.get_PageBreakBefore());
                    $('#paragraph-page-orphan input:checkbox').prop('checked', _paragraphObject.get_WidowControl());
                    $('#paragraph-page-keeptogether input:checkbox').prop('checked', _paragraphObject.get_KeepLines());
                    $('#paragraph-page-keepnext input:checkbox').prop('checked', _paragraphObject.get_KeepNext());

                    // Background color
                    var shade = _paragraphObject.get_Shade(),
                        backColor = 'transparent';

                    if (!_.isNull(shade) && !_.isUndefined(shade) && shade.get_Value()===Asc.c_oAscShdClear) {
                        var color = shade.get_Color();
                        if (color) {
                            if (color.get_type() == Asc.c_oAscColor.COLOR_TYPE_SCHEME) {
                                backColor = {
                                    color: Common.Utils.ThemeColor.getHexColor(color.get_r(), color.get_g(), color.get_b()),
                                    effectValue: color.get_value()
                                };
                            } else {
                                backColor = Common.Utils.ThemeColor.getHexColor(color.get_r(), color.get_g(), color.get_b());
                            }
                        }
                    }

                    $('#paragraph-background .color-preview').css('background-color', (backColor === 'transparent') ? backColor : ('#' + (_.isObject(backColor) ? backColor.color : backColor)));

                    var palette = me.getView('EditParagraph').paletteBackgroundColor;

                    if (palette) {
                        palette.select(backColor);
                    }

                    $('#paragraph-list input[name=paragraph-style]').val([_styleName]);
                }
            },

            onStyleClick: function (view, e) {
                var $item = $(e.currentTarget).find('input');

                if ($item) {
                    this.api.put_Style($item.prop('value'));
                }
            },

            // Public
            getStyles: function () {
                return _styles || [];
            },

            getThumbSize: function () {
                return _styleThumbSize || {width: 0, height: 0};
            },

            // Handlers

            onBackgroundColor: function (palette, color) {
                var me = this;

                $('#paragraph-background .color-preview').css('background-color', (color === 'transparent') ? color : ('#' + (_.isObject(color) ? color.color : color)));

                if (me.api) {
                    var properties = new Asc.asc_CParagraphProperty();

                    properties.put_Shade(new Asc.asc_CParagraphShd());

                    if (color == 'transparent') {
                        properties.get_Shade().put_Value(Asc.c_oAscShdNil);
                    } else {
                        properties.get_Shade().put_Value(Asc.c_oAscShdClear);
                        properties.get_Shade().put_Color(Common.Utils.ThemeColor.getRgbColor(color));
                    }

                    me.api.paraApply(properties);
                }
            },

            onDistanceBefore: function (e) {
                var $button = $(e.currentTarget),
                    distance = _paragraphInfo.spaceBefore;

                if ($button.hasClass('decrement')) {
                    distance = Math.max(-1, --distance);
                } else {
                    distance = Math.min(100, ++distance);
                }

                _paragraphInfo.spaceBefore = distance;

                $('#paragraph-distance-before .item-after label').text(_paragraphInfo.spaceBefore < 0 ? 'Auto' : (_paragraphInfo.spaceBefore) + ' ' + metricText);

                this.api.put_LineSpacingBeforeAfter(0, (_paragraphInfo.spaceBefore < 0) ? -1 : Common.Utils.Metric.fnRecalcToMM(_paragraphInfo.spaceBefore));
            },

            onDistanceAfter: function (e) {
                var $button = $(e.currentTarget),
                    distance = _paragraphInfo.spaceAfter;

                if ($button.hasClass('decrement')) {
                    distance = Math.max(-1, --distance);
                } else {
                    distance = Math.min(100, ++distance);
                }
            },

            onSpinFirstLine: function(e) {
                var $button = $(e.currentTarget),
                    distance = _paragraphProperty.get_Ind().get_FirstLine();

                if ($button.hasClass('decrement')) {
                    distance = Math.max(-999, --distance);
                } else {
                    distance = Math.min(999, ++distance);
                }

                _paragraphProperty.get_Ind().put_FirstLine(distance)

                $('#paragraph-spin-first-line .item-after label').text(distance + ' ' + metricText);
                this.api.paraApply(_paragraphProperty);
            },

            onSpaceBetween: function (e) {
                var $checkbox = $(e.currentTarget);
                this.api.put_AddSpaceBetweenPrg($checkbox.is(':checked'));
            },

            onBreakBefore: function (e) {
                var $checkbox = $(e.currentTarget);
                var properties = new Asc.asc_CParagraphProperty();

                properties.put_PageBreakBefore($checkbox.is(':checked'));
                this.api.paraApply(properties);
            },

            onOrphan: function (e) {
                var $checkbox = $(e.currentTarget);
                var properties = new Asc.asc_CParagraphProperty();

                properties.put_WidowControl($checkbox.is(':checked'));
                this.api.paraApply(properties);
            },

            onKeepTogether: function (e) {
                var $checkbox = $(e.currentTarget);
                var properties = new Asc.asc_CParagraphProperty();

                properties.put_KeepLines($checkbox.is(':checked'));
                this.api.paraApply(properties);
            },

            onKeepNext: function (e) {
                var $checkbox = $(e.currentTarget);
                var properties = new Asc.asc_CParagraphProperty();

                properties.put_KeepNext($checkbox.is(':checked'));
                this.api.paraApply(properties);
            },

            // API handlers

            onApiFocusObject: function (objects) {
                _stack = objects;

                var paragraphs = [];

                _.each(_stack, function(object) {
                    if (object.get_ObjectType() == Asc.c_oAscTypeSelectElement.Paragraph) {
                        paragraphs.push(object);
                    }
                });

                if (paragraphs.length > 0) {
                    var object = paragraphs[paragraphs.length - 1]; // get top
                    _paragraphObject = object.get_ObjectValue();
                } else {
                    _paragraphObject = undefined;
                }
            },

            onApiInitEditorStyles: function (styles) {
                window.styles_loaded = false;

                if (styles.length < 1) {
                    return;
                }

                _styles = [];
                _styleThumbSize = {
                    width   : styles.STYLE_THUMBNAIL_WIDTH,
                    height  : styles.STYLE_THUMBNAIL_HEIGHT
                };

                _.each(styles.get_MergedStyles(), function(style){
                    _styles.push({
                        image   : style.asc_getImage(),
                        name    : style.get_Name()
                    });
                });

                window.styles_loaded = true;
            },

            onApiParagraphStyleChange: function(name) {
                _styleName = name;
                $('#paragraph-list input[name=paragraph-style]').val([_styleName]);
            }
        }
    })(), DE.Controllers.EditParagraph || {}))
});<commit_msg>[DE mobile] Fix for rev.2592bffef1df37996f8d521ba247d2fa277b2a62 ( 13 марта 2019 г. 13:59:41 [de] Add edit of first line of the paragraph)<commit_after>/*
 *
 * (c) Copyright Ascensio System SIA 2010-2019
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
 * street, Riga, Latvia, EU, LV-1050.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
 */

/**
 *  EditParagraph.js
 *  Document Editor
 *
 *  Created by Alexander Yuzhin on 10/14/16
 *  Copyright (c) 2018 Ascensio System SIA. All rights reserved.
 *
 */

define([
    'core',
    'documenteditor/mobile/app/view/edit/EditParagraph',
    'jquery',
    'underscore',
    'backbone'
], function (core, view, $, _, Backbone) {
    'use strict';

    DE.Controllers.EditParagraph = Backbone.Controller.extend(_.extend((function() {
        // Private
        var _stack = [],
            _paragraphInfo = {},
            _paragraphObject = undefined,
            _paragraphProperty = undefined,
            _styles = [],
            _styleThumbSize,
            _styleName,
            metricText = Common.Utils.Metric.getCurrentMetricName();

        return {
            models: [],
            collections: [],
            views: [
                'EditParagraph'
            ],

            initialize: function () {
                Common.NotificationCenter.on('editcontainer:show', _.bind(this.initEvents, this));
                Common.NotificationCenter.on('editcategory:show',  _.bind(this.categoryShow, this));

                this.addListeners({
                    'EditParagraph': {
                        'page:show'     : this.onPageShow,
                        'style:click'   : this.onStyleClick
                    }
                });
            },

            setApi: function (api) {
                var me = this;
                me.api = api;

                me.api.asc_setParagraphStylesSizes(330, 38);

                me.api.asc_registerCallback('asc_onInitEditorStyles',   _.bind(me.onApiInitEditorStyles, me));
                me.api.asc_registerCallback('asc_onFocusObject',        _.bind(me.onApiFocusObject, me));
                me.api.asc_registerCallback('asc_onParaStyleName',      _.bind(me.onApiParagraphStyleChange, me));
            },

            onLaunch: function () {
                this.createView('EditParagraph').render();
            },

            initEvents: function () {
                var me = this;

                me.initSettings();
            },

            categoryShow: function (e) {
                var $target = $(e.currentTarget);

                if ($target && $target.prop('id') === 'edit-paragraph') {
                    this.initSettings();
                }
            },

            onPageShow: function () {
                var me = this,
                    paletteBackgroundColor = me.getView('EditParagraph').paletteBackgroundColor;

                $('#paragraph-distance-before .button').single('click',          _.bind(me.onDistanceBefore, me));
                $('#paragraph-distance-after .button').single('click',           _.bind(me.onDistanceAfter, me));
                $('#paragraph-spin-first-line .button').single('click',          _.bind(me.onSpinFirstLine, me));
                $('#paragraph-space input:checkbox').single('change',            _.bind(me.onSpaceBetween, me));
                $('#paragraph-page-break input:checkbox').single('change',       _.bind(me.onBreakBefore, me));
                $('#paragraph-page-orphan input:checkbox').single('change',      _.bind(me.onOrphan, me));
                $('#paragraph-page-keeptogether input:checkbox').single('change',_.bind(me.onKeepTogether, me));
                $('#paragraph-page-keepnext input:checkbox').single('change',    _.bind(me.onKeepNext, me));

                paletteBackgroundColor && paletteBackgroundColor.on('select',    _.bind(me.onBackgroundColor, me));

                me.initSettings();
            },

            initSettings: function () {
                var me = this;

                var selectedElements = me.api.getSelectedElements();
                if (selectedElements && _.isArray(selectedElements)) {
                    for (var i = selectedElements.length - 1; i >= 0; i--) {
                        if (Asc.c_oAscTypeSelectElement.Paragraph == selectedElements[i].get_ObjectType()) {
                            _paragraphProperty = selectedElements[i].get_ObjectValue();
                            break;
                        }
                    }
                }

                if (_paragraphProperty) {
                    if (_paragraphProperty.get_Ind()===null || _paragraphProperty.get_Ind()===undefined) {
                        _paragraphProperty.get_Ind().put_FirstLine(0);
                    }
                    $('#paragraph-spin-first-line .item-after label').text(_paragraphProperty.get_Ind().get_FirstLine() + ' ' + metricText);
                }

                if (_paragraphObject) {
                    _paragraphInfo.spaceBefore = _paragraphObject.get_Spacing().get_Before() < 0 ? _paragraphObject.get_Spacing().get_Before() : Common.Utils.Metric.fnRecalcFromMM(_paragraphObject.get_Spacing().get_Before());
                    _paragraphInfo.spaceAfter  = _paragraphObject.get_Spacing().get_After() < 0 ? _paragraphObject.get_Spacing().get_After() : Common.Utils.Metric.fnRecalcFromMM(_paragraphObject.get_Spacing().get_After());
                    $('#paragraph-distance-before .item-after label').text(_paragraphInfo.spaceBefore < 0 ? 'Auto' : _paragraphInfo.spaceBefore + ' ' + metricText);
                    $('#paragraph-distance-after .item-after label').text(_paragraphInfo.spaceAfter < 0 ? 'Auto' : _paragraphInfo.spaceAfter + ' ' + metricText);

                    $('#paragraph-space input:checkbox').prop('checked', _paragraphObject.get_ContextualSpacing());
                    $('#paragraph-page-break input:checkbox').prop('checked', _paragraphObject.get_PageBreakBefore());
                    $('#paragraph-page-orphan input:checkbox').prop('checked', _paragraphObject.get_WidowControl());
                    $('#paragraph-page-keeptogether input:checkbox').prop('checked', _paragraphObject.get_KeepLines());
                    $('#paragraph-page-keepnext input:checkbox').prop('checked', _paragraphObject.get_KeepNext());

                    // Background color
                    var shade = _paragraphObject.get_Shade(),
                        backColor = 'transparent';

                    if (!_.isNull(shade) && !_.isUndefined(shade) && shade.get_Value()===Asc.c_oAscShdClear) {
                        var color = shade.get_Color();
                        if (color) {
                            if (color.get_type() == Asc.c_oAscColor.COLOR_TYPE_SCHEME) {
                                backColor = {
                                    color: Common.Utils.ThemeColor.getHexColor(color.get_r(), color.get_g(), color.get_b()),
                                    effectValue: color.get_value()
                                };
                            } else {
                                backColor = Common.Utils.ThemeColor.getHexColor(color.get_r(), color.get_g(), color.get_b());
                            }
                        }
                    }

                    $('#paragraph-background .color-preview').css('background-color', (backColor === 'transparent') ? backColor : ('#' + (_.isObject(backColor) ? backColor.color : backColor)));

                    var palette = me.getView('EditParagraph').paletteBackgroundColor;

                    if (palette) {
                        palette.select(backColor);
                    }

                    $('#paragraph-list input[name=paragraph-style]').val([_styleName]);
                }
            },

            onStyleClick: function (view, e) {
                var $item = $(e.currentTarget).find('input');

                if ($item) {
                    this.api.put_Style($item.prop('value'));
                }
            },

            // Public
            getStyles: function () {
                return _styles || [];
            },

            getThumbSize: function () {
                return _styleThumbSize || {width: 0, height: 0};
            },

            // Handlers

            onBackgroundColor: function (palette, color) {
                var me = this;

                $('#paragraph-background .color-preview').css('background-color', (color === 'transparent') ? color : ('#' + (_.isObject(color) ? color.color : color)));

                if (me.api) {
                    var properties = new Asc.asc_CParagraphProperty();

                    properties.put_Shade(new Asc.asc_CParagraphShd());

                    if (color == 'transparent') {
                        properties.get_Shade().put_Value(Asc.c_oAscShdNil);
                    } else {
                        properties.get_Shade().put_Value(Asc.c_oAscShdClear);
                        properties.get_Shade().put_Color(Common.Utils.ThemeColor.getRgbColor(color));
                    }

                    me.api.paraApply(properties);
                }
            },

            onDistanceBefore: function (e) {
                var $button = $(e.currentTarget),
                    distance = _paragraphInfo.spaceBefore;

                if ($button.hasClass('decrement')) {
                    distance = Math.max(-1, --distance);
                } else {
                    distance = Math.min(100, ++distance);
                }

                _paragraphInfo.spaceBefore = distance;

                $('#paragraph-distance-before .item-after label').text(_paragraphInfo.spaceBefore < 0 ? 'Auto' : (_paragraphInfo.spaceBefore) + ' ' + metricText);

                this.api.put_LineSpacingBeforeAfter(0, (_paragraphInfo.spaceBefore < 0) ? -1 : Common.Utils.Metric.fnRecalcToMM(_paragraphInfo.spaceBefore));
            },

            onDistanceAfter: function (e) {
                var $button = $(e.currentTarget),
                    distance = _paragraphInfo.spaceAfter;

                if ($button.hasClass('decrement')) {
                    distance = Math.max(-1, --distance);
                } else {
                    distance = Math.min(100, ++distance);
                }

                _paragraphInfo.spaceAfter = distance;

                $('#paragraph-distance-after .item-after label').text(_paragraphInfo.spaceAfter < 0 ? 'Auto' : (_paragraphInfo.spaceAfter) + ' ' + metricText);
                this.api.put_LineSpacingBeforeAfter(1, (_paragraphInfo.spaceAfter < 0) ? -1 : Common.Utils.Metric.fnRecalcToMM(_paragraphInfo.spaceAfter));
            },

            onSpinFirstLine: function(e) {
                var $button = $(e.currentTarget),
                    distance = _paragraphProperty.get_Ind().get_FirstLine();

                if ($button.hasClass('decrement')) {
                    distance = Math.max(-999, --distance);
                } else {
                    distance = Math.min(999, ++distance);
                }

                _paragraphProperty.get_Ind().put_FirstLine(distance)

                $('#paragraph-spin-first-line .item-after label').text(distance + ' ' + metricText);
                this.api.paraApply(_paragraphProperty);
            },

            onSpaceBetween: function (e) {
                var $checkbox = $(e.currentTarget);
                this.api.put_AddSpaceBetweenPrg($checkbox.is(':checked'));
            },

            onBreakBefore: function (e) {
                var $checkbox = $(e.currentTarget);
                var properties = new Asc.asc_CParagraphProperty();

                properties.put_PageBreakBefore($checkbox.is(':checked'));
                this.api.paraApply(properties);
            },

            onOrphan: function (e) {
                var $checkbox = $(e.currentTarget);
                var properties = new Asc.asc_CParagraphProperty();

                properties.put_WidowControl($checkbox.is(':checked'));
                this.api.paraApply(properties);
            },

            onKeepTogether: function (e) {
                var $checkbox = $(e.currentTarget);
                var properties = new Asc.asc_CParagraphProperty();

                properties.put_KeepLines($checkbox.is(':checked'));
                this.api.paraApply(properties);
            },

            onKeepNext: function (e) {
                var $checkbox = $(e.currentTarget);
                var properties = new Asc.asc_CParagraphProperty();

                properties.put_KeepNext($checkbox.is(':checked'));
                this.api.paraApply(properties);
            },

            // API handlers

            onApiFocusObject: function (objects) {
                _stack = objects;

                var paragraphs = [];

                _.each(_stack, function(object) {
                    if (object.get_ObjectType() == Asc.c_oAscTypeSelectElement.Paragraph) {
                        paragraphs.push(object);
                    }
                });

                if (paragraphs.length > 0) {
                    var object = paragraphs[paragraphs.length - 1]; // get top
                    _paragraphObject = object.get_ObjectValue();
                } else {
                    _paragraphObject = undefined;
                }
            },

            onApiInitEditorStyles: function (styles) {
                window.styles_loaded = false;

                if (styles.length < 1) {
                    return;
                }

                _styles = [];
                _styleThumbSize = {
                    width   : styles.STYLE_THUMBNAIL_WIDTH,
                    height  : styles.STYLE_THUMBNAIL_HEIGHT
                };

                _.each(styles.get_MergedStyles(), function(style){
                    _styles.push({
                        image   : style.asc_getImage(),
                        name    : style.get_Name()
                    });
                });

                window.styles_loaded = true;
            },

            onApiParagraphStyleChange: function(name) {
                _styleName = name;
                $('#paragraph-list input[name=paragraph-style]').val([_styleName]);
            }
        }
    })(), DE.Controllers.EditParagraph || {}))
});<|endoftext|>