<commit_before>import elem from "./_elem.js";

var convert = {
    addSassVariables: () =>{
        elem.el.codeBox.classList.remove("css_box", "less_box", "js_box");
        elem.el.codeBox.classList.add("sass_box");

        elem.el.codeBoxBorder.classList.remove("css_border", "less_border", "js_border");
        elem.el.codeBoxBorder.classList.add("sass_border");

        elem.el.innerCodeBox.innerHTML = `$num: ${elem.s.pixSize};<br>`;
        for(let x = 0; x < elem.s.storeColors.length; x++){
            elem.el.innerCodeBox.innerHTML += `$colors${x}: ${elem.s.storeColors[x]};`;
        }

        elem.el.innerCodeBox.innerHTML += "
";

        for(let x = 0; x < elem.s.columnCount; x++){
            elem.el.innerCodeBox.innerHTML += `$X${x}: $num*${x}px; `;
        }
        //elem.el.innerCodeBox.innerHTML += `$num: ${elem.s.pixSize};<br>`;
        for(var y = 0; y < elem.s.columnCount; y++){
            elem.el.innerCodeBox.innerHTML += `$O${y}: $num*${y}px; `;
        }
        elem.el.innerCodeBox.innerHTML += "

";
    },

    convertToSass: () =>{

        elem.el.innerCodeBox.innerHTML += "box-shadow: ";
        for(var x = 0; x < elem.s.storeValues.length; x++) {
            elem.el.innerCodeBox.innerHTML += ` $X${parseFloat(elem.s.storeValues[x][0]) / elem.s.pixSize}`;
            elem.el.innerCodeBox.innerHTML += ` $O${parseFloat(elem.s.storeValues[x][1]) / elem.s.pixSize}`;
            //need to add support with name that color

            for(var y = 0; y < elem.s.storeColors.length; y++){
                if(elem.s.storeValues[x][2] === elem.s.storeColors[y]){
                    elem.el.innerCodeBox.innerHTML += ` ${elem.s.sassColorVariables[y]}`;
                }
            }
            if(x === elem.s.storeValues.length - 1){
                elem.el.innerCodeBox.innerHTML += ";";
            }
            else{
                elem.el.innerCodeBox.innerHTML += ",";
            }
        }
    },

    addLessVariables: () =>{
        elem.el.codeBox.classList.remove("css_box", "sass_box", "js_box");
        elem.el.codeBox.classList.add("less_box");

        elem.el.codeBoxBorder.classList.remove("css_border", "sass_border", "js_border");
        elem.el.codeBoxBorder.classList.add("less_border");

        elem.el.innerCodeBox.innerHTML = "@num:" + elem.s.pixSize + ";
";

        for(let x = 0; x < elem.s.storeColors.length; x++){
            elem.el.innerCodeBox.innerHTML += `@colors${x}: ${elem.s.storeColors[x]};`;
        }

        elem.el.innerCodeBox.innerHTML += "
";

        for(let x = 0; x < elem.s.columnCount; x++){
            elem.el.innerCodeBox.innerHTML += `@X${x}: @num*${x}px; `;
        }
        elem.el.innerCodeBox.innerHTML += `$num: ${elem.s.pixSize};<br>`;
        for(let y = 0; y < elem.s.columnCount; y++){
            elem.el.innerCodeBox.innerHTML += `@O${y}: @num*${y}px; `;
        }
        elem.el.innerCodeBox.innerHTML += "

";
    },

    convertToLess: () => {
        elem.el.innerCodeBox.innerHTML += "box-shadow: ";
        for (var xyz = 0; xyz < elem.s.storeValues.length; xyz++) {
            elem.el.innerCodeBox.innerHTML += " @X" + parseFloat(elem.s.storeValues[xyz][0]) / elem.s.pixSize;
            elem.el.innerCodeBox.innerHTML += " @O" + parseFloat(elem.s.storeValues[xyz][1]) / elem.s.pixSize;

            for(var avi = 0; avi < elem.s.storeColors.length; avi++){
                if(elem.s.storeValues[xyz][2] === elem.s.storeColors[avi]){
                    elem.el.innerCodeBox.innerHTML += " " + elem.s.lessColorVariables[avi];
                }
            }

            if (xyz === elem.s.storeValues.length - 1) {
                elem.el.innerCodeBox.innerHTML += ";";
            }
            else {
                elem.el.innerCodeBox.innerHTML += ",";
            }
        }
    }
};

export default convert;

<commit_msg>fix sass function, to allow for multiple colors<commit_after>import elem from "./_elem.js";

var convert = {
    addSassVariables: () =>{
        elem.el.codeBox.classList.remove("css_box", "less_box", "js_box");
        elem.el.codeBox.classList.add("sass_box");

        elem.el.codeBoxBorder.classList.remove("css_border", "less_border", "js_border");
        elem.el.codeBoxBorder.classList.add("sass_border");

        elem.el.innerCodeBox.innerHTML = `$num: ${elem.s.pixSize};<br>`;
        for(let x = 0; x < elem.s.storeColors.length; x++){
            elem.el.innerCodeBox.innerHTML += `$colors ${x + 1}: ${elem.s.storeColors[x]}; `;
        }

        elem.el.innerCodeBox.innerHTML += "
";

        for(let x = 0; x < elem.s.columnCount; x++){
            elem.el.innerCodeBox.innerHTML += `$X${x}: $num*${x}px; `;
        }
        //elem.el.innerCodeBox.innerHTML += `$num: ${elem.s.pixSize};<br>`;
        for(var y = 0; y < elem.s.columnCount; y++){
            elem.el.innerCodeBox.innerHTML += `$O${y}: $num*${y}px; `;
        }
        elem.el.innerCodeBox.innerHTML += "

";
    },

    convertToSass: () =>{

        elem.el.innerCodeBox.innerHTML += "box-shadow: ";
        for(var x = 0; x < elem.s.storeValues.length; x++) {
            elem.el.innerCodeBox.innerHTML += ` $X${parseFloat(elem.s.storeValues[x][0]) / elem.s.pixSize}`;
            elem.el.innerCodeBox.innerHTML += ` $O${parseFloat(elem.s.storeValues[x][1]) / elem.s.pixSize}`;
            //need to add support with name that color
            for(var y = 0; y < elem.s.storeColors.length; y++){
                if(elem.s.storeValues[x][2] === elem.s.storeColors[y]){
                    elem.el.innerCodeBox.innerHTML += ` $Colors ${elem.s.storeColors.indexOf(elem.s.storeValues[x][2]) + 1}`;
                }
            }
            if(x === elem.s.storeValues.length - 1){
                elem.el.innerCodeBox.innerHTML += ";";
            }
            else{
                elem.el.innerCodeBox.innerHTML += ",";
            }
        }
    },

    addLessVariables: () =>{
        elem.el.codeBox.classList.remove("css_box", "sass_box", "js_box");
        elem.el.codeBox.classList.add("less_box");

        elem.el.codeBoxBorder.classList.remove("css_border", "sass_border", "js_border");
        elem.el.codeBoxBorder.classList.add("less_border");

        elem.el.innerCodeBox.innerHTML = "@num:" + elem.s.pixSize + ";
";

        for(let x = 0; x < elem.s.storeColors.length; x++){
            elem.el.innerCodeBox.innerHTML += `@colors${x}: ${elem.s.storeColors[x]};`;
        }

        elem.el.innerCodeBox.innerHTML += "
";

        for(let x = 0; x < elem.s.columnCount; x++){
            elem.el.innerCodeBox.innerHTML += `@X${x}: @num*${x}px; `;
        }
        elem.el.innerCodeBox.innerHTML += `$num: ${elem.s.pixSize};<br>`;
        for(let y = 0; y < elem.s.columnCount; y++){
            elem.el.innerCodeBox.innerHTML += `@O${y}: @num*${y}px; `;
        }
        elem.el.innerCodeBox.innerHTML += "

";
    },

    convertToLess: () => {
        elem.el.innerCodeBox.innerHTML += "box-shadow: ";
        for (var xyz = 0; xyz < elem.s.storeValues.length; xyz++) {
            elem.el.innerCodeBox.innerHTML += " @X" + parseFloat(elem.s.storeValues[xyz][0]) / elem.s.pixSize;
            elem.el.innerCodeBox.innerHTML += " @O" + parseFloat(elem.s.storeValues[xyz][1]) / elem.s.pixSize;

            for(var avi = 0; avi < elem.s.storeColors.length; avi++){
                if(elem.s.storeValues[xyz][2] === elem.s.storeColors[avi]){
                    elem.el.innerCodeBox.innerHTML += " " + elem.s.lessColorVariables[avi];
                }
            }

            if (xyz === elem.s.storeValues.length - 1) {
                elem.el.innerCodeBox.innerHTML += ";";
            }
            else {
                elem.el.innerCodeBox.innerHTML += ",";
            }
        }
    }
};

export default convert;

<|endoftext|>


<commit_before>module.exports = function (grunt) {

    /*
     * Configuration settings
     */
    var bowerPaths = {
        bowerrc: '.bowerrc',
        bowerDirectory: 'bower_components',
        bowerJson: 'bower.json'
    };

    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-sync-json');
    grunt.loadNpmTasks('grunt-bower-install-simple');
    grunt.loadNpmTasks('main-bower-files');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-execute');
    grunt.loadNpmTasks('grunt-publish');
    grunt.loadNpmTasks('grunt-bump');
    grunt.loadNpmTasks('grunt-bump');
    grunt.loadNpmTasks('grunt-mocha-test');

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        'sync-json': {
            options: {
                indent: 2,
                include: [
                    'name', 'version', 'description', 'authors', 'main', 'repository', 'keywords', 'license', 'private'
                ]
            },
            dep: {
                files: {
                    'bower.json': 'package.json'
                }
            }
        },

        /*
         * Task used to install bower dependencies.
         */
        'bower-install-simple': {
            dep: {
                options: {
                    production: false
                }
            }
        },

        /*
         * Modify the bower dependencies and move the needed files to the
         * target location.
         */
        bower: {
            dep: {
                options: {
                    includeDev: true,
                    checkExistence: true,
                    paths: bowerPaths,
                    overrides: {
                        'r.js': {main: ['dist/r.js']}
                    }
                },
                dest: 'www-root/scripts'
            }
        },

        /*
         * The watch tasks observes changes on the file-system, which
         * allow us to see changes directly in the browser.
         *
         * Set spawn == false, ee documentation: Setting this option to false speeds
         * up the reaction time of the watch (usually 500ms faster
         * for most)
         */
        watch: {
            server: {
                options: {
                    livereload: true,
                    spawn: false
                },

                // define the task to run when a change happens
                tasks: ['01-resolve-dependencies', 'copy:setup'],

                // files to observe, can be an array
                files: ['gruntfile.js', 'package.json', 'src/**/*', 'public/**/*', 'test/**/*']
            },
            dist: {
                options: {
                    livereload: true,
                    spawn: false
                },

                // define the task to run when a change happens
                tasks: ['04-deploy', 'copy:dist'],

                // files to observe, can be an array
                files: ['public/testDistribution.html', 'src/Optimizer.js']
            }
        },

        /*
         * The connect task starts a web server for us to see our results and
         * do some testing.
         */
        connect: {
            server: {
                options: {
                    port: '<%= server.port %>',
                    base: 'www-root'
                }
            },
            dist: {
                options: {
                    port: '<%= server.port %>',
                    base: 'www-dist'
                }
            }
        },

        /*
         * Copies the files into the right location for the web server.
         */
        copy: {
            setup: {
                files: [
                    {expand: true, flatten: false, cwd: 'src', src: '**/*', dest: 'www-root/scripts'},
                    {expand: true, flatten: false, cwd: 'test', src: '**/*', dest: 'www-root/scripts'},
                    {expand: true, flatten: false, cwd: 'public', src: '**/*', dest: 'www-root'}
                ]
            },
            dist: {
                files: [
                    {
                        expand: true,
                        flatten: false,
                        cwd: bowerPaths.bowerDirectory + '/qunit/qunit',
                        src: '**/*',
                        dest: 'www-dist/scripts'
                    },
                    {expand: true, flatten: false, cwd: 'dist', src: '**/*', dest: 'www-dist/scripts'},
                    {expand: true, flatten: false, cwd: 'public', src: 'testDistribution.html', dest: 'www-dist'}
                ]
            }
        },

        execute: {
            compile: {
                call: function (grunt, option, async) {
                    var requirejs = require('requirejs');
                    var extend = require('util')._extend;
                    var fs = require('fs');

                    var done = async();
                    var currentDir = process.cwd();
                    var prefixFilename = currentDir + '/dist/' + grunt.config('pkg.name');

                    var baseConfig = {
                        baseUrl: 'scripts',
                        name: 'almond',
                        include: 'Optimizer',
                        wrap: true
                    };

                    var optimize = function (config, callback) {

                        requirejs.optimize(config, function () {
                            callback(true);
                        }, function (err) {
                            grunt.log.error(err);
                            callback(false);
                        });
                    };

                    var cleanUp = function () {
                        process.chdir(currentDir);
                        done();
                    };

                    // run the actual optimization
                    process.chdir('www-root');
                    optimize(extend({
                        optimize: 'none',
                        out: prefixFilename + '.js'
                    }, baseConfig), function (success) {

                        if (success) {
                            optimize(extend({
                                out: prefixFilename + '.min.js'
                            }, baseConfig), cleanUp);
                        } else {
                            cleanUp();
                        }
                    });
                }
            }
        },

        mochaTest: {
            test: {
                options: {
                },
                src: ['specs/**/*.js']
            }
        },

        publish: {
            options: {
                ignore: ['node_modules', 'bower_components']
            },
            deploy: {
                src: './'
            }
        },

        bump: {
            options: {
                files: ['package.json', 'bower.json'],
                commitFiles: ['.'],
                pushTo: 'origin'
            }
        }
    });

    grunt.registerTask('01-resolve-dependencies', 'Resolve all the dependencies', function () {
        grunt.task.run('sync-json:dep', 'bower-install-simple:dep', 'bower:dep');
    });

    grunt.registerTask('02-compile-sources', 'Update the current root-directory', function () {
        grunt.task.run('01-resolve-dependencies', 'copy:setup', 'execute:compile');
    });

    // 03-run-test-suite
    grunt.registerTask('03-run-test-suite', 'Test the testable stuff', function () {
        grunt.task.run('02-compile-sources', 'mochaTest:test');
    });

    grunt.registerTask('04-deploy', 'Update the current root-directory', function () {
        grunt.config.set('log.msg', 'Make sure your bower project is registered using: ' + '\n' +
            '$ bower register ' + grunt.config('pkg.name') + ' ' + grunt.config('pkg.repository.bump') + '\n' +
            'Make sure your npm users are added: ' + '\n' +
            '$ npm adduser');

        grunt.task.run('02-compile-sources', 'log', 'bump', 'publish:deploy');
    });

    grunt.registerTask('98-run-server', 'Start the web-server for fast debugging.', function (port) {
        port = typeof port === 'undefined' || port === null || isNaN(parseFloat(port)) || !isFinite(port) ? 20000 : parseInt(port);
        grunt.config.set('server.port', port);
        grunt.config.set('log.msg', 'For testing   : http://localhost:' + port + '/test.html' + '\n' +
            'For an example: http://localhost:' + port + '/index.html');

        grunt.task.run('01-resolve-dependencies', 'copy:setup', 'connect:server', 'log', 'watch:server');
    });

    grunt.registerTask('99-run-dist-server', 'Runs a server with the dist-version', function (port) {
        port = typeof port === 'undefined' || port === null || isNaN(parseFloat(port)) || !isFinite(port) ? 20000 : parseInt(port);
        grunt.config.set('server.port', port);
        grunt.config.set('log.msg', 'Test the distribution: http://localhost:' + port + '/testDistribution.html');

        grunt.task.run('02-compile-sources', 'copy:dist', 'connect:dist', 'log', 'watch:dist');
    });

    grunt.registerTask('log', 'Writes a log messages', function () {
        grunt.log.writeln(grunt.config.get('log.msg'));
    });
};<commit_msg>removed duplicate<commit_after>module.exports = function (grunt) {

    /*
     * Configuration settings
     */
    var bowerPaths = {
        bowerrc: '.bowerrc',
        bowerDirectory: 'bower_components',
        bowerJson: 'bower.json'
    };

    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-sync-json');
    grunt.loadNpmTasks('grunt-bower-install-simple');
    grunt.loadNpmTasks('main-bower-files');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-execute');
    grunt.loadNpmTasks('grunt-publish');
    grunt.loadNpmTasks('grunt-bump');
    grunt.loadNpmTasks('grunt-mocha-test');

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        'sync-json': {
            options: {
                indent: 2,
                include: [
                    'name', 'version', 'description', 'authors', 'main', 'repository', 'keywords', 'license', 'private'
                ]
            },
            dep: {
                files: {
                    'bower.json': 'package.json'
                }
            }
        },

        /*
         * Task used to install bower dependencies.
         */
        'bower-install-simple': {
            dep: {
                options: {
                    production: false
                }
            }
        },

        /*
         * Modify the bower dependencies and move the needed files to the
         * target location.
         */
        bower: {
            dep: {
                options: {
                    includeDev: true,
                    checkExistence: true,
                    paths: bowerPaths,
                    overrides: {
                        'r.js': {main: ['dist/r.js']}
                    }
                },
                dest: 'www-root/scripts'
            }
        },

        /*
         * The watch tasks observes changes on the file-system, which
         * allow us to see changes directly in the browser.
         *
         * Set spawn == false, ee documentation: Setting this option to false speeds
         * up the reaction time of the watch (usually 500ms faster
         * for most)
         */
        watch: {
            server: {
                options: {
                    livereload: true,
                    spawn: false
                },

                // define the task to run when a change happens
                tasks: ['01-resolve-dependencies', 'copy:setup'],

                // files to observe, can be an array
                files: ['gruntfile.js', 'package.json', 'src/**/*', 'public/**/*', 'test/**/*']
            },
            dist: {
                options: {
                    livereload: true,
                    spawn: false
                },

                // define the task to run when a change happens
                tasks: ['04-deploy', 'copy:dist'],

                // files to observe, can be an array
                files: ['public/testDistribution.html', 'src/Optimizer.js']
            }
        },

        /*
         * The connect task starts a web server for us to see our results and
         * do some testing.
         */
        connect: {
            server: {
                options: {
                    port: '<%= server.port %>',
                    base: 'www-root'
                }
            },
            dist: {
                options: {
                    port: '<%= server.port %>',
                    base: 'www-dist'
                }
            }
        },

        /*
         * Copies the files into the right location for the web server.
         */
        copy: {
            setup: {
                files: [
                    {expand: true, flatten: false, cwd: 'src', src: '**/*', dest: 'www-root/scripts'},
                    {expand: true, flatten: false, cwd: 'test', src: '**/*', dest: 'www-root/scripts'},
                    {expand: true, flatten: false, cwd: 'public', src: '**/*', dest: 'www-root'}
                ]
            },
            dist: {
                files: [
                    {
                        expand: true,
                        flatten: false,
                        cwd: bowerPaths.bowerDirectory + '/qunit/qunit',
                        src: '**/*',
                        dest: 'www-dist/scripts'
                    },
                    {expand: true, flatten: false, cwd: 'dist', src: '**/*', dest: 'www-dist/scripts'},
                    {expand: true, flatten: false, cwd: 'public', src: 'testDistribution.html', dest: 'www-dist'}
                ]
            }
        },

        execute: {
            compile: {
                call: function (grunt, option, async) {
                    var requirejs = require('requirejs');
                    var extend = require('util')._extend;
                    var fs = require('fs');

                    var done = async();
                    var currentDir = process.cwd();
                    var prefixFilename = currentDir + '/dist/' + grunt.config('pkg.name');

                    var baseConfig = {
                        baseUrl: 'scripts',
                        name: 'almond',
                        include: 'Optimizer',
                        wrap: true
                    };

                    var optimize = function (config, callback) {

                        requirejs.optimize(config, function () {
                            callback(true);
                        }, function (err) {
                            grunt.log.error(err);
                            callback(false);
                        });
                    };

                    var cleanUp = function () {
                        process.chdir(currentDir);
                        done();
                    };

                    // run the actual optimization
                    process.chdir('www-root');
                    optimize(extend({
                        optimize: 'none',
                        out: prefixFilename + '.js'
                    }, baseConfig), function (success) {

                        if (success) {
                            optimize(extend({
                                out: prefixFilename + '.min.js'
                            }, baseConfig), cleanUp);
                        } else {
                            cleanUp();
                        }
                    });
                }
            }
        },

        mochaTest: {
            test: {
                options: {
                },
                src: ['specs/**/*.js']
            }
        },

        publish: {
            options: {
                ignore: ['node_modules', 'bower_components']
            },
            deploy: {
                src: './'
            }
        },

        bump: {
            options: {
                files: ['package.json', 'bower.json'],
                commitFiles: ['.'],
                pushTo: 'origin'
            }
        }
    });

    grunt.registerTask('01-resolve-dependencies', 'Resolve all the dependencies', function () {
        grunt.task.run('sync-json:dep', 'bower-install-simple:dep', 'bower:dep');
    });

    grunt.registerTask('02-compile-sources', 'Update the current root-directory', function () {
        grunt.task.run('01-resolve-dependencies', 'copy:setup', 'execute:compile');
    });

    // 03-run-test-suite
    grunt.registerTask('03-run-test-suite', 'Test the testable stuff', function () {
        grunt.task.run('02-compile-sources', 'mochaTest:test');
    });

    grunt.registerTask('04-deploy', 'Update the current root-directory', function () {
        grunt.config.set('log.msg', 'Make sure your bower project is registered using: ' + '\n' +
            '$ bower register ' + grunt.config('pkg.name') + ' ' + grunt.config('pkg.repository.bump') + '\n' +
            'Make sure your npm users are added: ' + '\n' +
            '$ npm adduser');

        grunt.task.run('02-compile-sources', 'log', 'bump', 'publish:deploy');
    });

    grunt.registerTask('98-run-server', 'Start the web-server for fast debugging.', function (port) {
        port = typeof port === 'undefined' || port === null || isNaN(parseFloat(port)) || !isFinite(port) ? 20000 : parseInt(port);
        grunt.config.set('server.port', port);
        grunt.config.set('log.msg', 'For testing   : http://localhost:' + port + '/test.html' + '\n' +
            'For an example: http://localhost:' + port + '/index.html');

        grunt.task.run('01-resolve-dependencies', 'copy:setup', 'connect:server', 'log', 'watch:server');
    });

    grunt.registerTask('99-run-dist-server', 'Runs a server with the dist-version', function (port) {
        port = typeof port === 'undefined' || port === null || isNaN(parseFloat(port)) || !isFinite(port) ? 20000 : parseInt(port);
        grunt.config.set('server.port', port);
        grunt.config.set('log.msg', 'Test the distribution: http://localhost:' + port + '/testDistribution.html');

        grunt.task.run('02-compile-sources', 'copy:dist', 'connect:dist', 'log', 'watch:dist');
    });

    grunt.registerTask('log', 'Writes a log messages', function () {
        grunt.log.writeln(grunt.config.get('log.msg'));
    });
};<|endoftext|>


<commit_before>(function() {
  window.shared || (window.shared = {});
  var dom = window.shared.ReactHelpers.dom;
  var createEl = window.shared.ReactHelpers.createEl;
  var merge = window.shared.ReactHelpers.merge;

  var MathDetails = window.shared.MathDetails = React.createClass({
    render: function() {
      return dom.div({}, 'yo!');
    }
  });
})();<commit_msg>Functional math_details page (essentially copy-pasted from ela_details).<commit_after>(function() {
window.shared || (window.shared = {});
var dom = window.shared.ReactHelpers.dom;
var createEl = window.shared.ReactHelpers.createEl;
var merge = window.shared.ReactHelpers.merge;

var ProfileChartSettings = window.ProfileChartSettings;
var HighchartsWrapper = window.shared.HighchartsWrapper;

var MathDetails = window.shared.MathDetails = React.createClass({
    displayName: 'MathDetails',

    propTypes: {
      chartData: React.PropTypes.shape({
        star_series_math_percentile: React.PropTypes.array.isRequired,
        mcas_series_math_scaled: React.PropTypes.array.isRequired,
        mcas_series_math_growth: React.PropTypes.array.isRequired
      }).isRequired
    },

    getDefaultProps: function() {
      return {
        now: new Date(),
        intervalBack: [4, 'years']
      };
    },

    // TODO(kr/er) align these to school year?
    // The intent of fixing this date range is that when staff are looking at profile of different students,
    // the scales are consistent (and not changing between 3 mos and 6 years depending on the student's record,
    // since that's easy to miss and misinterpret.
    timestampRange: function() {
      return {
        min: moment(this.props.now).subtract(this.props.intervalBack[0], this.props.intervalBack[1]).toDate().getTime(),
        max: this.props.now.getTime()
      };
    },

    render: function() {
      return dom.div({ className: 'MathDetails' },
        this.renderStarMath(),
        this.renderMCASMathScores(),
        this.renderMCASMathGrowth()
      );
    },

    renderStarMath: function() {
      return createEl(HighchartsWrapper, merge(this.baseOptions(), {
        title: {
          text: 'STAR Math, last 4 years',
          align: 'left'
        },
        series: [{
          name: 'Percentile rank',
          data: this.quadsToPairs(this.props.chartData.star_series_math_percentile || [])
        }],
        yAxis: this.percentileYAxis()
      }));
    },

    renderMCASMathScores: function() {
      return createEl(HighchartsWrapper, merge(this.baseOptions(), {
        title: {
          text: 'MCAS Math scores, last 4 years',
          align: 'left'
        },
        series: [{
          name: 'Scaled score',
          data: this.quadsToPairs(this.props.chartData.mcas_series_math_scaled || [])
        }],
        yAxis: merge(ProfileChartSettings.default_mcas_score_yaxis, {
          plotLines: ProfileChartSettings.mcas_level_bands
        })
      }));
    },

    renderMCASMathGrowth: function() {
      return createEl(HighchartsWrapper, merge(this.baseOptions(), {
        title: {
          text: 'MCAS Math Growth, last 4 years',
          align: 'left'
        },
        series: [{
          name: 'Growth percentile',
          data: this.quadsToPairs(this.props.chartData.mcas_series_math_growth || [])
        }],
        yAxis: this.percentileYAxis()
      }));
    },

    // TODO(kr/er) factor out
    quadsToPairs: function(quads) {
      return quads.map(function(quad) {
        var date = Date.UTC(quad[0], quad[1] - 1, quad[2]);
        return [date, quad[3]];
      });
    },

    // TODO(kr/er) factor out
    baseOptions: function() {
      // TODO(kr/er) intervention plot bands, based on particular
      // interventions?
      var timestampRange = this.timestampRange();
      return merge(ProfileChartSettings.base_options, {
        xAxis: merge(ProfileChartSettings.x_axis_datetime, {
          plotLines: this.x_axis_bands,
          min: timestampRange.min,
          max: timestampRange.max
        })
      });
    },

    // TODO(kr/er) factor out
    percentileYAxis: function() {
      return merge(ProfileChartSettings.percentile_yaxis, {
        plotLines: [{
          color: '#666',
          width: 1,
          zIndex: 3,
          value: 50,
          label: {
            text: '50th percentile',
            align: 'center',
            style: {
              color: '#999999'
            }
          }
        }]
      });
    }
});
})();<|endoftext|>


<commit_before>import SPELLS from 'common/SPELLS';

import CoreAbilities from 'parser/core/modules/Abilities';
//import { SpellLink } from 'interface';

class Abilities extends CoreAbilities {
  spellbook() {
    const combatant = this.selectedCombatant;
    return [
      {
        spell: SPELLS.CONSECRATION_CAST,
        buffSpellId: SPELLS.CONSECRATION_BUFF.id,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: haste => 4.5 / (1 + haste),
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.BLESSED_HAMMER_TALENT,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: haste => 6 / (1 + haste),
        gcd: {
          base: 1500,
        },
        charges: 3,
        enabled: combatant.hasTalent(SPELLS.BLESSED_HAMMER_TALENT.id),
        castEfficiency: {
          suggestion: false,
          recommendedEfficiency: 0.9,
        },
      },
      {
        spell: SPELLS.AVENGERS_SHIELD,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: haste => 15 / (1 + haste),
        gcd: {
          base: 1500,
        },
        castEfficiency: {
          suggestion: true,
          recommendedEfficiency: 0.9,
        },
      },
      // Probably useless to try to count the number of casts
      //Note by yajinni: Since this is thier main source of damage mitigation, without it they get hit like by a truck.
      //And a main source of damage, it should be tracked somewhat. Keeping it at 80% for now.
      {
        spell: SPELLS.SHIELD_OF_THE_RIGHTEOUS,
        buffSpellId: SPELLS.SHIELD_OF_THE_RIGHTEOUS_BUFF.id,
        isDefensive: true,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: null,
      },
      { // T15: Holy Shield
        spell: SPELLS.HAMMER_OF_THE_RIGHTEOUS,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: haste => 6 / (1 + haste),
        charges: 2,
        gcd: {
          base: 1500,
        },
        enabled: !combatant.hasTalent(SPELLS.BLESSED_HAMMER_TALENT.id),
        castEfficiency: {
          suggestion: false,
        },
      },
      {
        spell: SPELLS.JUDGMENT_CAST_PROTECTION,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: haste => 6 / (1 + haste),
        charges: combatant.hasTalent(SPELLS.CRUSADERS_JUDGMENT_TALENT.id) ? 2 : 1,
        gcd: {
          base: 1500,
        },
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.WORD_OF_GLORY,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        gcd: {
          base: 1500,
        },
      },
      //COOLDOWNS
      {
        spell: SPELLS.ARDENT_DEFENDER,
        buffSpellId: SPELLS.ARDENT_DEFENDER.id,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        cooldown: 120 * (combatant.hasTalent(SPELLS.UNBREAKABLE_SPIRIT_TALENT.id) ? 0.7 : 1),
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: [SPELLS.GUARDIAN_OF_ANCIENT_KINGS, SPELLS.GUARDIAN_OF_ANCIENT_KINGS_QUEEN],
        buffSpellId: [SPELLS.GUARDIAN_OF_ANCIENT_KINGS.id, SPELLS.GUARDIAN_OF_ANCIENT_KINGS_QUEEN.id],
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        cooldown: 300,
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.SERAPHIM_TALENT,
        buffSpellId: SPELLS.SERAPHIM_TALENT.id,
        category: Abilities.SPELL_CATEGORIES.SEMI_DEFENSIVE,
        cooldown: 45,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.SERAPHIM_TALENT.id),
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.AVENGING_WRATH,
        buffSpellId: SPELLS.AVENGING_WRATH.id,
        category: Abilities.SPELL_CATEGORIES.SEMI_DEFENSIVE,
        gcd: {
          base: 1500,
        },
        cooldown: 120,
        // castEfficiency: {
        //   suggestion: true,
        //   recommendedEfficiency: 0.85,
        // },
      },
      {
        spell: SPELLS.LAY_ON_HANDS,
        isDefensive: true,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 600,
        castEfficiency: {
          suggestion: true,
          recommendedEfficiency: 0.1,
        },
      },
      {
        spell: SPELLS.FLASH_OF_LIGHT,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.DIVINE_STEED,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 45,
        charges: combatant.hasTalent(SPELLS.CAVALIER_TALENT.id) ? 2 : 1,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.BLESSING_OF_FREEDOM,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 25,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.BLESSING_OF_PROTECTION,
        isDefensive: true,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 5 * 60,
        gcd: {
          base: 1500,
        },
        enabled: !combatant.hasTalent(SPELLS.BLESSING_OF_SPELLWARDING_TALENT.id),
      },
      {
        spell: SPELLS.BLESSING_OF_SPELLWARDING_TALENT,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 180,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.BLESSING_OF_SPELLWARDING_TALENT.id),
      },
      {
        spell: SPELLS.BLESSING_OF_SACRIFICE,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 120,
      },
      {
        spell: SPELLS.CLEANSE_TOXINS,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 8,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.HAMMER_OF_JUSTICE,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 60,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.HAMMER_OF_WRATH,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: haste => 7.5 / (1 + haste),
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.HAND_OF_RECKONING,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 8,
      },
      {
        spell: SPELLS.REBUKE,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 15,
      },
      {
        spell: SPELLS.BLINDING_LIGHT_TALENT,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 90,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.BLINDING_LIGHT_TALENT.id),
      },
      {
        spell: SPELLS.REPENTANCE_TALENT,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 15,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.REPENTANCE_TALENT.id),
      },
      {
        spell: SPELLS.FINAL_STAND_CAST,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        cooldown: 300 * (combatant.hasTalent(SPELLS.UNBREAKABLE_SPIRIT_TALENT.id) ? 0.7 : 1),
        castEfficiency: {
          suggestion: true,
          recommendedEfficiency: 0.6,
        },
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.FINAL_STAND_TALENT.id),
      },
    ];
  }
}

export default Abilities;
<commit_msg>Fixed issue with Final Stand being double counted.<commit_after>import SPELLS from 'common/SPELLS';

import CoreAbilities from 'parser/core/modules/Abilities';
//import { SpellLink } from 'interface';

class Abilities extends CoreAbilities {
  spellbook() {
    const combatant = this.selectedCombatant;
    return [
      {
        spell: SPELLS.CONSECRATION_CAST,
        buffSpellId: SPELLS.CONSECRATION_BUFF.id,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: haste => 4.5 / (1 + haste),
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.BLESSED_HAMMER_TALENT,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: haste => 6 / (1 + haste),
        gcd: {
          base: 1500,
        },
        charges: 3,
        enabled: combatant.hasTalent(SPELLS.BLESSED_HAMMER_TALENT.id),
        castEfficiency: {
          suggestion: false,
          recommendedEfficiency: 0.9,
        },
      },
      {
        spell: SPELLS.AVENGERS_SHIELD,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: haste => 15 / (1 + haste),
        gcd: {
          base: 1500,
        },
        castEfficiency: {
          suggestion: true,
          recommendedEfficiency: 0.9,
        },
      },
      // Probably useless to try to count the number of casts
      //Note by yajinni: Since this is thier main source of damage mitigation, without it they get hit like by a truck.
      //And a main source of damage, it should be tracked somewhat. Keeping it at 80% for now.
      {
        spell: SPELLS.SHIELD_OF_THE_RIGHTEOUS,
        buffSpellId: SPELLS.SHIELD_OF_THE_RIGHTEOUS_BUFF.id,
        isDefensive: true,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: null,
      },
      { // T15: Holy Shield
        spell: SPELLS.HAMMER_OF_THE_RIGHTEOUS,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: haste => 6 / (1 + haste),
        charges: 2,
        gcd: {
          base: 1500,
        },
        enabled: !combatant.hasTalent(SPELLS.BLESSED_HAMMER_TALENT.id),
        castEfficiency: {
          suggestion: false,
        },
      },
      {
        spell: SPELLS.JUDGMENT_CAST_PROTECTION,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: haste => 6 / (1 + haste),
        charges: combatant.hasTalent(SPELLS.CRUSADERS_JUDGMENT_TALENT.id) ? 2 : 1,
        gcd: {
          base: 1500,
        },
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.WORD_OF_GLORY,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        gcd: {
          base: 1500,
        },
      },
      //COOLDOWNS
      {
        spell: SPELLS.ARDENT_DEFENDER,
        buffSpellId: SPELLS.ARDENT_DEFENDER.id,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        cooldown: 120 * (combatant.hasTalent(SPELLS.UNBREAKABLE_SPIRIT_TALENT.id) ? 0.7 : 1),
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: [SPELLS.GUARDIAN_OF_ANCIENT_KINGS, SPELLS.GUARDIAN_OF_ANCIENT_KINGS_QUEEN],
        buffSpellId: [SPELLS.GUARDIAN_OF_ANCIENT_KINGS.id, SPELLS.GUARDIAN_OF_ANCIENT_KINGS_QUEEN.id],
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        cooldown: 300,
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.SERAPHIM_TALENT,
        buffSpellId: SPELLS.SERAPHIM_TALENT.id,
        category: Abilities.SPELL_CATEGORIES.SEMI_DEFENSIVE,
        cooldown: 45,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.SERAPHIM_TALENT.id),
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.AVENGING_WRATH,
        buffSpellId: SPELLS.AVENGING_WRATH.id,
        category: Abilities.SPELL_CATEGORIES.SEMI_DEFENSIVE,
        gcd: {
          base: 1500,
        },
        cooldown: 120,
        // castEfficiency: {
        //   suggestion: true,
        //   recommendedEfficiency: 0.85,
        // },
      },
      {
        spell: SPELLS.LAY_ON_HANDS,
        isDefensive: true,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 600,
        castEfficiency: {
          suggestion: true,
          recommendedEfficiency: 0.1,
        },
      },
      {
        spell: SPELLS.FLASH_OF_LIGHT,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.DIVINE_STEED,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 45,
        charges: combatant.hasTalent(SPELLS.CAVALIER_TALENT.id) ? 2 : 1,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.BLESSING_OF_FREEDOM,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 25,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.BLESSING_OF_PROTECTION,
        isDefensive: true,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 5 * 60,
        gcd: {
          base: 1500,
        },
        enabled: !combatant.hasTalent(SPELLS.BLESSING_OF_SPELLWARDING_TALENT.id),
      },
      {
        spell: SPELLS.BLESSING_OF_SPELLWARDING_TALENT,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 180,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.BLESSING_OF_SPELLWARDING_TALENT.id),
      },
      {
        spell: SPELLS.BLESSING_OF_SACRIFICE,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 120,
      },
      {
        spell: SPELLS.CLEANSE_TOXINS,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 8,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.HAMMER_OF_JUSTICE,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 60,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.HAMMER_OF_WRATH,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: haste => 7.5 / (1 + haste),
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.HAND_OF_RECKONING,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 8,
      },
      {
        spell: SPELLS.REBUKE,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 15,
      },
      {
        spell: SPELLS.BLINDING_LIGHT_TALENT,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 90,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.BLINDING_LIGHT_TALENT.id),
      },
      {
        spell: SPELLS.REPENTANCE_TALENT,
        category: Abilities.SPELL_CATEGORIES.UTILITY,
        cooldown: 15,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.REPENTANCE_TALENT.id),
      },
      {
        spell: SPELLS.DIVINE_SHIELD,
        buffSpellId: SPELLS.DIVINE_SHIELD.id,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        cooldown: 300 * (combatant.hasTalent(SPELLS.UNBREAKABLE_SPIRIT_TALENT.id) ? 0.7 : 1),
        castEfficiency: {
          suggestion: true,
          recommendedEfficiency: 0.6,
        },
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.FINAL_STAND_TALENT.id),
      },
    ];
  }
}

export default Abilities;
<|endoftext|>


<commit_before>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt

frappe.provide("erpnext.accounts");
frappe.require("assets/erpnext/js/utils.js");

erpnext.accounts.JournalVoucher = frappe.ui.form.Controller.extend({
	onload: function() {
		this.load_defaults();
		this.setup_queries();
		this.setup_balance_formatter();
	},

	onload_post_render: function() {
		cur_frm.get_field("accounts").grid.set_multiple_add("account");
	},

	load_defaults: function() {
		if(this.frm.doc.__islocal && this.frm.doc.company) {
			frappe.model.set_default_values(this.frm.doc);
			$.each(this.frm.doc.accounts || [], function(i, jvd) {
					frappe.model.set_default_values(jvd);
				}
			);

			if(!this.frm.doc.amended_from) this.frm.doc.posting_date = get_today();
		}
	},

	setup_queries: function() {
		var me = this;

		$.each(["account", "cost_center"], function(i, fieldname) {
			me.frm.set_query(fieldname, "accounts", function() {
				frappe.model.validate_missing(me.frm.doc, "company");
				return {
					filters: {
						company: me.frm.doc.company,
						group_or_ledger: "Ledger"
					}
				};
			});
		});

		me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) {
			return {
				filters: {"name": ["in", ["Customer", "Supplier"]]}
			}
		});

		$.each([["against_voucher", "Purchase Invoice", "supplier"],
			["against_invoice", "Sales Invoice", "customer"]], function(i, opts) {
				me.frm.set_query(opts[0], "accounts", function(doc, cdt, cdn) {
					var jvd = frappe.get_doc(cdt, cdn);
					frappe.model.validate_missing(jvd, "party_type");
					frappe.model.validate_missing(jvd, "party");
					return {
						filters: [
							[opts[1], opts[2], "=", jvd.party],
							[opts[1], "docstatus", "=", 1],
							[opts[1], "outstanding_amount", ">", 0]
						]
					};
				});
		});

		this.frm.set_query("against_jv", "accounts", function(doc, cdt, cdn) {
			var jvd = frappe.get_doc(cdt, cdn);
			frappe.model.validate_missing(jvd, "account");

			return {
				query: "erpnext.accounts.doctype.journal_entry.journal_entry.get_against_jv",
				filters: {
					account: jvd.account,
					party: jvd.party
				}
			};
		});
	},

	setup_balance_formatter: function() {
		var me = this;
		$.each(["balance", "party_balance"], function(i, field) {
			var df = frappe.meta.get_docfield("Journal Entry Account", field, me.frm.doc.name);
			df.formatter = function(value, df, options, doc) {
				var currency = frappe.meta.get_field_currency(df, doc);
				var dr_or_cr = value ? ('' + (value > 0.0 ? __("Dr") : __("Cr")) + '') : "";
				return "
"
					+ ((value==null || value==="") ? "" : format_currency(Math.abs(value), currency))
					+ " " + dr_or_cr
					+ "
";
			}
		})
	},

	against_voucher: function(doc, cdt, cdn) {
		var d = frappe.get_doc(cdt, cdn);
		if (d.against_voucher && !flt(d.debit)) {
			this.get_outstanding('Purchase Invoice', d.against_voucher, d);
		}
	},

	against_invoice: function(doc, cdt, cdn) {
		var d = frappe.get_doc(cdt, cdn);
		if (d.against_invoice && !flt(d.credit)) {
			this.get_outstanding('Sales Invoice', d.against_invoice, d);
		}
	},

	against_jv: function(doc, cdt, cdn) {
		var d = frappe.get_doc(cdt, cdn);
		if (d.against_jv && d.party && !flt(d.credit) && !flt(d.debit)) {
			this.get_outstanding('Journal Entry', d.against_jv, d);
		}
	},

	get_outstanding: function(doctype, docname, child) {
		var me = this;
		var args = {
			"doctype": doctype,
			"docname": docname,
			"party": child.party
		}

		return this.frm.call({
			child: child,
			method: "get_outstanding",
			args: { args: args},
			callback: function(r) {
				cur_frm.cscript.update_totals(me.frm.doc);
			}
		});
	}
});

cur_frm.script_manager.make(erpnext.accounts.JournalVoucher);

cur_frm.cscript.refresh = function(doc) {
	cur_frm.cscript.is_opening(doc)
	erpnext.toggle_naming_series();
	cur_frm.cscript.voucher_type(doc);
	if(doc.docstatus==1) {
		cur_frm.add_custom_button(__('View Ledger'), function() {
			frappe.route_options = {
				"voucher_no": doc.name,
				"from_date": doc.posting_date,
				"to_date": doc.posting_date,
				"company": doc.company,
				group_by_voucher: 0
			};
			frappe.set_route("query-report", "General Ledger");
		}, "icon-table");
	}
}

cur_frm.cscript.company = function(doc, cdt, cdn) {
	cur_frm.refresh_fields();
	erpnext.get_fiscal_year(doc.company, doc.posting_date);
}

cur_frm.cscript.posting_date = function(doc, cdt, cdn){
	erpnext.get_fiscal_year(doc.company, doc.posting_date);
}

cur_frm.cscript.is_opening = function(doc, cdt, cdn) {
	hide_field('aging_date');
	if (doc.is_opening == 'Yes') unhide_field('aging_date');
}

cur_frm.cscript.update_totals = function(doc) {
	var td=0.0; var tc =0.0;
	var el = doc.accounts || [];
	for(var i in el) {
		td += flt(el[i].debit, precision("debit", el[i]));
		tc += flt(el[i].credit, precision("credit", el[i]));
	}
	var doc = locals[doc.doctype][doc.name];
	doc.total_debit = td;
	doc.total_credit = tc;
	doc.difference = flt((td - tc), precision("difference"));
	refresh_many(['total_debit','total_credit','difference']);
}

cur_frm.cscript.debit = function(doc,dt,dn) { cur_frm.cscript.update_totals(doc); }
cur_frm.cscript.credit = function(doc,dt,dn) { cur_frm.cscript.update_totals(doc); }

cur_frm.cscript.get_balance = function(doc,dt,dn) {
	cur_frm.cscript.update_totals(doc);
	return $c_obj(cur_frm.doc, 'get_balance', '', function(r, rt){
	cur_frm.refresh();
	});
}
// Get balance
// -----------

cur_frm.cscript.account = function(doc,dt,dn) {
	var d = locals[dt][dn];
	if(d.account) {
		return frappe.call({
			method: "erpnext.accounts.utils.get_balance_on",
			args: {account: d.account, date: doc.posting_date},
			callback: function(r) {
				d.balance = r.message;
				refresh_field('balance', d.name, 'accounts');
			}
		});
	}
}

cur_frm.cscript.validate = function(doc,cdt,cdn) {
	cur_frm.cscript.update_totals(doc);
}

cur_frm.cscript.select_print_heading = function(doc,cdt,cdn){
	if(doc.select_print_heading){
		// print heading
		cur_frm.pformat.print_heading = doc.select_print_heading;
	}
	else
		cur_frm.pformat.print_heading = __("Journal Entry");
}

cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
	cur_frm.set_df_property("cheque_no", "reqd", doc.voucher_type=="Bank Entry");
	cur_frm.set_df_property("cheque_date", "reqd", doc.voucher_type=="Bank Entry");

	if((doc.accounts || []).length!==0 || !doc.company) // too early
		return;

	var update_jv_details = function(doc, r) {
		var jvdetail = frappe.model.add_child(doc, "Journal Entry Account", "accounts");
		$.each(r, function(i, d) {
			var row = frappe.model.add_child(doc, "Journal Entry Account", "accounts");
			row.account = d.cash_bank_account;
			row.balance = d.balance;
		});
		refresh_field("accounts");
	}

	if(in_list(["Bank Entry", "Cash Entry"], doc.voucher_type)) {
		return frappe.call({
			type: "GET",
			method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account",
			args: {
				"voucher_type": doc.voucher_type,
				"company": doc.company
			},
			callback: function(r) {
				if(r.message) {
					update_jv_details(doc, [r.message]);
				}
			}
		})
	} else if(doc.voucher_type=="Opening Entry") {
		return frappe.call({
			type:"GET",
			method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_opening_accounts",
			args: {
				"company": doc.company
			},
			callback: function(r) {
				frappe.model.clear_table(doc, "accounts");
				if(r.message) {
					update_jv_details(doc, r.message);
				}
				cur_frm.set_value("is_opening", "Yes")
			}
		})
	}
}

frappe.ui.form.on("Journal Entry Account", "party", function(frm, cdt, cdn) {
	var d = frappe.get_doc(cdt, cdn);
	if(!d.account && d.party_type && d.party) {
		return frm.call({
			method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_party_account_and_balance",
			child: d,
			args: {
				company: frm.doc.company,
				party_type: d.party_type,
				party: d.party
			}
		});
	}
})

frappe.ui.form.on("Journal Entry Account", "accounts_remove", function(frm) {
	cur_frm.cscript.update_totals(frm.doc);
});

<commit_msg>[usability] journal entry type fixes #3085<commit_after>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt

frappe.provide("erpnext.accounts");
frappe.require("assets/erpnext/js/utils.js");

erpnext.accounts.JournalVoucher = frappe.ui.form.Controller.extend({
	onload: function() {
		this.load_defaults();
		this.setup_queries();
		this.setup_balance_formatter();
	},

	onload_post_render: function() {
		cur_frm.get_field("accounts").grid.set_multiple_add("account");
	},

	load_defaults: function() {
		if(this.frm.doc.__islocal && this.frm.doc.company) {
			frappe.model.set_default_values(this.frm.doc);
			$.each(this.frm.doc.accounts || [], function(i, jvd) {
					frappe.model.set_default_values(jvd);
				}
			);

			if(!this.frm.doc.amended_from) this.frm.doc.posting_date = get_today();
		}
	},

	setup_queries: function() {
		var me = this;

		$.each(["account", "cost_center"], function(i, fieldname) {
			me.frm.set_query(fieldname, "accounts", function() {
				frappe.model.validate_missing(me.frm.doc, "company");
				return {
					filters: {
						company: me.frm.doc.company,
						group_or_ledger: "Ledger"
					}
				};
			});
		});

		me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) {
			return {
				filters: {"name": ["in", ["Customer", "Supplier"]]}
			}
		});

		$.each([["against_voucher", "Purchase Invoice", "supplier"],
			["against_invoice", "Sales Invoice", "customer"]], function(i, opts) {
				me.frm.set_query(opts[0], "accounts", function(doc, cdt, cdn) {
					var jvd = frappe.get_doc(cdt, cdn);
					frappe.model.validate_missing(jvd, "party_type");
					frappe.model.validate_missing(jvd, "party");
					return {
						filters: [
							[opts[1], opts[2], "=", jvd.party],
							[opts[1], "docstatus", "=", 1],
							[opts[1], "outstanding_amount", ">", 0]
						]
					};
				});
		});

		this.frm.set_query("against_jv", "accounts", function(doc, cdt, cdn) {
			var jvd = frappe.get_doc(cdt, cdn);
			frappe.model.validate_missing(jvd, "account");

			return {
				query: "erpnext.accounts.doctype.journal_entry.journal_entry.get_against_jv",
				filters: {
					account: jvd.account,
					party: jvd.party
				}
			};
		});
	},

	setup_balance_formatter: function() {
		var me = this;
		$.each(["balance", "party_balance"], function(i, field) {
			var df = frappe.meta.get_docfield("Journal Entry Account", field, me.frm.doc.name);
			df.formatter = function(value, df, options, doc) {
				var currency = frappe.meta.get_field_currency(df, doc);
				var dr_or_cr = value ? ('' + (value > 0.0 ? __("Dr") : __("Cr")) + '') : "";
				return "
"
					+ ((value==null || value==="") ? "" : format_currency(Math.abs(value), currency))
					+ " " + dr_or_cr
					+ "
";
			}
		})
	},

	against_voucher: function(doc, cdt, cdn) {
		var d = frappe.get_doc(cdt, cdn);
		if (d.against_voucher && !flt(d.debit)) {
			this.get_outstanding('Purchase Invoice', d.against_voucher, d);
		}
	},

	against_invoice: function(doc, cdt, cdn) {
		var d = frappe.get_doc(cdt, cdn);
		if (d.against_invoice && !flt(d.credit)) {
			this.get_outstanding('Sales Invoice', d.against_invoice, d);
		}
	},

	against_jv: function(doc, cdt, cdn) {
		var d = frappe.get_doc(cdt, cdn);
		if (d.against_jv && d.party && !flt(d.credit) && !flt(d.debit)) {
			this.get_outstanding('Journal Entry', d.against_jv, d);
		}
	},

	get_outstanding: function(doctype, docname, child) {
		var me = this;
		var args = {
			"doctype": doctype,
			"docname": docname,
			"party": child.party
		}

		return this.frm.call({
			child: child,
			method: "get_outstanding",
			args: { args: args},
			callback: function(r) {
				cur_frm.cscript.update_totals(me.frm.doc);
			}
		});
	}
});

cur_frm.script_manager.make(erpnext.accounts.JournalVoucher);

cur_frm.cscript.refresh = function(doc) {
	cur_frm.cscript.is_opening(doc)
	erpnext.toggle_naming_series();
	cur_frm.cscript.voucher_type(doc);
	if(doc.docstatus==1) {
		cur_frm.add_custom_button(__('View Ledger'), function() {
			frappe.route_options = {
				"voucher_no": doc.name,
				"from_date": doc.posting_date,
				"to_date": doc.posting_date,
				"company": doc.company,
				group_by_voucher: 0
			};
			frappe.set_route("query-report", "General Ledger");
		}, "icon-table");
	}
}

cur_frm.cscript.company = function(doc, cdt, cdn) {
	cur_frm.refresh_fields();
	erpnext.get_fiscal_year(doc.company, doc.posting_date);
}

cur_frm.cscript.posting_date = function(doc, cdt, cdn){
	erpnext.get_fiscal_year(doc.company, doc.posting_date);
}

cur_frm.cscript.is_opening = function(doc, cdt, cdn) {
	hide_field('aging_date');
	if (doc.is_opening == 'Yes') unhide_field('aging_date');
}

cur_frm.cscript.update_totals = function(doc) {
	var td=0.0; var tc =0.0;
	var el = doc.accounts || [];
	for(var i in el) {
		td += flt(el[i].debit, precision("debit", el[i]));
		tc += flt(el[i].credit, precision("credit", el[i]));
	}
	var doc = locals[doc.doctype][doc.name];
	doc.total_debit = td;
	doc.total_credit = tc;
	doc.difference = flt((td - tc), precision("difference"));
	refresh_many(['total_debit','total_credit','difference']);
}

cur_frm.cscript.debit = function(doc,dt,dn) { cur_frm.cscript.update_totals(doc); }
cur_frm.cscript.credit = function(doc,dt,dn) { cur_frm.cscript.update_totals(doc); }

cur_frm.cscript.get_balance = function(doc,dt,dn) {
	cur_frm.cscript.update_totals(doc);
	return $c_obj(cur_frm.doc, 'get_balance', '', function(r, rt){
	cur_frm.refresh();
	});
}
// Get balance
// -----------

cur_frm.cscript.account = function(doc,dt,dn) {
	var d = locals[dt][dn];
	if(d.account) {
		return frappe.call({
			method: "erpnext.accounts.utils.get_balance_on",
			args: {account: d.account, date: doc.posting_date},
			callback: function(r) {
				d.balance = r.message;
				refresh_field('balance', d.name, 'accounts');
			}
		});
	}
}

cur_frm.cscript.validate = function(doc,cdt,cdn) {
	cur_frm.cscript.update_totals(doc);
}

cur_frm.cscript.select_print_heading = function(doc,cdt,cdn){
	if(doc.select_print_heading){
		// print heading
		cur_frm.pformat.print_heading = doc.select_print_heading;
	}
	else
		cur_frm.pformat.print_heading = __("Journal Entry");
}

cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
	cur_frm.set_df_property("cheque_no", "reqd", doc.voucher_type=="Bank Entry");
	cur_frm.set_df_property("cheque_date", "reqd", doc.voucher_type=="Bank Entry");

	if(!doc.company) return;

	cur_frm.clear_table("accounts");

	var update_jv_details = function(doc, r) {
		var jvdetail = frappe.model.add_child(doc, "Journal Entry Account", "accounts");
		$.each(r, function(i, d) {
			var row = frappe.model.add_child(doc, "Journal Entry Account", "accounts");
			row.account = d.cash_bank_account;
			row.balance = d.balance;
		});
		refresh_field("accounts");
	}

	if(in_list(["Bank Entry", "Cash Entry"], doc.voucher_type)) {
		return frappe.call({
			type: "GET",
			method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_default_bank_cash_account",
			args: {
				"voucher_type": doc.voucher_type,
				"company": doc.company
			},
			callback: function(r) {
				if(r.message) {
					update_jv_details(doc, [r.message]);
				}
			}
		})
	} else if(doc.voucher_type=="Opening Entry") {
		return frappe.call({
			type:"GET",
			method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_opening_accounts",
			args: {
				"company": doc.company
			},
			callback: function(r) {
				frappe.model.clear_table(doc, "accounts");
				if(r.message) {
					update_jv_details(doc, r.message);
				}
				cur_frm.set_value("is_opening", "Yes")
			}
		})
	}
}

frappe.ui.form.on("Journal Entry Account", "party", function(frm, cdt, cdn) {
	var d = frappe.get_doc(cdt, cdn);
	if(!d.account && d.party_type && d.party) {
		return frm.call({
			method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_party_account_and_balance",
			child: d,
			args: {
				company: frm.doc.company,
				party_type: d.party_type,
				party: d.party
			}
		});
	}
})

frappe.ui.form.on("Journal Entry Account", "accounts_remove", function(frm) {
	cur_frm.cscript.update_totals(frm.doc);
});

<|endoftext|>


<commit_before>const URI_WITH = "https://www.google.com/search?q=test&safe=active&ssui=on";
const URI_WITHOUT = "https://www.google.com/search?q=test";

describe("Addon", function() {
  describe("should alter search URLs to use safe search", function() {
    it("for Google", function() {
      let uri = "http://google.de/search?q=test";

      expect(_alter(uri)).toEqual(uri + "&safe=active&ssui=on");
    });
  });

  describe("should not alter no-search URLs to use safe search", function() {
    it("for Google no search", function() {
      let uri = "http://google.de";

      expect(_alter(uri)).toEqual(false);
    });
  });

  describe("should clean duplicate parameters", function() {
    it("for Google", function() {
      let uri = "http://google.de/search?q=test&safe=vss";

      expect(_alter(uri)).toEqual(
        "http://google.de/search?q=test&safe=active&ssui=on");
    });

    it("for Google triplicate", function() {
      let uri = "http://google.de/search?q=test&safe=vss&safe=vss";

      expect(_alter(uri)).toEqual(
        "http://google.de/search?q=test&safe=active&ssui=on");
    });

    it("for Google triplicate with other stuff in-between", function() {
      let uri = "http://google.de/search?q=test&safe=vss&hello=world&safe=vss";

      expect(_alter(uri)).toEqual(
        "http://google.de/search?q=test&safe=active&hello=world&ssui=on");
    });

    it("for Google triplicate with different values", function() {
      let uri = "http://google.de/search?q=test&safe=active&hello=world&safe=off";

      expect(_alter(uri)).toEqual(
        "http://google.de/search?q=test&safe=active&hello=world&ssui=on");
    });
  });

  describe("should use _meta_add correctly", function() {
    it("for uri containing correct params", function() {
      expect(_meta_add(URI_WITH, ["ssui"], ["on"])).toEqual(false);
      expect(_meta_add(URI_WITH, ["safe"], ["active"])).toEqual(false);
      expect(_meta_add(URI_WITH, ["ssui", "safe"], ["on", "active"])).toEqual(false);
    });
    it("for uri not containing correct params", function() {
      expect(_meta_add(URI_WITHOUT, ["safe", "ssui"], ["active", "on"])).toEqual(URI_WITH);
    });
  });
});
<commit_msg>test: lacked google search detection unit tests<commit_after>const URI_WITH = "https://www.google.com/search?q=test&safe=active&ssui=on";
const URI_WITHOUT = "https://www.google.com/search?q=test";

describe("Addon", function() {
  describe("should alter search URLs to use safe search", function() {
    it("for Google", function() {
      let uri = "http://google.de/search?q=test";

      expect(_alter(uri)).toEqual(uri + "&safe=active&ssui=on");
    });
  });

  describe("should not alter no-search URLs to use safe search", function() {
    it("for Google no search", function() {
      let uri = "http://google.de";

      expect(_alter(uri)).toEqual(false);
    });
  });

  describe("should clean duplicate parameters", function() {
    it("for Google", function() {
      let uri = "http://google.de/search?q=test&safe=vss";

      expect(_alter(uri)).toEqual(
        "http://google.de/search?q=test&safe=active&ssui=on");
    });

    it("for Google triplicate", function() {
      let uri = "http://google.de/search?q=test&safe=vss&safe=vss";

      expect(_alter(uri)).toEqual(
        "http://google.de/search?q=test&safe=active&ssui=on");
    });

    it("for Google triplicate with other stuff in-between", function() {
      let uri = "http://google.de/search?q=test&safe=vss&hello=world&safe=vss";

      expect(_alter(uri)).toEqual(
        "http://google.de/search?q=test&safe=active&hello=world&ssui=on");
    });

    it("for Google triplicate with different values", function() {
      let uri = "http://google.de/search?q=test&safe=active&hello=world&safe=off";

      expect(_alter(uri)).toEqual(
        "http://google.de/search?q=test&safe=active&hello=world&ssui=on");
    });
  });

  describe("should use _meta_add correctly", function() {
    it("for uri containing correct params", function() {
      expect(_meta_add(URI_WITH, ["ssui"], ["on"])).toEqual(false);
      expect(_meta_add(URI_WITH, ["safe"], ["active"])).toEqual(false);
      expect(_meta_add(URI_WITH, ["ssui", "safe"], ["on", "active"])).toEqual(false);
    });
    it("for uri not containing correct params", function() {
      expect(_meta_add(URI_WITHOUT, ["safe", "ssui"], ["active", "on"])).toEqual(URI_WITH);
    });
  });

  describe("should detect google search URLs", function() {
    it("for searches above", function() {
      expect(isGoogle(new URL(URI_WITH))).toEqual(true);
      expect(isGoogle(new URL(URI_WITHOUT))).toEqual(true);
    });
    it("for live URL", function() {
      expect(isGoogle(new URL('https://www.google.com/search?tbm=isch&source=hp&biw=1050&bih=714&ei=YqEPXYbDBIbPwAK4z4OgBg&q=porn&oq=porn&gs_l=img.3...3333.3580..3593...0.0..0.68.396.8......0....1..gws-wiz-img.....0..0.UehEPMi_-34&safe=active&ssui=on#imgrc=qLfN9H5CSrJQsM:'))).toEqual(true);
    });
    it("should not detect ducky as a google URL", function() {
      expect(isGoogle(new URL("http://duckduckgo.com"))).toEqual(false);
    });
    it("should not detect google maps as a search URL", function() {
      expect(true).toEqual(false);  // not implemented
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

import React, { Component } from 'react';
import {
    View,
    Text,
    RefreshControl,
    PanResponder,
    Animated,
    Easing,
    Dimensions,
    ActivityIndicator,
} from 'react-native';

import styles from './style/index.css';

// const padding = 2; //scrollview与外面容器的距离
const pullOkMargin = 100; //下拉到ok状态时topindicator距离顶部的距离
const defaultTopIndicatorHeight = 30; //顶部刷新指示器的高度
const defaultDuration = 300;
const isDownGesture = (x, y) => {
    return y > 0 && (y > Math.abs(x));
};
const isUpGesture = (x, y) => {
    return y < 0 && (Math.abs(x) < Math.abs(y));
};
const isVerticalGesture = (x, y) => {
    return (Math.abs(x) < Math.abs(y));
};

export default class extends Component {
    constructor(props) {
        super(props);
        this.pullable = this.props.refreshControl == null;
        this.defaultScrollEnabled = false; //!(this.props.onPulling || this.props.onPullOk || this.props.onPullRelease); //定义onPull***属性时scrollEnabled为false
        let topIndicatorHeight = this.props.topIndicatorHeight ? this.props.topIndicatorHeight : defaultTopIndicatorHeight;
        this.defaultXY = {x: 0, y: topIndicatorHeight * -1};
        this.pullOkMargin = this.props.pullOkMargin ? this.props.pullOkMargin : pullOkMargin;
        this.duration = this.props.duration ? this.props.duration : defaultDuration;
        this.state = Object.assign({}, props, {
            pullPan: new Animated.ValueXY(this.defaultXY),
            scrollEnabled: this.defaultScrollEnabled,
            height: 0,
            topIndicatorHeight: topIndicatorHeight,
            gesturePosition: {x: 0, y: 0}
        });
        this.onScroll = this.onScroll.bind(this);
        this.onLayout = this.onLayout.bind(this);
        this.isPullState = this.isPullState.bind(this);
        this.resetDefaultXYHandler = this.resetDefaultXYHandler.bind(this);
        this.panResponder = PanResponder.create({
            onStartShouldSetPanResponder: this.onShouldSetPanResponder.bind(this),
            onMoveShouldSetPanResponder: this.onShouldSetPanResponder.bind(this),
            onPanResponderGrant: () => {},
            onPanResponderMove: this.onPanResponderMove.bind(this),
            onPanResponderRelease: this.onPanResponderRelease.bind(this),
            onPanResponderTerminate: this.onPanResponderRelease.bind(this),
        });
    }

    onShouldSetPanResponder(e, gesture) {
        if (!this.pullable || !isVerticalGesture(gesture.dx, gesture.dy)) { //不使用pullable,或非向上 或向下手势不响应
            return false;
        }
        // if (this.props.onPulling || this.props.onPullOk || this.props.onPullRelease) {
        //     return !this.state.scrollEnabled;
        // }
        if (!this.state.scrollEnabled) {
            this.lastY = this.state.pullPan.y._value;
            return true;
        } else {
            return false;
        }
    }

    onPanResponderMove(e, gesture) {
        this.state.gesturePosition = {x: this.defaultXY.x, y: gesture.dy};
        if (isUpGesture(gesture.dx, gesture.dy)) { //向上滑动
            if(this.isPullState()) {
                this.resetDefaultXYHandler()
            } else if(this.props.onPushing && this.props.onPushing(this.state.gesturePosition)) {
                // do nothing, handling by this.props.onPushing
            } else {
                this.scroll.scrollTo({x:0, y: gesture.dy * -1});
            }
            return;
        } else if (isDownGesture(gesture.dx, gesture.dy)) { //下拉
            this.state.pullPan.setValue({x: this.defaultXY.x, y: this.lastY + gesture.dy / 3});
            if (gesture.dy < this.state.topIndicatorHeight + this.pullOkMargin) { //正在下拉
                if (!this.state.pulling) {
                    this.props.onPulling && this.props.onPulling(this.resetDefaultXYHandler);
                }
                this.setState({pulling: true, pullok: false, pullrelease: false});
            } else { //下拉到位
                if (!this.state.pullok) {
                    this.props.onPullOk && this.props.onPullOk(this.resetDefaultXYHandler);
                }
                this.setState({pulling: false, pullok: true, pullrelease: false});
            }
        }
    }

    onPanResponderRelease(e, gesture) {
        if (this.state.pulling) { //没有下拉到位
            this.resetDefaultXYHandler(); //重置状态
        }
        if (this.state.pullok) {
            if (!this.state.pullrelease) {
                if (this.props.onPullRelease) {
                     this.props.onPullRelease(this.resetDefaultXYHandler);
                } else {
                    setTimeout(() => {this.resetDefaultXYHandler()}, 3000);
                }
            }
            this.setState({pulling: false, pullok: false, pullrelease: true}); //完成下拉，已松开
            Animated.timing(this.state.pullPan, {
                toValue: {x: 0, y: 0},
                easing: Easing.linear,
                duration: this.duration
            }).start();
        }
    }

    onScroll(e) {
        if (e.nativeEvent.contentOffset.y <= 0) {
            this.setState({scrollEnabled: this.defaultScrollEnabled});
        } else if(!this.isPullState()) {
            this.setState({scrollEnabled: true});
        }
    }

    isPullState() {
        return this.state.pulling || this.state.pullok || this.state.pullrelease;
    }

    resetDefaultXYHandler() {
        if (this.state.pulling || this.state.pullrelease) {
            this.setState({pulling: false, pullok: false, pullrelease: false});
            this.state.pullPan.setValue(this.defaultXY);
        }
    }

    componentWillUpdate(nextProps, nextState) {
        if (nextProps.isPullEnd && this.state.pullrelease) {
            this.resetDefaultXYHandler();
        }
    }

    onLayout(e) {
        if (this.state.width != e.nativeEvent.layout.width || this.state.height != e.nativeEvent.layout.height) {
            this.setState({width: e.nativeEvent.layout.width});
            this.setState({height: e.nativeEvent.layout.height});
        }
    }

    render() {
        let refreshControl = this.props.refreshControl;
        // if (this.props.refreshControl == null && this.props.refreshing != null && this.props.onRefresh != null) {
        //     refreshControl = <RefreshControl refreshing={this.props.refreshing} onRefresh={this.props.onRefresh} />;
        // }
        let topIndicator;
        if (this.props.topIndicatorRender == null) {
            topIndicator = (
                <View style={{flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', height: defaultTopIndicatorHeight}}>
                    <ActivityIndicator size="small" color="gray" />
                    {this.state.pulling ? <Text>下拉刷新...</Text> : null}
                    {this.state.pullok ? <Text>松开刷新......</Text> : null}
                    {this.state.pullrelease ? <Text>玩命刷新中......</Text> : null}
                </View>
            );
        } else {
            let {pulling, pullok, pullrelease} = this.state;
            topIndicator = this.props.topIndicatorRender(pulling, pullok, pullrelease, this.state.gesturePosition);
        }

        return (
            <View style={[styles.wrap, this.props.style]} onLayout={this.onLayout}>
                <Animated.View ref={(c) => {this.ani = c;}} style={[this.state.pullPan.getLayout()]}>
                    {topIndicator}
                    <View {...this.panResponder.panHandlers} style={{width: this.state.width, height: this.state.height}}>
                        {this.getScrollable(refreshControl)}
                    </View>
                </Animated.View>
            </View>
        );
    }
}
<commit_msg>fix style import<commit_after>'use strict';

import React, { Component } from 'react';
import {
    View,
    Text,
    RefreshControl,
    PanResponder,
    Animated,
    Easing,
    Dimensions,
    ActivityIndicator,
} from 'react-native';

import styles from './style/index.css.js';

// const padding = 2; //scrollview与外面容器的距离
const pullOkMargin = 100; //下拉到ok状态时topindicator距离顶部的距离
const defaultTopIndicatorHeight = 30; //顶部刷新指示器的高度
const defaultDuration = 300;
const isDownGesture = (x, y) => {
    return y > 0 && (y > Math.abs(x));
};
const isUpGesture = (x, y) => {
    return y < 0 && (Math.abs(x) < Math.abs(y));
};
const isVerticalGesture = (x, y) => {
    return (Math.abs(x) < Math.abs(y));
};

export default class extends Component {
    constructor(props) {
        super(props);
        this.pullable = this.props.refreshControl == null;
        this.defaultScrollEnabled = false; //!(this.props.onPulling || this.props.onPullOk || this.props.onPullRelease); //定义onPull***属性时scrollEnabled为false
        let topIndicatorHeight = this.props.topIndicatorHeight ? this.props.topIndicatorHeight : defaultTopIndicatorHeight;
        this.defaultXY = {x: 0, y: topIndicatorHeight * -1};
        this.pullOkMargin = this.props.pullOkMargin ? this.props.pullOkMargin : pullOkMargin;
        this.duration = this.props.duration ? this.props.duration : defaultDuration;
        this.state = Object.assign({}, props, {
            pullPan: new Animated.ValueXY(this.defaultXY),
            scrollEnabled: this.defaultScrollEnabled,
            height: 0,
            topIndicatorHeight: topIndicatorHeight,
            gesturePosition: {x: 0, y: 0}
        });
        this.onScroll = this.onScroll.bind(this);
        this.onLayout = this.onLayout.bind(this);
        this.isPullState = this.isPullState.bind(this);
        this.resetDefaultXYHandler = this.resetDefaultXYHandler.bind(this);
        this.panResponder = PanResponder.create({
            onStartShouldSetPanResponder: this.onShouldSetPanResponder.bind(this),
            onMoveShouldSetPanResponder: this.onShouldSetPanResponder.bind(this),
            onPanResponderGrant: () => {},
            onPanResponderMove: this.onPanResponderMove.bind(this),
            onPanResponderRelease: this.onPanResponderRelease.bind(this),
            onPanResponderTerminate: this.onPanResponderRelease.bind(this),
        });
    }

    onShouldSetPanResponder(e, gesture) {
        if (!this.pullable || !isVerticalGesture(gesture.dx, gesture.dy)) { //不使用pullable,或非向上 或向下手势不响应
            return false;
        }
        // if (this.props.onPulling || this.props.onPullOk || this.props.onPullRelease) {
        //     return !this.state.scrollEnabled;
        // }
        if (!this.state.scrollEnabled) {
            this.lastY = this.state.pullPan.y._value;
            return true;
        } else {
            return false;
        }
    }

    onPanResponderMove(e, gesture) {
        this.state.gesturePosition = {x: this.defaultXY.x, y: gesture.dy};
        if (isUpGesture(gesture.dx, gesture.dy)) { //向上滑动
            if(this.isPullState()) {
                this.resetDefaultXYHandler()
            } else if(this.props.onPushing && this.props.onPushing(this.state.gesturePosition)) {
                // do nothing, handling by this.props.onPushing
            } else {
                this.scroll.scrollTo({x:0, y: gesture.dy * -1});
            }
            return;
        } else if (isDownGesture(gesture.dx, gesture.dy)) { //下拉
            this.state.pullPan.setValue({x: this.defaultXY.x, y: this.lastY + gesture.dy / 3});
            if (gesture.dy < this.state.topIndicatorHeight + this.pullOkMargin) { //正在下拉
                if (!this.state.pulling) {
                    this.props.onPulling && this.props.onPulling(this.resetDefaultXYHandler);
                }
                this.setState({pulling: true, pullok: false, pullrelease: false});
            } else { //下拉到位
                if (!this.state.pullok) {
                    this.props.onPullOk && this.props.onPullOk(this.resetDefaultXYHandler);
                }
                this.setState({pulling: false, pullok: true, pullrelease: false});
            }
        }
    }

    onPanResponderRelease(e, gesture) {
        if (this.state.pulling) { //没有下拉到位
            this.resetDefaultXYHandler(); //重置状态
        }
        if (this.state.pullok) {
            if (!this.state.pullrelease) {
                if (this.props.onPullRelease) {
                     this.props.onPullRelease(this.resetDefaultXYHandler);
                } else {
                    setTimeout(() => {this.resetDefaultXYHandler()}, 3000);
                }
            }
            this.setState({pulling: false, pullok: false, pullrelease: true}); //完成下拉，已松开
            Animated.timing(this.state.pullPan, {
                toValue: {x: 0, y: 0},
                easing: Easing.linear,
                duration: this.duration
            }).start();
        }
    }

    onScroll(e) {
        if (e.nativeEvent.contentOffset.y <= 0) {
            this.setState({scrollEnabled: this.defaultScrollEnabled});
        } else if(!this.isPullState()) {
            this.setState({scrollEnabled: true});
        }
    }

    isPullState() {
        return this.state.pulling || this.state.pullok || this.state.pullrelease;
    }

    resetDefaultXYHandler() {
        if (this.state.pulling || this.state.pullrelease) {
            this.setState({pulling: false, pullok: false, pullrelease: false});
            this.state.pullPan.setValue(this.defaultXY);
        }
    }

    componentWillUpdate(nextProps, nextState) {
        if (nextProps.isPullEnd && this.state.pullrelease) {
            this.resetDefaultXYHandler();
        }
    }

    onLayout(e) {
        if (this.state.width != e.nativeEvent.layout.width || this.state.height != e.nativeEvent.layout.height) {
            this.setState({width: e.nativeEvent.layout.width});
            this.setState({height: e.nativeEvent.layout.height});
        }
    }

    render() {
        let refreshControl = this.props.refreshControl;
        // if (this.props.refreshControl == null && this.props.refreshing != null && this.props.onRefresh != null) {
        //     refreshControl = <RefreshControl refreshing={this.props.refreshing} onRefresh={this.props.onRefresh} />;
        // }
        let topIndicator;
        if (this.props.topIndicatorRender == null) {
            topIndicator = (
                <View style={{flex: 1, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', height: defaultTopIndicatorHeight}}>
                    <ActivityIndicator size="small" color="gray" />
                    {this.state.pulling ? <Text>下拉刷新...</Text> : null}
                    {this.state.pullok ? <Text>松开刷新......</Text> : null}
                    {this.state.pullrelease ? <Text>玩命刷新中......</Text> : null}
                </View>
            );
        } else {
            let {pulling, pullok, pullrelease} = this.state;
            topIndicator = this.props.topIndicatorRender(pulling, pullok, pullrelease, this.state.gesturePosition);
        }

        return (
            <View style={[styles.wrap, this.props.style]} onLayout={this.onLayout}>
                <Animated.View ref={(c) => {this.ani = c;}} style={[this.state.pullPan.getLayout()]}>
                    {topIndicator}
                    <View {...this.panResponder.panHandlers} style={{width: this.state.width, height: this.state.height}}>
                        {this.getScrollable(refreshControl)}
                    </View>
                </Animated.View>
            </View>
        );
    }
}
<|endoftext|>


<commit_before>import Controller from '@ember/controller';
import { computed, get } from '@ember/object';
import { inject as service } from '@ember/service';

export default Controller.extend({
  modalService:       service('modal'),
  router:             service(),
  scope:              service(),
  growl:              service(),
  intl:               service(),
  securityScanConfig: service(),

  tableHeaders: [
    {
      name:           'collapse',
      width:          40,
    },
    {
      name:           'state',
      sort:           ['state', 'sortableId'],
      translationKey: 'cis.scan.detail.table.state',
      width:          100,
    },
    {
      name:           'id',
      sort:           ['sortableId'],
      translationKey: 'cis.scan.detail.table.number',
      width:          100,
    },
    {
      name:           'description',
      sort:           ['description', 'sortableId'],
      translationKey: 'cis.scan.detail.table.description',
    },
    {
      name:           'buttons',
      width:          120,
    }
  ],
  sortBy: 'id',

  runningClusterScans: computed.filterBy('clusterScans', 'isRunning', true),

  disableRunScanButton: computed.notEmpty('runningClusterScans'),

  actions: {
    async runScan() {
      this.securityScanConfig.validateSecurityScanConfig();
      await get(this, 'scope.currentCluster').doAction('runSecurityScan', {
        failuresOnly: false,
        skip:         []
      });
      get(this, 'router').replaceWith('authenticated.cluster.cis/scan');
    },
    download() {
      get(this, 'model.scan').send('download');
    },
    async delete() {
      await get(this, 'modalService').toggleModal('confirm-delete', {
        escToClose:       true,
        resources:        [get(this, 'model.scan')],
        onDeleteFinished: () => get(this, 'router').replaceWith('authenticated.cluster.cis/scan')
      });
    }
  },

  tests: computed('model.scan.report', 'securityScanConfig.skipList', function() {
    const results = get(this, 'model.scan.report.results');

    if (!results) {
      return [];
    }

    const tests = results.reduce((agg, result) => [...agg, ...result.checks], []);

    return tests.map((test) => {
      const state = this.getCheckState(test);
      const nodeTypes = test.node_type;

      const nodeNames = nodeTypes.reduce((agg, nodeType) => [...agg, ...get(this, `model.scan.report.nodes.${ nodeType }`)], []);
      const uniqueNodeNames = Object.keys(nodeNames.reduce((agg, nodeName) => ({
        ...agg,
        [nodeName]: true
      }), {}));
      const nodes = uniqueNodeNames.map((nodeName) => ({
        state,
        nodeId: get(this, 'model.nodes').findBy('nodeName', nodeName).id,
        name:   nodeName
      }));

      return {
        state,
        id:                test.id,
        sortableId:        this.createSortableId(test.id),
        description:       test.description,
        remediation:       state === 'Fail' ? test.remediation : null,
        nodes,
        toggleSkip:        () => {
          this.toggleSkip(test.id)
        },
        skipList:          get(this, 'securityScanConfig.skipList'),
        _availableActions: []
      };
    });
  }),

  clusterScans: computed('model.clusterScans.@each', function() {
    return get(this, 'model.clusterScans').filterBy('clusterId', get(this, 'scope.currentCluster.id'));
  }),

  /**
   * Converts an id that looks like 1.1.9 into 000010000100009. This
   * allows us to appropriately compare the ids as if they are versions
   * instead of just doing a naive string comparison.
   * @param {*} id
   */
  createSortableId(id) {
    const columnWidth = 5;
    const splitId = id.split('.');

    return splitId
      .map((column) => {
        const columnPaddingWidth = Math.max(columnWidth - column.length, 0)

        return '0'.repeat(columnPaddingWidth) + column;
      })
      .join('');
  },

  toggleSkip(testId) {
    this.securityScanConfig.validateSecurityScanConfig();
    const isSkipped = get(this, 'securityScanConfig.skipList').indexOf(testId) !== -1;
    const fn = isSkipped ? this.unskip : this.skip;

    fn.call(this, testId);
  },

  skip(testId) {
    const newSkipList = [...get(this, 'securityScanConfig.skipList'), testId];

    this.securityScanConfig.editSkipList(newSkipList);
  },

  unskip(testId) {
    const newSkipList = get(this, 'securityScanConfig.skipList').filter((skippedTestId) => skippedTestId !== testId);

    this.securityScanConfig.editSkipList(newSkipList);
  },

  getCheckState(check) {
    switch (check.state) {
    case 'pass':
      return 'Pass';
    case 'skip':
      return 'Skipped';
    default:
      return 'Fail';
    }
  }

});
<commit_msg>Adding support for the nodes field in the CIS report<commit_after>import Controller from '@ember/controller';
import { computed, get } from '@ember/object';
import { inject as service } from '@ember/service';

export default Controller.extend({
  modalService:       service('modal'),
  router:             service(),
  scope:              service(),
  growl:              service(),
  intl:               service(),
  securityScanConfig: service(),

  tableHeaders: [
    {
      name:           'collapse',
      width:          40,
    },
    {
      name:           'state',
      sort:           ['state', 'sortableId'],
      translationKey: 'cis.scan.detail.table.state',
      width:          100,
    },
    {
      name:           'id',
      sort:           ['sortableId'],
      translationKey: 'cis.scan.detail.table.number',
      width:          100,
    },
    {
      name:           'description',
      sort:           ['description', 'sortableId'],
      translationKey: 'cis.scan.detail.table.description',
    },
    {
      name:           'buttons',
      width:          120,
    }
  ],
  sortBy: 'id',

  runningClusterScans: computed.filterBy('clusterScans', 'isRunning', true),

  disableRunScanButton: computed.notEmpty('runningClusterScans'),

  actions: {
    async runScan() {
      this.securityScanConfig.validateSecurityScanConfig();
      await get(this, 'scope.currentCluster').doAction('runSecurityScan', {
        failuresOnly: false,
        skip:         []
      });
      get(this, 'router').replaceWith('authenticated.cluster.cis/scan');
    },
    download() {
      get(this, 'model.scan').send('download');
    },
    async delete() {
      await get(this, 'modalService').toggleModal('confirm-delete', {
        escToClose:       true,
        resources:        [get(this, 'model.scan')],
        onDeleteFinished: () => get(this, 'router').replaceWith('authenticated.cluster.cis/scan')
      });
    }
  },

  tests: computed('model.scan.report', 'securityScanConfig.skipList', function() {
    const results = get(this, 'model.scan.report.results');

    if (!results) {
      return [];
    }

    const tests = results.reduce((agg, result) => [...agg, ...result.checks], []);

    return tests.map((test) => {
      const state = this.getCheckState(test);
      const nodeTypes = test.node_type;

      const nodeNames = nodeTypes.reduce((agg, nodeType) => [...agg, ...get(this, `model.scan.report.nodes.${ nodeType }`)], []);
      const uniqueNodeNames = Object.keys(nodeNames.reduce((agg, nodeName) => ({
        ...agg,
        [nodeName]: true
      }), {}));
      const checkNodes = test.nodes || [];
      const nodes = uniqueNodeNames.map((nodeName) => ({
        state: this.getNodeState(test, nodeName, checkNodes),
        nodeId: get(this, 'model.nodes').findBy('nodeName', nodeName).id,
        name:   nodeName
      }));

      return {
        state,
        id:                test.id,
        sortableId:        this.createSortableId(test.id),
        description:       test.description,
        remediation:       state === 'Fail' ? test.remediation : null,
        nodes,
        toggleSkip:        () => {
          this.toggleSkip(test.id)
        },
        skipList:          get(this, 'securityScanConfig.skipList'),
        _availableActions: []
      };
    });
  }),

  clusterScans: computed('model.clusterScans.@each', function() {
    return get(this, 'model.clusterScans').filterBy('clusterId', get(this, 'scope.currentCluster.id'));
  }),

  /**
   * Converts an id that looks like 1.1.9 into 000010000100009. This
   * allows us to appropriately compare the ids as if they are versions
   * instead of just doing a naive string comparison.
   * @param {*} id
   */
  createSortableId(id) {
    const columnWidth = 5;
    const splitId = id.split('.');

    return splitId
      .map((column) => {
        const columnPaddingWidth = Math.max(columnWidth - column.length, 0)

        return '0'.repeat(columnPaddingWidth) + column;
      })
      .join('');
  },

  toggleSkip(testId) {
    this.securityScanConfig.validateSecurityScanConfig();
    const isSkipped = get(this, 'securityScanConfig.skipList').indexOf(testId) !== -1;
    const fn = isSkipped ? this.unskip : this.skip;

    fn.call(this, testId);
  },

  skip(testId) {
    const newSkipList = [...get(this, 'securityScanConfig.skipList'), testId];

    this.securityScanConfig.editSkipList(newSkipList);
  },

  unskip(testId) {
    const newSkipList = get(this, 'securityScanConfig.skipList').filter((skippedTestId) => skippedTestId !== testId);

    this.securityScanConfig.editSkipList(newSkipList);
  },

  getCheckState(check) {
    switch (check.state) {
    case 'pass':
      return 'Pass';
    case 'skip':
      return 'Skipped';
    default:
      return 'Fail';
    }
  },

  /**
   * Per the API.
   * When check state is pass Pass.
   * When check state is fail Fail.
   * When check state is skip Skip.
   * When check state is mixed fail if nodeName is in checkNodes otherwise pass
   */
  getNodeState(check, nodeName, checkNodes) {
    if (check.state === 'pass') {
      return 'Pass';
    }

    if (check.state === 'fail') {
      return 'Fail';
    }

    if (check.state === 'skip') {
      return 'Skipped';
    }

    return checkNodes.includes(nodeName)
      ? 'Fail'
      : 'Pass';
  }

});
<|endoftext|>