<commit_before>'use strict';

var util     = require('util')
    ,qs      = require('querystring')
    ,request = require('request');

var API = '/api/json';
var NEWJOB = '%s/createItem/?name=%s';
var DELETE = '%s/job/%s/doDelete';
var BUILD = '%s/job/%s/build' + API;
var STOP_BUILD = '%s/job/%s/%s/stop' + API;
var BUILD_INFO = '%s/job/%s/%s' + API;
var DISABLE = '%s/job/%s/disable';
var ENABLE = '%s/job/%s/enable';
var BUILDWITHPARAMS = '%s/job/%s/buildWithParameters';
var CONFIG = '%s/job/%s/config.xml';
var JOBINFO = '%s/job/%s' + API;
var LIST = '%s' + API;
var LIST_VIEW = '%s/view/%s' + API;
var LAST_SUCCESS = '%s/job/%s/lastSuccessfulBuild' + API;
var TEST_REPORT = '%s/job/%s/lastSuccessfulBuild/testReport' + API;
var LAST_BUILD = '%s/job/%s/lastBuild' + API;
var LAST_COMPLETED_BUILD = '%s/job/%s/lastCompletedBuild' + API;
var LAST_REPORT = '%s/job/%s/lastBuild' + API;
var QUEUE = '%s/queue' + API;
var COMPUTERS = '%s/computer' + API;
var JOB_OUTPUT = '%s/job/%s/consoleText' + API;

var init = exports.init = function(host, options) {

    if (options) {
        request = request.defaults(options);
    }

    //Helper Functions
    var build_url = function(command) {
        /*
        Builds REST url to Jenkins
        */

        // Create the url using the format function
        var url = util.format.call(this, command, host);

        // if command is the only arg, we are done
        if (arguments.length == 1) return url;

        // Grab the arguments except for the first (command)
        var args = Array.prototype.slice.call(arguments).slice(1);

        // Append url to front of args array
        args.unshift(url);

        // Create full url with all the arguments
        url = util.format.apply(this, args);

        return url;

    };
    return {
        build: function(jobname, params, callback) {
            var buildurl;
            /*
            Trigger Jenkins to build.
            */
            if (typeof params === 'function') {
                buildurl = build_url(BUILD, jobname);
                callback = params;
            } else {
                buildurl = build_url(BUILDWITHPARAMS+"?"+qs.stringify(params), jobname)
            }

            request({method: 'POST', url: buildurl }, function(error, response) {
                if ( error || (response.statusCode !== 201 && response.statusCode !== 302) ) {
                    callback(error, response);
                    return;
                }
                /*
                Return queue location of newly-created job as per
                  https://issues.jenkins-ci.org/browse/JENKINS-12827?focusedCommentId=201381#comment-201381
                */
                var data = {
                    message: "job is executed",
                    location: response.headers["Location"] || response.headers["location"]
                };
                callback(null, data);
            });
        },
        stop_build: function(jobname, buildNumber, callback) {
            var buildurl;
            buildurl = build_url(STOP_BUILD, jobname, buildNumber);

            request({method: 'POST', url: buildurl }, function(error, response) {
                if ( error || (response.statusCode !== 201 && response.statusCode !== 302) ) {
                    callback(error, response);
                    return;
                }
                var data = "job is stopped";
                callback(null, data);
            });
        },
        all_jobs: function(callback) {
            /*
            Return a list of object literals containing the name and color of all jobs on the Jenkins server
            */
            request({method: 'GET', url: build_url(LIST)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                var data = JSON.parse(body.toString()).jobs;
                callback(null, data);
            });
        },
        all_jobs_in_view: function(view, callback) {
            /*
            Return a list of objet literals containing the name and color of all the jobs for a view on the Jenkins server
             */
            request({method: 'GET', url: build_url(LIST_VIEW, view)}, function (error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                var data = JSON.parse(body.toString()).jobs;
                callback(null, data);
            })
        },
        job_info: function(jobname, callback) {
            /*
            Get all information for a job
            */
            request({method: 'GET', url: build_url(JOBINFO, jobname)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        last_build_info: function(jobname, callback) {
            /*
            Get information for the last build of a job
            */
            request({method: 'GET', url: build_url(LAST_BUILD, jobname)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        last_completed_build_info: function(jobname, callback) {
            /*
            Get information for the last completed build of a job
            */
            request({method: 'GET', url: build_url(LAST_COMPLETED_BUILD, jobname)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        build_info: function(jobname, number, callback) {
            /*
            Get information for the build number of a job
            */
            request({method: 'GET', url: build_url(BUILD_INFO, jobname, number)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        last_build_report: function(jobname, callback) {
            /*
            Get the last build report for a job
            */
            request({method: 'GET', url: build_url(LAST_REPORT, jobname)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        get_config_xml: function(jobname, callback) {
            /*
            Get the config xml for a job
            */
            request({method: 'GET', url: build_url(CONFIG, jobname)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                var data = body;
                callback(null, data);
            });
        },
        create_job: function(jobname, job_config, callback) {
            /*
           Create a new job based on a job_config string
            */

            request(
                {method: 'POST'
                ,url: build_url(NEWJOB, jobname)
                ,body: job_config
                ,headers: { "content-type": "application/xml"}
                },

                function(error, response, body) {
                    if ( error || response.statusCode !== 200 ) {
                        callback(error || true, response);
                        return;
                    }
                    var data = body;
                    callback(null, data);
                }
            );
        },
        update_job: function(jobname, modifyfunction, callback) {
            /*
            Copies a job and allows you to pass in a function to modify the configuration
            of the job you would like to copy
            */

            this.get_config_xml(jobname, function(error, data) {
                if (error) {
                    callback(error, data);
                    return;
                }
                request({method: 'POST', url: build_url(CONFIG, jobname), body: modifyfunction(data)}, function(error, response, body) {
                    if ( error || response.statusCode !== 200 ) {
                        callback(error || true, response);
                        return;
                    }
                    var data = body;
                    callback(null, data);
                });
            });

        },
        copy_job: function(jobname, new_job, modifyfunction, callback) {
            /*
            Copies a job and allows you to pass in a function to modify the configuration
            of the job you would like to copy
            */

            var self = this;
            this.get_config_xml(jobname, function(error, data) {
                if (error) {
                    callback(error, data);
                    return;
                }
                self.create_job(new_job, modifyfunction(data), function(error, data) {
                    if (error) {
                        callback(error, data);
                        return;
                    }
                    callback(null, data);
                });
            });

        },
        delete_job: function(jobname, callback) {
            /*
            Deletes a job
            */
            request({method: 'POST', url: build_url(DELETE, jobname)}, function(error, response, body) {
                if ( error || response.statusCode === 404 ) {
                    callback(error || true, response);
                    return;
                }
                callback(null, body);
            });

        },
        disable_job: function(jobname, callback) {
            /*
            Disables a job
            */
            request({method: 'POST', url: build_url(DISABLE, jobname)}, function(error, response, body) {
                if ( error || response.statusCode === 404 ) {
                    callback(error || true, response);
                    return;
                }
                callback(null, body);
            });
        },
        enable_job: function(jobname, callback) {
            /*
            Enables a job
            */
            request({method: 'POST', url: build_url(ENABLE, jobname)}, function(error, response, body) {
                if ( error || response.statusCode === 404 ) {
                    callback(error || true, response);
                    return;
                }
                callback(null, body);
            });
        },
        last_success: function(jobname, callback) {
            /*
            Get the last build report for a job
            */
            request({method: 'POST', url: build_url(LAST_SUCCESS, jobname)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                var data = JSON.parse(body);
                callback(null, data);
            });

        },
        last_result: function(jobname, callback) {
            /*
            Get the last result for a job
            */
            this.job_info(jobname, function(error, data) {
                var last_result_url = data.lastBuild.url;

                request({method: 'GET', url: build_url(last_result_url + API, jobname)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                        callback(error || true, response);
                        return;
                    }
                    data = JSON.parse(body);
                    callback(null, data);
                });
            });

        },
        queue: function(callback) {
            /*
             Get all queued items
             */
            request({method: 'GET', url: build_url(QUEUE)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        computers: function(callback) {
            /*
             Get details about all jenkins workers including currently executing jobs
             */
            request({method: 'GET', url: build_url(COMPUTERS + '?depth=1')}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        job_output: function(jobname, buildname, callback) {
            /*
            Get the output for a job's build
            */
            request({method: 'POST', url: build_url(JOB_OUTPUT, jobname + '/' + buildname)}, function(error, response, body) {
                if (response.statusCode !== 200 || error) {
                    callback(error || true, response);
                    return;
                }
                var data = JSON.stringify({"output": body});
                data = JSON.parse(data);
                callback(null, data);
            });
        }
    }
};

if (!module.parent) {
}
<commit_msg>Update main.js<commit_after>'use strict';

var util     = require('util')
    ,qs      = require('querystring')
    ,request = require('request');

var API = '/api/json';
var NEWJOB = '%s/createItem/?name=%s';
var DELETE = '%s/job/%s/doDelete';
var BUILD = '%s/job/%s/build' + API;
var STOP_BUILD = '%s/job/%s/%s/stop' + API;
var BUILD_INFO = '%s/job/%s/%s' + API;
var DISABLE = '%s/job/%s/disable';
var ENABLE = '%s/job/%s/enable';
var BUILDWITHPARAMS = '%s/job/%s/buildWithParameters';
var CONFIG = '%s/job/%s/config.xml';
var JOBINFO = '%s/job/%s' + API;
var LIST = '%s' + API;
var LIST_VIEW = '%s/view/%s' + API;
var LAST_SUCCESS = '%s/job/%s/lastSuccessfulBuild' + API;
var TEST_REPORT = '%s/job/%s/lastSuccessfulBuild/testReport' + API;
var LAST_BUILD = '%s/job/%s/lastBuild' + API;
var LAST_COMPLETED_BUILD = '%s/job/%s/lastCompletedBuild' + API;
var LAST_REPORT = '%s/job/%s/lastBuild' + API;
var QUEUE = '%s/queue' + API;
var COMPUTERS = '%s/computer' + API;
var JOB_OUTPUT = '%s/job/%s/consoleText' + API;
//var ALL_BUILD = '%s/job/%s' + API + '?tree=allBuilds[id,timestamp,result,duration]';
var ALL_BUILD = '%s/job/%s' + API + '?tree=allBuilds[%s]';
var CANCEL_ITEM = '%s/queue/cancelItem?id=%s';

var init = exports.init = function(host, options) {

    if (options) {
        request = request.defaults(options);
    }

    //Helper Functions
    var build_url = function(command) {
        /*
        Builds REST url to Jenkins
        */

        // Create the url using the format function
        var url = util.format.call(this, command, host);

        // if command is the only arg, we are done
        if (arguments.length == 1) return url;

        // Grab the arguments except for the first (command)
        var args = Array.prototype.slice.call(arguments).slice(1);

        // Append url to front of args array
        args.unshift(url);

        // Create full url with all the arguments
        url = util.format.apply(this, args);

        return url;

    };
    return {
        build: function(jobname, params, callback) {
            var buildurl;
            /*
            Trigger Jenkins to build.
            */
            if (typeof params === 'function') {
                buildurl = build_url(BUILD, jobname);
                callback = params;
            } else {
                buildurl = build_url(BUILDWITHPARAMS+"?"+qs.stringify(params), jobname)
            }

            request({method: 'POST', url: buildurl }, function(error, response) {
                if ( error || (response.statusCode !== 201 && response.statusCode !== 302) ) {
                    callback(error, response);
                    return;
                }
                /*
                Return queue location of newly-created job as per
                  https://issues.jenkins-ci.org/browse/JENKINS-12827?focusedCommentId=201381#comment-201381
                */
                var data = {
                    message: "job is executed",
                    location: response.headers["Location"] || response.headers["location"]
                };
                callback(null, data);
            });
        },
        stop_build: function(jobname, buildNumber, callback) {
            var buildurl;
            buildurl = build_url(STOP_BUILD, jobname, buildNumber);

            request({method: 'POST', url: buildurl }, function(error, response) {
                if ( error || (response.statusCode !== 201 && response.statusCode !== 302) ) {
                    callback(error, response);
                    return;
                }
                var data = "job is stopped";
                callback(null, data);
            });
        },
        all_jobs: function(callback) {
            /*
            Return a list of object literals containing the name and color of all jobs on the Jenkins server
            */
            request({method: 'GET', url: build_url(LIST)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                body = body.replace(/\x1b/g,"");
                var data = JSON.parse(body.toString()).jobs;
                callback(null, data);
            });
        },
        all_jobs_in_view: function(view, callback) {
            /*
            Return a list of objet literals containing the name and color of all the jobs for a view on the Jenkins server
             */
            request({method: 'GET', url: build_url(LIST_VIEW, view)}, function (error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                body = body.replace(/\x1b/g,"");
                var data = JSON.parse(body.toString()).jobs;
                callback(null, data);
            })
        },
        job_info: function(jobname, callback) {
            /*
            Get all information for a job
            */
            request({method: 'GET', url: build_url(JOBINFO, jobname)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                body = body.replace(/\x1b/g,"");
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        last_build_info: function(jobname, callback) {
            /*
            Get information for the last build of a job
            */
            request({method: 'GET', url: build_url(LAST_BUILD, jobname)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                body = body.replace(/\x1b/g,"");
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        last_completed_build_info: function(jobname, callback) {
            /*
            Get information for the last completed build of a job
            */
            request({method: 'GET', url: build_url(LAST_COMPLETED_BUILD, jobname)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                body = body.replace(/\x1b/g,"");
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        build_info: function(jobname, number, callback) {
            /*
            Get information for the build number of a job
            */
            request({method: 'GET', url: build_url(BUILD_INFO, jobname, number)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                body = body.replace(/\x1b/g,"");
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        all_build: function(jobname,param,callback) {
            /*
            Get information for the all build
            */
            request({method: 'GET', url: build_url(ALL_BUILD, jobname,param)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                body = body.replace(/\x1b/g,"");
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        last_build_report: function(jobname, callback) {
            /*
            Get the last build report for a job
            */
            request({method: 'GET', url: build_url(LAST_REPORT, jobname)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                body = body.replace(/\x1b/g,"");
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        get_config_xml: function(jobname, callback) {
            /*
            Get the config xml for a job
            */
            request({method: 'GET', url: build_url(CONFIG, jobname)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                var data = body;
                callback(null, data);
            });
        },
        create_job: function(jobname, job_config, callback) {
            /*
           Create a new job based on a job_config string
            */

            request(
                {method: 'POST'
                ,url: build_url(NEWJOB, jobname)
                ,body: job_config
                ,headers: { "content-type": "application/xml"}
                },

                function(error, response, body) {
                    if ( error || response.statusCode !== 200 ) {
                        callback(error || true, response);
                        return;
                    }
                    var data = body;
                    callback(null, data);
                }
            );
        },
        update_job: function(jobname, modifyfunction, callback) {
            /*
            Copies a job and allows you to pass in a function to modify the configuration
            of the job you would like to copy
            */

            this.get_config_xml(jobname, function(error, data) {
                if (error) {
                    callback(error, data);
                    return;
                }
                request({method: 'POST', url: build_url(CONFIG, jobname), body: modifyfunction(data)}, function(error, response, body) {
                    if ( error || response.statusCode !== 200 ) {
                        callback(error || true, response);
                        return;
                    }
                    var data = body;
                    callback(null, data);
                });
            });

        },
        copy_job: function(jobname, new_job, modifyfunction, callback) {
            /*
            Copies a job and allows you to pass in a function to modify the configuration
            of the job you would like to copy
            */

            var self = this;
            this.get_config_xml(jobname, function(error, data) {
                if (error) {
                    callback(error, data);
                    return;
                }
                self.create_job(new_job, modifyfunction(data), function(error, data) {
                    if (error) {
                        callback(error, data);
                        return;
                    }
                    callback(null, data);
                });
            });

        },
        delete_job: function(jobname, callback) {
            /*
            Deletes a job
            */
            request({method: 'POST', url: build_url(DELETE, jobname)}, function(error, response, body) {
                if ( error || response.statusCode === 404 ) {
                    callback(error || true, response);
                    return;
                }
                callback(null, body);
            });

        },
        disable_job: function(jobname, callback) {
            /*
            Disables a job
            */
            request({method: 'POST', url: build_url(DISABLE, jobname)}, function(error, response, body) {
                if ( error || response.statusCode === 404 ) {
                    callback(error || true, response);
                    return;
                }
                callback(null, body);
            });
        },
        enable_job: function(jobname, callback) {
            /*
            Enables a job
            */
            request({method: 'POST', url: build_url(ENABLE, jobname)}, function(error, response, body) {
                if ( error || response.statusCode === 404 ) {
                    callback(error || true, response);
                    return;
                }
                callback(null, body);
            });
        },
        last_success: function(jobname, callback) {
            /*
            Get the last build report for a job
            */
            request({method: 'POST', url: build_url(LAST_SUCCESS, jobname)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                body = body.replace(/\x1b/g,"");
                var data = JSON.parse(body);
                callback(null, data);
            });

        },
        last_result: function(jobname, callback) {
            /*
            Get the last result for a job
            */
            this.job_info(jobname, function(error, data) {
                var last_result_url = data.lastBuild.url;

                request({method: 'GET', url: build_url(last_result_url + API, jobname)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                        callback(error || true, response);
                        return;
                    }
                    data = JSON.parse(body);
                    callback(null, data);
                });
            });

        },
        queue: function(callback) {
            /*
             Get all queued items
             */
            request({method: 'GET', url: build_url(QUEUE)}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                body = body.replace(/\x1b/g,"");
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        cancel_item: function(itemID, callback) {
            /*
             * Cancel a queued item
             */
            request({method: 'POST', url: build_url(CANCEL_ITEM, itemID)}, function(error, response) {
                callback(error);
            });
        },
        computers: function(callback) {
            /*
             Get details about all jenkins workers including currently executing jobs
             */
            request({method: 'GET', url: build_url(COMPUTERS + '?depth=1')}, function(error, response, body) {
                if ( error || response.statusCode !== 200 ) {
                    callback(error || true, response);
                    return;
                }
                body = body.replace(/\x1b/g,"");
                var data = JSON.parse(body.toString());
                callback(null, data);
            });
        },
        job_output: function(jobname, buildname, callback) {
            /*
            Get the output for a job's build
            */
            request({method: 'POST', url: build_url(JOB_OUTPUT, jobname + '/' + buildname)}, function(error, response, body) {
                if (response.statusCode !== 200 || error) {
                    callback(error || true, response);
                    return;
                }
                body = body.replace(/\x1b/g,"");
                var data = JSON.stringify({"output": body});
                data = JSON.parse(data);
                callback(null, data);
            });
        }
    }
};

if (!module.parent) {
}
<|endoftext|>


<commit_before>
$( document ).ready(function() {
  /* Translate component ids for products */
  $("div.component-list-input").each(function(i, e){
      translate_component_ids(e);
  });

  /* Plain javascript style and no jquery since it's from bootstrap docs */
  var componentsModal = document.getElementById('componentsModal')
  componentsModal.addEventListener('show.bs.modal', function (event) {
    // Button that triggered the modal
    var button = event.relatedTarget
    // Extract info from data-* attributes
    var product_id = button.getAttribute('data-product')

    var product = global_products_json[product_id]
    // If necessary, you could initiate an AJAX request here
    // and then do the updating in a callback.
    //
    // Update the modal's content.
    var modalTitle = componentsModal.querySelector('.modal-title')

    modalTitle.textContent = 'Edit components for ' + product.REF_ID
  })
});

function translate_component_ids(element) {
    var component_names = new Array();
    if ($(element).attr('data-component-ids') != "[]"){
        components = JSON.parse($(element).attr('data-component-ids'));
        components.forEach(function(component_id){
            component_names.push(global_components_json[component_id]["Product name"]);
        });
        $(element).children('.component-display').html(component_names.join('
'));
    }
}

const all_products_reactive = Vue.reactive(global_products_json)
const all_components_reactive = Vue.reactive(global_components_json)

const ProductForm = {
    data() {
        return {
            all_components: all_components_reactive,
            all_products: all_products_reactive,
            modal_product_id: "52" //Should probably be null when we handle that edge case
        }
    },
    methods: {
        showModalFn(event) {
            if (event) {
                this.modal_product_id = event.target.dataset.productId
            }
            var myModal = new bootstrap.Modal(document.getElementById('myModal'))
            myModal.show()
        }
    }
}

const app = Vue.createApp(ProductForm)

app.component('modal-component', {
    computed: {
        product() {
            return this.$parent.all_products[this.$parent.modal_product_id]
        },
        altComponentIds() {
            return this.product['Alternative Components']
        },
        altComponents() {
            var components = new Array();
            for (comp_id in this.altComponentIds) {
                components.push(this.$parent.all_components[comp_id])
            }
            return components
        }
      },
    template:
        `

Edit components for {{this.product.REF_ID}}

              <button type="button" class="btn-close" data-dismiss="modal" aria-label="Close"></button>

              <form>

Selected Components

{{this.altComponentIds}}

All components

                  <template v-for="(component, component_id) in this.$parent.all_components">
                    {{ component['Product name']}}

                  </template>

              </form>

        `
})

app.component('alt-component-item', {
    template: `<template v-for="component in altComponents">
                 {{component["Product name"]}}

               </template>`,
    computed: {
        product() {
            return this.$parent.all_products[this.product_id]
        },
        altComponentIds() {
            return this.product['Alternative Components']
        },
        altComponents() {
            var components = new Array();
            for (comp_id in this.altComponentIds) {
                components.push(this.$parent.all_components[comp_id])
            }
            return components
        }
    },
    props: ['product_id']
})

app.mount('#product_list')
<commit_msg>Slightly nicer modal for Vue<commit_after>
$( document ).ready(function() {
  /* Translate component ids for products */
  $("div.component-list-input").each(function(i, e){
      translate_component_ids(e);
  });

  /* Plain javascript style and no jquery since it's from bootstrap docs */
  var componentsModal = document.getElementById('componentsModal')
  componentsModal.addEventListener('show.bs.modal', function (event) {
    // Button that triggered the modal
    var button = event.relatedTarget
    // Extract info from data-* attributes
    var product_id = button.getAttribute('data-product')

    var product = global_products_json[product_id]
    // If necessary, you could initiate an AJAX request here
    // and then do the updating in a callback.
    //
    // Update the modal's content.
    var modalTitle = componentsModal.querySelector('.modal-title')

    modalTitle.textContent = 'Edit components for ' + product.REF_ID
  })
});

function translate_component_ids(element) {
    var component_names = new Array();
    if ($(element).attr('data-component-ids') != "[]"){
        components = JSON.parse($(element).attr('data-component-ids'));
        components.forEach(function(component_id){
            component_names.push(global_components_json[component_id]["Product name"]);
        });
        $(element).children('.component-display').html(component_names.join('
'));
    }
}

const all_products_reactive = Vue.reactive(global_products_json)
const all_components_reactive = Vue.reactive(global_components_json)

const ProductForm = {
    data() {
        return {
            all_components: all_components_reactive,
            all_products: all_products_reactive,
            modal_product_id: "52" //Should probably be null when we handle that edge case
        }
    },
    methods: {
        showModalFn(event) {
            if (event) {
                this.modal_product_id = event.target.dataset.productId
            }
            var myModal = new bootstrap.Modal(document.getElementById('myModal'))
            myModal.show()
        }
    }
}

const app = Vue.createApp(ProductForm)

app.component('modal-component', {
    computed: {
        product() {
            return this.$parent.all_products[this.$parent.modal_product_id]
        },
        altComponentIds() {
            return this.product['Alternative Components']
        },
        altComponents() {
            var components = new Array();
            for (comp_id in this.altComponentIds) {
                components.push(this.$parent.all_components[comp_id])
            }
            return components
        }
      },
    template:
        `

Edit components for {{this.product.REF_ID}}

              <button type="button" class="btn-close" data-dismiss="modal" aria-label="Close"></button>

              <form>

Selected Components

                  <template v-for="component in this.altComponents">
                    {{component['Product name']}}

                  </template>

All components

                  <template v-for="(component, component_id) in this.$parent.all_components">
                    <template v-if="component['Status'] != 'Discontinued'">
                        {{ component['Product name']}}

                    </template>
                  </template>

              </form>

        `
})

app.component('alt-component-item', {
    template: `<template v-for="component in altComponents">
                 {{component["Product name"]}}

               </template>`,
    computed: {
        product() {
            return this.$parent.all_products[this.product_id]
        },
        altComponentIds() {
            return this.product['Alternative Components']
        },
        altComponents() {
            var components = new Array();
            for (comp_id in this.altComponentIds) {
                components.push(this.$parent.all_components[comp_id])
            }
            return components
        }
    },
    props: ['product_id']
})

app.mount('#product_list')
<|endoftext|>


<commit_before>/**
 * Created by SLedunois on 01/05/2016.
 */

exports.inodesta = function(params){

    var request = require('request');

    var api = {
        params : params,
        oAuth : {},
        media : {},
        user : {}
    };

    /**
     * Get the uri needs to authorize the application.
     * @return {string} Authorization uri.
     */
    api.oAuth.getAuthorizeUri = function(){
        return "https://api.instagram.com/oauth/authorize/?client_id="+api.params.client_id+"" +
            "&redirect_uri="+api.params.redirect_uri+"&response_type=code";
    };

    /**
     * Get the oAuth access token for a user id.
     * @param  {string}   code     user code.
     * @param  {Function} callback
     * @return {object}
     */
    api.oAuth.getAccessToken = function(code, callback){
        var req = {
            method: 'POST',
            uri: 'https://api.instagram.com/oauth/access_token',
            form: {
                client_id : params.client_id,
                client_secret : params.client_secret,
                grant_type : "authorization_code",
                redirect_uri : "http://localhost:3000/oAuth",
                code : code
            }
        };

        request(req, function(error, request, body) {
            callback(JSON.parse(body));
        });
    };

    /**
     * Get informations about the owner of the access token.
     * @param  {string}   accessToken A valid access Token
     * @param  {Function} callback
     * @return {object}
     */
    api.user.getSelfUserInfo = function(accessToken, callback) {
      var req = {
          method : 'GET',
          uri : 'https://api.instagram.com/v1/users/self/?access_token='+accessToken
      }

        request(req, function(error, request, body) {
            callback(JSON.parse(body));
        });
    };

    /**
     * Get information about a user. This endpoint requires the public_content scope
     * if the user-id is not the owner of the access_token.
     * @param  {string}   accessToken A valid access token.
     * @param  {string}   userId      userId User ID.
     * @param  {Function} callback
     * @return {object}
     */
    api.user.getUserInfo = function(accessToken, userId, callback) {
        var req = {
            method : 'GET',
            uri : 'https://api.instagram.com/v1/users/'+userId+'/?access_token='+accessToken
        }

        request(req, function(error, request, body) {
            callback(JSON.parse(body));
        });
    };

    /**
     * Get the most recent media published by the owner of the access_token.
     * By default, returns 10 media. Set as null every optional parameter if not used.
     * @param  {string}   accessToken A valid access token.
     * @param  {integer}   count       [Optional] Count of media to return
     * @param  {string}   minId       [Optional] Returns media later than this min_id.
     * @param  {string}   maxId       [Optional] Returns media earlier than this max_id.
     * @param  {Function} callback
     * @return {object}
     */
    api.user.getSelfRecentMedia = function(accessToken, count, minId, maxId, callback) {
        var uri = 'https://api.instagram.com/v1/users/self/media/recent/?access_token='+accessToken;
        if(count !== null) uri += '&count='+count;
        if(minId !== null) uri += '&min_id'+minId;
        if(maxId !== null) uri += '&max_id'+maxId
        var req = {
            method : 'GET',
            uri : uri
        }

        request(req, function(error, request, body) {
            callback(JSON.parse(body));
        });
    };

    /**
     * Get the most recent media published by a user.
     * By default, returns 10 media. Set as null every optional parameter if not used.
     * @param  {string}   userId      User id.
     * @param  {string}   accessToken A valid access token.
     * @param  {int}      count       [Optional] Count of media to return.
     * @param  {string}   minId       [Optional] Return media later than this min_id.
     * @param  {string}   maxId       [Optional] Return media earlier than this max_id.
     * @param  {Function} callback
     * @return {object}               Returns the most recent media published by a user.
     */
    api.user.getUserRecentMedia = function(userId, accessToken, count, minId, maxId, callback) {
        var uri= 'https://api.instagram.com/v1/users/'+userId+'/media/recent/?access_token='+accessToken;
        if(count !== null) uri += '&count='+count;
        if(minId !== null) uri += '&min_id'+minId;
        if(maxId !== null) uri += '&max_id'+maxId
        var req = {
            method : 'GET',
            uri : uri
        }

        request(req, function(error, request, body) {
            callback(JSON.parse(body));
        });
    };

    /**
     * Get the list of recent media like by the owner of the accessToken.
     * @param  {string}   accessToken A valid access token.
     * @param  {integer}  count       Count of media to return.
     * @param  {string}   maxLikeId   Return media liked before the id.
     * @param  {Function} callback
     * @return {object}               Returns the list of recent media like by the owner of the accessToken.
     */
    api.user.getSeldMediaLiked = function(accessToken, count, maxLikeId, callback) {
        var uri = 'https://api.instagram.com/v1/users/self/media/liked?access_token='+accessToken;
        if(count !== null) uri += '&count='+count;
        if(maxLikeId !== null) uri += '&max_like_id'+maxLikeId;
        var req = {
            method : 'GET',
            uri : uri
        }

        request(req, function(error, request, body) {
            callback(JSON.parse(body));
        });
    };

    /**
     * Get a list of users matching the query.
     * @param  {string}   accessToken A valid access token.
     * @param  {string}   query       A query string.
     * @param  {Function} callback
     * @return {object}               Returns a list of users matching the query.
     */
    api.user.search = function(accessToken, query, callback) {
        var uri = 'https://api.instagram.com/v1/users/search?q='+query+'&access_token='+accessToken;
        var req = {
            method : 'GET',
            uri : uri
        }

        request(req, function(error, request, body) {
            callback(JSON.parse(body));
        });
    }

    return api;
};<commit_msg>Updating request callback : Adding error statement<commit_after>/**
 * Created by SLedunois on 01/05/2016.
 */

exports.inodesta = function(params){

    var request = require('request');

    var api = {
        params : params,
        oAuth : {},
        media : {},
        user : {}
    };

    /**
     * Get the uri needs to authorize the application.
     * @return {string} Authorization uri.
     */
    api.oAuth.getAuthorizeUri = function(){
        return "https://api.instagram.com/oauth/authorize/?client_id="+api.params.client_id+"" +
            "&redirect_uri="+api.params.redirect_uri+"&response_type=code";
    };

    /**
     * Get the oAuth access token for a user id.
     * @param  {string}   code     user code.
     * @param  {Function} callback
     * @return {object}
     */
    api.oAuth.getAccessToken = function(code, callback){
        var req = {
            method: 'POST',
            uri: 'https://api.instagram.com/oauth/access_token',
            form: {
                client_id : params.client_id,
                client_secret : params.client_secret,
                grant_type : "authorization_code",
                redirect_uri : "http://localhost:3000/oAuth",
                code : code
            }
        };

        request(req, function(error, request, body) {
            if(!error){
                callback(JSON.parse(body));
            } else {
                console.log(error);
            }
        });
    };

    /**
     * Get informations about the owner of the access token.
     * @param  {string}   accessToken A valid access Token
     * @param  {Function} callback
     * @return {object}
     */
    api.user.getSelfUserInfo = function(accessToken, callback) {
      var req = {
          method : 'GET',
          uri : 'https://api.instagram.com/v1/users/self/?access_token='+accessToken
      }

        request(req, function(error, request, body) {
            if(!error){
                callback(JSON.parse(body));
            } else {
                console.log(error);
            }
        });
    };

    /**
     * Get information about a user. This endpoint requires the public_content scope
     * if the user-id is not the owner of the access_token.
     * @param  {string}   accessToken A valid access token.
     * @param  {string}   userId      userId User ID.
     * @param  {Function} callback
     * @return {object}
     */
    api.user.getUserInfo = function(accessToken, userId, callback) {
        var req = {
            method : 'GET',
            uri : 'https://api.instagram.com/v1/users/'+userId+'/?access_token='+accessToken
        }

        request(req, function(error, request, body) {
            if(!error){
                callback(JSON.parse(body));
            } else {
                console.log(error);
            }
        });
    };

    /**
     * Get the most recent media published by the owner of the access_token.
     * By default, returns 10 media. Set as null every optional parameter if not used.
     * @param  {string}   accessToken A valid access token.
     * @param  {integer}   count       [Optional] Count of media to return
     * @param  {string}   minId       [Optional] Returns media later than this min_id.
     * @param  {string}   maxId       [Optional] Returns media earlier than this max_id.
     * @param  {Function} callback
     * @return {object}
     */
    api.user.getSelfRecentMedia = function(accessToken, count, minId, maxId, callback) {
        var uri = 'https://api.instagram.com/v1/users/self/media/recent/?access_token='+accessToken;
        if(count !== null) uri += '&count='+count;
        if(minId !== null) uri += '&min_id'+minId;
        if(maxId !== null) uri += '&max_id'+maxId
        var req = {
            method : 'GET',
            uri : uri
        }

        request(req, function(error, request, body) {
            if(!error){
                callback(JSON.parse(body));
            } else {
                console.log(error);
            }
        });
    };

    /**
     * Get the most recent media published by a user.
     * By default, returns 10 media. Set as null every optional parameter if not used.
     * @param  {string}   userId      User id.
     * @param  {string}   accessToken A valid access token.
     * @param  {int}      count       [Optional] Count of media to return.
     * @param  {string}   minId       [Optional] Return media later than this min_id.
     * @param  {string}   maxId       [Optional] Return media earlier than this max_id.
     * @param  {Function} callback
     * @return {object}               Returns the most recent media published by a user.
     */
    api.user.getUserRecentMedia = function(userId, accessToken, count, minId, maxId, callback) {
        var uri= 'https://api.instagram.com/v1/users/'+userId+'/media/recent/?access_token='+accessToken;
        if(count !== null) uri += '&count='+count;
        if(minId !== null) uri += '&min_id'+minId;
        if(maxId !== null) uri += '&max_id'+maxId
        var req = {
            method : 'GET',
            uri : uri
        }

        request(req, function(error, request, body) {
            if(!error){
                callback(JSON.parse(body));
            } else {
                console.log(error);
            }
        });
    };

    /**
     * Get the list of recent media like by the owner of the accessToken.
     * @param  {string}   accessToken A valid access token.
     * @param  {integer}  count       Count of media to return.
     * @param  {string}   maxLikeId   Return media liked before the id.
     * @param  {Function} callback
     * @return {object}               Returns the list of recent media like by the owner of the accessToken.
     */
    api.user.getSeldMediaLiked = function(accessToken, count, maxLikeId, callback) {
        var uri = 'https://api.instagram.com/v1/users/self/media/liked?access_token='+accessToken;
        if(count !== null) uri += '&count='+count;
        if(maxLikeId !== null) uri += '&max_like_id'+maxLikeId;
        var req = {
            method : 'GET',
            uri : uri
        }

        request(req, function(error, request, body) {
            if(!error){
                callback(JSON.parse(body));
            } else {
                console.log(error);
            }
        });
    };

    /**
     * Get a list of users matching the query.
     * @param  {string}   accessToken A valid access token.
     * @param  {string}   query       A query string.
     * @param  {Function} callback
     * @return {object}               Returns a list of users matching the query.
     */
    api.user.search = function(accessToken, query, callback) {
        var uri = 'https://api.instagram.com/v1/users/search?q='+query+'&access_token='+accessToken;
        var req = {
            method : 'GET',
            uri : uri
        }

        request(req, function(error, request, body) {
            if(!error){
                callback(JSON.parse(body));
            } else {
                console.log(error);
            }
        });
    }

    return api;
};<|endoftext|>


<commit_before>// Copyright 2013 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

goog.provide('goog.async.run');

goog.require('goog.async.WorkQueue');
goog.require('goog.async.nextTick');
goog.require('goog.async.throwException');

/**
 * Fires the provided callback just before the current callstack unwinds, or as
 * soon as possible after the current JS execution context.
 * @param {function(this:THIS)} callback
 * @param {THIS=} opt_context Object to use as the "this value" when calling
 *     the provided function.
 * @template THIS
 */
goog.async.run = function(callback, opt_context) {
  if (!goog.async.run.schedule_) {
    goog.async.run.initializeRunner_();
  }
  if (!goog.async.run.workQueueScheduled_) {
    // Nothing is currently scheduled, schedule it now.
    goog.async.run.schedule_();
    goog.async.run.workQueueScheduled_ = true;
  }

  goog.async.run.workQueue_.add(callback, opt_context);
};

/**
 * Initializes the function to use to process the work queue.
 * @private
 */
goog.async.run.initializeRunner_ = function() {
  // If native Promises are available in the browser, just schedule the callback
  // on a fulfilled promise, which is specified to be async, but as fast as
  // possible.
  if (goog.global.Promise && goog.global.Promise.resolve) {
    var promise = goog.global.Promise.resolve(undefined);
    goog.async.run.schedule_ = function() {
      promise.then(goog.async.run.processWorkQueue);
    };
  } else {
    goog.async.run.schedule_ = function() {
      goog.async.nextTick(goog.async.run.processWorkQueue);
    };
  }
};

/**
 * Forces goog.async.run to use nextTick instead of Promise.
 *
 * This should only be done in unit tests. It's useful because MockClock
 * replaces nextTick, but not the browser Promise implementation, so it allows
 * Promise-based code to be tested with MockClock.
 *
 * However, we also want to run promises if the MockClock is no longer in
 * control so we schedule a backup "setTimeout" to the unmocked timeout if
 * provided.
 *
 * @param {function(function())=} opt_realSetTimeout
 */
goog.async.run.forceNextTick = function(opt_realSetTimeout) {
  goog.async.run.schedule_ = function() {
    goog.async.nextTick(goog.async.run.processWorkQueue);
    if (opt_realSetTimeout) {
      opt_realSetTimeout(goog.async.run.processWorkQueue);
    }
  };
};

/**
 * The function used to schedule work asynchronousely.
 * @private {function()}
 */
goog.async.run.schedule_;

/** @private {boolean} */
goog.async.run.workQueueScheduled_ = false;

/** @private {!goog.async.WorkQueue} */
goog.async.run.workQueue_ = new goog.async.WorkQueue();

if (goog.DEBUG) {
  /**
   * Reset the work queue. Only available for tests in debug mode.
   */
  goog.async.run.resetQueue = function() {
    goog.async.run.workQueueScheduled_ = false;
    goog.async.run.workQueue_ = new goog.async.WorkQueue();
  };
}

/**
 * Run any pending goog.async.run work items. This function is not intended
 * for general use, but for use by entry point handlers to run items ahead of
 * goog.async.nextTick.
 */
goog.async.run.processWorkQueue = function() {
  // NOTE: additional work queue items may be added while processing.
  var item = null;
  while (item = goog.async.run.workQueue_.remove()) {
    item.fn.call(item.scope);
    goog.async.run.workQueue_.returnUnused(item);
  }

  // There are no more work items, allow processing to be scheduled again.
  goog.async.run.workQueueScheduled_ = false;
};
<commit_msg>Wrap goog.async.run inside React batchedUpdates<commit_after>// Copyright 2013 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

goog.provide('goog.async.run');

goog.require('goog.async.WorkQueue');
goog.require('goog.async.nextTick');
goog.require('goog.async.throwException');

/**
 * Fires the provided callback just before the current callstack unwinds, or as
 * soon as possible after the current JS execution context.
 * @param {function(this:THIS)} callback
 * @param {THIS=} opt_context Object to use as the "this value" when calling
 *     the provided function.
 * @template THIS
 */
goog.async.run = function(callback, opt_context) {
  if (!goog.async.run.schedule_) {
    goog.async.run.initializeRunner_();
  }
  if (!goog.async.run.workQueueScheduled_) {
    // Nothing is currently scheduled, schedule it now.
    goog.async.run.schedule_();
    goog.async.run.workQueueScheduled_ = true;
  }

  goog.async.run.workQueue_.add(callback, opt_context);
};

/**
 * Initializes the function to use to process the work queue.
 * @private
 */
goog.async.run.initializeRunner_ = function() {
  // If native Promises are available in the browser, just schedule the callback
  // on a fulfilled promise, which is specified to be async, but as fast as
  // possible.
  if (goog.global.Promise && goog.global.Promise.resolve) {
    var promise = goog.global.Promise.resolve(undefined);
    goog.async.run.schedule_ = function() {
      promise.then(goog.async.run.processWorkQueue);
    };
  } else {
    goog.async.run.schedule_ = function() {
      goog.async.nextTick(goog.async.run.processWorkQueue);
    };
  }
};

/**
 * Forces goog.async.run to use nextTick instead of Promise.
 *
 * This should only be done in unit tests. It's useful because MockClock
 * replaces nextTick, but not the browser Promise implementation, so it allows
 * Promise-based code to be tested with MockClock.
 *
 * However, we also want to run promises if the MockClock is no longer in
 * control so we schedule a backup "setTimeout" to the unmocked timeout if
 * provided.
 *
 * @param {function(function())=} opt_realSetTimeout
 */
goog.async.run.forceNextTick = function(opt_realSetTimeout) {
  goog.async.run.schedule_ = function() {
    goog.async.nextTick(goog.async.run.processWorkQueue);
    if (opt_realSetTimeout) {
      opt_realSetTimeout(goog.async.run.processWorkQueue);
    }
  };
};

/**
 * The function used to schedule work asynchronousely.
 * @private {function()}
 */
goog.async.run.schedule_;

/** @private {boolean} */
goog.async.run.workQueueScheduled_ = false;

/** @private {!goog.async.WorkQueue} */
goog.async.run.workQueue_ = new goog.async.WorkQueue();

if (goog.DEBUG) {
  /**
   * Reset the work queue. Only available for tests in debug mode.
   */
  goog.async.run.resetQueue = function() {
    goog.async.run.workQueueScheduled_ = false;
    goog.async.run.workQueue_ = new goog.async.WorkQueue();
  };
}

/**
 * Run any pending goog.async.run work items. This function is not intended
 * for general use, but for use by entry point handlers to run items ahead of
 * goog.async.nextTick.
 */
goog.async.run.processWorkQueue = function() {
  // NOTE: additional work queue items may be added while processing.
  ReactDOM.unstable_batchedUpdates(function() {
    var item = null;
    while (item = goog.async.run.workQueue_.remove()) {
      item.fn.call(item.scope);
      goog.async.run.workQueue_.returnUnused(item);
    }
  });

  // There are no more work items, allow processing to be scheduled again.
  goog.async.run.workQueueScheduled_ = false;
};
<|endoftext|>


<commit_before>"use babel";

export default {
    config: {
        executable: {
            type: "string",
            default: "gfortran"
        },
        gfortran_flags: {
            type: "string",
            default: "-Wall -Wextra"
        },
    },

    activate() {
        require("atom-package-deps").install("linter-gfortran");
    },

    provideLinter() {
        const helpers = require("atom-linter");
        const path = require('path');
        const regex = "(?<file>[^\n:]+):(?<line>\\d+)([\.:](?<col>\\d+))?:((.|\\r|\\n)*?)(?<type>(Error|Warning|Note)):\\s*(?<message>.*)";
        const tmpdir = require('tmp').dirSync().name;
        return {
            name: "gfortran",
            grammarScopes: [
                "source.fortran.free",
                "source.fortran.fixed",
                "source.fortran.modern",
                "source.fortran.punchcard"
            ],
            scope: "file",
            lintOnFly: true,
            lint: (activeEditor) => {
                const command = atom.config.get("linter-gfortran.executable");
                const fileContents = activeEditor.getText()
                const filePath = activeEditor.getPath();
                const fileDir = path.dirname(filePath);

                // Split the users flag string and append flags to specific syntax checking and temporary file directory.
                const args = atom.config
                                 .get("linter-gfortran.gfortran_flags")
                                 .split(" ")
                                 .concat(["-fsyntax-only"])
                                 .concat(["-J", tmpdir])
                                 .concat(["-I", fileDir]);

                // Execute gfortran on a temporary file in order for on-the-fly linter to work.
                return helpers.tempFile(path.basename(filePath), fileContents, (tmpFilename) => {
                    args.push(tmpFilename);
                    return helpers.exec(command, args, { stream: "stderr"}).then(output => {
                        errors = helpers.parse(output, regex, { filePath : filePath });
                        errors.forEach((error) => {
                            console.log(error);
                            if (error.filePath == tmpFilename) {
                                // Set main file path to the real path instead
                                // of the temporary file path
                                error.filePath = filePath;
                            } else {
                                // Set others file path to be relative to the
                                // main file path
                                if (! path.isAbsolute(error.filePath)) {
                                    error.filePath = fileDir + "/" + error.filePath;
                                }
                            }
                        });
                        return errors;
                    });
                });
            }
        };
    }
};
<commit_msg>Remove debug code<commit_after>"use babel";

export default {
    config: {
        executable: {
            type: "string",
            default: "gfortran"
        },
        gfortran_flags: {
            type: "string",
            default: "-Wall -Wextra"
        },
    },

    activate() {
        require("atom-package-deps").install("linter-gfortran");
    },

    provideLinter() {
        const helpers = require("atom-linter");
        const path = require('path');
        const regex = "(?<file>[^\n:]+):(?<line>\\d+)([\.:](?<col>\\d+))?:((.|\\r|\\n)*?)(?<type>(Error|Warning|Note)):\\s*(?<message>.*)";
        const tmpdir = require('tmp').dirSync().name;
        return {
            name: "gfortran",
            grammarScopes: [
                "source.fortran.free",
                "source.fortran.fixed",
                "source.fortran.modern",
                "source.fortran.punchcard"
            ],
            scope: "file",
            lintOnFly: true,
            lint: (activeEditor) => {
                const command = atom.config.get("linter-gfortran.executable");
                const fileContents = activeEditor.getText()
                const filePath = activeEditor.getPath();
                const fileDir = path.dirname(filePath);

                // Split the users flag string and append flags to specific syntax checking and temporary file directory.
                const args = atom.config
                                 .get("linter-gfortran.gfortran_flags")
                                 .split(" ")
                                 .concat(["-fsyntax-only"])
                                 .concat(["-J", tmpdir])
                                 .concat(["-I", fileDir]);

                // Execute gfortran on a temporary file in order for on-the-fly linter to work.
                return helpers.tempFile(path.basename(filePath), fileContents, (tmpFilename) => {
                    args.push(tmpFilename);
                    return helpers.exec(command, args, { stream: "stderr"}).then(output => {
                        errors = helpers.parse(output, regex, { filePath : filePath });
                        errors.forEach((error) => {
                            if (error.filePath == tmpFilename) {
                                // Set main file path to the real path instead
                                // of the temporary file path
                                error.filePath = filePath;
                            } else {
                                // Set others file path to be relative to the
                                // main file path
                                if (! path.isAbsolute(error.filePath)) {
                                    error.filePath = fileDir + "/" + error.filePath;
                                }
                            }
                        });
                        return errors;
                    });
                });
            }
        };
    }
};
<|endoftext|>


<commit_before>const path = require('path');

const getCacheDirs = (constants, inputs) => [
  constants.PUBLISH_DIR,
  inputs.cacheDir || env.CECIL_CACHE_DIR || '.cache'
];

module.exports = {
  async onPreBuild({constants, inputs, utils}) {
    if (process.cwd() === constants.PUBLISH_DIR) {
      utils.build.failBuild(
        `Your site’s publish directory is not set correctly (“${constants.PUBLISH_DIR}”).`
      );
    }

    const cacheDirs = getCacheDirs(constants, inputs);

    if (await utils.cache.restore(cacheDirs)) {
      utils.status.show({
        title: 'Build cache',
        summary: 'Cecil cache restored from previous build.',
        text: (await utils.cache.list()).join("\n")
      })
      console.log('Found the Cecil cache (%s).', cacheDirs.join(', '));
    } else {
      console.log('Cecil cache not found.');
    }
  },
  async onPostBuild({constants, inputs, utils}) {
    const cacheDirs = getCacheDirs(constants, inputs);

    if (await utils.cache.save(cacheDirs)) {
      utils.status.show({
        title: 'Build cache',
        summary: 'Cecil cache stored for future builds.',
        text: (await utils.cache.list()).join("\n")
      })
      console.log('Stored the Cecil cache (%s) to speed up next builds.', cacheDirs.join(', '));
    } else {
      console.log('No Cecil build found.');
    }
  },
};
<commit_msg>Update index.js<commit_after>const path = require('path');

const getCacheDirs = (constants, inputs) => [
  constants.PUBLISH_DIR,
  inputs.cacheDir || env.CECIL_CACHE_DIR || '.cache'
];

module.exports = {
  async onPreBuild({constants, inputs, utils}) {
    if (process.cwd() === constants.PUBLISH_DIR) {
      utils.build.failBuild(
        `Your site’s publish directory is not set correctly (“${constants.PUBLISH_DIR}”).`
      );
    }

    const cacheDirs = getCacheDirs(constants, inputs);

    if (await utils.cache.restore(cacheDirs)) {
      utils.status.show({
        title: 'Build cache',
        summary: 'Cecil cache restored from previous build.',
        text: (await utils.cache.list()).join("\n")
      })
      console.log('Cecil cache (%s) restored from previous build.', cacheDirs.join(', '));
    } else {
      console.log('Cecil cache not found.');
    }
  },
  async onPostBuild({constants, inputs, utils}) {
    const cacheDirs = getCacheDirs(constants, inputs);

    if (await utils.cache.save(cacheDirs)) {
      utils.status.show({
        title: 'Build cache',
        summary: 'Cecil cache stored to speed up next builds.',
        text: (await utils.cache.list()).join("\n")
      })
      console.log('Cecil cache (%s) stored to speed up next builds.', cacheDirs.join(', '));
    } else {
      console.log('No Cecil build found.');
    }
  },
};
<|endoftext|>


<commit_before>define(function (require) {
	'use strict';

	/**
	 * Module dependencies.
	 */
	var Aloha = require('aloha'),
		Ui = require('ui/ui'),
		Button = require('ui/button'),
		PubSub = require('PubSub'),
		plugin = require('aloha/plugin'),
		Dom = require('../../../lib/dom'),
		Css = require('../../../lib/css'),
		Selection = require('../../../lib/selection'),
		Range = require('../../../lib/range'),
		Style = require('../../../lib/style'),
		$ = require('jquery');

	/**
	 * Plugin CSS dependencies.
	 */
	require('css!textresize/css/textresize');

	/**
	 * Return object keys.
	 *
	 * @param  {Object} obj
	 * @return {Array}
	 */
	function keys(obj) {
		var a = [];
		$.each(obj, function (k) {
			a.push(k);
		});
		return a;
	}

	/**
	 * Store a reference to the original publish method.
	 *
	 * @type {Function}
	 */
	var origPub = PubSub.pub;

	/**
	 * This method is needed to avoid triggering the "aloha.selection.context-change" while holding down a keyboard
	 * shortcut key for resizing the text. Many plugins listening on that event so without this fix, things be very
	 * slow since the event will trigger very rapidly when resizing.
	 *
	 * @param {String} channel
	 * @param {*} message
	 * @return {Number}
	 */
	function overloadPubSubPublish(channel, message) {
		if (channel !== 'aloha.selection.context-change') {
			return origPub.call(PubSub, channel, message);
		}
	}

	/**
	 * This method is needed to avoid triggering the "aloha.selection.context-change" while holding down a keyboard
	 * shortcut key for resizing the text. Many plugins listening on that event so without this fix, things be very
	 * slow since the event will trigger very rapidly when resizing.
	 *
	 * @param  {Boolean} active
	 */
	function filterPubSubEvents(active) {
		PubSub.pub = active ? overloadPubSubPublish : origPub;
	}

	/**
	 * Fix floating point number problems when doing calculations.
	 *
	 * @param  {Number} num
	 * @return {Number}
	 */
	function floatFix(num) {
		return parseFloat(num.toFixed(10));
	}

	/**
	 * Create & register the plugin.
	 */
	return plugin.create('textresize', {

		/**
		 * Buttons elements.
		 *
		 * @type {Object}
		 */
		buttons: {},

		/**
		 * Spinner elements.
		 *
		 * @type {Object}
		 */
		spinners: {},

		/**
		 * List of CssClassApplier instances (one per style).
		 *
		 * @type {Object}
		 */
		cssClassAppliers: {},

		/**
		 * Config for the spinners (key in camelCased style).
		 *
		 * unit = Unit to use when applying the value
		 * step = Size of the step to take when changing values
		 * page = Number of steps to take when paging (pageUp/pageDown or shift key)
		 * min = Minimum allowed value
		 * max = Maximum allowed value
		 * value = Initial and default value
		 *
		 * @type {Object}
		 */
		config: {
			fontSize: {
				unit: 'px',
				step: 1,
				page: 10,
				min: 10,
				max: 128,
				value: 16
			},
			lineHeight: {
				unit: 'em',
				step: 0.1,
				page: 10,
				min: 0,
				max: 3,
				value: 1.2
			},
			letterSpacing: {
				unit: 'em',
				step: 0.1,
				page: 10,
				min: -1,
				max: 3,
				value: 0
			},
			wordSpacing: {
				unit: 'em',
				step: 0.1,
				page: 10,
				min: -1,
				max: 2,
				value: 0
			}
		},

		/**
		 * HotKeys used for special actions.
		 */
		hotKey: {
			decreaseFontSize: 'ctrl+left ctrl+shift+left',
			increaseFontSize: 'ctrl+right ctrl+shift+right',
			decreaseLineHeight: 'ctrl+up ctrl+shift+up',
			increaseLineHeight: 'ctrl+down ctrl+shift+down'
		},

		/**
		 * Executed on plugin initialization.
		 */
		init: function () {
			var self = this;

			// iterate over all different styles
			$.each(this.config, function (key) {

				// merge user config with default
				if (self.settings.config && self.settings.config[key]) {
					$.extend(self.config[key], self.settings.config[key]);
				}

				// create button
				self.buttons[key] = Ui.adopt(key, Button, {
					'class': 'aloha-plugin-textresize-button'
				});

				$(self.buttons[key].element).attr('title', 'Change text ' + key.toLowerCase());

				self.cssClassAppliers[key] = Css.createClassApplier(self.getStyleClass(key));

				// create spinner for the style
				self.createSpinner(
					key,
					self.config[key],
					self['change' + key.substr(0, 1).toUpperCase() + key.substr(1)]
				);
			});

			this.subscribeEvents();
		},

		/**
		 * Subscribe for events.
		 */
		subscribeEvents: function () {
			var self = this;

			PubSub.sub('aloha.selection.context-change', function (message) {
				if (Aloha.activeEditable) {
					self.onSelectionChanged(message.range);
				}
			});

			Aloha.bind('aloha-editable-created', function (e, editable) {
				$.each(self.hotKey, function (fn, keyCombo) {
					editable.obj.bind('keydown', keyCombo, function (e) {
						filterPubSubEvents(true);
						self[fn](e);
						return false;
					});

					editable.obj.bind('keyup', keyCombo, function (e) {
						filterPubSubEvents(false);
					});
				});
			});
		},

		/**
		 * Create the jQuery UI spinner.
		 * - http://api.jqueryui.com/spinner/
		 *
		 * @param  {String}   name
		 * @param  {Object}   options
		 * @param  {Function} cb
		 */
		createSpinner: function (name, options, cb) {
			var self = this,
				$input = $('<input class="aloha-plugin-textresize-spinner">').appendTo(
					$(this.buttons[name].element)
				);

			// TODO: why doesn't it work changing values with the mousewheel?
			this.spinners[name] = $input.spinner($.extend({}, options, {
				stop: function () {
					cb.call(self, $(this).val());
				}
			})).keyup(function () {
				// prevent losing focus when using up/down arrow keys in text input field
				$(this).focus();

				var val = parseFloat($(this).val());
				// prevent min/max boundary when entering values manually
				if (val < self.config[name].min || val > self.config[name].max) {
					return false;
				}
			});

			$input.spinner('value', this.config[name].value).spinner('widget').css('height', '24px');
		},

		/**
		 * Will be called every time the context of the selection changes.
		 *
		 * @param  {GENTICS.Utils.RangeObject} range
		 */
		onSelectionChanged: function (range) {
			var self = this;

			$.each(this.getStyles(range), function (style, value) {
				if (self.spinners[style]) {
					self.spinners[style].val(value);
				}
			});
		},

		/**
		 * Get the given style of current selection or cursor position.
		 *
		 * @param  {String} style
		 * @param  {Number} defaultValue
		 * @return {Number}
		 */
		getCurrentStyle: function (style, defaultValue) {
			var self = this,
				range = Aloha.Selection.getRangeObject(),
				styleValueRegex = new RegExp('([0-9\\-\\.]+)' + this.config[style].unit),
				match;

			var element = range.findMarkup(function () {
				return Style.hasStyle(this, style);
			}, Aloha.activeEditable.obj);

			if (!element) {
				element = range.getCommonAncestorContainer();
			}

			if (!element) {
				return defaultValue;
			}

			// check style set on element
			match = element.style[style].match(styleValueRegex);
			if (match) {
				return parseFloat(match[1]);
			}

			// fallback to computed style for element
			// TODO: convert px to em for line-height?
			match = Style.getComputedStyle($(element).get(0), style).match(styleValueRegex);
			if (match) {
				return parseFloat(match[1]);
			}

			return defaultValue;
		},

		/**
		 * Get values for a styles.
		 *
		 * @param  {GENTICS.Utils.RangeObject} range
		 * @return {Object}
		 */
		getStyles: function (range) {
			var self = this,
				styles = {};

			$.each(this.config, function (style, config) {
				var value = self.getCurrentStyle(style);
				if (value) {
					styles[style] = value;
				}
			});

			return styles;
		},

		/**
		 * Return a classname for the given style (used temporary in the changeStyle method).
		 *
		 * @param  {String} style
		 * @return {String}
		 */
		getStyleClass: function (style) {
			return 'tmpStyleClass' + style;
		},

		/**
		 * Change the style for the selection / cursor target.
		 *
		 * @param  {Object} attr
		 */
		changeStyle: function (attr) {
			var self = this;

			// remove previous styles in the selection
			Dom.elementCleanup(function (el) {
				$.each(attr, function (style) {
					Style.removeStyle(el, style);
				});
			});

			// iterate over each style and apply it to the selection
			$.each(attr, function (style, value) {
				var range = Aloha.Selection.getRangeObject(),
					styleClass = self.getStyleClass(style),
					rangyRange = range.isCollapsed() ? Range.createExpandedRangeFromCollapsed(range) :
						Range.rangeObjectToRangyRange(range);

				if (rangyRange) {
					self.cssClassAppliers[style].applyToRange(rangyRange);
					Selection.selectTextFromRange(rangyRange);
				}

				// convert temporary class to inline style (tempfix until Rangy has a proper way to set style attribute)
				var $classElement = $('.' + styleClass, Aloha.activeEditable.obj);
				if (!$classElement.css(style, value).removeClass(styleClass).attr('class')) {
					// $classElement.removeAttr('class');
					// TODO: the cssClassApplier seems to remove other classes when remove the entire class attribute
				}
			});
		},

		/**
		 * Change the font-size value of the active selection.
		 *
		 * @param  {Number} value
		 */
		changeFontSize: function (value) {
			if (value >= this.config.fontSize.min && value <= this.config.fontSize.max) {
				this.changeStyle({
					fontSize: value + this.config.fontSize.unit,
					lineHeight: ''
				});
				this.spinners.fontSize.val(value);
				this.spinners.lineHeight.val(this.config.lineHeight.value);
			}
		},

		/**
		 * Change the line-height value of the active selection.
		 *
		 * @param  {Number} value
		 */
		changeLineHeight: function (value) {
			if (value >= this.config.lineHeight.min && value <= this.config.lineHeight.max) {
				this.changeStyle({
					lineHeight: value + this.config.lineHeight.unit
				});
			}
			this.spinners.lineHeight.val(value);
		},

		/**
		 * Change the letter-spacing value of the active selection.
		 *
		 * @param  {Number} value
		 */
		changeLetterSpacing: function (value) {
			if (value >= this.config.letterSpacing.min && value <= this.config.letterSpacing.max) {
				this.changeStyle({
					letterSpacing: value + this.config.letterSpacing.unit
				});
				this.spinners.letterSpacing.val(value);
			}
		},

		/**
		 * Change the word-spacing value of the active selection.
		 *
		 * @param  {Number} value
		 */
		changeWordSpacing: function (value) {
			if (value >= this.config.wordSpacing.min && value <= this.config.wordSpacing.max) {
				this.changeStyle({
					wordSpacing: value + this.config.wordSpacing.unit
				});
				this.spinners.wordSpacing.val(value);
			}
		},

		/**
		 * Decrease the font-size one step.
		 *
		 * @param {jQuery.Event} e
		 */
		decreaseFontSize: function (e) {
			var step = this.config.fontSize.step;

			if (e.shiftKey) {
				step = step * this.config.fontSize.page;
			}

			this.changeFontSize(
				floatFix(this.getCurrentStyle('fontSize', this.config.fontSize.value) - step)
			);
		},

		/**
		 * Increase the font-size one step.
		 *
		 * @param {jQuery.Event} e
		 */
		increaseFontSize: function (e) {
			var step = this.config.fontSize.step;

			if (e.shiftKey) {
				step = step * this.config.fontSize.page;
			}

			this.changeFontSize(
				floatFix(this.getCurrentStyle('fontSize', this.config.fontSize.value) + step)
			);
		},

		/**
		 * Decrease the line-height one step.
		 *
		 * @param {jQuery.Event} e
		 */
		decreaseLineHeight: function (e) {
			var step = this.config.lineHeight.step;

			if (e.shiftKey) {
				step = step * this.config.lineHeight.page;
			}

			this.changeLineHeight(
				floatFix(this.getCurrentStyle('lineHeight', this.config.lineHeight.value) - step)
			);
		},

		/**
		 * Increase the line-height one step.
		 *
		 * @param {jQuery.Event} e
		 */
		increaseLineHeight: function (e) {
			var step = this.config.lineHeight.step;

			if (e.shiftKey) {
				step = step * this.config.lineHeight.page;
			}

			this.changeLineHeight(
				floatFix(this.getCurrentStyle('lineHeight', this.config.lineHeight.value) + step)
			);
		}

	});

});
<commit_msg>Some performance fixes in textresize plugin.<commit_after>define(function (require) {
	'use strict';

	/**
	 * Module dependencies.
	 */
	var Aloha = require('aloha'),
		Ui = require('ui/ui'),
		Button = require('ui/button'),
		PubSub = require('PubSub'),
		plugin = require('aloha/plugin'),
		Dom = require('../../../lib/dom'),
		Css = require('../../../lib/css'),
		Selection = require('../../../lib/selection'),
		Range = require('../../../lib/range'),
		Style = require('../../../lib/style'),
		$ = require('jquery');

	/**
	 * Plugin CSS dependencies.
	 */
	require('css!textresize/css/textresize');

	/**
	 * Return object keys.
	 *
	 * @param  {Object} obj
	 * @return {Array}
	 */
	function keys(obj) {
		var a = [];
		$.each(obj, function (k) {
			a.push(k);
		});
		return a;
	}

	/**
	 * Returns a function, that, as long as it continues to be invoked, will not
	 * be triggered. The function will be called after it stops being called for
	 * N milliseconds. If `immediate` is passed, trigger the function on the
	 * leading edge, instead of the trailing.
	 *
	 * @param {Function} func
	 * @param {Number} wait
	 * @param {Boolean} immediate
	 * @return {Function}
	 */
	function debounce(func, wait, immediate) {
		var timeout, result;
		return function () {
			var context = this, args = arguments;
			var later = function () {
				timeout = null;
				if (!immediate) {
					result = func.apply(context, args);
				}
			};
			var callNow = immediate && !timeout;
			clearTimeout(timeout);
			timeout = setTimeout(later, wait);
			if (callNow) {
				result = func.apply(context, args);
			}
			return result;
		};
	}

	/**
	 * Returns a function, that, when invoked, will only be triggered at most once during a given window of time.
	 *
	 * @param  {Function} func
	 * @param  {Number} wait
	 * @return {Function}
	 */
	function throttle(func, wait) {
		var context, args, timeout, throttling, more, result;
		var whenDone = debounce(function () {
			more = throttling = false;
		}, wait);
		return function () {
			context = this;
			args = arguments;
			var later = function () {
				timeout = null;
				if (more) {
					result = func.apply(context, args);
				}
				whenDone();
			};
			if (!timeout) {
				timeout = setTimeout(later, wait);
			}
			if (throttling) {
				more = true;
			} else {
				throttling = true;
				result = func.apply(context, args);
			}
			whenDone();
			return result;
		};
	}

	/**
	 * Store a reference to the original publish method.
	 *
	 * @type {Function}
	 */
	var origPub = PubSub.pub;

	/**
	 * This method is needed to avoid triggering the "aloha.selection.context-change" while holding down a keyboard
	 * shortcut key for resizing the text. Many plugins listening on that event so without this fix, things be very
	 * slow since the event will trigger very rapidly when resizing.
	 *
	 * @param {String} channel
	 * @param {*} message
	 * @return {Number}
	 */
	function overloadPubSubPublish(channel, message) {
		if (channel !== 'aloha.selection.context-change') {
			return origPub.call(PubSub, channel, message);
		}
	}

	/**
	 * This method is needed to avoid triggering the "aloha.selection.context-change" while holding down a keyboard
	 * shortcut key for resizing the text. Many plugins listening on that event so without this fix, things be very
	 * slow since the event will trigger very rapidly when resizing.
	 *
	 * @param  {Boolean} active
	 */
	function filterPubSubEvents(active) {
		PubSub.pub = active ? overloadPubSubPublish : origPub;
	}

	/**
	 * Fix floating point number problems when doing calculations.
	 *
	 * @param  {Number} num
	 * @return {Number}
	 */
	function floatFix(num) {
		return parseFloat(num.toFixed(10));
	}

	/**
	 * Create & register the plugin.
	 */
	return plugin.create('textresize', {

		/**
		 * Buttons elements.
		 *
		 * @type {Object}
		 */
		buttons: {},

		/**
		 * Spinner elements.
		 *
		 * @type {Object}
		 */
		spinners: {},

		/**
		 * List of CssClassApplier instances (one per style).
		 *
		 * @type {Object}
		 */
		cssClassAppliers: {},

		/**
		 * Config for the spinners (key in camelCased style).
		 *
		 * unit = Unit to use when applying the value
		 * step = Size of the step to take when changing values
		 * page = Number of steps to take when paging (pageUp/pageDown or shift key)
		 * min = Minimum allowed value
		 * max = Maximum allowed value
		 * value = Initial and default value
		 *
		 * @type {Object}
		 */
		config: {
			fontSize: {
				unit: 'px',
				step: 1,
				page: 10,
				min: 10,
				max: 128,
				value: 16
			},
			lineHeight: {
				unit: 'em',
				step: 0.1,
				page: 10,
				min: 0,
				max: 3,
				value: 1.2
			},
			letterSpacing: {
				unit: 'em',
				step: 0.1,
				page: 10,
				min: -1,
				max: 3,
				value: 0
			},
			wordSpacing: {
				unit: 'em',
				step: 0.1,
				page: 10,
				min: -1,
				max: 2,
				value: 0
			}
		},

		/**
		 * HotKeys used for special actions.
		 */
		hotKey: {
			decreaseFontSize: 'ctrl+left ctrl+shift+left',
			increaseFontSize: 'ctrl+right ctrl+shift+right',
			decreaseLineHeight: 'ctrl+up ctrl+shift+up',
			increaseLineHeight: 'ctrl+down ctrl+shift+down'
		},

		/**
		 * Executed on plugin initialization.
		 */
		init: function () {
			var self = this;

			// iterate over all different styles
			$.each(this.config, function (key) {

				// merge user config with default
				if (self.settings.config && self.settings.config[key]) {
					$.extend(self.config[key], self.settings.config[key]);
				}

				// create button
				self.buttons[key] = Ui.adopt(key, Button, {
					'class': 'aloha-plugin-textresize-button'
				});

				$(self.buttons[key].element).attr('title', 'Change text ' + key.toLowerCase());

				self.cssClassAppliers[key] = Css.createClassApplier(self.getStyleClass(key));

				// create spinner for the style
				self.createSpinner(
					key,
					self.config[key],
					self['change' + key.substr(0, 1).toUpperCase() + key.substr(1)]
				);
			});

			this.subscribeEvents();

			// Use same delay as Aloha.activeEditable.sccDelay
			this.debouncedTriggerSmartContentChange = debounce(this.triggerSmartContentChange, 500);
		},

		/**
		 * Subscribe for events.
		 */
		subscribeEvents: function () {
			var self = this;

			PubSub.sub('aloha.selection.context-change', function (message) {
				if (Aloha.activeEditable) {
					self.onSelectionChanged(message.range);
				}
			});

			Aloha.bind('aloha-editable-created', function (e, editable) {
				$.each(self.hotKey, function (fn, keyCombo) {
					editable.obj.bind('keydown', keyCombo, function (e) {
						filterPubSubEvents(true);
						self[fn](e);
						return false;
					});

					editable.obj.bind('keyup', keyCombo, function (e) {
						filterPubSubEvents(false);
						self.triggerSmartContentChange();
					});
				});
			});
		},

		/**
		 * Create the jQuery UI spinner.
		 * - http://api.jqueryui.com/spinner/
		 *
		 * @param  {String}   name
		 * @param  {Object}   options
		 * @param  {Function} cb
		 */
		createSpinner: function (name, options, cb) {
			var self = this,
				$input = $('<input class="aloha-plugin-textresize-spinner">').appendTo(
					$(this.buttons[name].element)
				);

			// TODO: why doesn't it work changing values with the mousewheel?
			this.spinners[name] = $input.spinner($.extend({}, options, {
				stop: function () {
					cb.call(self, $(this).val());
				}
			})).keyup(function () {
				// prevent losing focus when using up/down arrow keys in text input field
				$(this).focus();

				var val = parseFloat($(this).val());
				// prevent min/max boundary when entering values manually
				if (val < self.config[name].min || val > self.config[name].max) {
					return false;
				}
			});

			$input.spinner('value', this.config[name].value).spinner('widget').css('height', '24px');
		},

		/**
		 * Will be called every time the context of the selection changes.
		 *
		 * @param  {GENTICS.Utils.RangeObject} range
		 */
		onSelectionChanged: function (range) {
			var self = this;

			$.each(this.getStyles(range), function (style, value) {
				if (self.spinners[style]) {
					self.spinners[style].val(value);
				}
			});
		},

		/**
		 * Get the given style of current selection or cursor position.
		 *
		 * @param  {String} style
		 * @param  {Number} defaultValue
		 * @return {Number}
		 */
		getCurrentStyle: function (style, defaultValue) {
			var self = this,
				range = Aloha.Selection.getRangeObject(),
				styleValueRegex = new RegExp('([0-9\\-\\.]+)' + this.config[style].unit),
				match;

			var element = range.findMarkup(function () {
				return Style.hasStyle(this, style);
			}, Aloha.activeEditable.obj);

			if (!element) {
				element = range.getCommonAncestorContainer();
			}

			if (!element) {
				return defaultValue;
			}

			// check style set on element
			match = element.style[style].match(styleValueRegex);
			if (match) {
				return parseFloat(match[1]);
			}

			// fallback to computed style for element
			// TODO: convert px to em for line-height?
			match = Style.getComputedStyle($(element).get(0), style).match(styleValueRegex);
			if (match) {
				return parseFloat(match[1]);
			}

			return defaultValue;
		},

		/**
		 * Get values for a styles.
		 *
		 * @param  {GENTICS.Utils.RangeObject} range
		 * @return {Object}
		 */
		getStyles: function (range) {
			var self = this,
				styles = {};

			$.each(this.config, function (style, config) {
				var value = self.getCurrentStyle(style);
				if (value) {
					styles[style] = value;
				}
			});

			return styles;
		},

		/**
		 * Return a classname for the given style (used temporary in the changeStyle method).
		 *
		 * @param  {String} style
		 * @return {String}
		 */
		getStyleClass: function (style) {
			return 'tmpStyleClass' + style;
		},

		/**
		 * Change the style for the selection / cursor target.
		 *
		 * @param  {Object} attr
		 */
		changeStyle: function (attr) {
			var self = this;

			// remove previous styles in the selection
			Dom.elementCleanup(function (el) {
				$.each(attr, function (style) {
					Style.removeStyle(el, style);
				});
			});

			// iterate over each style and apply it to the selection
			$.each(attr, function (style, value) {
				var range = Aloha.Selection.getRangeObject(),
					styleClass = self.getStyleClass(style),
					rangyRange = range.isCollapsed() ? Range.createExpandedRangeFromCollapsed(range) :
						Range.rangeObjectToRangyRange(range);

				if (rangyRange) {
					self.cssClassAppliers[style].applyToRange(rangyRange);
					Selection.selectTextFromRange(rangyRange);
				}

				// convert temporary class to inline style (tempfix until Rangy has a proper way to set style attribute)
				var $classElement = $('.' + styleClass, Aloha.activeEditable.obj);
				if (!$classElement.css(style, value).removeClass(styleClass).attr('class')) {
					// $classElement.removeAttr('class');
					// TODO: the cssClassApplier seems to remove other classes when remove the entire class attribute
				}
			});

			this.debouncedTriggerSmartContentChange();
		},

		/**
		 * Trigger a aloha-smart-content-changed event. We should be able to use the
		 * Aloha.activeEditable.smartContentChange method but it seems to be a bit broken right now.
		 */
		triggerSmartContentChange: function () {
			var snapshot = null;

			function getSnapshotContent() {
				if (null === snapshot) {
					snapshot = Aloha.activeEditable.getSnapshotContent();
				}
				return snapshot;
			}

			Aloha.trigger('aloha-smart-content-changed', {
				'editable': Aloha.activeEditable,
				'keyIdentifier': null,
				'keyCode': null,
				'char': null,
				'triggerType': 'text-resize',
				'getSnapshotContent': getSnapshotContent
			});
		},

		/**
		 * Change the font-size value of the active selection.
		 *
		 * @param  {Number} value
		 */
		changeFontSize: function (value) {
			if (value >= this.config.fontSize.min && value <= this.config.fontSize.max) {
				this.changeStyle({
					fontSize: value + this.config.fontSize.unit,
					lineHeight: ''
				});
				this.spinners.fontSize.val(value);
				this.spinners.lineHeight.val(this.config.lineHeight.value);
			}
		},

		/**
		 * Change the line-height value of the active selection.
		 *
		 * @param  {Number} value
		 */
		changeLineHeight: function (value) {
			if (value >= this.config.lineHeight.min && value <= this.config.lineHeight.max) {
				this.changeStyle({
					lineHeight: value + this.config.lineHeight.unit
				});
			}
			this.spinners.lineHeight.val(value);
		},

		/**
		 * Change the letter-spacing value of the active selection.
		 *
		 * @param  {Number} value
		 */
		changeLetterSpacing: function (value) {
			if (value >= this.config.letterSpacing.min && value <= this.config.letterSpacing.max) {
				this.changeStyle({
					letterSpacing: value + this.config.letterSpacing.unit
				});
				this.spinners.letterSpacing.val(value);
			}
		},

		/**
		 * Change the word-spacing value of the active selection.
		 *
		 * @param  {Number} value
		 */
		changeWordSpacing: function (value) {
			if (value >= this.config.wordSpacing.min && value <= this.config.wordSpacing.max) {
				this.changeStyle({
					wordSpacing: value + this.config.wordSpacing.unit
				});
				this.spinners.wordSpacing.val(value);
			}
		},

		/**
		 * Decrease the font-size one step.
		 *
		 * @param {jQuery.Event} e
		 */
		decreaseFontSize: function (e) {
			var step = this.config.fontSize.step;

			if (e.shiftKey) {
				step = step * this.config.fontSize.page;
			}

			this.changeFontSize(
				floatFix(this.getCurrentStyle('fontSize', this.config.fontSize.value) - step)
			);
		},

		/**
		 * Increase the font-size one step.
		 *
		 * @param {jQuery.Event} e
		 */
		increaseFontSize: function (e) {
			var step = this.config.fontSize.step;

			if (e.shiftKey) {
				step = step * this.config.fontSize.page;
			}

			this.changeFontSize(
				floatFix(this.getCurrentStyle('fontSize', this.config.fontSize.value) + step)
			);
		},

		/**
		 * Decrease the line-height one step.
		 *
		 * @param {jQuery.Event} e
		 */
		decreaseLineHeight: function (e) {
			var step = this.config.lineHeight.step;

			if (e.shiftKey) {
				step = step * this.config.lineHeight.page;
			}

			this.changeLineHeight(
				floatFix(this.getCurrentStyle('lineHeight', this.config.lineHeight.value) - step)
			);
		},

		/**
		 * Increase the line-height one step.
		 *
		 * @param {jQuery.Event} e
		 */
		increaseLineHeight: function (e) {
			var step = this.config.lineHeight.step;

			if (e.shiftKey) {
				step = step * this.config.lineHeight.page;
			}

			this.changeLineHeight(
				floatFix(this.getCurrentStyle('lineHeight', this.config.lineHeight.value) + step)
			);
		}

	});

});
<|endoftext|>