<commit_before>'use strict';

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

//
// `dist`, `.tmp`, `src` dirs are used for dev to serve and watch files
// `dist` dir is used for build to generate optmized builds
//

module.exports = function(grunt) {
  // Load grunt tasks automatically
  require('load-grunt-tasks')(grunt);
  // load the rest of non-grunt tasks
  grunt.loadNpmTasks('assemble');
  // Time how long tasks take. Can help when optimizing build times
  require('time-grunt')(grunt);

  // Project configuration.
  grunt.initConfig({

    config: {
      src: 'src',
      dist: 'dist'
    },

    watch: {
      assemble: {
        files: ['<%= config.src %>/{content,data,templates}/{,*/}*.{md,hbs,yml,json}'],
        tasks: ['newer:assemble']
      },
      sass: {
        files: ['<%= config.src %>/assets/styles/{,*/}*.scss'],
        tasks: ['newer:sass']
      },
      coffee: {
        files: ['<%= config.src %>/assets/scripts/{,*/}*.coffee'],
        tasks: ['newer:coffee']
      },
      js: {
        files: ['<%= config.src %>/assets/scripts/{,*/}*.js'],
        tasks: ['newer:jshint']
      },

      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          // reload when assemble generates html files
          '<%= config.dist %>/{,*/}*.html',
          // reload when sass generates css files
          '.tmp/assets/styles/{,*/}*.css',
          //reload when coffeescript generates js files
          '.tmp/assets/scripts/{,*/}*.js',
          // reload when plain css files changes
          '<%= config.src %>/assets/styles/{,*/}*.css',
          // reload when plain js files
          '<%= config.src %>/assets/scripts/{,*/}*.js',
          // reload when images changes
          '<%= config.src %>/assets/images/{,*/}*.{png,jpg,jpeg,gif}',
          // reload when fonts changes
          '<%= config.src %>/assets/fonts/{,*/}*.{eot,woff,ttf,svg}'
        ]
      }
    },

    connect: {
      options: {
        port: 9000,
        livereload: 35729,
        // change this to '0.0.0.0' to access the server from outside
        hostname: 'localhost'
      },
      livereload: {
        options: {
          open: true,
          base: [
            // for css and js generated by SASS and CoffeeScript
            '.tmp',
            // other assets found directly in source
            '<%= config.src %>',
            // for html files generated by assemble
            '<%= config.dist %>'
          ]
        }
      }
    },

    assemble: {
      pages: {
        options: {
          flatten: true,
          assets: '<%= config.dist %>/assets',
          layout: '<%= config.src %>/templates/layouts/default.hbs',
          data: '<%= config.src %>/data/*.{json,yml}',
          partials: '<%= config.src %>/templates/partials/*.hbs'
        },
        files: {
          '<%= config.dist %>/': ['<%= config.src %>/templates/pages/*.hbs']
        }
      }
    },

    sass: {
      dist: {
        options: {
          // node-neat package includes both bourbon and neat
          // we can use just node-bourbon if we don't want neat lib
          includePaths: require('node-neat').includePaths
        },

        files: [{
          expand: true,
          cwd: '<%= config.src %>/assets/styles',
          src: '{,*/}*.scss',
          dest: '.tmp/assets/styles',
          ext: '.css'
        }]
      }
    },

    coffee: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= config.src %>/assets/scripts',
          src: '{,*/}*.coffee',
          dest: '.tmp/assets/scripts',
          ext: '.js'
        }]
      }
    },

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

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

    // Usemin adds files to concat
    concat: {},
    // Usemin adds files to uglify
    uglify: {},
    // Usemin adds files to cssmin
    cssmin: {
      dist: {
        options: {
          check: 'gzip'
        }
      }
    },

    // Renames files for browser caching purposes
    rev: {
      dist: {
        files: {
          src: [
            '<%= config.dist %>/assets/scripts/{,*/}*.js',
            '<%= config.dist %>/assets/styles/{,*/}*.css',
            '<%= config.dist %>/assets/images/{,*/}*.{png,jpg,jpeg,gif}',
            '<%= config.dist %>/assets/fonts/{,*/}*.{eot,woff,ttf,svg}'
          ]
        }
      }
    },

    imagemin: {
      dist: {
        options: {
          optimizationLevel: 3
        },

        files: [{
          expand: true,
          cwd: '<%= config.src %>/assets/images',
          src: '{,*/}*.{png,jpg,jpeg,gif}',
          dest: '<%= config.dist %>/assets/images'
        }]
      }
    },

    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: [
        'Gruntfile.js',
        '<%= config.src %>/assets/scripts/{,*/}*.js'
      ]
    },

    copy: {
      // copy plain js and css files right next to
      // the other css and js files generated by SASS and CoffeeScript
      // in order to be optimized.
      plain: {
        expand: true,
        cwd: '<%= config.src %>/assets',
        src: [
          'scripts/{,*}/*.js',
          'styles/{,*}/*.css'
        ],
        dest: '.tmp/assets'
      },

      dist: {
        expand: true,
        cwd: '<%= config.src %>/assets',
        src: [
          // NOTE: images are copied by the imagemin task
          // TODO: add other assets here
          // Fonts
          'fonts/{,*}/*.{eot,woff,ttf,svg}'
        ],
        dest: '<%= config.dist %>/assets'
      }
    },

    clean: {
      dist: ['<%= config.dist %>/', '.tmp/']
    }
  });

  grunt.registerTask('dev', [
    'jshint',
    'clean',
    'assemble',
    'sass',
    'coffee'
  ]);

  grunt.registerTask('server', [
    'dev',
    'connect:livereload',
    'watch'
  ]);

  grunt.registerTask('build', [
    'clean',
    'assemble',
    'copy:plain',
    'copy:dist',
    'sass',
    'coffee',
    'useminPrepare',
    'concat',
    'uglify',
    'cssmin',
    'rev',
    'usemin',
    'imagemin'
  ]);

  grunt.registerTask('default', ['server']);
};
<commit_msg>Update Gruntfile.js<commit_after>'use strict';

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

//
// `dist`, `.tmp`, `src` dirs are used for dev to serve and watch files
// `dist` dir is used for build to generate optmized builds
//

module.exports = function(grunt) {
  // Load grunt tasks automatically
  require('load-grunt-tasks')(grunt);
  // load the rest of non-grunt tasks
  grunt.loadNpmTasks('assemble');
  // Time how long tasks take. Can help when optimizing build times
  require('time-grunt')(grunt);

  // Project configuration.
  grunt.initConfig({

    config: {
      src: 'src',
      dist: 'dist'
    },

    watch: {
      assemble: {
        files: ['<%= config.src %>/{content,data,templates}/{,*/}*.{md,hbs,yml,json}'],
        tasks: ['newer:assemble']
      },
      sass: {
        files: ['<%= config.src %>/assets/styles/{,*/}*.scss'],
        tasks: ['sass']
      },
      coffee: {
        files: ['<%= config.src %>/assets/scripts/{,*/}*.coffee'],
        tasks: ['newer:coffee']
      },
      js: {
        files: ['<%= config.src %>/assets/scripts/{,*/}*.js'],
        tasks: ['newer:jshint']
      },

      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          // reload when assemble generates html files
          '<%= config.dist %>/{,*/}*.html',
          // reload when sass generates css files
          '.tmp/assets/styles/{,*/}*.css',
          //reload when coffeescript generates js files
          '.tmp/assets/scripts/{,*/}*.js',
          // reload when plain css files changes
          '<%= config.src %>/assets/styles/{,*/}*.css',
          // reload when plain js files
          '<%= config.src %>/assets/scripts/{,*/}*.js',
          // reload when images changes
          '<%= config.src %>/assets/images/{,*/}*.{png,jpg,jpeg,gif}',
          // reload when fonts changes
          '<%= config.src %>/assets/fonts/{,*/}*.{eot,woff,ttf,svg}'
        ]
      }
    },

    connect: {
      options: {
        port: 9000,
        livereload: 35729,
        // change this to '0.0.0.0' to access the server from outside
        hostname: 'localhost'
      },
      livereload: {
        options: {
          open: true,
          base: [
            // for css and js generated by SASS and CoffeeScript
            '.tmp',
            // other assets found directly in source
            '<%= config.src %>',
            // for html files generated by assemble
            '<%= config.dist %>'
          ]
        }
      }
    },

    assemble: {
      pages: {
        options: {
          flatten: true,
          assets: '<%= config.dist %>/assets',
          layout: '<%= config.src %>/templates/layouts/default.hbs',
          data: '<%= config.src %>/data/*.{json,yml}',
          partials: '<%= config.src %>/templates/partials/*.hbs'
        },
        files: {
          '<%= config.dist %>/': ['<%= config.src %>/templates/pages/*.hbs']
        }
      }
    },

    sass: {
      dist: {
        options: {
          // node-neat package includes both bourbon and neat
          // we can use just node-bourbon if we don't want neat lib
          includePaths: require('node-neat').includePaths
        },

        files: [{
          expand: true,
          cwd: '<%= config.src %>/assets/styles',
          src: '{,*/}*.scss',
          dest: '.tmp/assets/styles',
          ext: '.css'
        }]
      }
    },

    coffee: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= config.src %>/assets/scripts',
          src: '{,*/}*.coffee',
          dest: '.tmp/assets/scripts',
          ext: '.js'
        }]
      }
    },

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

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

    // Usemin adds files to concat
    concat: {},
    // Usemin adds files to uglify
    uglify: {},
    // Usemin adds files to cssmin
    cssmin: {
      dist: {
        options: {
          check: 'gzip'
        }
      }
    },

    // Renames files for browser caching purposes
    rev: {
      dist: {
        files: {
          src: [
            '<%= config.dist %>/assets/scripts/{,*/}*.js',
            '<%= config.dist %>/assets/styles/{,*/}*.css',
            '<%= config.dist %>/assets/images/{,*/}*.{png,jpg,jpeg,gif}',
            '<%= config.dist %>/assets/fonts/{,*/}*.{eot,woff,ttf,svg}'
          ]
        }
      }
    },

    imagemin: {
      dist: {
        options: {
          cache: false
        },

        files: [{
          expand: true,
          cwd: '<%= config.src %>/assets/images',
          src: '{,*/}*.{png,jpg,jpeg,gif}',
          dest: '<%= config.dist %>/assets/images'
        }]
      }
    },

    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: [
        'Gruntfile.js',
        '<%= config.src %>/assets/scripts/{,*/}*.js'
      ]
    },

    copy: {
      // copy plain js and css files right next to
      // the other css and js files generated by SASS and CoffeeScript
      // in order to be optimized.
      plain: {
        expand: true,
        cwd: '<%= config.src %>/assets',
        src: [
          'scripts/{,*}/*.js',
          'styles/{,*}/*.css'
        ],
        dest: '.tmp/assets'
      },

      dist: {
        expand: true,
        cwd: '<%= config.src %>/assets',
        src: [
          // NOTE: images are copied by the imagemin task
          // TODO: add other assets here
          // Fonts
          'fonts/{,*}/*.{eot,woff,ttf,svg}'
        ],
        dest: '<%= config.dist %>/assets'
      }
    },

    clean: {
      dist: ['<%= config.dist %>/', '.tmp/']
    }
  });

  grunt.registerTask('dev', [
    'jshint',
    'clean',
    'assemble',
    'sass',
    'coffee'
  ]);

  grunt.registerTask('server', [
    'dev',
    'connect:livereload',
    'watch'
  ]);

  grunt.registerTask('build', [
    'clean',
    'assemble',
    'copy:plain',
    'copy:dist',
    'sass',
    'coffee',
    'useminPrepare',
    'concat',
    'uglify',
    'cssmin',
    'rev',
    'usemin',
    'imagemin'
  ]);

  grunt.registerTask('default', ['server']);
};
<|endoftext|>


<commit_before>// Generated on 2014-01-11 using generator-webapp 0.4.6
'use strict';

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

module.exports = function (grunt) {

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

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

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

        // Project settings
        yeoman: {
            // Configurable paths
            app: 'app',
            dist: 'dist',
            cms: 'cms-files'
        },

        // Watches files for changes and runs tasks based on the changed files
        watch: {
            js: {
                files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
                tasks: ['jshint'],
                options: {
                    livereload: true
                }
            },
            jstest: {
                files: ['test/spec/{,*/}*.js'],
                tasks: ['test:watch']
            },
            gruntfile: {
                files: ['Gruntfile.js']
            },
            less: {
                files: ['<%= yeoman.app %>/styles/less/{,*/}*.less'],
                tasks: ['less', 'copy:styles'],
                options: {
                    livereload: true
                }
            },
            livereload: {
                options: {
                    livereload: '<%= connect.options.livereload %>'
                },
                files: [
                    '<%= yeoman.app %>/{,*/}*.html',
                    '<%= yeoman.app %>/styles/{,*/}*.css',
                    '<%= yeoman.app %>/images/{,*/}*.{gif,jpeg,jpg,png,svg,webp}'
                ]
            }
        },

        // The actual grunt server settings
        connect: {
            options: {
                port: 9000,
                livereload: 35729,
                // Change this to '0.0.0.0' to access the server from outside
                hostname: 'localhost'
            },
            livereload: {
                options: {
                    open: true,
                    base: [
                        '.tmp',
                        '<%= yeoman.app %>'
                    ]
                }
            },
            test: {
                options: {
                    port: 9001,
                    base: [
                        '.tmp',
                        'test',
                        '<%= yeoman.app %>'
                    ]
                }
            },
            dist: {
                options: {
                    open: true,
                    base: '<%= yeoman.dist %>',
                    livereload: false
                }
            }
        },

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

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

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

        // Compile LESS files
        less: {
            options: {
                paths: ['<%= yeoman.app %>/styles/less'],
                sourceMap: true,
                sourceMapFilename: '<%= yeoman.app %>/styles/master.css.map'
              //  sourceRoothPath: './styles'
            },
            files: {
                src: '<%= yeoman.app %>/styles/less/master.less',
                dest: '<%= yeoman.app %>/styles/master.css'
            }
        },

       // Add vendor prefixed styles
        // autoprefixer: {
        //     options: {
        //         browsers: ['last 2 versions', '> 1%']
        //     },
        //     dist: {
        //         files: [{
        //             expand: true,
        //             src: ['<%= less.files.dest %>'],
        //             // src: ['app/.tmp/main.css']
        //             dest: './app/styles',
        //             flatten: true
        //         }]
        //     }
        // },
        // Automatically inject Bower components into the HTML file
        'bower-install': {
            app: {
                html: '<%= yeoman.app %>/index.html',
                ignorePath: '<%= yeoman.app %>/'
            }
        },

        // Renames files for browser caching purposes
        rev: {
            dist: {
                files: {
                    src: [
                        '<%= yeoman.dist %>/scripts/{,*/}*.js',
                        '!<%= yeoman.dist %>/scripts/jquery-1.11.0.min.js',
                        '<%= yeoman.dist %>/styles/{,*/}*.css',
                        '<%= yeoman.dist %>/images/{,*/}*.{gif,jpeg,jpg,png,webp}',
                        '<%= yeoman.dist %>/styles/fonts/{,*/}*.*'
                    ]
                }
            }
        },

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

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

        // The following *-min tasks produce minified files in the dist folder
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= yeoman.app %>/img',
                    src: '{,*/}*.{gif,jpeg,jpg,png}',
                    dest: '<%= yeoman.dist %>/img'
                }]
            }
        },
        svgmin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= yeoman.app %>/img',
                    src: '{,*/}*.svg',
                    dest: '<%= yeoman.dist %>/img'
                }]
            }
        },
        htmlmin: {
            dist: {
                options: {
                    collapseBooleanAttributes: true,
                    collapseWhitespace: true,
                    removeAttributeQuotes: true,
                    removeCommentsFromCDATA: true,
                    removeEmptyAttributes: true,
                    removeOptionalTags: true,
                    removeRedundantAttributes: true,
                    useShortDoctype: true
                },
                files: [{
                    expand: true,
                    cwd: '<%= yeoman.dist %>',
                    src: '{,*/}*.html',
                    dest: '<%= yeoman.dist %>'
                }]
            }
        },

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

        // Copies remaining files to places other tasks can use
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%= yeoman.app %>',
                    dest: '<%= yeoman.dist %>',
                    src: [
                        '*.{ico,png,txt}',
                        '.htaccess',
                        'images/{,*/}*.webp',
                        '{,*/}*.html',
                        'styles/fonts/{,*/}*.*',
                        'bower_components/jquery/jquery.min.js',
                        'scripts/jquery-1.11.0.min.js'
                    ]
                }]
            },
            styles: {
                expand: true,
                dot: true,
                cwd: '<%= yeoman.app %>/styles',
                dest: '<%= yeoman.app %>/.tmp/styles/',
                src: '{,*/}*.css'
            },
            cms: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%= yeoman.app %>',
                    dest: '<%= yeoman.cms %>',
                    src: [
                        'img/{,*/}*.*',
                        'styles/less/{,*/}*.less',
                        'scripts/jquery-1.11.0.min.js'
                    ]
                }]
            }
        },

        // Generates a custom Modernizr build that includes only the tests you
        // reference in your app
        modernizr: {
            devFile: '<%= yeoman.app %>/bower_components/modernizr/modernizr.js',
            outputFile: '<%= yeoman.dist %>/bower_components/modernizr/modernizr.js',
            files: [
                '<%= yeoman.dist %>/scripts/{,*/}*.js',
                '<%= yeoman.dist %>/styles/{,*/}*.css',
                '!<%= yeoman.dist %>/scripts/vendor/*'
            ],
            uglify: true
        },

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

    grunt.registerTask('serve', function (target) {
        if (target === 'dist') {
            return grunt.task.run(['build', 'connect:dist:keepalive']);
        }
        grunt.task.run([
            // Cleans out app/.tmp folder
            'clean:server',
            // Compiles less files for the first time
            'concurrent:server',
            // Starts livereload
            'connect:livereload',
            // Watches files for changes
            'watch'
        ]);
        grunt.log.subhead('Server is started, remember to type ctrl + c to stop');
    });

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

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

    grunt.registerTask('build', [
        // Empty out the dist folder for a fresh build
        'clean:dist',
        // Checks JavaScript for badness
        'jshint',
        // Create settings/tasks from html file for concatenation/minification
        'useminPrepare',
        // Tasks to minify images, svg, and compile LESS styles to app/.tmp/styles
        'concurrent:dist',
        // Concatenates css and js files from index into a .tmp folder
        'concat',
        // Minifies css into dist/styles
        'cssmin',
        // Uglifies js into dist/scripts
        'uglify',
        // Copies files from app into dist
        'copy:dist',
        // Generates a custom modernizr file using only tests that are referenced
        'modernizr',
        // Renames css and js files to avoid browser caching
        'rev',
        // Minifies HTML, replaces css and js src with the renamed one from above
       'usemin'
    ]);

    grunt.registerTask('cms', [
        'clean:cms',
        'copy:cms'
    ]);

    grunt.registerTask('default', [
        'newer:jshint',
        'test',
        'build'
    ]);
};<commit_msg>Updated build task<commit_after>// Generated on 2014-01-11 using generator-webapp 0.4.6
'use strict';

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

module.exports = function (grunt) {

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

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

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

        // Project settings
        yeoman: {
            // Configurable paths
            app: 'app',
            dist: 'dist',
            cms: 'cms-files'
        },

        // Watches files for changes and runs tasks based on the changed files
        watch: {
            js: {
                files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
                tasks: ['jshint'],
                options: {
                    livereload: true
                }
            },
            jstest: {
                files: ['test/spec/{,*/}*.js'],
                tasks: ['test:watch']
            },
            gruntfile: {
                files: ['Gruntfile.js']
            },
            less: {
                files: ['<%= yeoman.app %>/styles/less/{,*/}*.less'],
                tasks: ['less', 'copy:styles'],
                options: {
                    livereload: true
                }
            },
            livereload: {
                options: {
                    livereload: '<%= connect.options.livereload %>'
                },
                files: [
                    '<%= yeoman.app %>/{,*/}*.html',
                    '<%= yeoman.app %>/styles/{,*/}*.css',
                    '<%= yeoman.app %>/images/{,*/}*.{gif,jpeg,jpg,png,svg,webp}'
                ]
            }
        },

        // The actual grunt server settings
        connect: {
            options: {
                port: 9000,
                livereload: 35729,
                // Change this to '0.0.0.0' to access the server from outside
                hostname: 'localhost'
            },
            livereload: {
                options: {
                    open: true,
                    base: [
                        '.tmp',
                        '<%= yeoman.app %>'
                    ]
                }
            },
            test: {
                options: {
                    port: 9001,
                    base: [
                        '.tmp',
                        'test',
                        '<%= yeoman.app %>'
                    ]
                }
            },
            dist: {
                options: {
                    open: true,
                    base: '<%= yeoman.dist %>',
                    livereload: false
                }
            }
        },

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

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

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

        // Compile LESS files
        less: {
            options: {
                paths: ['<%= yeoman.app %>/styles/less'],
                sourceMap: true,
                sourceMapFilename: '<%= yeoman.app %>/styles/master.css.map'
              //  sourceRoothPath: './styles'
            },
            files: {
                src: '<%= yeoman.app %>/styles/less/master.less',
                dest: '<%= yeoman.app %>/styles/master.css'
            }
        },

       // Add vendor prefixed styles
        // autoprefixer: {
        //     options: {
        //         browsers: ['last 2 versions', '> 1%']
        //     },
        //     dist: {
        //         files: [{
        //             expand: true,
        //             src: ['<%= less.files.dest %>'],
        //             // src: ['app/.tmp/main.css']
        //             dest: './app/styles',
        //             flatten: true
        //         }]
        //     }
        // },
        // Automatically inject Bower components into the HTML file
        'bower-install': {
            app: {
                html: '<%= yeoman.app %>/index.html',
                ignorePath: '<%= yeoman.app %>/'
            }
        },

        // Renames files for browser caching purposes
        rev: {
            dist: {
                files: {
                    src: [
                        '<%= yeoman.dist %>/scripts/{,*/}*.js',
                        '!<%= yeoman.dist %>/scripts/jquery-1.11.0.min.js',
                        '<%= yeoman.dist %>/styles/{,*/}*.css',
                        '<%= yeoman.dist %>/images/{,*/}*.{gif,jpeg,jpg,png,webp}',
                        '<%= yeoman.dist %>/styles/fonts/{,*/}*.*'
                    ]
                }
            }
        },

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

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

        // The following *-min tasks produce minified files in the dist folder
        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= yeoman.app %>/img',
                    src: '{,*/}*.{gif,jpeg,jpg,png}',
                    dest: '<%= yeoman.dist %>/img'
                }]
            }
        },
        svgmin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%= yeoman.app %>/img',
                    src: '{,*/}*.svg',
                    dest: '<%= yeoman.dist %>/img'
                }]
            }
        },
        htmlmin: {
            dist: {
                options: {
                    collapseBooleanAttributes: true,
                    collapseWhitespace: true,
                    removeAttributeQuotes: true,
                    removeCommentsFromCDATA: true,
                    removeEmptyAttributes: true,
                    removeOptionalTags: true,
                    removeRedundantAttributes: true,
                    useShortDoctype: true
                },
                files: [{
                    expand: true,
                    cwd: '<%= yeoman.dist %>',
                    src: '{,*/}*.html',
                    dest: '<%= yeoman.dist %>'
                }]
            }
        },

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

        // Copies remaining files to places other tasks can use
        copy: {
            dist: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%= yeoman.app %>',
                    dest: '<%= yeoman.dist %>',
                    src: [
                        '*.{ico,png,txt}',
                        '.htaccess',
                        'images/{,*/}*.webp',
                        '{,*/}*.html',
                        '!{,*/}kitchen-sink.html'
                        'fonts/{,*/}*.*',
                        'bower_components/jquery/jquery.min.js',
                        'scripts/jquery-1.11.0.min.js'
                    ]
                }]
            },
            styles: {
                expand: true,
                dot: true,
                cwd: '<%= yeoman.app %>/styles',
                dest: '<%= yeoman.app %>/.tmp/styles/',
                src: '{,*/}*.css'
            },
            cms: {
                files: [{
                    expand: true,
                    dot: true,
                    cwd: '<%= yeoman.app %>',
                    dest: '<%= yeoman.cms %>',
                    src: [
                        'img/{,*/}*.*',
                        'styles/less/{,*/}*.less',
                        'scripts/jquery-1.11.0.min.js'
                    ]
                }]
            }
        },

        // Generates a custom Modernizr build that includes only the tests you
        // reference in your app
        modernizr: {
            devFile: '<%= yeoman.app %>/bower_components/modernizr/modernizr.js',
            outputFile: '<%= yeoman.dist %>/bower_components/modernizr/modernizr.js',
            files: [
                '<%= yeoman.dist %>/scripts/{,*/}*.js',
                '<%= yeoman.dist %>/styles/{,*/}*.css',
                '!<%= yeoman.dist %>/scripts/vendor/*'
            ],
            uglify: true
        },

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

    grunt.registerTask('serve', function (target) {
        if (target === 'dist') {
            return grunt.task.run(['build', 'connect:dist:keepalive']);
        }
        grunt.task.run([
            // Cleans out app/.tmp folder
            'clean:server',
            // Compiles less files for the first time
            'concurrent:server',
            // Starts livereload
            'connect:livereload',
            // Watches files for changes
            'watch'
        ]);
        grunt.log.subhead('Server is started, remember to type ctrl + c to stop');
    });

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

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

    grunt.registerTask('build', [
        // Empty out the dist folder for a fresh build
        'clean:dist',
        // Checks JavaScript for badness
        'jshint',
        // Create settings/tasks from html file for concatenation/minification
        'useminPrepare',
        // Tasks to minify images, svg, and compile LESS styles to app/.tmp/styles
        'concurrent:dist',
        // Concatenates css and js files from index into a .tmp folder
        'concat',
        // Minifies css into dist/styles
        'cssmin',
        // Uglifies js into dist/scripts
        'uglify',
        // Copies files from app into dist
        'copy:dist',
        // Generates a custom modernizr file using only tests that are referenced
        'modernizr',
        // Renames css and js files to avoid browser caching
        'rev',
        // Minifies HTML, replaces css and js src with the renamed one from above
       'usemin'
    ]);

    grunt.registerTask('cms', [
        'clean:cms',
        'copy:cms'
    ]);

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


<commit_before>module.exports = function(grunt) {
  require('load-grunt-tasks')(grunt);
  grunt.initConfig({
    // Configure a mochaTest task
    mochaTest: {
      test: {
        options: {
          reporter: 'spec'
        },
        src: ['test/**/*.js']
      }
    },
    watch: {
      options: {
        livereload: true,
      },
      express: {
        files:  [ '*.js','routes/*.js', 'models/*.js', 'config/*.js','api/*.js','apiObjects/*.js'  ],
        tasks:  [ 'express:dev' ],
        options: {
          spawn: false // Without this option specified express won't be reloaded
        }
      }
    },
    express: {
      options: {
        port : 3000,
        node_env: 'development'
      },
      dev: {
        options: {
          script: 'app.js',
          node_env: 'development'
        }
      },
      prod: {
        options: {
          script: 'app.js',
          node_env: 'production'
        }
      }
    },
    open: {
      server: {
        url: 'http://localhost:<%= express:options:port %>'
      }
    }
  });

  grunt.registerTask('test', 'mochaTest');

  grunt.registerTask('server', function(arg) {
    if(arg && arg == 'prod')
    {
      grunt.task.run([
        'express:prod',
        'open',
        'watch'
        ]);
    }
    else
    {
      grunt.task.run([
        'express:dev',
        'open',
        'watch'
        ]);
    }
  });
  grunt.registerTask('default', [ 'server' ]);
  grunt.registerTask('dist', [ 'server:prod' ]);

};
<commit_msg>fixed port<commit_after>module.exports = function(grunt) {
  require('load-grunt-tasks')(grunt);
  grunt.initConfig({
    // Configure a mochaTest task
    mochaTest: {
      test: {
        options: {
          reporter: 'spec'
        },
        src: ['test/**/*.js']
      }
    },
    watch: {
      options: {
        livereload: true,
      },
      express: {
        files:  [ '*.js','routes/*.js', 'models/*.js', 'config/*.js','api/*.js','apiObjects/*.js'  ],
        tasks:  [ 'express:dev' ],
        options: {
          spawn: false // Without this option specified express won't be reloaded
        }
      }
    },
    express: {
      options: {
        port : 3000,
        node_env: 'development'
      },
      dev: {
        options: {
          script: 'app.js',
          node_env: 'development'
        }
      },
      prod: {
        options: {
          script: 'app.js',
          node_env: 'production'
        }
      }
    },
    open: {
      server: {
        url: 'http://localhost:3000'
      }
    }
  });

  grunt.registerTask('test', 'mochaTest');

  grunt.registerTask('server', function(arg) {
    if(arg && arg == 'prod')
    {
      grunt.task.run([
        'express:prod',
        'open',
        'watch'
        ]);
    }
    else
    {
      grunt.task.run([
        'express:dev',
        'open',
        'watch'
        ]);
    }
  });
  grunt.registerTask('default', [ 'server' ]);
  grunt.registerTask('dist', [ 'server:prod' ]);

};
<|endoftext|>


<commit_before>// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %>
'use strict';

module.exports = function (grunt) {
    // load all grunt tasks
    require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

    // configurable paths
    var yeomanConfig = {
        appBase: 'app',
        devBase: 'dev',
        distBase: 'dist',
        <% if (wordpress === true) { %>
        themeUrl: '/wp-content/themes',
        app: 'app/wp-content/themes/<%= siteCamel %>',
        dev: 'dev/wp-content/themes/<%= siteCamel %>',
        dist: 'dist/wp-content/themes/<%= siteCamel %>'
        <% } else { %>
        app: 'app',
        dev: 'dev',
        dist: 'dist'
        <% } %>
    };

    grunt.initConfig({
        yeoman: yeomanConfig,

        clean: {
            dev: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%%= yeoman.devBase %>/*',
                        '!<%%= yeoman.devBase %>/.git*'
                    ]
                }]
            },

            dist: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%%= yeoman.distBase %>/*',
                        '!<%%= yeoman.distBase %>/.git*'
                    ]
                }]
            }
        },

        connect: {
            options: {
                port: 9001,
                livereload: 35729,
                hostname: 'localhost',
                base: '<%%= yeoman.devBase %>'
            },
            livereload: {
                options: {
                    open: true,
                    base: [
                        '<%%= yeoman.devBase %>'
                    ]
                }
            }
        },

        <% if (cssFramework === 'compassSusy') { %>compass: {
            dev: {
                options: {
                    sassDir: '<%%= yeoman.app %>/assets/scss',
                    cssDir: '<%%= yeoman.dev %>/assets/css',
                    environment: 'development'
                }
            },

            dist: {
                options: {
                    sassDir: '<%%= yeoman.app %>/assets/scss',
                    cssDir: '<%%= yeoman.dist %>/assets/css',
                    environment: 'production'
                }
            }
        },<% } %>

        copy: {
            dev: {
                files: [
                    {expand: true, cwd: '<%%= yeoman.appBase %>', src: ['**', '!**/scss/**', '!.htaccess', '!**/languages/**'], dest: '<%%= yeoman.devBase %>'},
                    {expand: true, cwd: '<%%= yeoman.app %>/assets/scss/fonts', src: ['**'], dest: '<%%= yeoman.dev %>/assets/css/fonts'},
                    //{expand: true, cwd: '<%%= yeoman.appBase %>', src: ['backgroundsize.min.htc'], dest: '/'},
                    {expand: true, cwd: 'bower_components', src: ['**'], dest: '<%%= yeoman.dev %>/assets/bower_components'},<% if (wordpress === true) { %>,
                        {expand: true, cwd: '<%%= yeoman.app %>/languages', src: ['_s.pot'], dest: '<%%= yeoman.dev %>/languages', rename: function (dest) {
                            return dest + '/<%= slugSiteName %>.pot';
                    }}<% } %>
                ]
            },

            dist: {
                files: [
                    {expand: true, cwd: '<%%= yeoman.appBase %>', src: ['**', '!**/img/sprite-assets/**', '!**/scss/**', '!**/js/*.js', '!**/languages/**'], dest: '<%%= yeoman.distBase %>'},
                    {expand: true, cwd: '<%%= yeoman.app %>', src: ['.htaccess'], dest: '<%%= yeoman.dist %>'},
                    {expand: true, cwd: '<%%= yeoman.app %>/assets/scss/fonts', src: ['**'], dest: '<%%= yeoman.dist %>/assets/css/fonts'},
                    {expand: true, cwd: 'bower_components/jquery', src: ['jquery.min.js'], dest: '<%%= yeoman.dist %>/assets/js/lib'},
                    {expand: true, cwd: 'bower_components/jquery-legacy', src: ['jquery.min.js'], dest: '<%%= yeoman.dist %>/assets/js/lib', rename: function (dest) {
                        return dest + '/jquery-legacy.min.js';
                    }},
                    // Only copy over the minified migrate plugin
                    {expand: true, cwd: 'bower_components/jquery-migrate', src: ['jquery-migrate.min.js'], dest: '<%%= yeoman.dist %>/assets/js/lib'}<% if (wordpress === true) { %>,
                    {expand: true, cwd: '<%%= yeoman.app %>/languages', src: ['_s.pot'], dest: '<%%= yeoman.dist %>/languages', rename: function (dest) {
                        return dest + '/<%= slugSiteName %>.pot';
                    }}<% } %>
                ]
            },

            html: {
                files: [
                    {expand: true, cwd: '<%%= yeoman.app %>', src: ['{,*/}*.html'], dest: '<%%= yeoman.dev %>'}
                ]
            }
        },

        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= yeoman.app %>/assets/img/',
                    src: ['**/*.{png,jpg,jpeg,gif,svg}', '!sprite-assets/*.png'],
                    dest: '<%%= yeoman.app %>/assets/img/'
                }]
            }
        },

        modernizr: {
            devFile: 'bower_components/modernizr/modernizr.js',
            outputFile: '<%%= yeoman.dist %>/assets/js/lib/modernizr-custom.min.js',
            files: ['<%%= yeoman.dist %>/**/*.js', '<%%= yeoman.dist %>/**/*.css', '<%%= yeoman.dist %>/**/*.scss']
        },

        open: {
            all: {
                path: 'http://localhost:<%%= connect.options.port %>'
            }
        },
        <% if (wordpress === true) { %>
        php: {
            options: {
                port: 80,
                hostname: 'gendev',
                keepalive: true,
                open: true
            },

            watch: {
            }
        },
        <% } %>
        processhtml: {
            options: {
                process: true,
                templateSettings: {
                    opener: '{!',
                    closer: '!}'
                }
            },
            dev: {
                options: {
                    data: {
                        jqMinLocal: 'assets/bower_components/jquery/jquery.min.js',
                        jqLegMinLocal: 'assets/bower_components/jquery-legacy/jquery.min.js',
                        jqMigrate: 'assets/bower_components/jquery-migrate/jquery-migrate.js'
                    }
                },
                files: {
                    '<%%= yeoman.dev %>/index.html': ['<%%= yeoman.dev %>/index.html']
                }
            },
            dist: {
                options: {
                    data: {
                        jqMinLocal: 'assets/js/lib/jquery.min.js',
                        jqLegMinLocal: 'assets/js/lib/jquery-legacy.min.js',
                        jqMigrate: 'assets/js/lib/jquery-migrate.min.js'
                    }
                },
                files: {
                    '<%%= yeoman.dist %>/index.html': ['<%%= yeoman.dist %>/index.html']
                }
            }
        },

        replace: {
            <% if (wordpress === true) { %>
            options: {
                patterns: [{
                    match: '/Text Domain: _s/g',
                    replacement: function () {
                        return 'Text Domain: <%= slugSiteName %>';
                    },
                    expression: true
                }, {
                    match: '/\'_s\'/g',
                    replacement: function () {
                        return "'<%= slugSiteName %>'";
                    },
                    expression: true
                }, {
                    match: '/_s_/g',
                    replacement: function () {
                        return "<%= slugSiteName %>_";
                    },
                    expression: true
                }, {
                    match: '/ _s/g',
                    replacement: function () {
                        var lowerCase = "<%= slugSiteName %>";
                        var capitalized = lowerCase.charAt(0).toUpperCase() + lowerCase.slice(1);
                        return ' ' + capitalized;
                    },
                    expression: true
                }, {
                    match: '/_s-/g',
                    replacement: function () {
                        return "<%= slugSiteName %>-";
                    },
                    expression: true
                }]
            },

            dev: {
                files: [
                    {expand: true, src: ['<%%= yeoman.dev %>/**', '<%%= yeoman.dev %>/languages/<%= slugSiteName %>.pot']}
                ]
            },

            dist: {
                files: [
                    {expand: true, src: ['<%%= yeoman.dist %>/**', '<%%= yeoman.dist %>/languages/<%= slugSiteName %>.pot']}
                ]
            }
            <% } else { %>
            options: {
                patterns: [{
                    match: '/@jquery-cdn/g',
                    replacement: function () {
                        var jQConf = grunt.file.readJSON('bower_components/jquery/bower.json');
                        return '//ajax.googleapis.com/ajax/libs/jquery/' + jQConf.version + '/jquery.min.js';
                    },
                    expression: true
                }, {
                    match: '/@jquery-legacy-cdn/g',
                    replacement: function () {
                        var jQLegConf = grunt.file.readJSON('bower_components/jquery-legacy/bower.json');
                        return '//ajax.googleapis.com/ajax/libs/jquery/' + jQLegConf.version + '/jquery.min.js';
                    },
                    expression: true
                }]
            },

            dev: {
                files: [
                    {src: ['dev/index.html'], dest: 'dev/index.html'}
                ]
            },

            dist: {
                files: [
                    {src: ['dist/index.html'], dest: 'dist/index.html'}
                ]
            }
            <% } %>
        },

        rev: {
            dist: {
                files: {
                    src: [
                        '<%%= yeoman.dist %>/assets/js/{,*/}*.js',
                        '<%%= yeoman.dist %>/assets/css/{,*/}*.css',
                        '<%%= yeoman.dist %>/assets/img/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
                        '<%%= yeoman.dist %>/assets/css/fonts/*'
                    ]
                }
            }
        },

        <% if (cssFramework !== 'compassSusy') { %>sass: {
            dev: {
                expand: true,
                cwd: '<%%= yeoman.app %>/assets/scss',
                src: ['*.scss'],
                dest: '<%%= yeoman.dev %>/assets/css',
                ext: '.css'
            },

            dist: {
                expand: true,
                cwd: '<%%= yeoman.app %>/assets/scss',
                src: ['*.scss'],
                dest: '<%%= yeoman.dist %>/assets/css',
                ext: '.css'
            }
        },<% } %>

        spriteHD: {
            options: {
                destImg: '<%%= yeoman.app %>/assets/img',
                destCSS: '<%%= yeoman.app %>/assets/scss/global',
                imgUrl: '../img'
            },

            all: {
                src: '<%%= yeoman.app %>/assets/img/sprite-assets/*',
                spriteName: 'sheet'
            }
        },

        svgmin: {
            options: {
                plugins: [{
                    removeViewBox: false
                }]
            },
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= yeoman.app %>/assets/img',
                    src: ['{,*/}*.svg'],
                    dest: '<%%= yeoman.app %>/assets/img/',
                    ext: '.svg'
                }]
            }
        },

        svg2png: {
            dist: {
                files: [
                    { src: ['<%%= yeoman.app %>/assets/img/{,*/}*.svg'] }
                ]
            }
        },

        usemin: {
            options: {
                dirs: ['<%%= yeoman.dist %>']
            },
            html: ['<%%= yeoman.dist %>/*.html'],
            css: '<%%= yeoman.dist %>/assets/css/*.css'
        },

        useminPrepare: {
            options: {
                dest: '<%%= yeoman.dist %>'
            },
            html: '<%%= yeoman.app %>/index.html',
            css: '<%%= yeoman.app %>/assets/scss/**/*.scss'
        },

        watch: {
            options: {
                livereload: true,
                port: 9001
            },
            css: {
                files: ['<%%= yeoman.app %>/assets/scss/{,*/}*.scss'],
                <% if (cssFramework === 'compassSusy') { %>
                tasks: ['compass:dev']
                <% } else { %>
                tasks: ['sass:dev']
                <% } %>
            },
            html: {
                files: ['<%%= yeoman.app %>/{,*/}*.html'],
                tasks: ['copy:html', 'replace', 'processhtml:dev']
            },
            sprites: {
                files: ['<%%= yeoman.app %>/assets/img/sprite-assets/*.png'],
                tasks: ['spriteHD', 'copy:dev']
            },
            php: {
                files: ['<%%= yeoman.app %>/{,*/}{,*/}*.php'],
                tasks: ['dev']
            },
            js: {
                files: ['<%= yeoman.app %>/assets/js/{,*/}*.js'],
                tasks: ['dev']
            },
            img: {
                files: ['<%= yeoman.app %>/assets/img/**'],
                tasks: ['dev']
            }
        }
    });

    grunt.registerTask('server', [
        'dev',<% if (wordpress === false) { %>
        'connect:livereload',
        <% } %>'watch'
    ]);

    grunt.registerTask('dev', [
        'clean:dev',
        'copy:dev',
        'spriteHD',<% if (cssFramework === 'compassSusy') { %>
        'compass:dev',<% } else { %>
        'sass:dev',<% } %>
        'processhtml:dev',
        'replace:dev'
    ]);

    grunt.registerTask('build', [
        'clean:dist',
        'useminPrepare',
        'svgmin',
        'imagemin:dist',
        'svg2png',
        'spriteHD',<% if (cssFramework === 'compassSusy') { %>
        'compass:dist',<% } else { %>
        'sass:dist',<% } %>
        'concat',
        'uglify',
        'modernizr',
        'copy:dist',
        'processhtml:dist',
        'replace:dist',
        'rev',
        'usemin'
    ]);
};<commit_msg>Fixed issue where build script wouldn't copy over index.html<commit_after>// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %>
'use strict';

module.exports = function (grunt) {
    // load all grunt tasks
    require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

    // configurable paths
    var yeomanConfig = {
        appBase: 'app',
        devBase: 'dev',
        distBase: 'dist',
        <% if (wordpress === true) { %>
        themeUrl: '/wp-content/themes',
        app: 'app/wp-content/themes/<%= siteCamel %>',
        dev: 'dev/wp-content/themes/<%= siteCamel %>',
        dist: 'dist/wp-content/themes/<%= siteCamel %>'
        <% } else { %>
        app: 'app',
        dev: 'dev',
        dist: 'dist'
        <% } %>
    };

    grunt.initConfig({
        yeoman: yeomanConfig,

        clean: {
            dev: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%%= yeoman.devBase %>/*',
                        '!<%%= yeoman.devBase %>/.git*'
                    ]
                }]
            },

            dist: {
                files: [{
                    dot: true,
                    src: [
                        '.tmp',
                        '<%%= yeoman.distBase %>/*',
                        '!<%%= yeoman.distBase %>/.git*'
                    ]
                }]
            }
        },

        connect: {
            options: {
                port: 9001,
                livereload: 35729,
                hostname: 'localhost',
                base: '<%%= yeoman.devBase %>'
            },
            livereload: {
                options: {
                    open: true,
                    base: [
                        '<%%= yeoman.devBase %>'
                    ]
                }
            }
        },

        <% if (cssFramework === 'compassSusy') { %>compass: {
            dev: {
                options: {
                    sassDir: '<%%= yeoman.app %>/assets/scss',
                    cssDir: '<%%= yeoman.dev %>/assets/css',
                    environment: 'development'
                }
            },

            dist: {
                options: {
                    sassDir: '<%%= yeoman.app %>/assets/scss',
                    cssDir: '<%%= yeoman.dist %>/assets/css',
                    environment: 'production'
                }
            }
        },<% } %>

        copy: {
            dev: {
                files: [
                    {expand: true, cwd: '<%%= yeoman.appBase %>', src: ['**', '!**/scss/**', '!.htaccess', '!**/languages/**'], dest: '<%%= yeoman.devBase %>'},
                    {expand: true, cwd: '<%%= yeoman.app %>/assets/scss/fonts', src: ['**'], dest: '<%%= yeoman.dev %>/assets/css/fonts'},
                    //{expand: true, cwd: '<%%= yeoman.appBase %>', src: ['backgroundsize.min.htc'], dest: '/'},
                    {expand: true, cwd: 'bower_components', src: ['**'], dest: '<%%= yeoman.dev %>/assets/bower_components'},<% if (wordpress === true) { %>,
                        {expand: true, cwd: '<%%= yeoman.app %>/languages', src: ['_s.pot'], dest: '<%%= yeoman.dev %>/languages', rename: function (dest) {
                            return dest + '/<%= slugSiteName %>.pot';
                    }}<% } %>
                ]
            },

            dist: {
                files: [
                    {expand: true, cwd: '<%%= yeoman.appBase %>', src: ['**', '!**/img/sprite-assets/**', '!**/scss/**', '!**/js/*.js', '!**/languages/**'], dest: '<%%= yeoman.distBase %>'},
                    {expand: true, cwd: '<%%= yeoman.app %>', src: ['.htaccess'], dest: '<%%= yeoman.dist %>'},
                    {expand: true, cwd: '<%%= yeoman.app %>/assets/scss/fonts', src: ['**'], dest: '<%%= yeoman.dist %>/assets/css/fonts'},
                    {expand: true, cwd: 'bower_components/jquery', src: ['jquery.min.js'], dest: '<%%= yeoman.dist %>/assets/js/lib'},
                    {expand: true, cwd: 'bower_components/jquery-legacy', src: ['jquery.min.js'], dest: '<%%= yeoman.dist %>/assets/js/lib', rename: function (dest) {
                        return dest + '/jquery-legacy.min.js';
                    }},
                    // Only copy over the minified migrate plugin
                    {expand: true, cwd: 'bower_components/jquery-migrate', src: ['jquery-migrate.min.js'], dest: '<%%= yeoman.dist %>/assets/js/lib'}<% if (wordpress === true) { %>,
                    {expand: true, cwd: '<%%= yeoman.app %>/languages', src: ['_s.pot'], dest: '<%%= yeoman.dist %>/languages', rename: function (dest) {
                        return dest + '/<%= slugSiteName %>.pot';
                    }}<% } %>
                ]
            },

            html: {
                files: [
                    {expand: true, cwd: '<%%= yeoman.app %>', src: ['{,*/}*.html'], dest: '<%%= yeoman.dev %>'}
                ]
            }
        },

        imagemin: {
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= yeoman.app %>/assets/img/',
                    src: ['**/*.{png,jpg,jpeg,gif,svg}', '!sprite-assets/*.png'],
                    dest: '<%%= yeoman.app %>/assets/img/'
                }]
            }
        },

        modernizr: {
            devFile: 'bower_components/modernizr/modernizr.js',
            outputFile: '<%%= yeoman.dist %>/assets/js/lib/modernizr-custom.min.js',
            files: ['<%%= yeoman.dist %>/**/*.js', '<%%= yeoman.dist %>/**/*.css', '<%%= yeoman.dist %>/**/*.scss']
        },

        open: {
            all: {
                path: 'http://localhost:<%%= connect.options.port %>'
            }
        },
        <% if (wordpress === true) { %>
        php: {
            options: {
                port: 80,
                hostname: 'gendev',
                keepalive: true,
                open: true
            },

            watch: {
            }
        },
        <% } %>
        processhtml: {
            options: {
                process: true,
                templateSettings: {
                    opener: '{!',
                    closer: '!}'
                }
            },
            dev: {
                options: {
                    data: {
                        jqMinLocal: 'assets/bower_components/jquery/jquery.min.js',
                        jqLegMinLocal: 'assets/bower_components/jquery-legacy/jquery.min.js',
                        jqMigrate: 'assets/bower_components/jquery-migrate/jquery-migrate.js'
                    }
                },
                files: {
                    '<%%= yeoman.dev %>/index.html': ['<%%= yeoman.dev %>/index.html']
                }
            },
            dist: {
                options: {
                    data: {
                        jqMinLocal: 'assets/js/lib/jquery.min.js',
                        jqLegMinLocal: 'assets/js/lib/jquery-legacy.min.js',
                        jqMigrate: 'assets/js/lib/jquery-migrate.min.js'
                    }
                },
                files: {
                    '<%%= yeoman.dist %>/index.html': ['<%%= yeoman.dist %>/index.html']
                }
            }
        },

        replace: {
            <% if (wordpress === true) { %>
            options: {
                patterns: [{
                    match: '/Text Domain: _s/g',
                    replacement: function () {
                        return 'Text Domain: <%= slugSiteName %>';
                    },
                    expression: true
                }, {
                    match: '/\'_s\'/g',
                    replacement: function () {
                        return "'<%= slugSiteName %>'";
                    },
                    expression: true
                }, {
                    match: '/_s_/g',
                    replacement: function () {
                        return "<%= slugSiteName %>_";
                    },
                    expression: true
                }, {
                    match: '/ _s/g',
                    replacement: function () {
                        var lowerCase = "<%= slugSiteName %>";
                        var capitalized = lowerCase.charAt(0).toUpperCase() + lowerCase.slice(1);
                        return ' ' + capitalized;
                    },
                    expression: true
                }, {
                    match: '/_s-/g',
                    replacement: function () {
                        return "<%= slugSiteName %>-";
                    },
                    expression: true
                }]
            },

            dev: {
                files: [
                    {expand: true, src: ['<%%= yeoman.dev %>/**', '<%%= yeoman.dev %>/languages/<%= slugSiteName %>.pot']}
                ]
            },

            dist: {
                files: [
                    {expand: true, src: ['<%%= yeoman.dist %>/**', '<%%= yeoman.dist %>/languages/<%= slugSiteName %>.pot']}
                ]
            }
            <% } else { %>
            options: {
                patterns: [{
                    match: '/@jquery-cdn/g',
                    replacement: function () {
                        var jQConf = grunt.file.readJSON('bower_components/jquery/bower.json');
                        return '//ajax.googleapis.com/ajax/libs/jquery/' + jQConf.version + '/jquery.min.js';
                    },
                    expression: true
                }, {
                    match: '/@jquery-legacy-cdn/g',
                    replacement: function () {
                        var jQLegConf = grunt.file.readJSON('bower_components/jquery-legacy/bower.json');
                        return '//ajax.googleapis.com/ajax/libs/jquery/' + jQLegConf.version + '/jquery.min.js';
                    },
                    expression: true
                }]
            },

            dev: {
                files: [
                    {src: ['dev/index.html'], dest: 'dev/index.html'}
                ]
            },

            dist: {
                files: [
                    {src: ['dist/index.html'], dest: 'dist/index.html'}
                ]
            }
            <% } %>
        },

        rev: {
            dist: {
                files: {
                    src: [
                        '<%%= yeoman.dist %>/assets/js/{,*/}*.js',
                        '<%%= yeoman.dist %>/assets/css/{,*/}*.css',
                        '<%%= yeoman.dist %>/assets/img/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
                        '<%%= yeoman.dist %>/assets/css/fonts/*'
                    ]
                }
            }
        },

        <% if (cssFramework !== 'compassSusy') { %>sass: {
            dev: {
                expand: true,
                cwd: '<%%= yeoman.app %>/assets/scss',
                src: ['*.scss'],
                dest: '<%%= yeoman.dev %>/assets/css',
                ext: '.css'
            },

            dist: {
                expand: true,
                cwd: '<%%= yeoman.app %>/assets/scss',
                src: ['*.scss'],
                dest: '<%%= yeoman.dist %>/assets/css',
                ext: '.css'
            }
        },<% } %>

        spriteHD: {
            options: {
                destImg: '<%%= yeoman.app %>/assets/img',
                destCSS: '<%%= yeoman.app %>/assets/scss/global',
                imgUrl: '../img'
            },

            all: {
                src: '<%%= yeoman.app %>/assets/img/sprite-assets/*',
                spriteName: 'sheet'
            }
        },

        svgmin: {
            options: {
                plugins: [{
                    removeViewBox: false
                }]
            },
            dist: {
                files: [{
                    expand: true,
                    cwd: '<%%= yeoman.app %>/assets/img',
                    src: ['{,*/}*.svg'],
                    dest: '<%%= yeoman.app %>/assets/img/',
                    ext: '.svg'
                }]
            }
        },

        svg2png: {
            dist: {
                files: [
                    { src: ['<%%= yeoman.app %>/assets/img/{,*/}*.svg'] }
                ]
            }
        },

        usemin: {
            options: {
                dirs: ['<%%= yeoman.dist %>']
            },
            html: ['<%%= yeoman.dist %>/*.html'],
            css: '<%%= yeoman.dist %>/assets/css/*.css'
        },

        useminPrepare: {
            options: {
                dest: '<%%= yeoman.dist %>'
            },
            html: '<%%= yeoman.app %>/index.html',
            css: '<%%= yeoman.app %>/assets/scss/**/*.scss'
        },

        watch: {
            options: {
                livereload: true,
                port: 9001
            },
            css: {
                files: ['<%%= yeoman.app %>/assets/scss/{,*/}*.scss'],
                <% if (cssFramework === 'compassSusy') { %>
                tasks: ['compass:dev']
                <% } else { %>
                tasks: ['sass:dev']
                <% } %>
            },
            html: {
                files: ['<%%= yeoman.app %>/{,*/}*.html'],
                tasks: ['copy:html', 'replace', 'processhtml:dev']
            },
            sprites: {
                files: ['<%%= yeoman.app %>/assets/img/sprite-assets/*.png'],
                tasks: ['spriteHD', 'copy:dev']
            },
            php: {
                files: ['<%%= yeoman.app %>/{,*/}{,*/}*.php'],
                tasks: ['dev']
            },
            js: {
                files: ['<%= yeoman.app %>/assets/js/{,*/}*.js'],
                tasks: ['dev']
            },
            img: {
                files: ['<%= yeoman.app %>/assets/img/**'],
                tasks: ['dev']
            }
        }
    });

    grunt.registerTask('server', [
        'dev',<% if (wordpress === false) { %>
        'connect:livereload',
        <% } %>'watch'
    ]);

    grunt.registerTask('dev', [
        'clean:dev',
        'copy:dev',
        'spriteHD',<% if (cssFramework === 'compassSusy') { %>
        'compass:dev',<% } else { %>
        'sass:dev',<% } %>
        'processhtml:dev',
        'replace:dev'
    ]);

    grunt.registerTask('build', [
        'clean:dist',
        'useminPrepare',
        'svgmin',
        'imagemin:dist',
        'svg2png',
        'spriteHD',<% if (cssFramework === 'compassSusy') { %>
        'compass:dist',<% } else { %>
        'sass:dist',<% } %>
        'concat',
        'uglify',
        'rev',
        'modernizr',
        'copy:dist',
        'processhtml:dist',
        'replace:dist',
        'usemin'
    ]);
};<|endoftext|>


<commit_before>'use strict';

var Context = require('./context').Context;

var isPretranslated = false;
var rtlList = ['ar', 'he', 'fa', 'ps', 'ur'];

var ctx = new Context();

// Public API

navigator.mozL10n = {
  translate: translateFragment,
  localize: localizeElement,
  get: ctx.get.bind(ctx),
  ready: ctx.ready.bind(ctx),
  get readyState() {
    return ctx.isReady ? 'complete' : 'loading';
  },
  language: {
    set code(lang) {
      initLocale(lang, true);
    },
    get code() {
      return ctx.supportedLocales[0];
    },
    get direction() {
      return getDirection(ctx.supportedLocales[0]);
    }
  }
};

function getDirection(lang) {
  return (rtlList.indexOf(lang) >= 0) ? 'rtl' : 'ltr';
}

var readyStates = {
  'loading': 0,
  'interactive': 1,
  'complete': 2
};

function waitFor(state, callback) {
  state = readyStates[state];
  if (readyStates[document.readyState] >= state) {
    callback();
    return;
  }
  document.addEventListener('readystatechange', function l10n_onrsc() {
    if (readyStates[document.readyState] >= state) {
      document.removeEventListener('readystatechange', l10n_onrsc);
      callback();
    }
  });
}

if (window.document) {
  isPretranslated = (document.documentElement.lang === navigator.language);

  if (isPretranslated) {
    waitFor('complete', function() {
      window.setTimeout(initDocumentLocalization.bind(null, initLocale));
    });
  } else {
    initDocumentLocalization(initLocale);
  }
}

function initDocumentLocalization(cb) {
  var resLinks = document.head.querySelectorAll('link[type="application/l10n"]');
  var iniLinks = [];
  var link;

  for (link of resLinks) {
    var url = link.getAttribute('href');
    var type = url.substr(url.lastIndexOf('.') + 1);
    if (type === 'ini') {
      iniLinks.push(url);
    } else {
      ctx.resLinks.push(url);
    }
  }

  var iniLoads = iniLinks.length;
  if (iniLoads === 0) {
    onIniLoaded();
  }

  function onIniLoaded() {
    iniLoads--;
    if (iniLoads <= 0) {
      cb();
    }
  }

  for (link of iniLinks) {
    loadINI(link, onIniLoaded);
  }
}

function initLocale(lang, forced) {
  ctx.ready(onReady.bind(null, forced));
  ctx.registerLocales('en-US');
  ctx.requestLocales(navigator.language);
}

function onReady(forced) {
  if (forced || !isPretranslated) {
    translateFragment();
  }
  fireLocalizedEvent();
}

function fireLocalizedEvent() {
  var event = document.createEvent('Event');
  event.initEvent('localized', false, false);
  event.language = ctx.supportedLocales[0];
  window.dispatchEvent(event);
}

// INI loader functions

function loadINI(url, cb) {
  io.load(url, function(err, source) {
    if (!source) {
      cb();
      return;
    }

    var ini = parseINI(source, url);
    var pos = ctx.resLinks.indexOf(url);

    var patterns = ini.resources.map(function(x) {
      return x.replace('en-US', '{{locale}}');
    });
    var args = [pos, 1].concat(patterns);
    ctx.resLinks.splice.apply(ctx.resLinks, args);
    cb();
  });
}

function relativePath(baseUrl, url) {
  if (url[0] === '/') {
    return url;
  }

  var dirs = baseUrl.split('/')
    .slice(0, -1)
    .concat(url.split('/'))
    .filter(function(path) {
      return path !== '.';
    });

  return dirs.join('/');
}

var iniPatterns = {
  'section': /^\s*\[(.*)\]\s*$/,
  'import': /^\s*@import\s+url\((.*)\)\s*$/i,
  'entry': /[\r\n]+/
};

function parseINI(source, iniPath) {
  var entries = source.split(iniPatterns.entry);
  var locales = ['en-US'];
  var genericSection = true;
  var uris = [];
  var match;

  for (var line of entries) {
    // we only care about en-US resources
    if (genericSection && iniPatterns['import'].test(line)) {
      match = iniPatterns['import'].exec(line);
      var uri = relativePath(iniPath, match[1]);
      uris.push(uri);
      continue;
    }

    // but we need the list of all locales in the ini, too
    if (iniPatterns.section.test(line)) {
      genericSection = false;
      match = iniPatterns.section.exec(line);
      locales.push(match[1]);
    }
  }
  return {
    locales: locales,
    resources: uris
  };
}

// HTML translation functions

function translateFragment(element) {
  element = element || document.documentElement;

  translateElement(element);
  var nodes = getTranslatableChildren(element);
  for (var node of nodes) {
    translateElement(node);
  }
}

function getTranslatableChildren(element) {
  return element ? element.querySelectorAll('*[data-l10n-id]') : [];
}

function localizeElement(element, id, args) {
  if (!element) {
    return;
  }

  if (!id) {
    element.removeAttribute('data-l10n-id');
    element.removeAttribute('data-l10n-args');
    setTextContent(element, '');
    return;
  }

  element.setAttribute('data-l10n-id', id);
  if (args && typeof args === 'object') {
    element.setAttribute('data-l10n-args', JSON.stringify(args));
  } else {
    element.removeAttribute('data-l10n-args');
  }

  if (ctx.isReady) {
    translateElement(element);
  }
}

function getL10nAttributes(element) {
  if (!element) {
    return {};
  }

  var l10nId = element.getAttribute('data-l10n-id');
  var l10nArgs = element.getAttribute('data-l10n-args');

  var args = {};
  if (l10nArgs) {
    args = JSON.parse(l10nArgs);
  }
  return {id: l10nId, args: args};
}

function translateElement(element) {
  var l10n = getL10nAttributes(element);
  if (!l10n.id) {
    return;
  }

  var entity = ctx.getEntity(l10n.id, l10n.args);
  if (!entity) {
    console.log(l10n);
    console.dir(entity);
  }

  if (entity.value) {
    setTextContent(element, entity.value);
  }

  for (var key in entity.attributes) {
    if (entity.attributes.hasOwnProperty(key)) {
      var attr = entity.attributes[key];
      var pos = key.indexOf('.');
      if (pos !== -1) {
        element[key.substr(0, pos)][key.substr(pos + 1)] = attr;
      } else if (key === 'ariaLabel') {
        element.setAttribute('aria-label', attr);
      } else {
        element[key] = attr;
      }
    }
  }
  return true;
}

function setTextContent(element, text) {
  // standard case: no element children
  if (!element.firstElementChild) {
    element.textContent = text;
    return;
  }

  // this element has element children: replace the content of the first
  // (non-blank) child textNode and clear other child textNodes
  var found = false;
  var reNotBlank = /\S/;
  for (var child = element.firstChild; child; child = child.nextSibling) {
    if (child.nodeType === 3 && reNotBlank.test(child.nodeValue)) {
      if (found) {
        child.nodeValue = '';
      } else {
        child.nodeValue = text;
        found = true;
      }
    }
  }
  // if no (non-empty) textNode is found, insert a textNode before the
  // element's first child.
  if (!found) {
    element.insertBefore(document.createTextNode(text), element.firstChild);
  }
}
<commit_msg>we want to store ini in resLinks to replace them in place with the right properties<commit_after>'use strict';

var Context = require('./context').Context;

var isPretranslated = false;
var rtlList = ['ar', 'he', 'fa', 'ps', 'ur'];

var ctx = new Context();

// Public API

navigator.mozL10n = {
  translate: translateFragment,
  localize: localizeElement,
  get: ctx.get.bind(ctx),
  ready: ctx.ready.bind(ctx),
  get readyState() {
    return ctx.isReady ? 'complete' : 'loading';
  },
  language: {
    set code(lang) {
      initLocale(lang, true);
    },
    get code() {
      return ctx.supportedLocales[0];
    },
    get direction() {
      return getDirection(ctx.supportedLocales[0]);
    }
  }
};

function getDirection(lang) {
  return (rtlList.indexOf(lang) >= 0) ? 'rtl' : 'ltr';
}

var readyStates = {
  'loading': 0,
  'interactive': 1,
  'complete': 2
};

function waitFor(state, callback) {
  state = readyStates[state];
  if (readyStates[document.readyState] >= state) {
    callback();
    return;
  }
  document.addEventListener('readystatechange', function l10n_onrsc() {
    if (readyStates[document.readyState] >= state) {
      document.removeEventListener('readystatechange', l10n_onrsc);
      callback();
    }
  });
}

if (window.document) {
  isPretranslated = (document.documentElement.lang === navigator.language);

  if (isPretranslated) {
    waitFor('complete', function() {
      window.setTimeout(initDocumentLocalization.bind(null, initLocale));
    });
  } else {
    initDocumentLocalization(initLocale);
  }
}

function initDocumentLocalization(cb) {
  var resLinks = document.head.querySelectorAll('link[type="application/l10n"]');
  var iniLinks = [];
  var link;

  for (link of resLinks) {
    var url = link.getAttribute('href');
    var type = url.substr(url.lastIndexOf('.') + 1);
    if (type === 'ini') {
      iniLinks.push(url);
    }
    ctx.resLinks.push(url);
  }

  var iniLoads = iniLinks.length;
  if (iniLoads === 0) {
    onIniLoaded();
  }

  function onIniLoaded() {
    iniLoads--;
    if (iniLoads <= 0) {
      cb();
    }
  }

  for (link of iniLinks) {
    loadINI(link, onIniLoaded);
  }
}

function initLocale(lang, forced) {
  ctx.ready(onReady.bind(null, forced));
  ctx.registerLocales('en-US');
  ctx.requestLocales(navigator.language);
}

function onReady(forced) {
  if (forced || !isPretranslated) {
    translateFragment();
  }
  fireLocalizedEvent();
}

function fireLocalizedEvent() {
  var event = document.createEvent('Event');
  event.initEvent('localized', false, false);
  event.language = ctx.supportedLocales[0];
  window.dispatchEvent(event);
}

// INI loader functions

function loadINI(url, cb) {
  io.load(url, function(err, source) {
    if (!source) {
      cb();
      return;
    }

    var ini = parseINI(source, url);
    var pos = ctx.resLinks.indexOf(url);

    var patterns = ini.resources.map(function(x) {
      return x.replace('en-US', '{{locale}}');
    });
    var args = [pos, 1].concat(patterns);
    ctx.resLinks.splice.apply(ctx.resLinks, args);
    cb();
  });
}

function relativePath(baseUrl, url) {
  if (url[0] === '/') {
    return url;
  }

  var dirs = baseUrl.split('/')
    .slice(0, -1)
    .concat(url.split('/'))
    .filter(function(path) {
      return path !== '.';
    });

  return dirs.join('/');
}

var iniPatterns = {
  'section': /^\s*\[(.*)\]\s*$/,
  'import': /^\s*@import\s+url\((.*)\)\s*$/i,
  'entry': /[\r\n]+/
};

function parseINI(source, iniPath) {
  var entries = source.split(iniPatterns.entry);
  var locales = ['en-US'];
  var genericSection = true;
  var uris = [];
  var match;

  for (var line of entries) {
    // we only care about en-US resources
    if (genericSection && iniPatterns['import'].test(line)) {
      match = iniPatterns['import'].exec(line);
      var uri = relativePath(iniPath, match[1]);
      uris.push(uri);
      continue;
    }

    // but we need the list of all locales in the ini, too
    if (iniPatterns.section.test(line)) {
      genericSection = false;
      match = iniPatterns.section.exec(line);
      locales.push(match[1]);
    }
  }
  return {
    locales: locales,
    resources: uris
  };
}

// HTML translation functions

function translateFragment(element) {
  element = element || document.documentElement;

  translateElement(element);
  var nodes = getTranslatableChildren(element);
  for (var node of nodes) {
    translateElement(node);
  }
}

function getTranslatableChildren(element) {
  return element ? element.querySelectorAll('*[data-l10n-id]') : [];
}

function localizeElement(element, id, args) {
  if (!element) {
    return;
  }

  if (!id) {
    element.removeAttribute('data-l10n-id');
    element.removeAttribute('data-l10n-args');
    setTextContent(element, '');
    return;
  }

  element.setAttribute('data-l10n-id', id);
  if (args && typeof args === 'object') {
    element.setAttribute('data-l10n-args', JSON.stringify(args));
  } else {
    element.removeAttribute('data-l10n-args');
  }

  if (ctx.isReady) {
    translateElement(element);
  }
}

function getL10nAttributes(element) {
  if (!element) {
    return {};
  }

  var l10nId = element.getAttribute('data-l10n-id');
  var l10nArgs = element.getAttribute('data-l10n-args');

  var args = {};
  if (l10nArgs) {
    args = JSON.parse(l10nArgs);
  }
  return {id: l10nId, args: args};
}

function translateElement(element) {
  var l10n = getL10nAttributes(element);
  if (!l10n.id) {
    return;
  }

  var entity = ctx.getEntity(l10n.id, l10n.args);
  if (!entity) {
    console.log(l10n);
    console.dir(entity);
  }

  if (entity.value) {
    setTextContent(element, entity.value);
  }

  for (var key in entity.attributes) {
    if (entity.attributes.hasOwnProperty(key)) {
      var attr = entity.attributes[key];
      var pos = key.indexOf('.');
      if (pos !== -1) {
        element[key.substr(0, pos)][key.substr(pos + 1)] = attr;
      } else if (key === 'ariaLabel') {
        element.setAttribute('aria-label', attr);
      } else {
        element[key] = attr;
      }
    }
  }
  return true;
}

function setTextContent(element, text) {
  // standard case: no element children
  if (!element.firstElementChild) {
    element.textContent = text;
    return;
  }

  // this element has element children: replace the content of the first
  // (non-blank) child textNode and clear other child textNodes
  var found = false;
  var reNotBlank = /\S/;
  for (var child = element.firstChild; child; child = child.nextSibling) {
    if (child.nodeType === 3 && reNotBlank.test(child.nodeValue)) {
      if (found) {
        child.nodeValue = '';
      } else {
        child.nodeValue = text;
        found = true;
      }
    }
  }
  // if no (non-empty) textNode is found, insert a textNode before the
  // element's first child.
  if (!found) {
    element.insertBefore(document.createTextNode(text), element.firstChild);
  }
}
<|endoftext|>


<commit_before>define([
  'dojo/on',
  'dojo/topic',
  'toastr'
], function(
  on, topic, toastr
) {

  function loadHandlers(initialStyle) {

    var layer = this.layer;
    var editor = this.editor;

    var styleHistory = [];

    on(document, 'keydown', function(e){
      if(e.ctrlKey && e.which === 83){ // Check for the Ctrl key being pressed, and if the key = [S] (83)
        var annotations = editor.getSession().getAnnotations();
        if (annotations.length) {
          toastr.error('Review style editor for errors')
          return;
        }
        var val = editor.getValue();
        var data = JSON.parse(val);
        styleHistory.push(data);
        layer.setStyle(data);
        return false;
      }
      if(e.ctrlKey && e.which === 90){ // Check for the Ctrl key being pressed, and if the key = [Z] (90)
        styleHistory.pop();
        var data2 = styleHistory[styleHistory.length - 1];
        if (!data) {
          styleHistory.push(initialStyle);
          data = initialStyle;
        }
        var val2 = JSON.stringify(data2, null, '\t');
        editor.setValue(val2);
        editor.gotoLine(0);
        topic.publish('update-layer-style');
        layer.setStyle(data2);
        return false;
      }
    });

    on(document.getElementById('submit'), 'click', function (e) {
      var annotations = editor.getSession().getAnnotations();
      if (annotations.length) {
        toastr.error('Review style editor for errors')
        return;
      }
      var val = editor.getValue();
      var data = JSON.parse(val);
      styleHistory.push(data);
      layer.setStyle(data);
    });

    on(document.getElementById('undo'), 'click', function (e) {
      styleHistory.pop();
      var data = styleHistory[styleHistory.length - 1];
      if (!data) {
        styleHistory.push(initialStyle);
        data = initialStyle;
      }
      var val = JSON.stringify(data, null, '\t');
      editor.setValue(val);
      editor.gotoLine(0);
      layer.setStyle(data);
    });

    on(document.getElementById('reset'), 'click', function (e) {
      styleHistory.length = 0;
      editor.setValue(initialStyle);
      editor.gotoLine(0);
      layer.setStyle(initialStyle);
    });

    on(document.getElementById('save'), 'click', function (e) {
      var annotations = editor.getSession().getAnnotations();
      if (annotations.length) {
        toastr.error('Review style editor for errors')
        return;
      }
      var val = editor.getValue();
      var data = JSON.parse(val);
      styleHistory.push(data);
      layer.setStyle(data);

      topic.publish('save-style', JSON.parse(val));

    });

  }

  function StyleHandlers(options) {
    this.layer = options.layer;
    this.editor = options.editor;
  }

  StyleHandlers.prototype.load = loadHandlers;

  return StyleHandlers;

});<commit_msg>fix the undo methods<commit_after>define([
  'dojo/on',
  'dojo/topic',
  'toastr'
], function(
  on, topic, toastr
) {

  function loadHandlers(initialStyle) {

    console.log('initial style', initialStyle);

    var initialStyleString = JSON.stringify(initialStyle, null, '\t');

    var layer = this.layer;
    var editor = this.editor;

    var styleHistory = [];

    on(document, 'keydown', function(e){
      if(e.ctrlKey && e.which === 83){ // Check for the Ctrl key being pressed, and if the key = [S] (83)
        var annotations = editor.getSession().getAnnotations();
        if (annotations.length) {
          toastr.error('Review style editor for errors')
          return;
        }
        var val = editor.getValue();
        var data = JSON.parse(val);
        styleHistory.push(data);
        layer.setStyle(JSON.parse(val));
        return false;
      }
      if(e.ctrlKey && e.which === 90){ // Check for the Ctrl key being pressed, and if the key = [Z] (90)
        styleHistory.pop();
        var data2 = styleHistory[styleHistory.length - 1];
        if (!data2) {
          styleHistory.push(JSON.parse(initialStyleString));
          data2 = JSON.parse(initialStyleString);
        }
        var val2 = JSON.stringify(data2, null, '\t');
        editor.setValue(val2);
        editor.gotoLine(0);
        topic.publish('update-layer-style');
        layer.setStyle(JSON.parse(val2));
        return false;
      }
    });

    on(document.getElementById('submit'), 'click', function (e) {
      var annotations = editor.getSession().getAnnotations();
      if (annotations.length) {
        toastr.error('Review style editor for errors')
        return;
      }
      var val = editor.getValue();
      styleHistory.push(JSON.parse(val));
      layer.setStyle(JSON.parse(val));
    });

    on(document.getElementById('undo'), 'click', function (e) {
      styleHistory.pop();
      var data = styleHistory[styleHistory.length - 1];
      if (!data) {
        styleHistory.push(JSON.parse(initialStyleString));
        data = JSON.parse(initialStyleString);
      }
      var val = JSON.stringify(data, null, '\t');
      editor.setValue(val);
      editor.gotoLine(0);
      layer.setStyle(data);
    });

    on(document.getElementById('reset'), 'click', function (e) {
      styleHistory.length = 0;
      editor.setValue(initialStyleString);
      editor.gotoLine(0);
      layer.setStyle(JSON.parse(initialStyleString));
    });

    on(document.getElementById('save'), 'click', function (e) {
      var annotations = editor.getSession().getAnnotations();
      if (annotations.length) {
        toastr.error('Review style editor for errors')
        return;
      }
      var val = editor.getValue();
      var data = JSON.parse(val);
      styleHistory.push(data);
      layer.setStyle(data);

      topic.publish('save-style', JSON.parse(val));

    });

  }

  function StyleHandlers(options) {
    this.layer = options.layer;
    this.editor = options.editor;
  }

  StyleHandlers.prototype.load = loadHandlers;

  return StyleHandlers;

});<|endoftext|>