<commit_before>module.exports = function (grunt) {
  "use strict";

  var _ = require("lodash");
  var log = require("./gruntLogHelper.js")(grunt);
  var basePath = require("path").dirname(grunt.option("gruntfile"));

  var gruntFileConfig = basePath + "/gruntfileConfig.json";
  var config = grunt.file.readJSON(gruntFileConfig);

  function root(path) {
    return getPath(config.root, path);
  }

  function integrate(path) {
    return getPath(config.integrate, path)
  }

  function release(path) {
    return getPath(config.release, path);
  }

  function build(path) {
    return getPath(config.build, path);
  }

  function src(path) {
    return getPath(config.src, path);
  }

  function assets(path) {
    return getPath(config.assets, path);
  }

  function theme(path) {
    return getPath(config.theme, path);
  }

  function getPath(configPath, path) {
    path = path || "";
    return configPath + path;
  }

  // return an array of paths with the src prepended
  // this should return the array in the same order it was configured
  // this is important because the styles may need to be processed in a
  // specific order for css cascading needs.
  function allPatternStructurePaths(path) {
    return _.map(config.patternStructure, function (structure) {
      return getPath(config.src + "/" + structure.path, path);
    });
  }

  function getBuildTasks(tasksConfig) {
    var buildTasks = ["clean:build", "styles-patterns"];
    var patternsTasks = ["assemble-patterns"];
    var patternLibraryTasks = ["assemble-pattern-library"];

    if (tasksConfig.library) {
      buildTasks = buildTasks.concat(patternLibraryTasks);
    }

    if (tasksConfig.patterns) {
      buildTasks = buildTasks.concat(patternsTasks);
    }

    log.verbose("PatternPack Grunt Tasks:");
    log.verbose(buildTasks);
    return buildTasks;
  }

  function getStyleTasks(cssPreprocessorConfig) {
    var sassTasks = ["sass_globbing:sass", "sass"];
    var lessTasks = ["sass_globbing:less", "less"];
    var cssTasks = ["autoprefixer:patterns", "copy:css"];
    var tasks = [];

    if (cssPreprocessorConfig === "sass") {
      tasks = tasks.concat(sassTasks);
    } else if (cssPreprocessorConfig === "less") {
      tasks = tasks.concat(lessTasks);
    }

    tasks = tasks.concat(cssTasks);

    log.verbose("PatternPack CSS Preprocessor Tasks:");
    log.verbose(tasks);
    return tasks;
  }

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

    gitadd: {
      task: {
        options: {
          all: true
        }
      }
    },

    bump: {
      options: {
        files: [
          root("/bower.json"),
          root("/package.json")
        ],
        updateConfigs: ["pkg"],
        commitFiles: ["-a"],
        push: false
      }
    },

    // Concurent tasks
    concurrent: {
      build: ["styles", "assemble"]
    },

    // Build HTML with Assemble.io
    assemble: {
      options: {
        patternStructure: config.patternStructure,
        helpers: ["assemble-helpers/assemble-helper-*.js"],
        partials: theme("/partials/*.hbs"),
        postprocess: require("pretty")
      },
      // Build the pattern library (fully functioning website)
      patternlibrary: {
        options: {
          assets: build("/pattern-library/assets"),
          layout: theme("/layouts/_pattern-library.hbs")
        },
        files: [
          {
            expand: true,
            cwd: src(),
            src: ["**/*.{md,hbs}", "!_pattern-library/**"],
            dest: build("/pattern-library/")
          }
        ]
      },
      // Bulid the patterns as raw html only (designed to be embedded in another website)
      patterns: {
        files: [
          {
            expand: true,
            cwd: src(),
            src: ["**/*.{md,hbs}", "!_pattern-library/**"],
            dest: build("/patterns/")
          }
        ]
      }
    },

    // Remove existing build artifacts
    clean: {
      options: {
        force: true
      },
      build: build(),
      release: release()
    },

    // Copy the artifacts for release
    copy: {
      release: {
        expand: true,
        cwd: build(),
        src: [
          "**",
          "!pattern-library/theme-assets/**"
        ],
        dest: release()
      },
      integrate: {
        expand: true,
        cwd: build(),
        src: [
          "**",
          "!pattern-library/theme-assets/**"
        ],
        dest: integrate()
      },
      css: {
        src: assets("/css/patterns.css"),
        dest: build("/css/patterns.css")
      },
      assets: {
        expand: true,
        cwd: assets(),
        src: [
          "**",
          "!sass/**"
        ],
        dest: build("/pattern-library/assets")
      },
      themeAssets: {
        expand: true,
        cwd: theme(),
        src: [
          "theme-assets/**"
        ],
        dest: build("/pattern-library")
      }
    },

    // Build styles
    sass: {
      options: {
        sourceMap: true,
        sourceMapContents: true,
        outputStyle: "compressed"
      },
      patterns: {
        files: [
          {
            src: assets("/sass/patterns.scss"),
            dest: assets("/css/patterns.css")
          }
        ]
      }
    },

    less: {
      options: {
        sourceMap: true,
        outputSourceFiles: true,
        compress: true
      },
      patterns: {
        files: [
          {
            src: assets("/less/patterns.less"),
            dest: assets("/css/patterns.css")
          }
        ]
      }
    },

    // Import all sass styles defined for patterns
    // Use the pattern structures to ensure that the styles are processed
    // in the specific order the user configures.
    "sass_globbing": {
      sass: {
        src: allPatternStructurePaths("/**/*.scss"),
        dest: assets("/sass/patternpack-patterns.scss")
      },
      less: {
        src: allPatternStructurePaths("/**/*.less"),
        dest: assets("/less/patternpack-patterns.less")
      }
    },

    autoprefixer: {
      options: {
        browsers: ["last 2 versions", "ie >= 9"],
        map: {
          inline: false
        }
      },
      patternlibrary: {
        files: [{
          expand: true,
          flatten: true,
          src: build("/pattern-library/assets/css/*.css"),
          dest: build("/pattern-library/assets/css/")
        }]
      },
      patterns: {
        files: [
          {
            expand: true,
            flatten: true,
            src: build("/css/*.css"),
            dest: build("/css/")
          }
        ]
      }
    },

    // Run tasks when files change
    watch: {
      assemble: {
        files: [
          theme("/**/*.{md,hbs}"),
          src("/**/*.{md,hbs}")
        ],
        tasks: ["assemble:patternlibrary"]
      },
      sass: {
        files: src("/**/*.scss"),
        tasks: ["styles-patterns"]
      },
      livereload: {
        files: build("/pattern-library/**"),
        options: {
          livereload: true
        }
      }
    },

    // Web server
    connect: {
      options: {
        base: build("/pattern-library"),
        hostname: "*"
      },
      server: {
        options: config.server
      }
    },

    eslint: {
      target: [
        "**/*.js",
        "!node_modules/**"
      ]
    }
  });

  // Load the tasks using the load-grunt-parent-tasks module.
  // This allows the grun tasks to still be loaded when the
  // calling pattern library happens to contain one of the
  // dependencies used by pattern pack.  For more info:
  // https://www.npmjs.com/package/load-grunt-parent-tasks
  require("load-grunt-parent-tasks")(grunt, {
    // The globbing pattern used to locate the desired grunt tasks
    pattern: [
      "grunt-*",
      "assemble"
    ],
    // The list of dependencies to include
    // ["dependencies", "optionalDependencies"]
    scope: ["dependencies"]
  });

  // Modular tasks
  // These smaller grunt tasks organize work into logical groups
  // and are typically composed together into workflows
  grunt.registerTask("styles-patterns", getStyleTasks(config.cssPreprocessor));
  grunt.registerTask("assemble-patterns", ["assemble:patterns"]);
  grunt.registerTask("assemble-pattern-library", ["assemble:patternlibrary", "copy:assets", "copy:themeAssets"]);

  grunt.registerTask("server", ["connect", "watch"]);

  grunt.registerTask("release-patch", ["clean:release", "copy:release", "gitadd", "bump:patch"]);
  grunt.registerTask("release-minor", ["clean:release", "copy:release", "gitadd", "bump:minor"]);
  grunt.registerTask("release-major", ["clean:release", "copy:release", "gitadd", "bump:major"]);

  // Main tasks
  grunt.registerTask("integrate", ["build", "copy:integrate"]);
  grunt.registerTask("release", ["clean:release", "copy:release", "release-patch"]);
  grunt.registerTask("build", getBuildTasks(config.publish));
  grunt.registerTask("default", ["build", "server"]);
};
<commit_msg>Added copy task to CSS<commit_after>module.exports = function (grunt) {
  "use strict";

  var _ = require("lodash");
  var log = require("./gruntLogHelper.js")(grunt);
  var basePath = require("path").dirname(grunt.option("gruntfile"));

  var gruntFileConfig = basePath + "/gruntfileConfig.json";
  var config = grunt.file.readJSON(gruntFileConfig);

  function root(path) {
    return getPath(config.root, path);
  }

  function integrate(path) {
    return getPath(config.integrate, path)
  }

  function release(path) {
    return getPath(config.release, path);
  }

  function build(path) {
    return getPath(config.build, path);
  }

  function src(path) {
    return getPath(config.src, path);
  }

  function assets(path) {
    return getPath(config.assets, path);
  }

  function theme(path) {
    return getPath(config.theme, path);
  }

  function getPath(configPath, path) {
    path = path || "";
    return configPath + path;
  }

  // return an array of paths with the src prepended
  // this should return the array in the same order it was configured
  // this is important because the styles may need to be processed in a
  // specific order for css cascading needs.
  function allPatternStructurePaths(path) {
    return _.map(config.patternStructure, function (structure) {
      return getPath(config.src + "/" + structure.path, path);
    });
  }

  function getBuildTasks(tasksConfig) {
    var buildTasks = ["clean:build", "styles-patterns"];
    var patternsTasks = ["assemble-patterns"];
    var patternLibraryTasks = ["assemble-pattern-library"];

    if (tasksConfig.library) {
      buildTasks = buildTasks.concat(patternLibraryTasks);
    }

    if (tasksConfig.patterns) {
      buildTasks = buildTasks.concat(patternsTasks);
    }

    log.verbose("PatternPack Grunt Tasks:");
    log.verbose(buildTasks);
    return buildTasks;
  }

  function getStyleTasks(cssPreprocessorConfig) {
    var sassTasks = ["sass_globbing:sass", "sass"];
    var lessTasks = ["sass_globbing:less", "less"];
    var cssTasks = ["autoprefixer:patterns", "copy:css"];
    var tasks = [];

    if (cssPreprocessorConfig === "sass") {
      tasks = tasks.concat(sassTasks);
    } else if (cssPreprocessorConfig === "less") {
      tasks = tasks.concat(lessTasks);
    }

    tasks = tasks.concat(cssTasks);

    log.verbose("PatternPack CSS Preprocessor Tasks:");
    log.verbose(tasks);
    return tasks;
  }

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

    gitadd: {
      task: {
        options: {
          all: true
        }
      }
    },

    bump: {
      options: {
        files: [
          root("/bower.json"),
          root("/package.json")
        ],
        updateConfigs: ["pkg"],
        commitFiles: ["-a"],
        push: false
      }
    },

    // Concurent tasks
    concurrent: {
      build: ["styles", "assemble"]
    },

    // Build HTML with Assemble.io
    assemble: {
      options: {
        patternStructure: config.patternStructure,
        helpers: ["assemble-helpers/assemble-helper-*.js"],
        partials: theme("/partials/*.hbs"),
        postprocess: require("pretty")
      },
      // Build the pattern library (fully functioning website)
      patternlibrary: {
        options: {
          assets: build("/pattern-library/assets"),
          layout: theme("/layouts/_pattern-library.hbs")
        },
        files: [
          {
            expand: true,
            cwd: src(),
            src: ["**/*.{md,hbs}", "!_pattern-library/**"],
            dest: build("/pattern-library/")
          }
        ]
      },
      // Bulid the patterns as raw html only (designed to be embedded in another website)
      patterns: {
        files: [
          {
            expand: true,
            cwd: src(),
            src: ["**/*.{md,hbs}", "!_pattern-library/**"],
            dest: build("/patterns/")
          }
        ]
      }
    },

    // Remove existing build artifacts
    clean: {
      options: {
        force: true
      },
      build: build(),
      release: release()
    },

    // Copy the artifacts for release
    copy: {
      release: {
        expand: true,
        cwd: build(),
        src: [
          "**",
          "!pattern-library/theme-assets/**"
        ],
        dest: release()
      },
      integrate: {
        expand: true,
        cwd: build(),
        src: [
          "**",
          "!pattern-library/theme-assets/**"
        ],
        dest: integrate()
      },
      css: {
        src: assets("/css/patterns.css"),
        dest: build("/css/patterns.css")
      },
      assets: {
        expand: true,
        cwd: assets(),
        src: [
          "**",
          "!sass/**"
        ],
        dest: build("/pattern-library/assets")
      },
      themeAssets: {
        expand: true,
        cwd: theme(),
        src: [
          "theme-assets/**"
        ],
        dest: build("/pattern-library")
      }
    },

    // Build styles
    sass: {
      options: {
        sourceMap: true,
        sourceMapContents: true,
        outputStyle: "compressed"
      },
      patterns: {
        files: [
          {
            src: assets("/sass/patterns.scss"),
            dest: assets("/css/patterns.css")
          }
        ]
      }
    },

    less: {
      options: {
        sourceMap: true,
        outputSourceFiles: true,
        compress: true
      },
      patterns: {
        files: [
          {
            src: assets("/less/patterns.less"),
            dest: assets("/css/patterns.css")
          }
        ]
      }
    },

    // Import all sass styles defined for patterns
    // Use the pattern structures to ensure that the styles are processed
    // in the specific order the user configures.
    "sass_globbing": {
      sass: {
        src: allPatternStructurePaths("/**/*.scss"),
        dest: assets("/sass/patternpack-patterns.scss")
      },
      less: {
        src: allPatternStructurePaths("/**/*.less"),
        dest: assets("/less/patternpack-patterns.less")
      }
    },

    autoprefixer: {
      options: {
        browsers: ["last 2 versions", "ie >= 9"],
        map: {
          inline: false
        }
      },
      patternlibrary: {
        files: [{
          expand: true,
          flatten: true,
          src: build("/pattern-library/assets/css/*.css"),
          dest: build("/pattern-library/assets/css/")
        }]
      },
      patterns: {
        files: [
          {
            expand: true,
            flatten: true,
            src: build("/css/*.css"),
            dest: build("/css/")
          }
        ]
      }
    },

    // Run tasks when files change
    watch: {
      assemble: {
        files: [
          theme("/**/*.{md,hbs}"),
          src("/**/*.{md,hbs}")
        ],
        tasks: ["assemble:patternlibrary"]
      },
      sass: {
        files: src("/**/*.scss"),
        tasks: ["styles-patterns", "copy:css"]
      },
      livereload: {
        files: build("/pattern-library/**"),
        options: {
          livereload: true
        }
      }
    },

    // Web server
    connect: {
      options: {
        base: build("/pattern-library"),
        hostname: "*"
      },
      server: {
        options: config.server
      }
    },

    eslint: {
      target: [
        "**/*.js",
        "!node_modules/**"
      ]
    }
  });

  // Load the tasks using the load-grunt-parent-tasks module.
  // This allows the grun tasks to still be loaded when the
  // calling pattern library happens to contain one of the
  // dependencies used by pattern pack.  For more info:
  // https://www.npmjs.com/package/load-grunt-parent-tasks
  require("load-grunt-parent-tasks")(grunt, {
    // The globbing pattern used to locate the desired grunt tasks
    pattern: [
      "grunt-*",
      "assemble"
    ],
    // The list of dependencies to include
    // ["dependencies", "optionalDependencies"]
    scope: ["dependencies"]
  });

  // Modular tasks
  // These smaller grunt tasks organize work into logical groups
  // and are typically composed together into workflows
  grunt.registerTask("styles-patterns", getStyleTasks(config.cssPreprocessor));
  grunt.registerTask("assemble-patterns", ["assemble:patterns"]);
  grunt.registerTask("assemble-pattern-library", ["assemble:patternlibrary", "copy:assets", "copy:themeAssets"]);

  grunt.registerTask("server", ["connect", "watch"]);

  grunt.registerTask("release-patch", ["clean:release", "copy:release", "gitadd", "bump:patch"]);
  grunt.registerTask("release-minor", ["clean:release", "copy:release", "gitadd", "bump:minor"]);
  grunt.registerTask("release-major", ["clean:release", "copy:release", "gitadd", "bump:major"]);

  // Main tasks
  grunt.registerTask("integrate", ["build", "copy:integrate"]);
  grunt.registerTask("release", ["clean:release", "copy:release", "release-patch"]);
  grunt.registerTask("build", getBuildTasks(config.publish));
  grunt.registerTask("default", ["build", "server"]);
};
<|endoftext|>


<commit_before>// gruntfile.js
//
// Author: blinklv <blinklv@icloud.com>
// Create Time: 2017-03-22
// Maintainer: blinklv <blinklv@icloud.com>
// Last Change: 2017-05-03
// Purpose: The gruntfile.js for Web development.

module.exports = function(grunt) {

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

        // Watch all files.
        watch: {
            sass: {
                files: ["sass/*.sass", "sass/*.scss"],
                tasks: ["sass", "concat:css"]
            },
            css: {
                files: ["css/*.css", "!css/*.min.css"],
                tasks: ["concat:css"]
            },
            js: {
                files: ["js/*.js", "!js/main.js","!js/*.min.js"],
                tasks: ["concat:js", "jshint"]
            },
            html: {
                files: ["index.html", "html/**/*.html"],
                tasks: ["copy:devel"]
            },
            img: {
                files: ["img/**/*.{gif,jpg,jpeg,png,svg}"],
                tasks: ["responsive_images", "copy:devel"]
            }
        },

        // Copy files to build/devel directory.
        copy: {
            devel: {
                files: [{
                    expand: true,
                    flatten: true,
                    cwd: "vendor/",
                    src: ["**/*.css", "!**/*.min.css"],
                    dest: "build/devel/css/",
                },{
                    expand: true,
                    flatten: true,
                    cwd: "vendor/",
                    src: ["**/*.js", "!**/*.min.js"],
                    dest: "build/devel/js/",
                },{
                    expand: true,
                    src: ["index.html", "html/**/*.html"],
                    dest: "build/devel/"
                },{
                    expand: true,
                    cwd: "img/",
                    src: ["**/*.svg"],
                    dest: "build/devel/img/"
                },{
                    expand: true,
                    cwd: "font/",
                    src: ["**/*.woff", "**/*.woff2"],
                    dest: "build/devel/font/"
                },{
                    expand: true,
                    cwd: "font/",
                    src: ["**/*.css"],
                    dest: "build/devel/css/font/"
                }]
            },
            release: {
                files: [{
                    expand: true,
                    cwd: "build/devel/",
                    src: ["index.html", "html/**/*.html"],
                    dest: "build/release/"
                },{
                    expand: true,
                    cwd: "build/devel/img/",
                    src: ["**/*.{gif,jpg,jpeg,png,svg}"],
                    dest: "build/release/img/"
                },{
                    expand: true,
                    cwd: "build/devel/font/",
                    src: ["**/*.woff", "**/*.woff2"],
                    dest: "build/release/font/"
                }]
            }
        },

        // Generate multi-resolution images.
        responsive_images: {
            normal: {
                options: {
                    engine: "im",
                    sizes: [{
                        name: "s",
                        width: 320,
                        quality: 70
                    },{
                        name: "m",
                        width: 480,
                        quality: 70
                    },{
                        name: "l",
                        width: 600,
                        quality: 70
                    },{
                        name: "xl",
                        width: 1024,
                        quality: 70
                    },{
                        name: "xxl",
                        width: 1440,
                        quality: 70
                    }]
                },
                files: [{
                    expand: true,
                    cwd: "img/",
                    src: ["**/*.{gif,jpg,jpeg,png}","!**/logo.{gif,jpg,jpeg,png}","!**/*{-,_}logo.{gif,jpg,jpeg,png}"],
                    dest: "build/devel/img/"
                }]
            },

            // The shape of orignal logo picture is preferably square.
            logo: {
                options: {
                    engine: "im",
                    sizes: [{
                        name: "s",
                        width: 48
                    },{
                        name: "m",
                        width: 128,
                        quality: 90
                    },{
                        name: "l",
                        width: 256,
                        quality: 70
                    }]
                },
                files: [{
                    expand: true,
                    cwd: "img/",
                    src: ["**/logo.{gif,jpg,jpeg,png}", "**/*{-,_}logo.{gif,jpg,jpeg,png}"],
                    dest: "build/devel/img/"
                }]
            }
        },

        jshint: {
            options: {
                curly: true,
                eqeqeq: true,
                eqnull: true,
                browser: true,
                globals: {
                    jQuery: true
                },
            },
            target: ["gruntfile.js", "js/*.js", "build/devel/js/main.js"]
        },

        // Concatenate files, but exclude some files of 'min' suffix.
        concat: {
            css: {
                src: ["css/*.css", "!css/main.css","!css/*.min.css"],
                dest: "build/devel/css/main.css"
            },
            js: {
                src: ["js/*.js", "!js/main.js", "!js/*.min.js"],
                dest: "build/devel/js/main.js"
            }
        },

        // Compiling SASS files to CSS files.
        sass: {
            target: {
                files: [{
                    expand: true,
                    cwd: "sass/",
                    src: ["*.sass", "*.scss"],
                    dest: "css/",
                    ext: ".css"
                }]
            }
        },

        // Remove unused CSS.
        uncss: {
            target: {
                files: {
                    "build/devel/css/tidy.css": "build/devel/**/*.html"
                }
            }
        },

        // Minifying CSS files.
        cssmin: {
            target: {
                src: "build/devel/css/tidy.css",
                dest: "build/release/css/main.min.css"
            }
        },

        // Minifying JS files.
        uglify: {
            options: {
                mangle: false,
                compress: {
                    drop_console: true
                }
            },
            target: {
                files: [{
                    expand: true,
                    flatten: true,
                    cwd: "build/devel/js/",
                    src: "**/*.js",
                    dest: "build/release/js/",
                    ext: ".min.js",
                    extDot: "last"
                }]
            }
        },

        // Adding a banner information to some files.
        usebanner: {
            options: {
                position: "top",
                banner: "<%= create_banner() %>"
            },
            css: {
                src: "build/devel/css/main.css"
            },
            js: {
                src: "build/devel/js/main.js"
            }
        },

        clean: {
            devel: ["build/devel"],
            release: ["build/release"]
        },

        // Auxiliary method.
        create_banner: function() {
            var str = "";
            var pkg = this.pkg;

            // If 'pkg.name' is empty, the 'banner' is empty too.
            if (pkg.name) {
                str = "/*! " + pkg.name;
                str = pkg.version ? str + " v" + pkg.version : str;
                str += " " + grunt.template.today("yyyy-mm-dd");
                str = pkg.license ? str + " | " + pkg.license : str;
                str = pkg.url ? str +  " | " + pkg.url : str;
                str += " */";
            }

            return str;
        }
    });

    grunt.loadNpmTasks("grunt-contrib-watch");
    grunt.loadNpmTasks("grunt-responsive-images");
    grunt.loadNpmTasks("grunt-contrib-jshint");
    grunt.loadNpmTasks("grunt-contrib-copy");
    grunt.loadNpmTasks("grunt-uncss");
    grunt.loadNpmTasks("grunt-contrib-sass");
    grunt.loadNpmTasks("grunt-contrib-concat");
    grunt.loadNpmTasks("grunt-contrib-cssmin");
    grunt.loadNpmTasks("grunt-contrib-uglify");
    grunt.loadNpmTasks("grunt-contrib-clean");
    grunt.loadNpmTasks("grunt-banner");

    grunt.registerTask("devel", ["sass", "concat", "jshint", "usebanner", "responsive_images", "copy:devel"]);
    grunt.registerTask("release", ["devel", "uncss", "cssmin", "uglify", "copy:release"]);
    grunt.registerTask("rebuild-devel", ["clean:devel", "devel"]);
    grunt.registerTask("rebuild", ["clean", "release"]);
    grunt.registerTask("default", ["release"]);
};

<commit_msg>Update gruntfile.js file.<commit_after>// gruntfile.js
//
// Author: blinklv <blinklv@icloud.com>
// Create Time: 2017-03-22
// Maintainer: blinklv <blinklv@icloud.com>
// Last Change: 2017-05-03
// Purpose: The gruntfile.js for Web development.

module.exports = function(grunt) {

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

        // Watch all files.
        watch: {
            sass: {
                files: ["sass/*.sass", "sass/*.scss"],
                tasks: ["sass", "concat:css"]
            },
            css: {
                files: ["css/*.css", "!css/*.min.css"],
                tasks: ["concat:css"]
            },
            js: {
                files: ["js/*.js", "!js/main.js","!js/*.min.js"],
                tasks: ["concat:js", "jshint"]
            },
            html: {
                files: ["index.html", "html/**/*.html"],
                tasks: ["copy:devel"]
            },
            img: {
                files: ["img/**/*.{gif,jpg,jpeg,png,svg}"],
                tasks: ["responsive_images", "copy:devel"]
            }
        },

        // Copy files to build/devel directory.
        copy: {
            devel: {
                files: [{
                    expand: true,
                    flatten: true,
                    cwd: "vendor/",
                    src: ["**/*.css", "!**/*.min.css"],
                    dest: "build/devel/css/",
                },{
                    expand: true,
                    flatten: true,
                    cwd: "vendor/",
                    src: ["**/*.js", "!**/*.min.js"],
                    dest: "build/devel/js/",
                },{
                    expand: true,
                    src: ["index.html", "html/**/*.html"],
                    dest: "build/devel/"
                },{
                    expand: true,
                    cwd: "img/",
                    src: ["**/*.svg"],
                    dest: "build/devel/img/"
                },{
                    expand: true,
                    cwd: "font/",
                    src: ["**/*.woff", "**/*.woff2"],
                    dest: "build/devel/font/"
                }]
            },
            release: {
                files: [{
                    expand: true,
                    cwd: "build/devel/",
                    src: ["index.html", "html/**/*.html"],
                    dest: "build/release/"
                },{
                    expand: true,
                    cwd: "build/devel/img/",
                    src: ["**/*.{gif,jpg,jpeg,png,svg}"],
                    dest: "build/release/img/"
                },{
                    expand: true,
                    cwd: "build/devel/font/",
                    src: ["**/*.woff", "**/*.woff2"],
                    dest: "build/release/font/"
                }]
            }
        },

        // Generate multi-resolution images.
        responsive_images: {
            normal: {
                options: {
                    engine: "im",
                    sizes: [{
                        name: "s",
                        width: 320,
                        quality: 70
                    },{
                        name: "m",
                        width: 480,
                        quality: 70
                    },{
                        name: "l",
                        width: 600,
                        quality: 70
                    },{
                        name: "xl",
                        width: 1024,
                        quality: 70
                    },{
                        name: "xxl",
                        width: 1440,
                        quality: 70
                    }]
                },
                files: [{
                    expand: true,
                    cwd: "img/",
                    src: ["**/*.{gif,jpg,jpeg,png}","!**/logo.{gif,jpg,jpeg,png}","!**/*{-,_}logo.{gif,jpg,jpeg,png}"],
                    dest: "build/devel/img/"
                }]
            },

            // The shape of orignal logo picture is preferably square.
            logo: {
                options: {
                    engine: "im",
                    sizes: [{
                        name: "s",
                        width: 48
                    },{
                        name: "m",
                        width: 128,
                        quality: 90
                    },{
                        name: "l",
                        width: 256,
                        quality: 70
                    }]
                },
                files: [{
                    expand: true,
                    cwd: "img/",
                    src: ["**/logo.{gif,jpg,jpeg,png}", "**/*{-,_}logo.{gif,jpg,jpeg,png}"],
                    dest: "build/devel/img/"
                }]
            }
        },

        jshint: {
            options: {
                curly: true,
                eqeqeq: true,
                eqnull: true,
                browser: true,
                globals: {
                    jQuery: true
                },
            },
            target: ["gruntfile.js", "js/*.js", "build/devel/js/main.js"]
        },

        // Concatenate files, but exclude some files of 'min' suffix.
        concat: {
            css: {
                src: ["css/*.css", "font/*.css", "!css/main.css","!css/*.min.css"],
                dest: "build/devel/css/main.css"
            },
            js: {
                src: ["js/*.js", "!js/main.js", "!js/*.min.js"],
                dest: "build/devel/js/main.js"
            }
        },

        // Compiling SASS files to CSS files.
        sass: {
            target: {
                files: [{
                    expand: true,
                    cwd: "sass/",
                    src: ["*.sass", "*.scss"],
                    dest: "css/",
                    ext: ".css"
                }]
            }
        },

        // Remove unused CSS.
        uncss: {
            target: {
                files: {
                    "build/devel/css/tidy.css": "build/devel/**/*.html"
                }
            }
        },

        // Minifying CSS files.
        cssmin: {
            target: {
                src: "build/devel/css/tidy.css",
                dest: "build/release/css/main.min.css"
            }
        },

        // Minifying JS files.
        uglify: {
            options: {
                mangle: false,
                compress: {
                    drop_console: true
                }
            },
            target: {
                files: [{
                    expand: true,
                    flatten: true,
                    cwd: "build/devel/js/",
                    src: "**/*.js",
                    dest: "build/release/js/",
                    ext: ".min.js",
                    extDot: "last"
                }]
            }
        },

        // Adding a banner information to some files.
        usebanner: {
            options: {
                position: "top",
                banner: "<%= create_banner() %>"
            },
            css: {
                src: "build/devel/css/main.css"
            },
            js: {
                src: "build/devel/js/main.js"
            }
        },

        clean: {
            devel: ["build/devel"],
            release: ["build/release"]
        },

        // Auxiliary method.
        create_banner: function() {
            var str = "";
            var pkg = this.pkg;

            // If 'pkg.name' is empty, the 'banner' is empty too.
            if (pkg.name) {
                str = "/*! " + pkg.name;
                str = pkg.version ? str + " v" + pkg.version : str;
                str += " " + grunt.template.today("yyyy-mm-dd");
                str = pkg.license ? str + " | " + pkg.license : str;
                str = pkg.url ? str +  " | " + pkg.url : str;
                str += " */";
            }

            return str;
        }
    });

    grunt.loadNpmTasks("grunt-contrib-watch");
    grunt.loadNpmTasks("grunt-responsive-images");
    grunt.loadNpmTasks("grunt-contrib-jshint");
    grunt.loadNpmTasks("grunt-contrib-copy");
    grunt.loadNpmTasks("grunt-uncss");
    grunt.loadNpmTasks("grunt-contrib-sass");
    grunt.loadNpmTasks("grunt-contrib-concat");
    grunt.loadNpmTasks("grunt-contrib-cssmin");
    grunt.loadNpmTasks("grunt-contrib-uglify");
    grunt.loadNpmTasks("grunt-contrib-clean");
    grunt.loadNpmTasks("grunt-banner");

    grunt.registerTask("devel", ["sass", "concat", "jshint", "usebanner", "responsive_images", "copy:devel"]);
    grunt.registerTask("release", ["devel", "uncss", "cssmin", "uglify", "copy:release"]);
    grunt.registerTask("rebuild-devel", ["clean:devel", "devel"]);
    grunt.registerTask("rebuild", ["clean", "release"]);
    grunt.registerTask("default", ["release"]);
};

<|endoftext|>


<commit_before>var semver = require('semver'),
	format = require('util').format;

module.exports = function(grunt) {

    grunt.initConfig({

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

        banner: [
            ' // ----------------------------------------------------------------------------',
            ' // <%= pkg.description %>',
            ' // v<%= pkg.version %> - released <%= grunt.template.today("yyyy-mm-dd HH:MM") %>',
            ' // Licensed under the MIT license.',
            ' // http://buzz.jaysalvat.com/',
            ' // ----------------------------------------------------------------------------',
            ' // Copyright (C) 2010-<%= grunt.template.today("yyyy") %> Jay Salvat',
            ' // http://jaysalvat.com/',
            ' // ----------------------------------------------------------------------------',
            '\n'
        ].join('\n'),

        jshint: {
            files: ['gruntfile.js', 'src/**/*.js']
        },

        uglify: {
            options: {
                banner: '<%= banner %>'
            },
            js: {
                options: {
                    mangle: false,
                    compress: false,
                    beautify: true
                },
                src: 'src/<%= pkg.name %>.js',
                dest: 'dist/<%= pkg.name %>.js'
            },
            jsmin: {
                options: {
                    mangle: true,
                    compress: true
                },
                src: 'dist/<%= pkg.name %>.js',
                dest: 'dist/<%= pkg.name %>.min.js'
            }
        },

        exec: {
            publish: {
                cmd: [
                    'cp -r dist/ tmp/',
                    'zip -rj tmp/buzz.zip tmp/buzz.js',
                    'zip -rj tmp/buzz.zip tmp/buzz.min.js',
                    'git checkout gh-pages',
                    'rm -rf releases/latest/',
                    'cp -r tmp/ releases/<%= pkg.version %>/',
                    'cp -r tmp/ releases/latest/',
                    'git add -A releases/<%= pkg.version %>',
                    'git add -A releases/latest',
                    'git commit -m "Published v<%= pkg.version %>."',
                    'git push',
                    'git checkout -',
                    'rm -rf tmp/'
                ].join(' && ')
            },
            gitFailIfDirty: {
                cmd: 'test -z "$(git status --porcelain)"'
            },
            gitAdd: {
                cmd: 'git add .'
            },
            gitCommit: {
                cmd: function(message) {
                    return format('git commit -m "Build %s"', message);
                }
            },
            gitTag: {
                cmd: function(version) {
                    return format('git tag v%s -am "%s"', version, version);
                }
            },
            gitPush: {
                cmd: [
                    'git push',
                    'git push --tags'
                ].join(' && ')
            }
        }
    });

    grunt.loadNpmTasks('grunt-exec');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-uglify');

    grunt.registerTask('build',   ['jshint', 'uglify']);
    grunt.registerTask('publish', ['exec:publish']);
    grunt.registerTask('default', ['build']);

    grunt.registerTask('release', 'Release lib.', function(version) {
        var pkg = grunt.file.readJSON('package.json');

        version = semver.inc(pkg.version, version) || version;

        if (!semver.valid(version) || semver.lte(version, pkg.version)) {
            grunt.fatal('Invalid version.');
        }

        pkg.version = version;
        grunt.config.data.pkg = pkg;

        grunt.task.run([
            'exec:gitFailIfDirty',
            'build',
            'metadata:' + version,
            'manifests:' + version,
            'exec:gitAdd',
            'exec:gitCommit:' + version,
            'exec:gitTag:' + version,
            'exec:gitPush',
            'exec:publish'
        ]);
    });

    grunt.registerTask('manifests', 'Update manifests.', function(version) {
        var _   = grunt.util._,
            pkg = grunt.file.readJSON('package.json'),
            cpt = grunt.file.readJSON('component.json');

        if (!semver.valid(version)) {
            grunt.fatal('Invalid version');
        }

        pkg.version = version;

        cpt = JSON.stringify(_.extend(cpt,
            _.omit(pkg, 'dependencies', 'devDependencies')
        ), null, 2);

        pkg = JSON.stringify(pkg, null, 2);

        grunt.file.write('package.json', pkg);
        grunt.file.write('component.json', cpt);
    });

    grunt.registerTask('metadata', 'Create metadata file.', function(version) {
        var metadata = {
            'date': grunt.template.today("yyyy-mm-dd HH:MM:ss"),
            'version': version
        };

        grunt.file.write('dist/metadata.json', JSON.stringify(metadata, null, 2));
    });
};<commit_msg>Update gruntfile<commit_after>var semver = require('semver'),
	format = require('util').format;

module.exports = function(grunt) {

    grunt.initConfig({

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

        banner: [
            ' // ----------------------------------------------------------------------------',
            ' // <%= pkg.description %>',
            ' // v<%= pkg.version %> - released <%= grunt.template.today("yyyy-mm-dd HH:MM") %>',
            ' // Licensed under the MIT license.',
            ' // http://buzz.jaysalvat.com/',
            ' // ----------------------------------------------------------------------------',
            ' // Copyright (C) 2010-<%= grunt.template.today("yyyy") %> Jay Salvat',
            ' // http://jaysalvat.com/',
            ' // ----------------------------------------------------------------------------',
            '\n'
        ].join('\n'),

        jshint: {
            files: ['gruntfile.js', 'src/**/*.js']
        },

        uglify: {
            options: {
                banner: '<%= banner %>'
            },
            js: {
                options: {
                    mangle: false,
                    compress: false,
                    beautify: true
                },
                src: 'src/<%= pkg.name %>.js',
                dest: 'dist/<%= pkg.name %>.js'
            },
            jsmin: {
                options: {
                    mangle: true,
                    compress: true
                },
                src: 'dist/<%= pkg.name %>.js',
                dest: 'dist/<%= pkg.name %>.min.js'
            }
        },

        exec: {
            publish: {
                cmd: [
                    'cp -r dist/ tmp/',
                    'zip -rj tmp/buzz.zip tmp/buzz.js',
                    'zip -rj tmp/buzz.zip tmp/buzz.min.js',
                    'git checkout gh-pages',
                    'rm -rf releases/latest/',
                    'cp -r tmp/ releases/<%= pkg.version %>/',
                    'cp -r tmp/ releases/latest/',
                    'git add -A releases/<%= pkg.version %>',
                    'git add -A releases/latest',
                    'git commit -m "Published v<%= pkg.version %>."',
                    'git push origin gh-pages',
                    'git checkout -',
                    'rm -rf tmp/'
                ].join(' && ')
            },
            gitFailIfDirty: {
                cmd: 'test -z "$(git status --porcelain)"'
            },
            gitAdd: {
                cmd: 'git add .'
            },
            gitCommit: {
                cmd: function(message) {
                    return format('git commit -m "Build %s"', message);
                }
            },
            gitTag: {
                cmd: function(version) {
                    return format('git tag v%s -am "%s"', version, version);
                }
            },
            gitPush: {
                cmd: [
                    'git push',
                    'git push --tags'
                ].join(' && ')
            }
        }
    });

    grunt.loadNpmTasks('grunt-exec');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-uglify');

    grunt.registerTask('build',   ['jshint', 'uglify']);
    grunt.registerTask('publish', ['exec:publish']);
    grunt.registerTask('default', ['build']);

    grunt.registerTask('release', 'Release lib.', function(version) {
        var pkg = grunt.file.readJSON('package.json');

        version = semver.inc(pkg.version, version) || version;

        if (!semver.valid(version) || semver.lte(version, pkg.version)) {
            grunt.fatal('Invalid version.');
        }

        pkg.version = version;
        grunt.config.data.pkg = pkg;

        grunt.task.run([
            'exec:gitFailIfDirty',
            'build',
            'metadata:' + version,
            'manifests:' + version,
            'exec:gitAdd',
            'exec:gitCommit:' + version,
            'exec:gitTag:' + version,
            'exec:gitPush',
            'exec:publish'
        ]);
    });

    grunt.registerTask('manifests', 'Update manifests.', function(version) {
        var _   = grunt.util._,
            pkg = grunt.file.readJSON('package.json'),
            cpt = grunt.file.readJSON('component.json');

        if (!semver.valid(version)) {
            grunt.fatal('Invalid version');
        }

        pkg.version = version;

        cpt = JSON.stringify(_.extend(cpt,
            _.omit(pkg, 'dependencies', 'devDependencies')
        ), null, 2);

        pkg = JSON.stringify(pkg, null, 2);

        grunt.file.write('package.json', pkg);
        grunt.file.write('component.json', cpt);
    });

    grunt.registerTask('metadata', 'Create metadata file.', function(version) {
        var metadata = {
            'date': grunt.template.today("yyyy-mm-dd HH:MM:ss"),
            'version': version
        };

        grunt.file.write('dist/metadata.json', JSON.stringify(metadata, null, 2));
    });
};<|endoftext|>


<commit_before>/**
 * jspsych-survey-likert
 * a jspsych plugin for measuring items on a likert scale
 *
 * Josh de Leeuw (March 2013)
 * Updated October 2013
 *
 * parameters:
 *      questions: array of arrays. inner arrays are arrays of strings, where each string represents a prompt
 *                  for the user to respond to.
 *      labels: array of arrays of arrays. inner most arrays are label markers for the slider, e.g. ["Strongly Disagree", "Neutral", "Strongly Agree"].
 *              need one inner array for every question that is part of the trial. middle arrays group questions together.
 *      intervals: array of arrays. inner arrays are how many different responses the user can select from, e.g. 5, one for each question.
 *      show_ticks: graphically show tick marks on the slider bar to indicate the response levels.
 *      data: optional data object
 *
 */

(function($) {
    jsPsych['survey-likert'] = (function() {

        var plugin = {};

        plugin.create = function(params) {
            var trials = [];
            for (var i = 0; i < params.questions.length; i++) {
                trials.push({
                    type: "survey-likert",
                    questions: params.questions[i],
                    labels: params.labels[i],
                    intervals: params.intervals[i],
                    show_ticks: (typeof params.show_ticks === 'undefined') ? true : params.show_ticks,
                    data: (typeof params.data === 'undefined') ? {} : params.data[i]
                });
            }
            return trials;
        };

        plugin.trial = function(display_element, block, trial, part) {

            // add likert scale questions
            for (var i = 0; i < trial.questions.length; i++) {
                // create div
                display_element.append($('
', {
                    "id": 'survey-likert-' + i,
                    "class": 'survey-likert-question'
                }));

                // add question text
                $("#survey-likert-" + i).append('
' + trial.questions[i] + '
');

                // create slider
                $("#survey-likert-" + i).append($('
', {
                    "id": 'survey-likert-slider-' + i,
                    "class": 'survey-likert-slider survey-likert'
                }));
                $("#survey-likert-slider-" + i).slider({
                    value: Math.ceil(trial.intervals[i] / 2),
                    min: 1,
                    max: trial.intervals[i],
                    step: 1
                });

                // show tick marks
                if (trial.show_ticks) {
                    $("#survey-likert-" + i).append($('
', {
                        "id": 'survey-likert-sliderticks' + i,
                        "class": 'survey-likert-sliderticks survey-likert',
                        "css": {
                            "position": 'relative'
                        }
                    }));
                    for (var j = 1; j < trial.intervals[i] - 1; j++) {
                        $('#survey-likert-slider-' + i).append('

');
                    }

                    $('#survey-likert-slider-' + i + ' .survey-likert-slidertickmark').each(function(index) {
                        var left = (index + 1) * (100 / (trial.intervals[i] - 1));
                        $(this).css({
                            'position': 'absolute',
                            'left': left + '%',
                            'width': '1px',
                            'height': '100%',
                            'background-color': '#222222'
                        });
                    });
                }

                // create labels for slider
                $("#survey-likert-" + i).append($('
', {
                    "id": "survey-likert-sliderlabels" + i,
                    "class": 'survey-likert-sliderlabels survey-likert',
                    "css": {
                        "width": "100%",
                        "margin": "10px 0px 0px 0px",
                        "padding": "0px",
                        "display": "block",
                        "position": "relative"
                    }
                }));

                for (var j = 0; j < trial.labels[i].length; j++) {
                    $("#survey-likert-sliderlabels-" + i).append('
' + trial.labels[i][j] + '
');
                }

                // position labels to match slider intervals
                var slider_width = $("#survey-likert-slider-" + i).width();
                var num_items = trial.labels[i].length;
                var item_width = slider_width / num_items;
                var spacing_interval = slider_width / (num_items - 1);

                $("#survey-likert-sliderlabels-" + i + " li").each(function(index) {
                    $(this).css({
                        'display': 'inline-block',
                        'width': item_width + 'px',
                        'margin': '0px',
                        'padding': '0px',
                        'text-align': 'center',
                        'position': 'absolute',
                        'left': (spacing_interval * index) - (item_width / 2)
                    });
                });
            }

            // add submit button
            display_element.append($('<button>', {
                'id': 'survey-likert-next',
                'class': 'survey-likert'
            }));
            $("#survey-likert-next").html('Submit Answers');
            $("#survey-likert-next").click(function() {
                // measure response time
                var endTime = (new Date()).getTime();
                var response_time = endTime - startTime;

                // create object to hold responses
                var question_data = {};
                $("div.survey-likert-slider").each(function(index) {
                    var id = "Q" + index;
                    var val = $(this).slider("value");
                    var obje = {};
                    obje[id] = val;
                    $.extend(question_data, obje);
                });

                // save data
                block.writeData($.extend({}, {
                    "trial_type": "survey-likert",
                    "trial_index": block.trial_idx,
                    "rt": response_time
                }, question_data, trial.data));

                display_element.html('');

                // next trial
                block.next();
            });

            var startTime = (new Date()).getTime();
        }

        return plugin;
    })();
})(jQuery);
<commit_msg>css fix was applied incorrectly to survey-likert, resulting in a bug that failed to show slider labels<commit_after>/**
 * jspsych-survey-likert
 * a jspsych plugin for measuring items on a likert scale
 *
 * Josh de Leeuw (March 2013)
 * Updated October 2013
 *
 * parameters:
 *      questions: array of arrays. inner arrays are arrays of strings, where each string represents a prompt
 *                  for the user to respond to.
 *      labels: array of arrays of arrays. inner most arrays are label markers for the slider, e.g. ["Strongly Disagree", "Neutral", "Strongly Agree"].
 *              need one inner array for every question that is part of the trial. middle arrays group questions together.
 *      intervals: array of arrays. inner arrays are how many different responses the user can select from, e.g. 5, one for each question.
 *      show_ticks: graphically show tick marks on the slider bar to indicate the response levels.
 *      data: optional data object
 *
 */

(function($) {
    jsPsych['survey-likert'] = (function() {

        var plugin = {};

        plugin.create = function(params) {
            var trials = [];
            for (var i = 0; i < params.questions.length; i++) {
                trials.push({
                    type: "survey-likert",
                    questions: params.questions[i],
                    labels: params.labels[i],
                    intervals: params.intervals[i],
                    show_ticks: (typeof params.show_ticks === 'undefined') ? true : params.show_ticks,
                    data: (typeof params.data === 'undefined') ? {} : params.data[i]
                });
            }
            return trials;
        };

        plugin.trial = function(display_element, block, trial, part) {

            // add likert scale questions
            for (var i = 0; i < trial.questions.length; i++) {
                // create div
                display_element.append($('
', {
                    "id": 'jspsych-survey-likert-' + i,
                    "class": 'jspsych-survey-likert-question'
                }));

                // add question text
                $("#jspsych-survey-likert-" + i).append('
' + trial.questions[i] + '
');

                // create slider
                $("#jspsych-survey-likert-" + i).append($('
', {
                    "id": 'jspsych-survey-likert-slider-' + i,
                    "class": 'jspsych-survey-likert-slider jspsych-survey-likert'
                }));
                $("#jspsych-survey-likert-slider-" + i).slider({
                    value: Math.ceil(trial.intervals[i] / 2),
                    min: 1,
                    max: trial.intervals[i],
                    step: 1
                });

                // show tick marks
                if (trial.show_ticks) {
                    $("#jspsych-survey-likert-" + i).append($('
', {
                        "id": 'jspsych-survey-likert-sliderticks' + i,
                        "class": 'jspsych-survey-likert-sliderticks jspsych-survey-likert',
                        "css": {
                            "position": 'relative'
                        }
                    }));
                    for (var j = 1; j < trial.intervals[i] - 1; j++) {
                        $('#jspsych-survey-likert-slider-' + i).append('

');
                    }

                    $('#jspsych-survey-likert-slider-' + i + ' .jspsych-survey-likert-slidertickmark').each(function(index) {
                        var left = (index + 1) * (100 / (trial.intervals[i] - 1));
                        $(this).css({
                            'position': 'absolute',
                            'left': left + '%',
                            'width': '1px',
                            'height': '100%',
                            'background-color': '#222222'
                        });
                    });
                }

                // create labels for slider
                $("#jspsych-survey-likert-" + i).append($('
', {
                    "id": "jspsych-survey-likert-sliderlabels-" + i,
                    "class": 'jspsych-survey-likert-sliderlabels survey-likert',
                    "css": {
                        "width": "100%",
                        "margin": "10px 0px 0px 0px",
                        "padding": "0px",
                        "display": "block",
                        "position": "relative"
                    }
                }));

                for (var j = 0; j < trial.labels[i].length; j++) {
                    $("#jspsych-survey-likert-sliderlabels-" + i).append('
' + trial.labels[i][j] + '
');
                }

                // position labels to match slider intervals
                var slider_width = $("#jspsych-survey-likert-slider-" + i).width();
                var num_items = trial.labels[i].length;
                var item_width = slider_width / num_items;
                var spacing_interval = slider_width / (num_items - 1);

                $("#jspsych-survey-likert-sliderlabels-" + i + " li").each(function(index) {
                    $(this).css({
                        'display': 'inline-block',
                        'width': item_width + 'px',
                        'margin': '0px',
                        'padding': '0px',
                        'text-align': 'center',
                        'position': 'absolute',
                        'left': (spacing_interval * index) - (item_width / 2)
                    });
                });
            }

            // add submit button
            display_element.append($('<button>', {
                'id': 'jspsych-survey-likert-next',
                'class': 'jspsych-survey-likert'
            }));
            $("#jspsych-survey-likert-next").html('Submit Answers');
            $("#jspsych-survey-likert-next").click(function() {
                // measure response time
                var endTime = (new Date()).getTime();
                var response_time = endTime - startTime;

                // create object to hold responses
                var question_data = {};
                $("div.jspsych-survey-likert-slider").each(function(index) {
                    var id = "Q" + index;
                    var val = $(this).slider("value");
                    var obje = {};
                    obje[id] = val;
                    $.extend(question_data, obje);
                });

                // save data
                block.writeData($.extend({}, {
                    "trial_type": "survey-likert",
                    "trial_index": block.trial_idx,
                    "rt": response_time
                }, question_data, trial.data));

                display_element.html('');

                // next trial
                block.next();
            });

            var startTime = (new Date()).getTime();
        };

        return plugin;
    })();
})(jQuery);
<|endoftext|>


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

    'use strict';

  var sourceFolder = "bower_components/Haku";

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

      bower: {
        install: {
          options : {
            copy : false
          }
        }
      },

      copy: {
          main: {
              files: [
                  { expand: true, cwd : sourceFolder, src: ['**', '!**/src/index.html', '!**/src/css-sass/*', '!**/*.bat' ] }
              ]
          }
      }

  });

  grunt.loadNpmTasks('grunt-bower-task');
  grunt.loadNpmTasks('grunt-contrib-copy');

  // Default task(s).
  grunt.registerTask('default', ['bower', 'copy']);

};<commit_msg>Update gruntfile.js<commit_after>module.exports = function(grunt) {

    'use strict';

  var sourceFolder = "bower_components/Haku";

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

      bower: {
        install: {
          options : {
            copy : false
          }
        }
      },

      copy: {
          main: {
              files: [
                  { expand: true, cwd : sourceFolder, src: ['**', '!**/src/index.html', '!**/src/css-sass/*', '!**/*.bat' , '!**/src/ext/*' ] }
              ]
          }
      }

  });

  grunt.loadNpmTasks('grunt-bower-task');
  grunt.loadNpmTasks('grunt-contrib-copy');

  // Default task(s).
  grunt.registerTask('default', ['bower', 'copy']);

};
<|endoftext|>


<commit_before>// ==UserScript==
// @id             iitc-plugin-player-frequency
// @name           IITC plugin: Player Frequency
// @category       Info
// @version        0.0.0.@@DATETIMEVERSION@@
// @namespace      https://github.com/mnoeljones/ingress-intel-total-conversion
// @updateURL      @@UPDATEURL@@
// @downloadURL    @@DOWNLOADURL@@
// @description    [@@BUILDNAME@@-@@BUILDDATE@@] Player Frequency Display Layer
// @include        https://www.ingress.com/intel*
// @include        http://www.ingress.com/intel*
// @match          https://www.ingress.com/intel*
// @match          http://www.ingress.com/intel*
// @include        https://www.ingress.com/mission/*
// @include        http://www.ingress.com/mission/*
// @match          https://www.ingress.com/mission/*
// @match          http://www.ingress.com/mission/*
// @grant          none
// ==/UserScript==

@@PLUGINSTART@@

// PLUGIN START ////////////////////////////////////////////////////////

// use own namespace for plugin
window.plugin.PlayerFrequency = function() {
};

window.plugin.PlayerFrequency.usercount = 0;

window.plugin.PlayerFrequency.FACTION_COLOURS = {
  ENLIGHTENED: "#00FF00",
  RESISTANCE:  "#0000FF"
};
window.plugin.PlayerFrequency.styles = {
  ENLIGHTENED: { color: plugin.PlayerFrequency.FACTION_COLOURS.ENLIGHTENED },
  RESISTANCE: { color: plugin.PlayerFrequency.FACTION_COLOURS.RESISTANCE }
};

window.plugin.PlayerFrequency.Filter = {
    enabled: false,
    enable: function() {
        self.enabled = true;
    },
    disable: function() {
        self.enabled = false;
    },
};

window.plugin.PlayerFrequency.userfilter = {
  filters: {},
  names: [],
  setfilter: function(nick) {
    console.log("Setting filters[" + nick + "] = 'on'");
    this.filters[nick] = "on";
    this.names[nick] = true;
  },
  unsetfilter: function(nick) {
    console.log("Setting filters[" + nick + "] = 'off'");
    this.filters[nick] = "off";
    this.names[nick] = true;
  },
};

window.plugin.PlayerFrequency.resonator = function(data) {
  portal = data.portals[0];
  //console.log("resonator event @ " + portal.latE6/1E6 + "," + portal.lngE6/1E6);
  lat = portal.latE6/1E6;
  lng = portal.lngE6/1E6;
  style = data.team;
  plugin.PlayerFrequency.addCircle(lat, lng, plugin.PlayerFrequency.styles[style]);
  window.plugin.PlayerFrequency.userfilter.setfilter(data.nick);
};

window.plugin.PlayerFrequency.portal = function(data) {
  portal = data.portals[0];
  //console.log("resonator event @ " + portal.latE6/1E6 + "," + portal.lngE6/1E6);
  lat = portal.latE6/1E6;
  lng = portal.lngE6/1E6;
  style = data.team;
  plugin.PlayerFrequency.addCircle(lat, lng, plugin.PlayerFrequency.styles[style]);
  window.plugin.PlayerFrequency.userfilter.setfilter(data.nick);
};

window.plugin.PlayerFrequency.linked_portal = function(data) {
  portal = data.portals[0];
  str = data.time + ": from " + portal.name + " to " + data.portals[1].name;
  str += " linked by " + data.nick;
  //console.log(str);
  //L.circle(L.latLng(portal.latE6/1E6, portal.lngE6/1E6), 40, fill=true).addTo(plugin.PlayerFrequency.layer)
  lat = portal.latE6/1E6;
  lng = portal.lngE6/1E6;
  style = data.team;
  plugin.PlayerFrequency.addCircle(lat, lng, plugin.PlayerFrequency.styles[style]);
  window.plugin.PlayerFrequency.userfilter.setfilter(data.nick);
};

window.plugin.PlayerFrequency.addCircle = function(lat, lng, style) {
  console.log("Adding circle at " + lat + ", " + lng);

  style.fill = true;

  L.circle(L.latLng(lat, lng), 40, style).addTo(plugin.PlayerFrequency.layer);
  // plugin.PlayerFrequency.showUsers();
};

window.plugin.PlayerFrequency.showUsers = function() {
  var stored = window.plugin.chatHooks.stored;
  if (stored) {
    console.log(Object.keys(stored).length + "<->" + plugin.PlayerFrequency.usercount);
    if (Object.keys(stored).length > plugin.PlayerFrequency.usercount) {
      var names = "";
      var first = true;
      for (var user in stored) {
        if (first) {
          first = false;
        } else {
          names = names + "\n";
        }
        names = names + user;
      }
      console.log(names);
      plugin.PlayerFrequency.usercount = Object.keys(stored).length;
    }
  }
};

window.plugin.PlayerFrequency.filterUsers = function() {
  var userfilter = window.plugin.PlayerFrequency.userfilter.filters;
  var names = window.plugin.PlayerFrequency.userfilter.names;
  var names_checkboxes = "<fieldset>";
  names_checkboxes += "<legend>Players with current frequency data:</legend>";

  console.log("filterUsers 1");
  for (var nick in names) {
    checked = userfilter[nick] === "on" ? "checked" : "";
    setfunction = userfilter[nick] === "on" ? "unsetfilter" : "setfilter";
    var value = 'value="' + nick + '"';
    var checked = checked ? 'checked' : '';
    var onclick = 'onclick="window.plugin.PlayerFrequency.userfilter.' + setfunction + '(\'' + nick + '\')"';
    console.log("value: " + value);
    console.log("checked: " + checked);
    console.log("onclick: " + onclick);
    names_checkboxes += '<input type="checkbox" name="players" ' + value + ' ' + checked + ' ' + onclick + ' />' + nick + '
';
  }
  console.log("filterUsers 2");
  names_checkboxes += "</fieldset>";

  dialog({
    text: names_checkboxes,
    title: 'Names',
    id: 'player-frequecy-userfilter',
    width: 350,
  });
};

var setup =  function() {
  if (!window.plugin.chatHooks) {

  }
  window.plugin.PlayerFrequency.layer = new L.LayerGroup();
  window.addLayerGroup('player-frequency', window.plugin.PlayerFrequency.layer, true);

  window.plugin.chatHooks.addChatHook('CH_PORTAL_LINKED', window.plugin.PlayerFrequency.linked_portal);
  window.plugin.chatHooks.addChatHook('CH_RESO_DESTROYED', window.plugin.PlayerFrequency.resonator); // :     "destroyed a Resonator",
  window.plugin.chatHooks.addChatHook('CH_RESO_DEPLOYED', window.plugin.PlayerFrequency.resonator); // :      "deployed a Resonator",
  window.plugin.chatHooks.addChatHook('CH_PORTAL_CAPTURED', window.plugin.PlayerFrequency.portal); // :    "captured",
  window.plugin.chatHooks.addChatHook('CH_PORTAL_ATTACKED', window.plugin.PlayerFrequency.portal); // :    "is under attack",
  window.plugin.chatHooks.addChatHook('CH_PORTAL_NEUTRALISED', window.plugin.PlayerFrequency.portal); // : "neutralized",
  /*
  CH_LINK_DESTROYED:     "destroyed the Link",
  CH_LINK_DESTROYED_OWN: "Your Link",
  CH_FIELD_CREATED:      "created a Control Field",
  CH_FIELD_DESTROYED:    "destroyed a Control Field"
  */
  //addHook('factionChatDataAvailable', window.plugin.chatHooks.handleFactionData);

  $('#toolbox').append(' Frequency player list');
};

// PLUGIN END //////////////////////////////////////////////////////////

@@PLUGINEND@@
<commit_msg>Using js-style objects (I hope!)<commit_after>// ==UserScript==
// @id             iitc-plugin-player-frequency
// @name           IITC plugin: Player Frequency
// @category       Info
// @version        0.0.0.@@DATETIMEVERSION@@
// @namespace      https://github.com/mnoeljones/ingress-intel-total-conversion
// @updateURL      @@UPDATEURL@@
// @downloadURL    @@DOWNLOADURL@@
// @description    [@@BUILDNAME@@-@@BUILDDATE@@] Player Frequency Display Layer
// @include        https://www.ingress.com/intel*
// @include        http://www.ingress.com/intel*
// @match          https://www.ingress.com/intel*
// @match          http://www.ingress.com/intel*
// @include        https://www.ingress.com/mission/*
// @include        http://www.ingress.com/mission/*
// @match          https://www.ingress.com/mission/*
// @match          http://www.ingress.com/mission/*
// @grant          none
// ==/UserScript==

@@PLUGINSTART@@

// PLUGIN START ////////////////////////////////////////////////////////

// use own namespace for plugin
window.plugin.PlayerFrequency = {
  // Constants
  CHATHOOKS: plugin.chatHooks,
  FACTION_COLOURS: {
    ENLIGHTENED: "#00FF00",
    RESISTANCE:  "#0000FF"
  },

  // Member classes
  Filter: {
    enabled: false,
    enable: function() {
        self.enabled = true;
    },
    disable: function() {
        self.enabled = false;
    },
  },

  // Member variables
  usercount: 0,
  styles: {
    ENLIGHTENED: { color: plugin.PlayerFrequency.FACTION_COLOURS.ENLIGHTENED },
    RESISTANCE: { color: plugin.PlayerFrequency.FACTION_COLOURS.RESISTANCE }
  },

  // Member functions
  userfilter: {
    filters: {},
    names: [],
    setfilter: function(nick) {
      console.log("Setting filters[" + nick + "] = 'on'");
      this.filters[nick] = "on";
      this.names[nick] = true;
    },
    unsetfilter: function(nick) {
      console.log("Setting filters[" + nick + "] = 'off'");
      this.filters[nick] = "off";
      this.names[nick] = true;
    },
  },
  resonator: function(data) {
    portal = data.portals[0];
    //console.log("resonator event @ " + portal.latE6/1E6 + "," + portal.lngE6/1E6);
    lat = portal.latE6/1E6;
    lng = portal.lngE6/1E6;
    style = data.team;
    this.addCircle(lat, lng, plugin.PlayerFrequency.styles[style]);
    this.userfilter.setfilter(data.nick);
  },
  portal: function(data) {
    portal = data.portals[0];
    //console.log("resonator event @ " + portal.latE6/1E6 + "," + portal.lngE6/1E6);
    lat = portal.latE6/1E6;
    lng = portal.lngE6/1E6;
    style = data.team;
    this.addCircle(lat, lng, plugin.PlayerFrequency.styles[style]);
    this.userfilter.setfilter(data.nick);
  },
  linked_portal: function(data) {
    portal = data.portals[0];
    str = data.time + ": from " + portal.name + " to " + data.portals[1].name;
    str += " linked by " + data.nick;
    //console.log(str);
    //L.circle(L.latLng(portal.latE6/1E6, portal.lngE6/1E6), 40, fill=true).addTo(plugin.PlayerFrequency.layer)
    lat = portal.latE6/1E6;
    lng = portal.lngE6/1E6;
    style = data.team;
    plugin.PlayerFrequency.addCircle(lat, lng, plugin.PlayerFrequency.styles[style]);
    window.plugin.PlayerFrequency.userfilter.setfilter(data.nick);
  };
  addCircle: function(lat, lng, style) {
    console.log("Adding circle at " + lat + ", " + lng);

    style.fill = true;

    L.circle(L.latLng(lat, lng), 40, style).addTo(this.layer);
    // plugin.PlayerFrequency.showUsers();
  },
  showUsers: function() {
    var stored = window.plugin.chatHooks.stored;
    if (stored) {
      console.log(Object.keys(stored).length + "<->" + this.usercount);
      if (Object.keys(stored).length > this.usercount) {
        var names = "";
        var first = true;
        for (var user in stored) {
          if (first) {
            first = false;
          } else {
            names = names + "\n";
          }
          names = names + user;
        }
        console.log(names);
        this.usercount = Object.keys(stored).length;
      }
    }
  },

  filterUsers: function() {
    var userfilter = this.userfilter.filters;
    var names = this.userfilter.names;
    var names_checkboxes = "<fieldset>";
    names_checkboxes += "<legend>Players with current frequency data:</legend>";

    console.log("filterUsers 1");
    for (var nick in names) {
      checked = userfilter[nick] === "on" ? "checked" : "";
      setfunction = userfilter[nick] === "on" ? "unsetfilter" : "setfilter";
      var value = 'value="' + nick + '"';
      var checked = checked ? 'checked' : '';
      var onclick = 'onclick="window.plugin.PlayerFrequency.userfilter.' + setfunction + '(\'' + nick + '\')"';
      console.log("value: " + value);
      console.log("checked: " + checked);
      console.log("onclick: " + onclick);
      names_checkboxes += '<input type="checkbox" name="players" ' + value + ' ' + checked + ' ' + onclick + ' />' + nick + '
';
    }
    console.log("filterUsers 2");
    names_checkboxes += "</fieldset>";

    dialog({
      text: names_checkboxes,
      title: 'Names',
      id: 'player-frequecy-userfilter',
      width: 350,
    });
  },

  setup: function() {
    if (!window.plugin.chatHooks) {

    }
    this.PlayerFrequency.layer = new L.LayerGroup();
    window.addLayerGroup('player-frequency', this.PlayerFrequency.layer, true);

    window.plugin.chatHooks.addChatHook('CH_PORTAL_LINKED', this.PlayerFrequency.linked_portal);
    window.plugin.chatHooks.addChatHook('CH_RESO_DESTROYED', this.PlayerFrequency.resonator); // :     "destroyed a Resonator",
    window.plugin.chatHooks.addChatHook('CH_RESO_DEPLOYED', this.PlayerFrequency.resonator); // :      "deployed a Resonator",
    window.plugin.chatHooks.addChatHook('CH_PORTAL_CAPTURED', this.PlayerFrequency.portal); // :    "captured",
    window.plugin.chatHooks.addChatHook('CH_PORTAL_ATTACKED', this.PlayerFrequency.portal); // :    "is under attack",
    window.plugin.chatHooks.addChatHook('CH_PORTAL_NEUTRALISED', this.PlayerFrequency.portal); // : "neutralized",
    /*
    CH_LINK_DESTROYED:     "destroyed the Link",
    CH_LINK_DESTROYED_OWN: "Your Link",
    CH_FIELD_CREATED:      "created a Control Field",
    CH_FIELD_DESTROYED:    "destroyed a Control Field"
    */
    //addHook('factionChatDataAvailable', window.plugin.chatHooks.handleFactionData);

    $('#toolbox').append(' Frequency player list');
  },
};

// PLUGIN END //////////////////////////////////////////////////////////

@@PLUGINEND@@
<|endoftext|>


<commit_before>function _resize() {
    // I couldn't figure out how to do this in CSS: resize the table
    // so that it takes as much space as it can without expanding the
    // page horizontally.
    var space = parseInt($("#lava-breadcrumbs").outerWidth() - $("#outer-table").outerWidth());
    space -= $("#lava-content").outerWidth() - $("#lava-content").width();
    var table = $("#results-table"), scroller=$("#scroller");
    var atRight = scroller.width() + scroller.scrollLeft() >= table.attr('scrollWidth');
    scroller.width(scroller.width() + space);
    if (atRight) scroller.scrollLeft(table.attr('scrollWidth'));
}
function _fixRowHeights () {
    var index = 0;
    var nameRows = $("#test-run-names > tbody > tr");
    var resultRows = $("#results-table > tbody > tr");
    for (; index < nameRows.length; index++) {
        var nameRow = $(nameRows[index]);
        var resultRow = $(resultRows[index]);
        var nameRowHeight = parseInt(nameRow.css('height'));
        var resultRowHeight = parseInt(resultRow.css('height'));
        nameRow.css('height', Math.max(nameRowHeight, resultRowHeight));
        resultRow.css('height', Math.max(nameRowHeight, resultRowHeight));
    }
}

function update_filters(column_data, test_run_names) {
    for (iter in column_data) {
	build_number = column_data[iter]["number"].split('.')[0];
	$("#build_number_start").append($('<option>', {
	    value: build_number,
	    text: build_number
	}));
	$("#build_number_end").append($('<option>', {
	    value: build_number,
	    text: build_number
	}));
    }
    $("#build_number_end option:last").attr("selected", true);

    for (iter in test_run_names) {
	selected = false;
	if (column_data[column_data.length-1]["test_runs"][test_run_names[iter]]) {
	    selected = true;
	}
	$("#test_select").append($('<option>', {
	    value: test_run_names[iter],
	    text: test_run_names[iter],
	    selected: selected
	}));
    }
}

function update_table(column_data, table_data, test_run_names) {

    if ($("#test_select").val() == null) {
	alert("Please select at least one test.");
	return false;
    }

    if ($("#build_number_start").val() > $("#build_number_end").val()) {
	alert("End build number must be greater then the start build number.");
	return false;
    }

    // Create row headlines.
    test_name_rows = "
Date
";
    for (iter in test_run_names) {
	if ($("#test_select").val().indexOf(test_run_names[iter]) >= 0) {
	    test_name = test_run_names[iter];
	    if (test_name.length > 20) {
		test_name = test_name.substring(0,20) + "...";
	    }
	    test_name_rows += "
" + test_name + "
";
	}
    }
    $("#test-run-names tbody").html(test_name_rows);

    // Create column headlines.
    result_table_head = "
";
    for (iter in column_data) {
	build_number = column_data[iter]["number"].split('.')[0];

	if (build_number <= $("#build_number_end").val() && build_number >= $("#build_number_start").val()) {
	    link = '' + build_number.split(' ')[0] + '';
	    result_table_head += "" + link + "	";
	}
    }
    result_table_head += "
";
    $("#results-table thead").html(result_table_head);

    // Create table body
    result_table_body = "
";
    for (iter in column_data) {
	build_number = column_data[iter]["number"].split('.')[0];
	build_date = column_data[iter]["date"].split('.')[0];

	if (build_number <= $("#build_number_end").val() && build_number >= $("#build_number_start").val()) {
	    result_table_body += "" + build_date.split(' ')[0] + "	";
	}

    }
    result_table_body += "
";

    for (cnt in test_run_names) {
	test = test_run_names[cnt];
	if ($("#test_select").val().indexOf(test) >= 0) {
	    result_table_body += "
";
	    row = table_data[test];

	    for (iter in row) {
		build_number = column_data[iter]["number"].split('.')[0];
		if (build_number <= $("#build_number_end").val() && build_number >= $("#build_number_start").val()) {
		    result_table_body += '';
		    if (row[iter]["uuid"]) {
			result_table_body += '' + row[iter]["passes"] + '/' + row[iter]["total"] + '';
			result_table_body += '';
			for (bug_id in row[iter]["bug_ids"]) {
			    bug = row[iter]["bug_ids"];
			    result_table_body += '[' + bug[bug_id] + ']';
			}
			result_table_body += '[+]';
			result_table_body += '';

		    } else {
			result_table_body += "—";
		    }
		    result_table_body += "	";
		}
	    }
	    result_table_body += "
";
	}
    }

    $("#results-table tbody").html(result_table_body);
    $("#scroller").scrollLeft($("#scroller")[0].scrollWidth);

    update_plot(column_data, table_data, test_run_names);
}

function update_plot(column_data, table_data, test_run_names) {

    // Get the plot data.

    data = [];
    for (test in table_data) {

	if ($("#test_select").val().indexOf(test) >= 0) {
	    row_data = [];

	    row = table_data[test];
	    for (iter in row) {
		build_number = column_data[iter]["number"].split('.')[0];
		if (build_number <= $("#build_number_end").val() && build_number >= $("#build_number_start").val()) {
		    if (row[iter]["cls"]) {
			if ($('input:radio[name=graph_type]:checked').val() == "number") {
			    row_data.push([iter, row[iter]["passes"]]);
			} else {
			    row_data.push([iter, 100*row[iter]["passes"]/row[iter]["total"]]);
			}
		    }
		}
	    }
	    data.push({label: test, data: row_data});
	}
    }

    // Get all build numbers to be used as tick labels.
    build_numbers = [];
    for (test in table_data) {
	row = table_data[test];
	for (iter in row) {
	    build_numbers.push(column_data[iter]["number"].split(' ')[0]);
	}
	// Each test has the same number of build numbers.
	break;
    }

    var options = {
	series: {
	    lines: { show: true },
	    points: { show: false }
	},
	legend: {
	    show: true,
	    position: "ne",
	    margin: 3,
	    container: "#legend-container",
	},
	xaxis: {
	    tickDecimals: 0,
	    tickFormatter: function (val, axis) {
		return build_numbers[val];
	    },
	},
	yaxis: {
	    tickDecimals: 0,
	},
    };

    if ($('input:radio[name=graph_type]:checked').val() == "percentage") {
	options["yaxis"]["max"] = 100;
    }

    $.plot($("#outer-container #inner-container"), data, options);
}

$(window).ready(
    function () {
        // Hook up the event and run resize ASAP (looks jumpy in FF if you
        // don't run it here).
        $(window).resize(_resize);
        $("#scroller").scrollLeft(100000);
        _resize();
        _fixRowHeights();

        function _submit() {
            $(this).submit();
        }
        var add_bug_dialog = $('#add-bug-dialog').dialog(
            {
                autoOpen: false,
                buttons: {'Cancel': function () {$(this).dialog('close');}, 'OK': _submit },
                modal: true,
                title: "Link bug to XXX"
            });
        var go_to_bug_dialog = $("#go-to-bug-dialog").dialog(
            {
                autoOpen: false,
                buttons: {'Cancel': function () {$(this).dialog('close');}, 'Remove link': _submit},
                modal: true,
                title: "Link bug to XXX"
            });

        function get_testrun_and_buildnumber (element) {
            var cell = element.closest('td');
            var row = cell.closest('tr');
            var testrun = $($("#test-run-names > tbody > tr")[row.index()]).text();
            var header_cells = element.closest('table').find('thead > tr > th');
            var buildnumber = $(header_cells[cell.index()]).text();
            return {testrun: $.trim(testrun), buildnumber: $.trim(buildnumber)};
        }

        function find_previous_bugs (element) {
            var td = $(element).closest('td');
            var bugs = [];
            var start = td;
            while ((td = td.prev()) && td.size()) {
                td.find(".bug-link").each(
                    function (index, link) {
                        var bug_id = $(link).data('bug-id');
                        if (bugs.indexOf(bug_id) < 0) bugs.push(bug_id);
                    });
            }
            var already_linked = [];
            start.find(".bug-link").each(
                function (index, link) {
                    var bug_id = $(link).data('bug-id');
                    if (bugs.indexOf(bug_id) >= 0) {
                        bugs.splice(bugs.indexOf(bug_id), 1);
                        already_linked.push(bug_id);
                    }
                });
            return {bugs:bugs, already_linked:already_linked};
        }

        $('a.add-bug-link').click(
            function (e) {
                e.preventDefault();

                var previous = find_previous_bugs($(this));
                var prev_div = add_bug_dialog.find('div.prev');
                var names = get_testrun_and_buildnumber($(this));

                if (previous.bugs.length) {
                    var html = '';
                    prev_div.show();
                    html = '
Use a bug previously linked to ' + names.testrun + ':

';
                    for (var i = 0; i < previous.already_linked.length; i++) {
                        html += '
' + previous.already_linked[i] + ' (already linked)
';
                    }
                    for (var i = 0; i < previous.bugs.length; i++) {
                        html += '
' +
                            previous.bugs[i] + '
';
                    }
                    html += '
';
                    html += "
Or enter another bug number:
";
                    prev_div.html(html);
                    prev_div.find('a').click(
                        function (e) {
                            e.preventDefault();
                            add_bug_dialog.find('input[name=bug]').val($(this).data('bug-id'));
                            add_bug_dialog.submit();
                        });
                } else {
                    prev_div.hide();
                }

                var title = "Link a bug to the '" + names.testrun +
                    "' run of build " + names.buildnumber;
                add_bug_dialog.find('input[name=uuid]').val($(this).closest('td').data('uuid'));
                add_bug_dialog.dialog('option', 'title', title);
                add_bug_dialog.dialog('open');
            });

        $("a.bug-link").click(
            function (e) {
                e.preventDefault();
                var names = get_testrun_and_buildnumber($(this));
                var title = "Bug linked to the '" + names.testrun +
                    "' run of build " + names.buildnumber;
                go_to_bug_dialog.find('input[name=uuid]').val($(this).closest('td').data('uuid'));
                go_to_bug_dialog.find('input[name=bug]').val($(this).data('bug-id'));
                go_to_bug_dialog.find('a').attr('href', $(this).attr('href'));
                go_to_bug_dialog.find('a').text('View bug ' + $(this).data('bug-id'));
                go_to_bug_dialog.dialog('option', 'title', title);
                go_to_bug_dialog.dialog('open');
            });
    });
// Because what resize does depends on the final sizes of elements,
// run it again after everything is loaded (things end up wrong in
// chromium if you don't do this).
$(window).load(_resize);
$(window).load(_fixRowHeights);
$(window).load(function() {update_filters(columns, test_names);});
$(window).load(function() {update_table(columns, chart_data, test_names);});
<commit_msg>Introduce zero values to the graph.<commit_after>function _resize() {
    // I couldn't figure out how to do this in CSS: resize the table
    // so that it takes as much space as it can without expanding the
    // page horizontally.
    var space = parseInt($("#lava-breadcrumbs").outerWidth() - $("#outer-table").outerWidth());
    space -= $("#lava-content").outerWidth() - $("#lava-content").width();
    var table = $("#results-table"), scroller=$("#scroller");
    var atRight = scroller.width() + scroller.scrollLeft() >= table.attr('scrollWidth');
    scroller.width(scroller.width() + space);
    if (atRight) scroller.scrollLeft(table.attr('scrollWidth'));
}
function _fixRowHeights () {
    var index = 0;
    var nameRows = $("#test-run-names > tbody > tr");
    var resultRows = $("#results-table > tbody > tr");
    for (; index < nameRows.length; index++) {
        var nameRow = $(nameRows[index]);
        var resultRow = $(resultRows[index]);
        var nameRowHeight = parseInt(nameRow.css('height'));
        var resultRowHeight = parseInt(resultRow.css('height'));
        nameRow.css('height', Math.max(nameRowHeight, resultRowHeight));
        resultRow.css('height', Math.max(nameRowHeight, resultRowHeight));
    }
}

function update_filters(column_data, test_run_names) {
    for (iter in column_data) {
	build_number = column_data[iter]["number"].split('.')[0];
	$("#build_number_start").append($('<option>', {
	    value: build_number,
	    text: build_number
	}));
	$("#build_number_end").append($('<option>', {
	    value: build_number,
	    text: build_number
	}));
    }
    $("#build_number_end option:last").attr("selected", true);

    for (iter in test_run_names) {
	selected = false;
	if (column_data[column_data.length-1]["test_runs"][test_run_names[iter]]) {
	    selected = true;
	}
	$("#test_select").append($('<option>', {
	    value: test_run_names[iter],
	    text: test_run_names[iter],
	    selected: selected
	}));
    }
}

function update_table(column_data, table_data, test_run_names) {

    if ($("#test_select").val() == null) {
	alert("Please select at least one test.");
	return false;
    }

    if ($("#build_number_start").val() > $("#build_number_end").val()) {
	alert("End build number must be greater then the start build number.");
	return false;
    }

    // Create row headlines.
    test_name_rows = "
Date
";
    for (iter in test_run_names) {
	if ($("#test_select").val().indexOf(test_run_names[iter]) >= 0) {
	    test_name = test_run_names[iter];
	    if (test_name.length > 20) {
		test_name = test_name.substring(0,20) + "...";
	    }
	    test_name_rows += "
" + test_name + "
";
	}
    }
    $("#test-run-names tbody").html(test_name_rows);

    // Create column headlines.
    result_table_head = "
";
    for (iter in column_data) {
	build_number = column_data[iter]["number"].split('.')[0];

	if (build_number <= $("#build_number_end").val() && build_number >= $("#build_number_start").val()) {
	    link = '' + build_number.split(' ')[0] + '';
	    result_table_head += "" + link + "	";
	}
    }
    result_table_head += "
";
    $("#results-table thead").html(result_table_head);

    // Create table body
    result_table_body = "
";
    for (iter in column_data) {
	build_number = column_data[iter]["number"].split('.')[0];
	build_date = column_data[iter]["date"].split('.')[0];

	if (build_number <= $("#build_number_end").val() && build_number >= $("#build_number_start").val()) {
	    result_table_body += "" + build_date.split(' ')[0] + "	";
	}

    }
    result_table_body += "
";

    for (cnt in test_run_names) {
	test = test_run_names[cnt];
	if ($("#test_select").val().indexOf(test) >= 0) {
	    result_table_body += "
";
	    row = table_data[test];

	    for (iter in row) {
		build_number = column_data[iter]["number"].split('.')[0];
		if (build_number <= $("#build_number_end").val() && build_number >= $("#build_number_start").val()) {
		    result_table_body += '';
		    if (row[iter]["uuid"]) {
			result_table_body += '' + row[iter]["passes"] + '/' + row[iter]["total"] + '';
			result_table_body += '';
			for (bug_id in row[iter]["bug_ids"]) {
			    bug = row[iter]["bug_ids"];
			    result_table_body += '[' + bug[bug_id] + ']';
			}
			result_table_body += '[+]';
			result_table_body += '';

		    } else {
			result_table_body += "—";
		    }
		    result_table_body += "	";
		}
	    }
	    result_table_body += "
";
	}
    }

    $("#results-table tbody").html(result_table_body);
    $("#scroller").scrollLeft($("#scroller")[0].scrollWidth);

    update_plot(column_data, table_data, test_run_names);
}

function update_plot(column_data, table_data, test_run_names) {

    // Get the plot data.

    data = [];
    for (test in table_data) {

	if ($("#test_select").val().indexOf(test) >= 0) {
	    row_data = [];

	    row = table_data[test];
	    for (iter in row) {
		build_number = column_data[iter]["number"].split('.')[0];
		if (build_number <= $("#build_number_end").val() && build_number >= $("#build_number_start").val()) {
		    if (row[iter]["cls"]) {
			if ($('input:radio[name=graph_type]:checked').val() == "number") {
			    row_data.push([iter, row[iter]["passes"]]);
			} else {
			    if (isNaN(row[iter]["passes"]/row[iter]["total"])) {
				row_data.push([iter, 0]);
			    } else {
				row_data.push([iter, 100*row[iter]["passes"]/row[iter]["total"]]);
			    }
			}
		    }
		}
	    }
	    data.push({label: test, data: row_data});
	}
    }

    // Get all build numbers to be used as tick labels.
    build_numbers = [];
    for (test in table_data) {
	row = table_data[test];
	for (iter in row) {
	    build_numbers.push(column_data[iter]["number"].split(' ')[0]);
	}
	// Each test has the same number of build numbers.
	break;
    }

    var options = {
	series: {
	    lines: { show: true },
	    points: { show: false }
	},
	legend: {
	    show: true,
	    position: "ne",
	    margin: 3,
	    container: "#legend-container",
	},
	xaxis: {
	    tickDecimals: 0,
	    tickFormatter: function (val, axis) {
		return build_numbers[val];
	    },
	},
	yaxis: {
	    tickDecimals: 0,
	},
    };

    if ($('input:radio[name=graph_type]:checked').val() == "percentage") {
	options["yaxis"]["max"] = 100;
    }

    $.plot($("#outer-container #inner-container"), data, options);
}

$(window).ready(
    function () {
        // Hook up the event and run resize ASAP (looks jumpy in FF if you
        // don't run it here).
        $(window).resize(_resize);
        $("#scroller").scrollLeft(100000);
        _resize();
        _fixRowHeights();

        function _submit() {
            $(this).submit();
        }
        var add_bug_dialog = $('#add-bug-dialog').dialog(
            {
                autoOpen: false,
                buttons: {'Cancel': function () {$(this).dialog('close');}, 'OK': _submit },
                modal: true,
                title: "Link bug to XXX"
            });
        var go_to_bug_dialog = $("#go-to-bug-dialog").dialog(
            {
                autoOpen: false,
                buttons: {'Cancel': function () {$(this).dialog('close');}, 'Remove link': _submit},
                modal: true,
                title: "Link bug to XXX"
            });

        function get_testrun_and_buildnumber (element) {
            var cell = element.closest('td');
            var row = cell.closest('tr');
            var testrun = $($("#test-run-names > tbody > tr")[row.index()]).text();
            var header_cells = element.closest('table').find('thead > tr > th');
            var buildnumber = $(header_cells[cell.index()]).text();
            return {testrun: $.trim(testrun), buildnumber: $.trim(buildnumber)};
        }

        function find_previous_bugs (element) {
            var td = $(element).closest('td');
            var bugs = [];
            var start = td;
            while ((td = td.prev()) && td.size()) {
                td.find(".bug-link").each(
                    function (index, link) {
                        var bug_id = $(link).data('bug-id');
                        if (bugs.indexOf(bug_id) < 0) bugs.push(bug_id);
                    });
            }
            var already_linked = [];
            start.find(".bug-link").each(
                function (index, link) {
                    var bug_id = $(link).data('bug-id');
                    if (bugs.indexOf(bug_id) >= 0) {
                        bugs.splice(bugs.indexOf(bug_id), 1);
                        already_linked.push(bug_id);
                    }
                });
            return {bugs:bugs, already_linked:already_linked};
        }

        $('a.add-bug-link').click(
            function (e) {
                e.preventDefault();

                var previous = find_previous_bugs($(this));
                var prev_div = add_bug_dialog.find('div.prev');
                var names = get_testrun_and_buildnumber($(this));

                if (previous.bugs.length) {
                    var html = '';
                    prev_div.show();
                    html = '
Use a bug previously linked to ' + names.testrun + ':

';
                    for (var i = 0; i < previous.already_linked.length; i++) {
                        html += '
' + previous.already_linked[i] + ' (already linked)
';
                    }
                    for (var i = 0; i < previous.bugs.length; i++) {
                        html += '
' +
                            previous.bugs[i] + '
';
                    }
                    html += '
';
                    html += "
Or enter another bug number:
";
                    prev_div.html(html);
                    prev_div.find('a').click(
                        function (e) {
                            e.preventDefault();
                            add_bug_dialog.find('input[name=bug]').val($(this).data('bug-id'));
                            add_bug_dialog.submit();
                        });
                } else {
                    prev_div.hide();
                }

                var title = "Link a bug to the '" + names.testrun +
                    "' run of build " + names.buildnumber;
                add_bug_dialog.find('input[name=uuid]').val($(this).closest('td').data('uuid'));
                add_bug_dialog.dialog('option', 'title', title);
                add_bug_dialog.dialog('open');
            });

        $("a.bug-link").click(
            function (e) {
                e.preventDefault();
                var names = get_testrun_and_buildnumber($(this));
                var title = "Bug linked to the '" + names.testrun +
                    "' run of build " + names.buildnumber;
                go_to_bug_dialog.find('input[name=uuid]').val($(this).closest('td').data('uuid'));
                go_to_bug_dialog.find('input[name=bug]').val($(this).data('bug-id'));
                go_to_bug_dialog.find('a').attr('href', $(this).attr('href'));
                go_to_bug_dialog.find('a').text('View bug ' + $(this).data('bug-id'));
                go_to_bug_dialog.dialog('option', 'title', title);
                go_to_bug_dialog.dialog('open');
            });
    });
// Because what resize does depends on the final sizes of elements,
// run it again after everything is loaded (things end up wrong in
// chromium if you don't do this).
$(window).load(_resize);
$(window).load(_fixRowHeights);
$(window).load(function() {update_filters(columns, test_names);});
$(window).load(function() {update_table(columns, chart_data, test_names);});
<|endoftext|>