<commit_before>// Generated on 2014-08-14 using generator-webapp 0.4.9
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

    // Load grunt tasks automatically
    require('load-grunt-tasks')(grunt);

    // Time how long tasks take. Can help when optimizing build times
    require('time-grunt')(grunt);

    // Configurable paths
    var config = {
        app: 'app',
        dist: 'dist'
    };

    var proxyRequests = require('grunt-connect-proxy/lib/utils').proxyRequest;

    // Define the configuration for all the tasks
    grunt.initConfig({

        // Project settings
        config: config,

        ts: {
            // use to override the default options, See: http://gruntjs.com/configuring-tasks#options
            // these are the default options to the typescript compiler for grunt-ts:
            // see `tsc --help` for a list of supported options.
            options: {
                compile: true,                 // perform compilation. [true (default) | false]
                comments: false,               // same as !removeComments. [true | false (default)]
                target: 'es3',                 // target javascript language. [es3 (default) | es5]
                module: 'amd',                 // target javascript module style. [amd (default) | commonjs]
                sourceMap: true,               // generate a source map for every output js file. [true (default) | false]
                sourceRoot: '',                // where to locate TypeScript files. [(default) '' == source ts location]
                mapRoot: '',                   // where to locate .map.js files. [(default) '' == generated js location.]
                declaration: false,            // generate a declaration .d.ts file for every output js file. [true | false (default)]
                htmlModuleTemplate: 'My.Module.<%= filename %>',    // Template for module name for generated ts from html files [(default) '<%= filename %>']
                htmlVarTemplate: '<%= ext %>'                       // Template for variable name used in generated ts from html files [(default) '<%= ext %>]
                // Both html templates accept the ext and filename parameters.
            },
            // a particular target
            dev: {
                src: ['app/**/*.ts'],          // The source typescript files, http://gruntjs.com/configuring-tasks#files
                html: ['app/**/**.tpl.html'],  // The source html files, https://github.com/basarat/grunt-ts#html-2-typescript-support
                reference: 'app/reference.ts', // If specified, generate this file that you can use for your reference management
                out: 'app/scripts/compiled/supler.out.js', // If specified, generate an out.js file which is the merged js file
                // use to override the grunt-ts project options above for this target
                options: {
                    module: 'commonjs'
                }
            }
        },

        // Watches files for changes and runs tasks based on the changed files
        watch: {
            bower: {
                files: ['bower.json'],
                tasks: ['bowerInstall']
            },
            ts: {
                files: ['<%= config.app %>/scripts/{,*/}*.ts'],
                tasks: ['ts:dev'],
                options: {
                    livereload: true
                }
            },
            js: {
                files: ['<%= config.app %>/scripts/{,*/}*.js'],
                tasks: ['jshint'],
                options: {
                    livereload: true
                }
            },
            jstest: {
                files: ['test/spec/{,*/}*.js'],
                tasks: ['test:watch']
            },
            gruntfile: {
                files: ['Gruntfile.js']
            },
            styles: {
                files: ['<%= config.app %>/styles/{,*/}*.css'],
                tasks: ['newer:copy:styles', 'autoprefixer']
            },
            livereload: {
                options: {
                    livereload: '<%= connect.options.livereload %>'
                },
                files: [
                    '<%= config.app %>/{,*/}*.html',
                    '.tmp/styles/{,*/}*.css',
                    '<%= config.app %>/images/{,*/}*'
                ]
            }
        },

        // The actual grunt server settings
        connect: {
            proxies: [
                {context: '/rest', host: 'localhost', port: 8080}
            ],
            options: {
                port: 9000,
                open: true,
                livereload: 35729,
                // Change this to '0.0.0.0' to access the server from outside
                hostname: 'localhost'
            },
            livereload: {
                options: {
                    middleware: function(connect) {
                        return [
                            proxyRequests,
                            connect.static('.tmp'),
                            connect().use('/bower_components', connect.static('./bower_components')),
                            connect.static(config.app)
                        ];
                    }
                }
            },
            test: {
                options: {
                    open: false,
                    port: 9001,
                    middleware: function(connect) {
                        return [
                            connect.static('.tmp'),
                            connect.static('test'),
                            connect().use('/bower_components', connect.static('./bower_components')),
                            connect.static(config.app)
                        ];
                    }
                }
            },
            dist: {
                options: {
                    base: '<%= config.dist %>',
                    livereload: false
                }
            }
        },

        // Empties folders to start fresh
        clean: {
            dist: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%= config.dist %>/*',
                        '!<%= config.dist %>/.git*'
                    ]
                }]
            },
            server: '.tmp'
        },

        // Make sure code styles are up to par and there are no obvious mistakes
        jshint: {
            options: {
                jshintrc: '.jshintrc',
                reporter: require('jshint-stylish')
            },
            all: [
                'Gruntfile.js',
                '<%= config.app %>/scripts/*.js',
                '!<%= config.app %>/scripts/vendor/*',
                'test/spec/{,*/}*.js'
            ]
        },

        // Mocha testing framework configuration options
        mocha: {
            all: {
                options: {
                    run: true,
                    urls: ['http://<%= connect.test.options.hostname %>:<%= connect.test.options.port %>/index.html']
                }
            }
        },

        // Add vendor prefixed styles
        autoprefixer: {
            options: {
                browsers: ['last 1 version']
            },
            dist: {
                files: [{
                    expand: true,
                    cwd: '.tmp/styles/',
                    src: '{,*/}*.css',
                    dest: '.tmp/styles/'
                }]
            }
        },

        // Automatically inject Bower components into the HTML file
        bowerInstall: {
            app: {
                src: ['<%= config.app %>/index.html'],
                exclude: ['bower_components/bootstrap/dist/js/bootstrap.js']
            }
        },

        // Renames files for browser caching purposes
        rev: {
            dist: {
                files: {
                    src: [
                        '<%= config.dist %>/scripts/{,*/}*.js',
                        '<%= config.dist %>/styles/{,*/}*.css',
                        '<%= config.dist %>/images/{,*/}*.*',
                        '<%= config.dist %>/styles/fonts/{,*/}*.*',
                        '<%= config.dist %>/*.{ico,png}'
                    ]
                }
            }
        },

        // Reads HTML for usemin blocks to enable smart builds that automatically
        // concat, minify and revision files. Creates configurations in memory so
        // additional tasks can operate on them
        useminPrepare: {
            options: {
                dest: '<%= config.dist %>'
            },
            html: '<%= config.app %>/index.html'
        },

        // Performs rewrites based on rev and the useminPrepare configuration
        usemin: {
            options: {
                assetsDirs: ['<%= config.dist %>', '<%= config.dist %>/images']
            },
            html: ['<%= config.dist %>/{,*/}*.html'],
            css: ['<%= config.dist %>/styles/{,*/}*.css']
        },

        // The following *-min tasks produce minified files in the dist folder
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= config.app %>/images',
                    src: '{,*/}*.{gif,jpeg,jpg,png}',
                    dest: '<%= config.dist %>/images'
                }]
            }
        },

        svgmin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= config.app %>/images',
                    src: '{,*/}*.svg',
                    dest: '<%= config.dist %>/images'
                }]
            }
        },

        htmlmin: {
            dist: {
                options: {
                    collapseBooleanAttributes: true,
                    collapseWhitespace: true,
                    removeAttributeQuotes: true,
                    removeCommentsFromCDATA: true,
                    removeEmptyAttributes: true,
                    removeOptionalTags: true,
                    removeRedundantAttributes: true,
                    useShortDoctype: true
                },
                files: [{
                    expand: true,
                    cwd: '<%= config.dist %>',
                    src: '{,*/}*.html',
                    dest: '<%= config.dist %>'
                }]
            }
        },

        // By default, your `index.html`'s <!-- Usemin block --> will take care of
        // minification. These next options are pre-configured if you do not wish
        // to use the Usemin blocks.
        // cssmin: {
        //     dist: {
        //         files: {
        //             '<%= config.dist %>/styles/main.css': [
        //                 '.tmp/styles/{,*/}*.css',
        //                 '<%= config.app %>/styles/{,*/}*.css'
        //             ]
        //         }
        //     }
        // },
        // uglify: {
        //     dist: {
        //         files: {
        //             '<%= config.dist %>/scripts/scripts.js': [
        //                 '<%= config.dist %>/scripts/scripts.js'
        //             ]
        //         }
        //     }
        // },
        // concat: {
        //     dist: {}
        // },

        // Copies remaining files to places other tasks can use
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%= config.app %>',
                    dest: '<%= config.dist %>',
                    src: [
                        '*.{ico,png,txt}',
                        '.htaccess',
                        'images/{,*/}*.webp',
                        '{,*/}*.html',
                        'styles/fonts/{,*/}*.*'
                    ]
                }, {
                    expand: true,
                    dot: true,
                    cwd: 'bower_components/bootstrap/dist',
                    src: ['fonts/*.*'],
                    dest: '<%= config.dist %>'
                }]
            },
            styles: {
                expand: true,
                dot: true,
                cwd: '<%= config.app %>/styles',
                dest: '.tmp/styles/',
                src: '{,*/}*.css'
            }
        },

        // Run some tasks in parallel to speed up build process
        concurrent: {
            server: [
                'copy:styles'
            ],
            test: [
                'copy:styles'
            ],
            dist: [
                'copy:styles',
                'imagemin',
                'svgmin'
            ]
        }
    });

    grunt.registerTask('serve', function (target) {
        if (target === 'dist') {
            return grunt.task.run(['build', 'connect:dist:keepalive']);
        }

        grunt.task.run([
            'ts:dev',
            'clean:server',
            'concurrent:server',
            'autoprefixer',
            'configureProxies',
            'connect:livereload',
            'watch'
        ]);
    });

    grunt.registerTask('server', function (target) {
        grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
        grunt.task.run([target ? ('serve:' + target) : 'serve']);
    });

    grunt.registerTask('test', function (target) {
        if (target !== 'watch') {
            grunt.task.run([
                'clean:server',
                'concurrent:test',
                'autoprefixer'
            ]);
        }

        grunt.task.run([
            'connect:test',
            'mocha'
        ]);
    });

    grunt.registerTask('build', [
        'clean:dist',
        'ts:dev',
        'useminPrepare',
        'concurrent:dist',
        'autoprefixer',
        'concat',
        'cssmin',
        'uglify',
        'copy:dist',
        'rev',
        'usemin',
        'htmlmin'
    ]);

    grunt.registerTask('default', [
        'newer:jshint',
        'test',
        'build'
    ]);
};
<commit_msg>Adding a grunt "dev" task which just watches & compiles TS<commit_after>// Generated on 2014-08-14 using generator-webapp 0.4.9
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

    // Load grunt tasks automatically
    require('load-grunt-tasks')(grunt);

    // Time how long tasks take. Can help when optimizing build times
    require('time-grunt')(grunt);

    // Configurable paths
    var config = {
        app: 'app',
        dist: 'dist'
    };

    var proxyRequests = require('grunt-connect-proxy/lib/utils').proxyRequest;

    // Define the configuration for all the tasks
    grunt.initConfig({

        // Project settings
        config: config,

        ts: {
            // use to override the default options, See: http://gruntjs.com/configuring-tasks#options
            // these are the default options to the typescript compiler for grunt-ts:
            // see `tsc --help` for a list of supported options.
            options: {
                compile: true,                 // perform compilation. [true (default) | false]
                comments: false,               // same as !removeComments. [true | false (default)]
                target: 'es3',                 // target javascript language. [es3 (default) | es5]
                module: 'amd',                 // target javascript module style. [amd (default) | commonjs]
                sourceMap: true,               // generate a source map for every output js file. [true (default) | false]
                sourceRoot: '',                // where to locate TypeScript files. [(default) '' == source ts location]
                mapRoot: '',                   // where to locate .map.js files. [(default) '' == generated js location.]
                declaration: false,            // generate a declaration .d.ts file for every output js file. [true | false (default)]
                htmlModuleTemplate: 'My.Module.<%= filename %>',    // Template for module name for generated ts from html files [(default) '<%= filename %>']
                htmlVarTemplate: '<%= ext %>'                       // Template for variable name used in generated ts from html files [(default) '<%= ext %>]
                // Both html templates accept the ext and filename parameters.
            },
            // a particular target
            dev: {
                src: ['app/**/*.ts'],          // The source typescript files, http://gruntjs.com/configuring-tasks#files
                html: ['app/**/**.tpl.html'],  // The source html files, https://github.com/basarat/grunt-ts#html-2-typescript-support
                reference: 'app/reference.ts', // If specified, generate this file that you can use for your reference management
                out: 'app/scripts/compiled/supler.out.js', // If specified, generate an out.js file which is the merged js file
                // use to override the grunt-ts project options above for this target
                options: {
                    module: 'commonjs'
                }
            }
        },

        // Watches files for changes and runs tasks based on the changed files
        watch: {
            bower: {
                files: ['bower.json'],
                tasks: ['bowerInstall']
            },
            ts: {
                files: ['<%= config.app %>/scripts/{,*/}*.ts'],
                tasks: ['ts:dev'],
                options: {
                    livereload: true
                }
            },
            js: {
                files: ['<%= config.app %>/scripts/{,*/}*.js'],
                tasks: ['jshint'],
                options: {
                    livereload: true
                }
            },
            jstest: {
                files: ['test/spec/{,*/}*.js'],
                tasks: ['test:watch']
            },
            gruntfile: {
                files: ['Gruntfile.js']
            },
            styles: {
                files: ['<%= config.app %>/styles/{,*/}*.css'],
                tasks: ['newer:copy:styles', 'autoprefixer']
            },
            livereload: {
                options: {
                    livereload: '<%= connect.options.livereload %>'
                },
                files: [
                    '<%= config.app %>/{,*/}*.html',
                    '.tmp/styles/{,*/}*.css',
                    '<%= config.app %>/images/{,*/}*'
                ]
            }
        },

        // The actual grunt server settings
        connect: {
            proxies: [
                {context: '/rest', host: 'localhost', port: 8080}
            ],
            options: {
                port: 9000,
                open: true,
                livereload: 35729,
                // Change this to '0.0.0.0' to access the server from outside
                hostname: 'localhost'
            },
            livereload: {
                options: {
                    middleware: function(connect) {
                        return [
                            proxyRequests,
                            connect.static('.tmp'),
                            connect().use('/bower_components', connect.static('./bower_components')),
                            connect.static(config.app)
                        ];
                    }
                }
            },
            test: {
                options: {
                    open: false,
                    port: 9001,
                    middleware: function(connect) {
                        return [
                            connect.static('.tmp'),
                            connect.static('test'),
                            connect().use('/bower_components', connect.static('./bower_components')),
                            connect.static(config.app)
                        ];
                    }
                }
            },
            dist: {
                options: {
                    base: '<%= config.dist %>',
                    livereload: false
                }
            }
        },

        // Empties folders to start fresh
        clean: {
            dist: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%= config.dist %>/*',
                        '!<%= config.dist %>/.git*'
                    ]
                }]
            },
            server: '.tmp'
        },

        // Make sure code styles are up to par and there are no obvious mistakes
        jshint: {
            options: {
                jshintrc: '.jshintrc',
                reporter: require('jshint-stylish')
            },
            all: [
                'Gruntfile.js',
                '<%= config.app %>/scripts/*.js',
                '!<%= config.app %>/scripts/vendor/*',
                'test/spec/{,*/}*.js'
            ]
        },

        // Mocha testing framework configuration options
        mocha: {
            all: {
                options: {
                    run: true,
                    urls: ['http://<%= connect.test.options.hostname %>:<%= connect.test.options.port %>/index.html']
                }
            }
        },

        // Add vendor prefixed styles
        autoprefixer: {
            options: {
                browsers: ['last 1 version']
            },
            dist: {
                files: [{
                    expand: true,
                    cwd: '.tmp/styles/',
                    src: '{,*/}*.css',
                    dest: '.tmp/styles/'
                }]
            }
        },

        // Automatically inject Bower components into the HTML file
        bowerInstall: {
            app: {
                src: ['<%= config.app %>/index.html'],
                exclude: ['bower_components/bootstrap/dist/js/bootstrap.js']
            }
        },

        // Renames files for browser caching purposes
        rev: {
            dist: {
                files: {
                    src: [
                        '<%= config.dist %>/scripts/{,*/}*.js',
                        '<%= config.dist %>/styles/{,*/}*.css',
                        '<%= config.dist %>/images/{,*/}*.*',
                        '<%= config.dist %>/styles/fonts/{,*/}*.*',
                        '<%= config.dist %>/*.{ico,png}'
                    ]
                }
            }
        },

        // Reads HTML for usemin blocks to enable smart builds that automatically
        // concat, minify and revision files. Creates configurations in memory so
        // additional tasks can operate on them
        useminPrepare: {
            options: {
                dest: '<%= config.dist %>'
            },
            html: '<%= config.app %>/index.html'
        },

        // Performs rewrites based on rev and the useminPrepare configuration
        usemin: {
            options: {
                assetsDirs: ['<%= config.dist %>', '<%= config.dist %>/images']
            },
            html: ['<%= config.dist %>/{,*/}*.html'],
            css: ['<%= config.dist %>/styles/{,*/}*.css']
        },

        // The following *-min tasks produce minified files in the dist folder
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= config.app %>/images',
                    src: '{,*/}*.{gif,jpeg,jpg,png}',
                    dest: '<%= config.dist %>/images'
                }]
            }
        },

        svgmin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= config.app %>/images',
                    src: '{,*/}*.svg',
                    dest: '<%= config.dist %>/images'
                }]
            }
        },

        htmlmin: {
            dist: {
                options: {
                    collapseBooleanAttributes: true,
                    collapseWhitespace: true,
                    removeAttributeQuotes: true,
                    removeCommentsFromCDATA: true,
                    removeEmptyAttributes: true,
                    removeOptionalTags: true,
                    removeRedundantAttributes: true,
                    useShortDoctype: true
                },
                files: [{
                    expand: true,
                    cwd: '<%= config.dist %>',
                    src: '{,*/}*.html',
                    dest: '<%= config.dist %>'
                }]
            }
        },

        // By default, your `index.html`'s <!-- Usemin block --> will take care of
        // minification. These next options are pre-configured if you do not wish
        // to use the Usemin blocks.
        // cssmin: {
        //     dist: {
        //         files: {
        //             '<%= config.dist %>/styles/main.css': [
        //                 '.tmp/styles/{,*/}*.css',
        //                 '<%= config.app %>/styles/{,*/}*.css'
        //             ]
        //         }
        //     }
        // },
        // uglify: {
        //     dist: {
        //         files: {
        //             '<%= config.dist %>/scripts/scripts.js': [
        //                 '<%= config.dist %>/scripts/scripts.js'
        //             ]
        //         }
        //     }
        // },
        // concat: {
        //     dist: {}
        // },

        // Copies remaining files to places other tasks can use
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%= config.app %>',
                    dest: '<%= config.dist %>',
                    src: [
                        '*.{ico,png,txt}',
                        '.htaccess',
                        'images/{,*/}*.webp',
                        '{,*/}*.html',
                        'styles/fonts/{,*/}*.*'
                    ]
                }, {
                    expand: true,
                    dot: true,
                    cwd: 'bower_components/bootstrap/dist',
                    src: ['fonts/*.*'],
                    dest: '<%= config.dist %>'
                }]
            },
            styles: {
                expand: true,
                dot: true,
                cwd: '<%= config.app %>/styles',
                dest: '.tmp/styles/',
                src: '{,*/}*.css'
            }
        },

        // Run some tasks in parallel to speed up build process
        concurrent: {
            server: [
                'copy:styles'
            ],
            test: [
                'copy:styles'
            ],
            dist: [
                'copy:styles',
                'imagemin',
                'svgmin'
            ]
        }
    });

    grunt.registerTask('serve', function (target) {
        if (target === 'dist') {
            return grunt.task.run(['build', 'connect:dist:keepalive']);
        }

        grunt.task.run([
            'ts:dev',
            'clean:server',
            'concurrent:server',
            'autoprefixer',
            'configureProxies',
            'connect:livereload',
            'watch'
        ]);
    });

    grunt.registerTask('server', function (target) {
        grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
        grunt.task.run([target ? ('serve:' + target) : 'serve']);
    });

    grunt.registerTask('test', function (target) {
        if (target !== 'watch') {
            grunt.task.run([
                'clean:server',
                'concurrent:test',
                'autoprefixer'
            ]);
        }

        grunt.task.run([
            'connect:test',
            'mocha'
        ]);
    });

    grunt.registerTask('build', [
        'clean:dist',
        'ts:dev',
        'useminPrepare',
        'concurrent:dist',
        'autoprefixer',
        'concat',
        'cssmin',
        'uglify',
        'copy:dist',
        'rev',
        'usemin',
        'htmlmin'
    ]);

    grunt.registerTask('dev', [
        'ts:dev',
        'watch'
    ]);

    grunt.registerTask('default', [
        'newer:jshint',
        'test',
        'build'
    ]);
};
<|endoftext|>


<commit_before>// C L I E N T  B U S

(function (window) {

	var Bus = function () {

		var bus = this;

		var socket = io.connect("http://waf.com");

		socket.on('*', function (paramArray) {
			var module     = paramArray[0]
			, method       = paramArray[1]
			, args         = paramArray[2]; // msgpacked object

			window[module][method](args);
		});

		bus.send = function (paramArray) {
			socket.emit('*', paramArray);
		}

	}

	window.Bus = Bus;
}(window));<commit_msg>live test<commit_after>// C L I E N T  B U S

(function (window) {

	var Bus = function () {

		var bus = this;

		var socket = io.connect("http://204.27.60.58");

		socket.on('*', function (paramArray) {
			var module     = paramArray[0]
			, method       = paramArray[1]
			, args         = paramArray[2]; // msgpacked object

			window[module][method](args);
		});

		bus.send = function (paramArray) {
			socket.emit('*', paramArray);
		}

	}

	window.Bus = Bus;
}(window));<|endoftext|>


<commit_before>/**
 * Django admin inlines
 *
 * Based on jQuery Formset 1.1
 * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com)
 * @requires jQuery 1.2.6 or later
 *
 * Copyright (c) 2009, Stanislaus Madueke
 * All rights reserved.
 *
 * Spiced up with Code from Zain Memon's GSoC project 2009
 * and modified for Django by Jannis Leidel, Travis Swicegood and Julien Phalip.
 *
 * Licensed under the New BSD License
 * See: http://www.opensource.org/licenses/bsd-license.php
 */
(function($) {
  $.fn.formset = function(opts) {
    var options = $.extend({}, $.fn.formset.defaults, opts);
    var $this = $(this);
    var $parent = $this.parent();
    var updateElementIndex = function(el, prefix, ndx) {
      var id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))");
      var replacement = prefix + "-" + ndx;
      var jel = $(el);
      if (jel.attr("for")) {
        $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
      }
      if (el.id) {
        el.id = el.id.replace(id_regex, replacement);
      }
      if (el.name) {
        el.name = el.name.replace(id_regex, replacement);
      }
      var modal = jel.find('.modal');
      if (modal.length) {
    	  modal.attr('id', 'modal-wrapper-'+replacement);
    	  jel.find('.inline-modal').attr('href', '#modal-wrapper-'+replacement);
      }
    };
    var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").attr("autocomplete", "off");
    var nextIndex = parseInt(totalForms.val(), 10);
    var maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").attr("autocomplete", "off");

    // add delete buttons to all rows that don't have a delete checkbox
	$(this).each(function() {
		if (!$(this).find("[name=" + $(this).attr("id") + "-id]").val()) {
		   var row = $(this);
		   if (row.is("tr")) {
	          // If the forms are laid out in table rows, insert
	          // the remove button into the last table cell:
	          row.children(":last").append('
 ' + options.deleteText + "
");
	        } else if (row.is("ul") || row.is("ol")) {
	          // If they're laid out as an ordered/unordered list,
	          // insert an
 after the last list item:
	          row.append('
' + options.deleteText + "
");
	        } else {
	          // Otherwise, just insert the remove button as the
	          // last child element of the form's container:
	          var modal = row.closest('.inline-related-modal');
	          var extra_class = (modal.length) ? '' : ' icon-white';
	          row.children(":first").append(' ' + options.deleteText + "");
	        }
	        // The delete button of each row triggers a bunch of other things
            $(this).find("a." + options.deleteCssClass).click(function(e) {
              e.preventDefault();
              // Remove the parent form containing this button:
              var row = $(this).parents("." + options.formCssClass);
              row.remove();
              nextIndex -= 1;
              // If a post-delete callback was provided, call it with the deleted form:
              if (options.removed) {
                options.removed(row);
              }
              // Update the TOTAL_FORMS form count.
              var forms = $("." + options.formCssClass);
              $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
              // Show add button again once we drop below max
              if ((maxForms.val() === '') || (maxForms.val()-forms.length) > 0) {
                addButton.parent().show();
              }
              // Also, update names and ids for all remaining form controls
              // so they remain in sequence:
              for (var i=0, formCount=forms.length; i<formCount; i++)
              {
                updateElementIndex($(forms).get(i), options.prefix, i);
                $(forms.get(i)).find("*").each(function() {
                  updateElementIndex(this, options.prefix, i);
                });
              }
            });
 		}
 	});

    // only show the add button if we are allowed to add more items,
        // note that max_num = None translates to a blank string.
    var showAddButton = maxForms.val() === '' || (maxForms.val()-totalForms.val()) > 0;
    $this.each(function(i) {
      $(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
    });
    if ($this.length && showAddButton) {
      var addButton;
      if ($this.prop("tagName") == "TR") {
        // If forms are laid out as table rows, insert the
        // "add" button in a new table row:
        var numCols = this.eq(-1).children().length;
        $parent.append('
 ' + options.addText + "
");
        addButton = $parent.find("tr:last a");
      } else {
        // Otherwise, insert it immediately after the last form:
        $this.filter(":last").after('
 ' + options.addText + "
");
        addButton = $this.filter(":last").next().find("a");
      }
      addButton.click(function(e) {
        e.preventDefault();
        var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS");
        var template = $("#" + options.prefix + "-empty");
        var row = template.clone(true);
        //handle possible select2 widgets
        var select2_cont = row.find('.select2-container');
        if (row.find('.select2-container').length) {
        	select2_cont.remove();
        	row.find('.select2-offscreen').select2();
        }
        row.removeClass(options.emptyCssClass)
          .addClass(options.formCssClass)
          .attr("id", options.prefix + "-" + nextIndex);
        var modal = row.find("#modal-wrapper-"+options.prefix + "-empty");
        if (modal.length) {
        	var modal_id = "modal-wrapper-"+options.prefix + "-" + nextIndex;
        	modal.attr("id", modal_id);
        	row.find('a.inline-modal').attr("href", "#" + modal_id);
        }

        row.find("*").each(function() {
          updateElementIndex(this, options.prefix, totalForms.val());
        });
        // Insert the new form when it has been fully edited
        row.insertBefore($(template));
        // Update number of total forms
        $(totalForms).val(parseInt(totalForms.val(), 10) + 1);
        nextIndex += 1;
        // Hide add button in case we've hit the max, except we want to add infinitely
        if ((maxForms.val() !== '') && (maxForms.val()-totalForms.val()) <= 0) {
          addButton.parent().hide();
        }
        // If a post-add callback was supplied, call it with the added form:
        if (options.added) {
          options.added(row);
        }
      });
    }
    return this;
  };

  /* Setup plugin defaults */
  $.fn.formset.defaults = {
    prefix: "form",          // The form prefix for your django formset
    addText: "add another",      // Text for the add link
    deleteText: "remove",      // Text for the delete link
    addCssClass: "add-row",      // CSS class applied to the add link
    deleteCssClass: "delete-row",  // CSS class applied to the delete link
    emptyCssClass: "empty-row",    // CSS class applied to the empty row
    formCssClass: "dynamic-form",  // CSS class applied to each form in a formset
    added: null,          // Function called each time a new form is added
    removed: null          // Function called each time a form is deleted
  };

  // Tabular inlines ---------------------------------------------------------
  $.fn.tabularFormset = function(options) {
    var $rows = $(this);
    var alternatingRows = function(row) {
      $($rows.selector).not(".add-row").removeClass("row1 row2")
        .filter(":even").addClass("row1").end()
        .filter(":odd").addClass("row2");
    };

    var reinitDateTimeShortCuts = function() {
      // Reinitialize the calendar and clock widgets by force
      if (typeof DateTimeShortcuts != "undefined") {
        $(".datetimeshortcuts").remove();
        DateTimeShortcuts.init();
      }
    };

    var updateSelectFilter = function() {
      // If any SelectFilter widgets are a part of the new form,
      // instantiate a new SelectFilter instance for it.
      if (typeof SelectFilter != 'undefined'){
        $('.selectfilter').each(function(index, value){
          var namearr = value.name.split('-');
          SelectFilter.init(value.id, namearr[namearr.length-1], false, options.adminStaticPrefix );
        });
        $('.selectfilterstacked').each(function(index, value){
          var namearr = value.name.split('-');
          SelectFilter.init(value.id, namearr[namearr.length-1], true, options.adminStaticPrefix );
        });
      }
    };

    var initPrepopulatedFields = function(row) {
      row.find('.prepopulated_field').each(function() {
        var field = $(this),
            input = field.find('input, select, textarea'),
            dependency_list = input.data('dependency_list') || [],
            dependencies = [];
        $.each(dependency_list, function(i, field_name) {
          dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id'));
        });
        if (dependencies.length) {
          input.prepopulate(dependencies, input.attr('maxlength'));
        }
      });
    };

    $rows.formset({
      prefix: options.prefix,
      addText: options.addText,
      formCssClass: "dynamic-" + options.prefix,
      deleteCssClass: "inline-deletelink",
      deleteText: options.deleteText,
      emptyCssClass: "empty-form",
      removed: alternatingRows,
      added: function(row) {
        initPrepopulatedFields(row);
        reinitDateTimeShortCuts();
        updateSelectFilter();
        alternatingRows(row);
      }
    });

    return $rows;
  };

  // Stacked inlines ---------------------------------------------------------
  $.fn.stackedFormset = function(options) {
    var $rows = $(this);
    var updateInlineLabel = function(row) {
      $($rows.selector).find(".inline_label").each(function(i) {
        var count = i + 1;
        $(this).html($(this).html().replace(/(#\d+)/g, "#" + count));
      });
    };

    var reinitDateTimeShortCuts = function() {
      // Reinitialize the calendar and clock widgets by force, yuck.
      if (typeof DateTimeShortcuts != "undefined") {
        $(".datetimeshortcuts").remove();
        DateTimeShortcuts.init();
      }
    };

    var updateSelectFilter = function() {
      // If any SelectFilter widgets were added, instantiate a new instance.
      if (typeof SelectFilter != "undefined"){
        $(".selectfilter").each(function(index, value){
          var namearr = value.name.split('-');
          SelectFilter.init(value.id, namearr[namearr.length-1], false, options.adminStaticPrefix);
        });
        $(".selectfilterstacked").each(function(index, value){
          var namearr = value.name.split('-');
          SelectFilter.init(value.id, namearr[namearr.length-1], true, options.adminStaticPrefix);
        });
      }
    };

    var initPrepopulatedFields = function(row) {
      row.find('.prepopulated_field').each(function() {
        var field = $(this),
            input = field.find('input, select, textarea'),
            dependency_list = input.data('dependency_list') || [],
            dependencies = [];
        $.each(dependency_list, function(i, field_name) {
          dependencies.push('#' + row.find('.form-row .field-' + field_name).find('input, select, textarea').attr('id'));
        });
        if (dependencies.length) {
          input.prepopulate(dependencies, input.attr('maxlength'));
        }
      });
    };

    $rows.formset({
      prefix: options.prefix,
      addText: options.addText,
      formCssClass: "dynamic-" + options.prefix,
      deleteCssClass: "inline-deletelink",
      deleteText: options.deleteText,
      emptyCssClass: "empty-form",
      removed: updateInlineLabel,
      added: (function(row) {
        initPrepopulatedFields(row);
        reinitDateTimeShortCuts();
        updateSelectFilter();
        updateInlineLabel(row);
      })
    });

    return $rows;
  };
})(yawdadmin.jQuery);<commit_msg>minor update for select2 widgets<commit_after>/**
 * Django admin inlines
 *
 * Based on jQuery Formset 1.1
 * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com)
 * @requires jQuery 1.2.6 or later
 *
 * Copyright (c) 2009, Stanislaus Madueke
 * All rights reserved.
 *
 * Spiced up with Code from Zain Memon's GSoC project 2009
 * and modified for Django by Jannis Leidel, Travis Swicegood and Julien Phalip.
 *
 * Licensed under the New BSD License
 * See: http://www.opensource.org/licenses/bsd-license.php
 */
(function($) {
  $.fn.formset = function(opts) {
    var options = $.extend({}, $.fn.formset.defaults, opts);
    var $this = $(this);
    var $parent = $this.parent();
    var updateElementIndex = function(el, prefix, ndx) {
      var id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))");
      var replacement = prefix + "-" + ndx;
      var jel = $(el);
      if (jel.attr("for")) {
        $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
      }
      if (el.id) {
        el.id = el.id.replace(id_regex, replacement);
      }
      if (el.name) {
        el.name = el.name.replace(id_regex, replacement);
      }
      var modal = jel.find('.modal');
      if (modal.length) {
    	  modal.attr('id', 'modal-wrapper-'+replacement);
    	  jel.find('.inline-modal').attr('href', '#modal-wrapper-'+replacement);
      }
    };
    var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").attr("autocomplete", "off");
    var nextIndex = parseInt(totalForms.val(), 10);
    var maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").attr("autocomplete", "off");

    // add delete buttons to all rows that don't have a delete checkbox
	$(this).each(function() {
		if (!$(this).find("[name=" + $(this).attr("id") + "-id]").val()) {
		   var row = $(this);
		   if (row.is("tr")) {
	          // If the forms are laid out in table rows, insert
	          // the remove button into the last table cell:
	          row.children(":last").append('
 ' + options.deleteText + "
");
	        } else if (row.is("ul") || row.is("ol")) {
	          // If they're laid out as an ordered/unordered list,
	          // insert an
 after the last list item:
	          row.append('
' + options.deleteText + "
");
	        } else {
	          // Otherwise, just insert the remove button as the
	          // last child element of the form's container:
	          var modal = row.closest('.inline-related-modal');
	          var extra_class = (modal.length) ? '' : ' icon-white';
	          row.children(":first").append(' ' + options.deleteText + "");
	        }
	        // The delete button of each row triggers a bunch of other things
            $(this).find("a." + options.deleteCssClass).click(function(e) {
              e.preventDefault();
              // Remove the parent form containing this button:
              var row = $(this).parents("." + options.formCssClass);
              row.remove();
              nextIndex -= 1;
              // If a post-delete callback was provided, call it with the deleted form:
              if (options.removed) {
                options.removed(row);
              }
              // Update the TOTAL_FORMS form count.
              var forms = $("." + options.formCssClass);
              $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
              // Show add button again once we drop below max
              if ((maxForms.val() === '') || (maxForms.val()-forms.length) > 0) {
                addButton.parent().show();
              }
              // Also, update names and ids for all remaining form controls
              // so they remain in sequence:
              for (var i=0, formCount=forms.length; i<formCount; i++)
              {
                updateElementIndex($(forms).get(i), options.prefix, i);
                $(forms.get(i)).find("*").each(function() {
                  updateElementIndex(this, options.prefix, i);
                });
              }
            });
 		}
 	});

    // only show the add button if we are allowed to add more items,
        // note that max_num = None translates to a blank string.
    var showAddButton = maxForms.val() === '' || (maxForms.val()-totalForms.val()) > 0;
    $this.each(function(i) {
      $(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
    });
    if ($this.length && showAddButton) {
      var addButton;
      if ($this.prop("tagName") == "TR") {
        // If forms are laid out as table rows, insert the
        // "add" button in a new table row:
        var numCols = this.eq(-1).children().length;
        $parent.append('
 ' + options.addText + "
");
        addButton = $parent.find("tr:last a");
      } else {
        // Otherwise, insert it immediately after the last form:
        $this.filter(":last").after('
 ' + options.addText + "
");
        addButton = $this.filter(":last").next().find("a");
      }
      addButton.click(function(e) {
        e.preventDefault();
        var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS");
        var template = $("#" + options.prefix + "-empty");
        var row = template.clone(true);
        //handle possible select2 widgets
        var select2_cont = row.find('.select2-container');
        if (select2_cont.length) {
        	select2_cont.remove();
        	var select2_offscreen = row.find('.select2-offscreen');
        	if (select2_offscreen.data('options-callback'))
        		select2_offscreen.select2(window[select2_offscreen.data('options-callback')]());
        	else
        		select2_offscreen.select2();
        }
        row.removeClass(options.emptyCssClass)
          .addClass(options.formCssClass)
          .attr("id", options.prefix + "-" + nextIndex);
        var modal = row.find("#modal-wrapper-"+options.prefix + "-empty");
        if (modal.length) {
        	var modal_id = "modal-wrapper-"+options.prefix + "-" + nextIndex;
        	modal.attr("id", modal_id);
        	row.find('a.inline-modal').attr("href", "#" + modal_id);
        }

        row.find("*").each(function() {
          updateElementIndex(this, options.prefix, totalForms.val());
        });
        // Insert the new form when it has been fully edited
        row.insertBefore($(template));
        // Update number of total forms
        $(totalForms).val(parseInt(totalForms.val(), 10) + 1);
        nextIndex += 1;
        // Hide add button in case we've hit the max, except we want to add infinitely
        if ((maxForms.val() !== '') && (maxForms.val()-totalForms.val()) <= 0) {
          addButton.parent().hide();
        }
        // If a post-add callback was supplied, call it with the added form:
        if (options.added) {
          options.added(row);
        }
      });
    }
    return this;
  };

  /* Setup plugin defaults */
  $.fn.formset.defaults = {
    prefix: "form",          // The form prefix for your django formset
    addText: "add another",      // Text for the add link
    deleteText: "remove",      // Text for the delete link
    addCssClass: "add-row",      // CSS class applied to the add link
    deleteCssClass: "delete-row",  // CSS class applied to the delete link
    emptyCssClass: "empty-row",    // CSS class applied to the empty row
    formCssClass: "dynamic-form",  // CSS class applied to each form in a formset
    added: null,          // Function called each time a new form is added
    removed: null          // Function called each time a form is deleted
  };

  // Tabular inlines ---------------------------------------------------------
  $.fn.tabularFormset = function(options) {
    var $rows = $(this);
    var alternatingRows = function(row) {
      $($rows.selector).not(".add-row").removeClass("row1 row2")
        .filter(":even").addClass("row1").end()
        .filter(":odd").addClass("row2");
    };

    var reinitDateTimeShortCuts = function() {
      // Reinitialize the calendar and clock widgets by force
      if (typeof DateTimeShortcuts != "undefined") {
        $(".datetimeshortcuts").remove();
        DateTimeShortcuts.init();
      }
    };

    var updateSelectFilter = function() {
      // If any SelectFilter widgets are a part of the new form,
      // instantiate a new SelectFilter instance for it.
      if (typeof SelectFilter != 'undefined'){
        $('.selectfilter').each(function(index, value){
          var namearr = value.name.split('-');
          SelectFilter.init(value.id, namearr[namearr.length-1], false, options.adminStaticPrefix );
        });
        $('.selectfilterstacked').each(function(index, value){
          var namearr = value.name.split('-');
          SelectFilter.init(value.id, namearr[namearr.length-1], true, options.adminStaticPrefix );
        });
      }
    };

    var initPrepopulatedFields = function(row) {
      row.find('.prepopulated_field').each(function() {
        var field = $(this),
            input = field.find('input, select, textarea'),
            dependency_list = input.data('dependency_list') || [],
            dependencies = [];
        $.each(dependency_list, function(i, field_name) {
          dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id'));
        });
        if (dependencies.length) {
          input.prepopulate(dependencies, input.attr('maxlength'));
        }
      });
    };

    $rows.formset({
      prefix: options.prefix,
      addText: options.addText,
      formCssClass: "dynamic-" + options.prefix,
      deleteCssClass: "inline-deletelink",
      deleteText: options.deleteText,
      emptyCssClass: "empty-form",
      removed: alternatingRows,
      added: function(row) {
        initPrepopulatedFields(row);
        reinitDateTimeShortCuts();
        updateSelectFilter();
        alternatingRows(row);
      }
    });

    return $rows;
  };

  // Stacked inlines ---------------------------------------------------------
  $.fn.stackedFormset = function(options) {
    var $rows = $(this);
    var updateInlineLabel = function(row) {
      $($rows.selector).find(".inline_label").each(function(i) {
        var count = i + 1;
        $(this).html($(this).html().replace(/(#\d+)/g, "#" + count));
      });
    };

    var reinitDateTimeShortCuts = function() {
      // Reinitialize the calendar and clock widgets by force, yuck.
      if (typeof DateTimeShortcuts != "undefined") {
        $(".datetimeshortcuts").remove();
        DateTimeShortcuts.init();
      }
    };

    var updateSelectFilter = function() {
      // If any SelectFilter widgets were added, instantiate a new instance.
      if (typeof SelectFilter != "undefined"){
        $(".selectfilter").each(function(index, value){
          var namearr = value.name.split('-');
          SelectFilter.init(value.id, namearr[namearr.length-1], false, options.adminStaticPrefix);
        });
        $(".selectfilterstacked").each(function(index, value){
          var namearr = value.name.split('-');
          SelectFilter.init(value.id, namearr[namearr.length-1], true, options.adminStaticPrefix);
        });
      }
    };

    var initPrepopulatedFields = function(row) {
      row.find('.prepopulated_field').each(function() {
        var field = $(this),
            input = field.find('input, select, textarea'),
            dependency_list = input.data('dependency_list') || [],
            dependencies = [];
        $.each(dependency_list, function(i, field_name) {
          dependencies.push('#' + row.find('.form-row .field-' + field_name).find('input, select, textarea').attr('id'));
        });
        if (dependencies.length) {
          input.prepopulate(dependencies, input.attr('maxlength'));
        }
      });
    };

    $rows.formset({
      prefix: options.prefix,
      addText: options.addText,
      formCssClass: "dynamic-" + options.prefix,
      deleteCssClass: "inline-deletelink",
      deleteText: options.deleteText,
      emptyCssClass: "empty-form",
      removed: updateInlineLabel,
      added: (function(row) {
        initPrepopulatedFields(row);
        reinitDateTimeShortCuts();
        updateSelectFilter();
        updateInlineLabel(row);
      })
    });

    return $rows;
  };
})(yawdadmin.jQuery);<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

import { colors, theme, typography } from '../theme/variables';

const BtnColor = props => props.color || theme.buttonText;
const Background = (props) => {
  if (props.bg) {
    return props.bg;
  } else if (props.type === 'secondary') {
    return colors.cyan;
  } else if (props.type === 'success') {
    return colors.green;
  } else if (props.type === 'warn') {
    return colors.red;
  } else if (props.type === 'login') {
    return colors.lightblack;
  }
  return theme.buttonColor;
};

const Btn = styled.button`
  border: none;
  padding: ${props => (props.arrows ? '0.25em 0.8em 0.25em 1.5em' : '.25em .7em')};
  position: relative;
  color: ${BtnColor};
  font-family: ${typography.monospace};
  background: ${Background};
  width: ${props => (props.wide ? '100%' : 'auto')};
  font-size: ${(props) => {
    if (props.small) {
      return '.8rem';
    } else if (props.large) {
      return '1.7rem';
    }
    return '1.1rem';
  }};
  index: 10;
  &.disabled {
    background: ${colors.grey};
    color: ${colors.black};
  }

  :before {
    content: '';
    display: ${props => (props.arrows ? 'block' : 'none')};
    position: absolute;
    top: 50%;
    left: -.6em;
    width: 1.2em;
    height: 1.2em;
    -webkit-transform: translateY(-50%) rotate(45deg);
    transform: translateY(-50%) rotate(45deg);
    transition: 0.2s ease-in;
    background: ${BtnColor};
    index: 9;
  }
  :after {
    content: '';
    display: ${props => (props.arrows ? 'block' : 'none')};
    position: absolute;
    top: 50%;
    right: -.6em;
    width: 1.2em;
    height: 1.2em;
    -webkit-transform: translateY(-50%) rotate(45deg);
    transform: translateY(-50%) rotate(45deg);
    transition: 0.2s ease-in;
    background: ${Background};
    index: 9;
  }
`;

const Button = props => (
  <Btn
    type={props.type}
    wide={props.wide}
    small={props.small}
    large={props.large}
    color={props.color}
    arrows={props.arrows}
    bg={props.bg}
  >
    {props.text || props.children}
  </Btn>
);

Button.propTypes = {
  children: PropTypes.element.isRequired,
  type: PropTypes.oneOf(['primary', 'secondary', 'login', 'success', 'warn']).isRequired,
  text: PropTypes.string,
  color: PropTypes.string,
  small: PropTypes.bool,
  large: PropTypes.bool,
  wide: PropTypes.bool,
  arrows: PropTypes.bool,
  bg: PropTypes.string,
};

Button.defaultProps = {
  text: null,
  color: theme.buttonText,
  bg: theme.buttonColor,
  small: false,
  large: false,
  wide: false,
  arrows: false,
};

export default Button;
<commit_msg>Props: styleType, children, bg<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

import { colors, theme, typography } from '../theme/variables';

const BtnColor = props => props.color || theme.buttonText;
const Background = (props) => {
  if (props.bg) {
    return props.bg;
  } else if (props.styleType === 'secondary') {
    return colors.cyan;
  } else if (props.styleType === 'success' || props.styleType === 'submit') {
    return colors.green;
  } else if (props.styleType === 'warn') {
    return colors.red;
  } else if (props.styleType === 'login') {
    return colors.lightblack;
  }
  return theme.buttonColor;
};

const Btn = styled.button`
  border: none;
  padding: ${props => (props.arrows ? '0.25em 0.8em 0.25em 1.5em' : '.25em .7em')};
  position: relative;
  color: ${BtnColor};
  font-family: ${typography.monospace};
  background: ${Background};

  width: ${props => (props.wide ? '100%' : 'auto')};
  font-size: ${(props) => {
    if (props.small) {
      return '.8rem';
    } else if (props.large) {
      return '1.7rem';
    }
    return '1.1rem';
  }};
  index: 10;
  &.disabled {
    background: ${colors.grey};
    color: ${colors.black};
  }

  :before {
    content: '';
    display: ${props => (props.arrows ? 'block' : 'none')};
    position: absolute;
    top: 50%;
    left: -.6em;
    width: 1.2em;
    height: 1.2em;
    -webkit-transform: translateY(-50%) rotate(45deg);
    transform: translateY(-50%) rotate(45deg);
    transition: 0.2s ease-in;
    background: ${props => props.arrows || BtnColor};
    index: 9;
  }
  :after {
    content: '';
    display: ${props => (props.arrows ? 'block' : 'none')};
    position: absolute;
    top: 50%;
    right: -.6em;
    width: 1.2em;
    height: 1.2em;
    -webkit-transform: translateY(-50%) rotate(45deg);
    transform: translateY(-50%) rotate(45deg);
    transition: 0.2s ease-in;
    background: ${Background};
    index: 9;
  }
`;

const Button = props => (
  <Btn
    type={props.type}
    styleType={props.styleType}
    wide={props.wide}
    small={props.small}
    large={props.large}
    color={props.color}
    arrows={props.arrows}
    bg={props.bg}
  >
    {props.text || props.children}
  </Btn>
);

Button.propTypes = {
  styleType: PropTypes.oneOf(['primary', 'secondary', 'login', 'success', 'warn', 'submit'])
    .isRequired,
  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
  type: PropTypes.string,
  text: PropTypes.string,
  color: PropTypes.string,
  small: PropTypes.bool,
  large: PropTypes.bool,
  wide: PropTypes.bool,
  arrows: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
  bg: PropTypes.string,
};

Button.defaultProps = {
  styleType: 'primary',
  children: null,
  text: null,
  type: null,
  color: theme.buttonText,
  bg: null,
  small: false,
  large: false,
  wide: false,
  arrows: false,
};

export default Button;
<|endoftext|>


<commit_before>var sFormat = require( 'stringformat' );
var transformTools = require( 'browserify-transform-tools' );
var path = require( 'path' );

var options = {
  excludeExtensions: [ '.json' ],
  evaluateArguments: true
};

module.exports = transformTools.makeRequireTransform( "requireTransform", options, function ( args, opts, cb ) {
  var configData = opts.configData || {};
  var config = configData.config || {};

  var key = args[ 0 ];

  var foundDep = config[ key ];

  if ( foundDep ) {
    return cb( null, sFormat( '({0})', foundDep ));
  }

  cb();
} );
<commit_msg>REF: Make sure we use single quotes<commit_after>var sFormat = require( 'stringformat' );
var transformTools = require( 'browserify-transform-tools' );
var path = require( 'path' );

var options = {
  excludeExtensions: [ '.json' ],
  evaluateArguments: true
};

module.exports = transformTools.makeRequireTransform( 'requireTransform', options, function ( args, opts, cb ) {
  var configData = opts.configData || {};
  var config = configData.config || {};

  var key = args[ 0 ];

  var foundDep = config[ key ];

  if ( foundDep ) {
    return cb( null, sFormat( '({0})', foundDep ));
  }

  cb();
} );
<|endoftext|>


<commit_before>angular.module('ssc').factory('Map', function(rx) {

  var paramsSubject = new rx.BehaviorSubject(),
      requestSubject = new rx.BehaviorSubject();

  return {
    updateParams: function(params) {
      paramsSubject.onNext(params);
    },
    onParamsUpdated: function(callback) {
      paramsSubject.subscribe(callback);
    },
    notifyRequest: function(request) {
      requestSubject.onNext(request);
    },
    onRequest: function(callback) {
      requestSubject.subscribe(callback);
    }
  };
})

angular.module('ssc').component('map', {
  templateUrl: '/templates/map.html',
  controllerAs: 'mapCtrl',
  controller: function($http, leafletData, $location, $log, Map, $scope) {

    var leafletMap,
        mapParams,
        currentPrecision,
        mapCtrl = this;

    mapCtrl.config = {
      center: {},
      markers: []
    };

    setCenterFromAddress();

    leafletData.getMap('map').then(function(map) {
      leafletMap = map;
      updateClusters();
    });

    $scope.$on('leafletDirectiveMap.map.moveend', updateClusters);
    $scope.$on('leafletDirectiveMarker.map.click', zoomToMarker);

    Map.onParamsUpdated(function(params) {
      mapParams = params;
      updateClusters();
    });

    function setCenterFromAddress() {

      var params = $location.search();

      var lat = parseFloat(params.lat),
          lng = parseFloat(params.lng),
          zoom = parseInt(params.zoom, 10);

      if (_.isFinite(lat) && _.isFinite(lng) && _.isFinite(zoom)) {
        _.extend(mapCtrl.config.center, {
          lat: lat,
          lng: lng,
          zoom: zoom
        });
      } else {
        _.extend(mapCtrl.config.center, {
          lat: 51.505,
          lng: -0.09,
          zoom: 3
        });
      }
    }

    function updateClusters() {
      if (!leafletMap || !mapParams) {
        return;
      }

      $location.search('lat', _.round(leafletMap.getCenter().lat, 5));
      $location.search('lng', _.round(leafletMap.getCenter().lng, 5));
      $location.search('zoom', leafletMap.getZoom());

      Promise
        .resolve()
        .then(fetchClusters)
        .then(updateMap)
        .then(_.bind($scope.$apply, $scope));
    }

    function fetchClusters() {

      var algorithm = mapParams.algorithm,
          bounds = leafletMap.getBounds(),
          start = new Date().getTime();

      return $http({
        url: '/api/clusters',
        params: {
          type: algorithm,
          bbox: bounds.toBBoxString()
        }
      }).then(function(res) {

        Map.notifyRequest({
          algorithm: algorithm,
          bounds: bounds,
          time: new Date().getTime() - start,
          algorithmTime: parseInt(res.headers('SSC-Algorithm-Time'), 10),
          response: res
        });

        return res.data;
      });
    }

    function updateMap(data) {

      $log.debug('Found ' + data.clusters.length + ' clusters at precision ' + data.precision + ' matching bbox');

      return Promise
        .resolve(data)
        .then(removeMarkers)
        .return(data.clusters)
        .each(addClusterMarker);
    }

    function removeMarkers(data) {

      var clusters = data.clusters,
          precision = data.precision;

      if (precision != currentPrecision) {
        mapCtrl.config.markers.length = 0;
        currentPrecision = precision;
      } else {
        mapCtrl.config.markers = _.filter(mapCtrl.config.markers, function(marker) {
          return leafletMap.getBounds().contains([ marker.lat, marker.lng ]) && _.find(clusters, { _id: marker._id });
        });
      }
    }

    function addClusterMarker(cluster) {

      var clusterData = _.pick(cluster, '_id', 'lat', 'lng', 'minLat', 'minLng', 'maxLat', 'maxLng');

      var existingMarker = _.find(mapCtrl.config.markers, {
        _id: clusterData._id
      });

      if (existingMarker) {
        _.extend(existingMarker, clusterData);
        return;
      }

      var clusterIcon = $('
');
      var value = $('').text(cluster.count).appendTo(clusterIcon);

      var marker = _.extend(clusterData, {
        icon: {
          type: 'div',
          html: clusterIcon[0].outerHTML,
          iconSize: [ 40, 40 ],
          iconAnchor: [ 20, 20 ]
        }
      });

      mapCtrl.config.markers.push(marker);
    }

    function zoomToMarker(event, marker) {

      var zoom = leafletMap.getZoom();
      if (zoom < leafletMap.getMaxZoom()) {
        zoom += 1;
      }

      leafletMap.setView([ marker.model.lat, marker.model.lng ], zoom);
    }
  }
});
<commit_msg>Display simple marker for 1-point clusters.<commit_after>angular.module('ssc').factory('Map', function(rx) {

  var paramsSubject = new rx.BehaviorSubject(),
      requestSubject = new rx.BehaviorSubject();

  return {
    updateParams: function(params) {
      paramsSubject.onNext(params);
    },
    onParamsUpdated: function(callback) {
      paramsSubject.subscribe(callback);
    },
    notifyRequest: function(request) {
      requestSubject.onNext(request);
    },
    onRequest: function(callback) {
      requestSubject.subscribe(callback);
    }
  };
})

angular.module('ssc').component('map', {
  templateUrl: '/templates/map.html',
  controllerAs: 'mapCtrl',
  controller: function($http, leafletData, $location, $log, Map, $scope) {

    var leafletMap,
        mapParams,
        currentPrecision,
        mapCtrl = this;

    mapCtrl.config = {
      center: {},
      markers: []
    };

    setCenterFromAddress();

    leafletData.getMap('map').then(function(map) {
      leafletMap = map;
      updateClusters();
    });

    $scope.$on('leafletDirectiveMap.map.moveend', updateClusters);
    $scope.$on('leafletDirectiveMarker.map.click', zoomToMarker);

    Map.onParamsUpdated(function(params) {
      mapParams = params;
      updateClusters();
    });

    function setCenterFromAddress() {

      var params = $location.search();

      var lat = parseFloat(params.lat),
          lng = parseFloat(params.lng),
          zoom = parseInt(params.zoom, 10);

      if (_.isFinite(lat) && _.isFinite(lng) && _.isFinite(zoom)) {
        _.extend(mapCtrl.config.center, {
          lat: lat,
          lng: lng,
          zoom: zoom
        });
      } else {
        _.extend(mapCtrl.config.center, {
          lat: 51.505,
          lng: -0.09,
          zoom: 3
        });
      }
    }

    function updateClusters() {
      if (!leafletMap || !mapParams) {
        return;
      }

      $location.search('lat', _.round(leafletMap.getCenter().lat, 5));
      $location.search('lng', _.round(leafletMap.getCenter().lng, 5));
      $location.search('zoom', leafletMap.getZoom());

      Promise
        .resolve()
        .then(fetchClusters)
        .then(updateMap)
        .then(_.bind($scope.$apply, $scope));
    }

    function fetchClusters() {

      var algorithm = mapParams.algorithm,
          bounds = leafletMap.getBounds(),
          start = new Date().getTime();

      return $http({
        url: '/api/clusters',
        params: {
          type: algorithm,
          bbox: bounds.toBBoxString()
        }
      }).then(function(res) {

        Map.notifyRequest({
          algorithm: algorithm,
          bounds: bounds,
          time: new Date().getTime() - start,
          algorithmTime: parseInt(res.headers('SSC-Algorithm-Time'), 10),
          response: res
        });

        return res.data;
      });
    }

    function updateMap(data) {

      $log.debug('Found ' + data.clusters.length + ' clusters matching bbox');

      return Promise
        .resolve(data)
        .then(removeMarkers)
        .return(data.clusters)
        .each(addClusterMarker);
    }

    function removeMarkers(data) {
      var clusters = data.clusters;
      mapCtrl.config.markers = _.filter(mapCtrl.config.markers, function(marker) {
        return leafletMap.getBounds().contains([ marker.lat, marker.lng ]) && !!_.find(clusters, { _id: marker._id });
      });
    }

    function addClusterMarker(cluster) {

      var markerData = _.pick(cluster, '_id', 'lat', 'lng', 'count');

      var marker = _.find(mapCtrl.config.markers, {
        _id: cluster._id
      });

      if (marker) {
        _.extend(marker, markerData);
      } else {
        marker = markerData;
        mapCtrl.config.markers.push(marker);
      }

      if (cluster.count >= 2) {
        marker.icon = createClusterIcon(cluster);
      } else {
        delete marker.icon;
      }
    }

    function createClusterIcon(cluster) {

      var clusterIcon = $('
');
      var value = $('').text(cluster.count).appendTo(clusterIcon);

      return {
        type: 'div',
        html: clusterIcon[0].outerHTML,
        iconSize: [ 40, 40 ],
        iconAnchor: [ 20, 20 ]
      };
    }

    function zoomToMarker(event, marker) {

      var zoom = leafletMap.getZoom();
      if (zoom < leafletMap.getMaxZoom()) {
        zoom += 1;
      }

      leafletMap.setView([ marker.model.lat, marker.model.lng ], zoom);
    }
  }
});
<|endoftext|>


<commit_before>$(document).ready(function(){
  var dataTableView = findViewObject(this.getElementsByClassName("bk-data-table")[0], Bokeh.index[modelid])
  var dataSource = dataTableView.mget("source")
  var fields = dataSource.attributes.column_names

  $(".plotdiv").append("<form id='column-filters'><input type='submit'></form>")
var optionsConstructor = function(source, fieldName){
  var result = "<option value=''></option>";
  var elements = getUniqueElements(source.attributes.data[fieldName])
  for(var i = 0; i < elements.length; i++){
    result += "<option value="+ elements[i] +">" + elements[i] + "</option>"
  }
  return result
}

var getUniqueElements = function(array){
  var u = {}, a = [];
     for(var i = 0; i < array.length; ++i){
        if(u.hasOwnProperty(array[i])) {
           continue;
        }
        a.push(array[i]);
        u[array[i]] = 1;
     }
     return a;
}<commit_msg>adds drop downs<commit_after>$(document).ready(function(){
  var dataTableView = findViewObject(this.getElementsByClassName("bk-data-table")[0], Bokeh.index[modelid])
  var dataSource = dataTableView.mget("source")
  var fields = dataSource.attributes.column_names

  $(".plotdiv").append("<form id='column-filters'><input type='submit'></form>")

  for (var i = 0; i < fields.length; i++){
    var optionsString = optionsConstructor(dataSource, fields[i])
    $("form#column-filters").append("<select name=" + fields[i] + ">"+ optionsString+"</select>")
  }

var optionsConstructor = function(source, fieldName){
  var result = "<option value=''></option>";
  var elements = getUniqueElements(source.attributes.data[fieldName])
  for(var i = 0; i < elements.length; i++){
    result += "<option value="+ elements[i] +">" + elements[i] + "</option>"
  }
  return result
}

var getUniqueElements = function(array){
  var u = {}, a = [];
     for(var i = 0; i < array.length; ++i){
        if(u.hasOwnProperty(array[i])) {
           continue;
        }
        a.push(array[i]);
        u[array[i]] = 1;
     }
     return a;
}<|endoftext|>


<commit_before>function include_user_filter(settings) {
    function createMenuButton(group, label) {
        return $('' + label + '');
    }

    const ADD_ACTION = true;
    const REMOVE_ACTION = false;

    YouTubeLive.onChatLoaded(function (youtube) {
        var theCss = "#brbtv-user-actions-menu {" +
            "background-color: white;" +
            "display: none;" +
            "position: absolute;}\n";
        theCss += ".brbtv-user-actions-item {color: black !important;}";
        theCss += ".show-brbtv-user-actions-menu {display: block !important;}";
        theCss += ".brbtv-highlighted-message .accent-bar {background-color: rgb(204, 0, 0) !important;}";
        theCss += ".brbtv-muted-message .yt-user-name {text-decoration: line-through !important;}";
        addCssToHead(theCss);

        var mutedUsers = new Set();
        for (let i = 0; i < settings.ignoredUsers.length; i++) {
            mutedUsers.add(settings.ignoredUsers[i].id);
        }

        var highlightedUsers = new Set();
        for (let i = 0; i < settings.highlightedUsers.length; i++) {
            highlightedUsers.add(settings.highlightedUsers[i].id);
        }

        chrome.storage.onChanged.addListener(function (changes, namespace) {
            var ignoredUserChange = changes["ignoredUsers"];
            if (ignoredUserChange) {
                mutedUsers = new Set();
                for (let i = 0; i < ignoredUserChange.newValue.length; i++) {
                    mutedUsers.add(ignoredUserChange.newValue[i].id);
                }
            }

            var highlightedUserChange = changes["highlightedUsers"];
            if (highlightedUserChange) {
                highlightedUsers = new Set();
                for (let i = 0; i < highlightedUserChange.newValue.length; i++) {
                    highlightedUsers.add(highlightedUserChange.newValue[i].id);
                }
            }
        });

        var jUserMenu = $('

');
        $("body").prepend(jUserMenu);

        function updateChromeStore(jUserLink, ytId, storageKey, isAddToList) {
            let query = {};
            query[storageKey] = [];
            chrome.storage.sync.get(query, function (items) {
                var theUpdatedArray = items[storageKey];
                if (isAddToList) {
                    theUpdatedArray.push({
                        name: jUserLink.text().trim(),
                        id: ytId,
                        addedTime: Date.now()
                    });
                } else {
                    theUpdatedArray = theUpdatedArray.filter(u => u.id != ytId);
                }

                query[storageKey] = theUpdatedArray;

                chrome.storage.sync.set(query);
            });
        }

        function addHighlightUserButton(ytId, jUserLink) {
            let jHighlightUser = createMenuButton("brbtv-highlight-button", chrome.i18n.getMessage("userActionHighlight"));
            jHighlightUser.click(function (e) {
                if (!highlightedUsers.has(ytId)) {
                    highlightedUsers.add(ytId);
                    updateChromeStore(jUserLink, ytId, "highlightedUsers", ADD_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (jIteratedMessage.find("a.yt-user-name[data-ytid='" + ytId + "']").length) {
                            jIteratedMessage.addClass("brbtv-highlighted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            jUserMenu.append(jHighlightUser);
        }

        function addUnhighlightUserButton(ytId, jUserLink) {
            let jUnhighlightUser = createMenuButton("brbtv-unhighlight-button", chrome.i18n.getMessage("userActionUnHighlight"));
            jUnhighlightUser.click(function (e) {
                if (highlightedUsers.has(ytId)) {
                    highlightedUsers.delete(ytId);
                    updateChromeStore(jUserLink, ytId, "highlightedUsers", REMOVE_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (jIteratedMessage.find("a.yt-user-name[data-ytid='" + ytId + "']").length) {
                            jIteratedMessage.removeClass("brbtv-highlighted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            jUserMenu.append(jUnhighlightUser);
        }

        function addMuteButton(ytId, jUserLink) {
            let jMuteUser = createMenuButton("brbtv-mute-button", chrome.i18n.getMessage("userActionMute"));
            jMuteUser.click(function (e) {
                if (!mutedUsers.has(ytId)) {
                    mutedUsers.add(ytId);
                    updateChromeStore(jUserLink, ytId, "ignoredUsers", ADD_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (jIteratedMessage.find("a.yt-user-name[data-ytid='" + ytId + "']").length) {
                            jIteratedMessage.addClass("brbtv-muted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            jUserMenu.append(jMuteUser);
        }

        function addUnmuteButton(ytId, jUserLink) {
            let jMuteUser = createMenuButton("brbtv-unmute-button", chrome.i18n.getMessage("userActionUnMute"));
            jMuteUser.click(function (e) {
                if (mutedUsers.has(ytId)) {
                    mutedUsers.delete(ytId);
                    updateChromeStore(jUserLink, ytId, "ignoredUsers", REMOVE_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (jIteratedMessage.find("a.yt-user-name[data-ytid='" + ytId + "']").length) {
                            jIteratedMessage.removeClass("brbtv-muted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            jUserMenu.append(jMuteUser);
        }

        function addHideMenuFunction(jUserLink) {
            var hideMenuFunction = function (e) {
                if (e.target != jUserLink[0]) {
                    jUserMenu.removeClass("show-brbtv-user-actions-menu");
                    $(this).off("click", hideMenuFunction);
                }
            };
            $("body").on("click", hideMenuFunction);
        }

        youtube.registerChatMessageObserver(function (message) {
            let jMessage = $(message);
            // don't show menu for yourself or VIP announcements
            if (jMessage.hasClass("author-viewing") || jMessage.hasClass("new-member-announcement")) return;

            var jUserLink = jMessage.find("a.yt-user-name");
            if (!jUserLink.length) return;
            let ytId = jUserLink.attr('data-ytid');

            if (mutedUsers.has(ytId)) {
                jMessage.remove();
                return;
            }

            if (highlightedUsers.has(ytId)) {
                jMessage.addClass("brbtv-highlighted-message");
            }

            jUserLink.click(function (e) {
                jUserMenu.empty();
                let linkPosition = jUserLink.offset();
                jUserMenu.css("top", linkPosition.top + jUserLink.height() + "px");
                jUserMenu.css("left", linkPosition.left + "px");

                let jVisitProfile = createMenuButton("brbtv-visit-button", chrome.i18n.getMessage("userActionVisitProfile"));
                jVisitProfile.attr("href", jUserLink.attr('href'));
                jUserMenu.append(jVisitProfile);

                if (highlightedUsers.has(ytId)) {
                    addUnhighlightUserButton(ytId, jUserLink);
                } else {
                    addHighlightUserButton(ytId, jUserLink);
                }

                if (!mutedUsers.has(ytId)) {
                    addMuteButton(ytId, jUserLink);
                } else {
                    addUnmuteButton(ytId, jUserLink);
                }
                e.preventDefault();
                addHideMenuFunction(jUserLink);
                jUserMenu.addClass("show-brbtv-user-actions-menu");
            });

        }, true);
    });
}<commit_msg>feature: doubleclick on username to use it as a mention<commit_after>function include_user_filter(settings) {
    function createMenuButton(group, label) {
        return $('' + label + '');
    }

    const ADD_ACTION = true;
    const REMOVE_ACTION = false;

    YouTubeLive.onChatLoaded(function (youtube) {
        var theCss = "#brbtv-user-actions-menu {" +
            "background-color: white;" +
            "display: none;" +
            "position: absolute;}\n";
        theCss += ".brbtv-user-actions-item {color: black !important;}";
        theCss += ".show-brbtv-user-actions-menu {display: block !important;}";
        theCss += ".brbtv-highlighted-message .accent-bar {background-color: rgb(204, 0, 0) !important;}";
        theCss += ".brbtv-muted-message .yt-user-name {text-decoration: line-through !important;}";
        addCssToHead(theCss);

        var mutedUsers = new Set();
        for (let i = 0; i < settings.ignoredUsers.length; i++) {
            mutedUsers.add(settings.ignoredUsers[i].id);
        }

        var highlightedUsers = new Set();
        for (let i = 0; i < settings.highlightedUsers.length; i++) {
            highlightedUsers.add(settings.highlightedUsers[i].id);
        }

        chrome.storage.onChanged.addListener(function (changes, namespace) {
            var ignoredUserChange = changes["ignoredUsers"];
            if (ignoredUserChange) {
                mutedUsers = new Set();
                for (let i = 0; i < ignoredUserChange.newValue.length; i++) {
                    mutedUsers.add(ignoredUserChange.newValue[i].id);
                }
            }

            var highlightedUserChange = changes["highlightedUsers"];
            if (highlightedUserChange) {
                highlightedUsers = new Set();
                for (let i = 0; i < highlightedUserChange.newValue.length; i++) {
                    highlightedUsers.add(highlightedUserChange.newValue[i].id);
                }
            }
        });

        var jUserMenu = $('

');
        $("body").prepend(jUserMenu);

        function updateChromeStore(jUserLink, ytId, storageKey, isAddToList) {
            let query = {};
            query[storageKey] = [];
            chrome.storage.sync.get(query, function (items) {
                var theUpdatedArray = items[storageKey];
                if (isAddToList) {
                    theUpdatedArray.push({
                        name: jUserLink.text().trim(),
                        id: ytId,
                        addedTime: Date.now()
                    });
                } else {
                    theUpdatedArray = theUpdatedArray.filter(u => u.id != ytId);
                }

                query[storageKey] = theUpdatedArray;

                chrome.storage.sync.set(query);
            });
        }

        function addHighlightUserButton(ytId, jUserLink) {
            let jHighlightUser = createMenuButton("brbtv-highlight-button", chrome.i18n.getMessage("userActionHighlight"));
            jHighlightUser.click(function (e) {
                if (!highlightedUsers.has(ytId)) {
                    highlightedUsers.add(ytId);
                    updateChromeStore(jUserLink, ytId, "highlightedUsers", ADD_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (jIteratedMessage.find("a.yt-user-name[data-ytid='" + ytId + "']").length) {
                            jIteratedMessage.addClass("brbtv-highlighted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            jUserMenu.append(jHighlightUser);
        }

        function addUnhighlightUserButton(ytId, jUserLink) {
            let jUnhighlightUser = createMenuButton("brbtv-unhighlight-button", chrome.i18n.getMessage("userActionUnHighlight"));
            jUnhighlightUser.click(function (e) {
                if (highlightedUsers.has(ytId)) {
                    highlightedUsers.delete(ytId);
                    updateChromeStore(jUserLink, ytId, "highlightedUsers", REMOVE_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (jIteratedMessage.find("a.yt-user-name[data-ytid='" + ytId + "']").length) {
                            jIteratedMessage.removeClass("brbtv-highlighted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            jUserMenu.append(jUnhighlightUser);
        }

        function addMuteButton(ytId, jUserLink) {
            let jMuteUser = createMenuButton("brbtv-mute-button", chrome.i18n.getMessage("userActionMute"));
            jMuteUser.click(function (e) {
                if (!mutedUsers.has(ytId)) {
                    mutedUsers.add(ytId);
                    updateChromeStore(jUserLink, ytId, "ignoredUsers", ADD_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (jIteratedMessage.find("a.yt-user-name[data-ytid='" + ytId + "']").length) {
                            jIteratedMessage.addClass("brbtv-muted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            jUserMenu.append(jMuteUser);
        }

        function addUnmuteButton(ytId, jUserLink) {
            let jMuteUser = createMenuButton("brbtv-unmute-button", chrome.i18n.getMessage("userActionUnMute"));
            jMuteUser.click(function (e) {
                if (mutedUsers.has(ytId)) {
                    mutedUsers.delete(ytId);
                    updateChromeStore(jUserLink, ytId, "ignoredUsers", REMOVE_ACTION);

                    youtube.iteratePastChatMessages(function (message) {
                        let jIteratedMessage = $(message);
                        if (jIteratedMessage.find("a.yt-user-name[data-ytid='" + ytId + "']").length) {
                            jIteratedMessage.removeClass("brbtv-muted-message");
                        }
                    });
                }
                e.preventDefault();
            });
            jUserMenu.append(jMuteUser);
        }

        function addHideMenuFunction(jUserLink) {
            var hideMenuFunction = function (e) {
                if (e.target != jUserLink[0]) {
                    jUserMenu.removeClass("show-brbtv-user-actions-menu");
                    $(this).off("click", hideMenuFunction);
                }
            };
            $("body").on("click", hideMenuFunction);
        }

        youtube.registerChatMessageObserver(function (message) {
            let jMessage = $(message);
            // don't show menu for yourself or VIP announcements
            if (jMessage.hasClass("author-viewing") || jMessage.hasClass("new-member-announcement")) return;

            var jUserLink = jMessage.find("a.yt-user-name");
            if (!jUserLink.length) return;
            let ytId = jUserLink.attr('data-ytid');

            if (mutedUsers.has(ytId)) {
                jMessage.remove();
                return;
            }

            if (highlightedUsers.has(ytId)) {
                jMessage.addClass("brbtv-highlighted-message");
            }

            jUserLink.click(function (e) {
                jUserMenu.empty();
                let linkPosition = jUserLink.offset();
                jUserMenu.css("top", linkPosition.top + jUserLink.height() + "px");
                jUserMenu.css("left", linkPosition.left + "px");

                let jVisitProfile = createMenuButton("brbtv-visit-button", chrome.i18n.getMessage("userActionVisitProfile"));
                jVisitProfile.attr("href", jUserLink.attr('href'));
                jUserMenu.append(jVisitProfile);

                if (highlightedUsers.has(ytId)) {
                    addUnhighlightUserButton(ytId, jUserLink);
                } else {
                    addHighlightUserButton(ytId, jUserLink);
                }

                if (!mutedUsers.has(ytId)) {
                    addMuteButton(ytId, jUserLink);
                } else {
                    addUnmuteButton(ytId, jUserLink);
                }
                e.preventDefault();
                addHideMenuFunction(jUserLink);
                jUserMenu.addClass("show-brbtv-user-actions-menu");
            });

			// insert the name as a mention on doubleclick
			jUserLink.dblclick( function(e) {

				jUserMenu.removeClass("show-brbtv-user-actions-menu");

				var replacement = '@' + $(e.currentTarget).text() + ' ';
				var textInput = youtube.getChatInputField();
				if (textInput) {

					/* TODO
					*  works roughly, but maybe someday we can use YouTube-own functions for this,
					*  like the one that inserts emojis to the input field when clicking on them
					*
					*  bug: when inserting multiple names, sometimes new names get inserted at the beginning
					*
					*  adapted in parts from http://stackoverflow.com/questions/6690752/insert-html-at-caret-in-a-contenteditable-div/6691294#6691294
					*/

					textInput.focus();

					window.setTimeout(function() {

						var sel, range;
						if (window.getSelection) {
							// IE9 and non-IE
							sel = window.getSelection();
							if (sel.getRangeAt && sel.rangeCount) {
								range = sel.getRangeAt(0);
								range.deleteContents();

								// Range.createContextualFragment() would be useful here but is
								// only relatively recently standardized and is not supported in
								// some browsers (IE9, for one)
								var el = document.createElement("div");
								el.innerHTML = replacement;
								var frag = document.createDocumentFragment(), node, lastNode;
								while ( (node = el.firstChild) ) {
									lastNode = frag.appendChild(node);
								}
								range.insertNode(frag);

								// Preserve the selection
								if (lastNode) {
									range = range.cloneRange();
									range.setStartAfter(lastNode);
									range.collapse(true);
									sel.removeAllRanges();
									sel.addRange(range);
								}
							}
						} else if (document.selection && document.selection.type != "Control") {
							// IE < 9
							document.selection.createRange().pasteHTML(replacement);
						}

					}, 1);

				}

			});

        }, true);
    });
}<|endoftext|>


<commit_before>const asyn = require('async');
const db = require('georap-db');

exports.updateEach = function (collection, iteratee, callback) {
  // Replace each document in a MongoDB collection. Iteratee is the update
  // function, takes in a document and must call the next(err, updatedDocument)
  // callback function. If updatedDocument is null, that document is left
  // unaltered.
  //
  // Parameters:
  //   collection
  //     MongoDB collection
  //   iteratee
  //     function (document, next)
  //       Parameters:
  //         document
  //           collection item
  //         next
  //           function (err, updatedDocument)
  //   callback
  //     function (err, stats), where stats is an object with props:
  //       numDocuments
  //         integer, num of read/processed documents
  //       numUpdated
  //         integer, num of changed documents i.e. where iteratee returned
  //           other than null.
  //
  // Example:
  //
  //   var iter = require('./lib/iter');
  //   var users = db.collection('users');
  //   iter.updateEach(users, function (doc, next) {
  //     doc.name = 'Dr. ' + doc.name;
  //     next(null, doc);
  //   }, function (err) {
  //     if (err) { throw err; }
  //     // else
  //     console.log('Now, everybody is a Doctor.');
  //   });
  //

  collection.find().toArray((err, allDocuments) => {
    if (err) {
      return callback(err);
    }

    const numDocs = allDocuments.length;
    let numUpdated = 0;

    asyn.eachSeries(allDocuments, (doc, eachNext) => {
      let id = doc._id;  // Take before modification

      // Ensure ObjectID.
      if (typeof id === 'string') {
        id = db.id(id);
      }

      try {
        iteratee(doc, (iterateeError, updatedDoc) => {
          if (iterateeError) {
            return eachNext(iterateeError);
          }

          // Skip null docs, no need to replace.
          if (updatedDoc === null) {
            return eachNext(null);
          }

          // Ensure _id is not replaced by an _id literal.
          delete updatedDoc._id;

          collection.replaceOne({ _id: id }, updatedDoc, {}, (err2) => {
            if (err2) {
              return eachNext(err2);
            }

            numUpdated += 1;

            return eachNext(null);
          });
        });
      } catch (e) {
        return eachNext(e);
      }
    }, (err3) => {
      if (err3) {
        return callback(err3);
      }

      return callback(null, {
        numDocuments: numDocs,
        numUpdated: numUpdated,
      });
    });
  });
};
<commit_msg>iter.updateEachReport<commit_after>const asyn = require('async');
const db = require('georap-db');

exports.updateEach = function (collection, iteratee, callback) {
  // Replace each document in a MongoDB collection. Iteratee is the update
  // function, takes in a document and must call the next(err, updatedDocument)
  // callback function. If updatedDocument is null, that document is left
  // unaltered.
  //
  // Parameters:
  //   collection
  //     MongoDB collection
  //   iteratee
  //     function (document, next)
  //       Parameters:
  //         document
  //           collection item
  //         next
  //           function (err, updatedDocument)
  //   callback
  //     function (err, stats), where stats is an object with props:
  //       numDocuments
  //         integer, num of read/processed documents
  //       numUpdated
  //         integer, num of changed documents i.e. where iteratee returned
  //           other than null.
  //
  // Example:
  //
  //   var iter = require('./lib/iter');
  //   var users = db.collection('users');
  //   iter.updateEach(users, function (doc, next) {
  //     doc.name = 'Dr. ' + doc.name;
  //     next(null, doc);
  //   }, function (err) {
  //     if (err) { throw err; }
  //     // else
  //     console.log('Now, everybody is a Doctor.');
  //   });
  //

  collection.find().toArray((err, allDocuments) => {
    if (err) {
      return callback(err);
    }

    const numDocs = allDocuments.length;
    let numUpdated = 0;

    asyn.eachSeries(allDocuments, (doc, eachNext) => {
      let id = doc._id;  // Take before modification

      // Ensure ObjectID.
      if (typeof id === 'string') {
        id = db.id(id);
      }

      try {
        iteratee(doc, (iterateeError, updatedDoc) => {
          if (iterateeError) {
            return eachNext(iterateeError);
          }

          // Skip null docs, no need to replace.
          if (updatedDoc === null) {
            return eachNext(null);
          }

          // Ensure _id is not replaced by an _id literal.
          delete updatedDoc._id;

          collection.replaceOne({ _id: id }, updatedDoc, {}, (err2) => {
            if (err2) {
              return eachNext(err2);
            }

            numUpdated += 1;

            return eachNext(null);
          });
        });
      } catch (e) {
        return eachNext(e);
      }
    }, (err3) => {
      if (err3) {
        return callback(err3);
      }

      return callback(null, {
        numDocuments: numDocs,
        numUpdated: numUpdated,
      });
    });
  });
};

exports.updateEachReport = function (nextStep) {
  // Returns a callback fn for iter.updateEach that
  // outputs iterResults
  //
  return (err, iterResults) => {
    if (err) {
      return nextStep(err);
    }

    console.log('  ' + iterResults.numDocuments + ' docs processed ' +
      'successfully.');
    console.log('  ' + iterResults.numUpdated + ' docs updated, ' +
      (iterResults.numDocuments - iterResults.numUpdated) + ' did not ' +
      'need an update');

    return nextStep();
  };
};
<|endoftext|>