<commit_before>(function(exports) {
  "use strict";

  // progress indicators
  var spinning = 0;

  function spinnerStart() {
    spinning++;

    // this stops us showing a spinner for cached queries which
    // return very quickly
    _.delay(function() {
      if (spinning > 0) $('#spinner').show();
    }, 200);
  }

  function spinnerStop() {
    spinning--;
    if (spinning === 0) {
      $('#spinner').hide();
    }
  }

  var Filters = Backbone.Model.extend({
    defaults: {
      munis: [],
    }
  });
  var Cells = Backbone.Model.extend({
    defaults: {
      items: [],
    }
  });
  var municipalities;

  /** The filters the user can choose
   */
  var FilterView = Backbone.View.extend({
    el: '.table-controls',
    events: {
      'click .del': 'muniRemoved',
      'click input[name=year]': 'yearChanged',
    },

    initialize: function(opts) {
      this.filters = opts.filters;
      this.filters.on('change', this.render, this);

      this.munis = [];
      this.preload();
    },

    preload: function() {
      var self = this;

      spinnerStart();
      $.get(MUNI_DATA_API + '/cubes/municipalities/facts', function(resp) {
        var munis = _.map(resp.data, function(muni) {
          // change municipality.foo to foo
          _.each(_.keys(muni), function(key) {
            if (key.startsWith("municipality.")) {
              muni[key.substring(13)] = muni[key];
              delete muni[key];
            }
          });
          return muni;
        });

        municipalities = _.indexBy(munis, 'demarcation_code');
        self.filters.trigger('change');
      }).always(spinnerStop);

      spinnerStart();
      $.get(MUNI_DATA_API + '/cubes/' + CUBE_NAME + '/members/financial_year_end.year', function(data) {
        self.years = _.pluck(data.data, "financial_year_end.year").sort().reverse();
        self.renderYears();
      }).always(spinnerStop);
    },

    render: function() {
      var self = this;

      if (municipalities && !this.$muniChooser) {
        this.renderMunis();
      }

      var munis = _.sortBy(
        _.map(this.filters.get('munis'), function(id) { return municipalities[id]; }),
        'long_name');
      var $list = this.$('.chosen-munis').empty();

      if (munis.length === 0) {
        $list.append('
').html('Choose a municipality below.');

      } else {
        _.each(munis, function(muni) {
          $list.append($('
')
            .text(muni.long_name)
            .data('id', muni.demarcation_code)
            .prepend(' ')
          );
        });
      }
    },

    renderMunis: function() {
      function formatMuni(item) {
        if (item.info) {
          return $("
" + item.info.name + " (" + item.id + ")
" + item.info.province_name + "
");
        } else {
          return item.text;
        }
      }

      var munis = _.map(municipalities, function(muni) {
        return {
          id: muni.demarcation_code,
          text: muni.long_name + " " + muni.demarcation_code,
          info: muni,
        };
      });

      this.$muniChooser = this.$('.muni-chooser').select2({
        data: munis,
        placeholder: "Find a municipality",
        allowClear: true,
        templateResult: formatMuni,
      })
        .on('select2:select', _.bind(this.muniSelected, this));
    },

    renderYears: function() {
      var $chooser = this.$('.year-chooser');

      for (var i = 0; i < this.years.length; i++) {
        var year = this.years[i];
        $chooser.append($('
<input type="radio" name="year" value="' + year + '"> ' + year + '
'));
      }

      $chooser.find('input:first').prop('checked', true).trigger('click');
    },

    muniSelected: function(e) {
      var munis = this.filters.get('munis');
      var id = e.params.data.id;

      if (id && _.indexOf(munis, id) === -1) {
        munis.push(id);
        this.filters.trigger('change');
      }

      this.$muniChooser.val(null).trigger('change');
    },

    muniRemoved: function(e) {
      e.preventDefault();
      var id = $(e.target).closest('li').data('id');
      this.filters.set('munis', _.without(this.filters.get('munis'), id));
    },

    yearChanged: function(e) {
      this.filters.set('year', Number.parseInt(this.$('input[name=year]:checked').val()));
    },
  });

  /** The data table portion of the page.
   */
  var TableView = Backbone.View.extend({
    el: '#table-view',

    events: {
      'click .scale': 'changeScale',
    },

    initialize: function(opts) {
      this.format = d3_format
        .formatLocale({decimal: ".", thousands: " ", grouping: [3], currency: "R"})
        .format(",d");
      this.scale = 1000;

      this.filters = opts.filters;
      this.filters.on('change', this.render, this);
      this.filters.on('change', this.update, this);

      this.cells = opts.cells;
      this.cells.on('change', this.render, this);

      this.preload();
    },

    preload: function() {
      var self = this;

      // TODO does this work for all cubes?
      spinnerStart();
      $.get(MUNI_DATA_API + '/cubes/' + CUBE_NAME + '/members/item', function(data) {
        self.rowHeadings = data.data;
        self.renderRowHeadings();
      }).always(spinnerStop);
    },

    changeScale: function() {
      var zeroes = this.$('.scale input:checked').attr('value');
      this.scale = Math.pow(10, Number.parseInt(zeroes));
      this.render();
    },

    /**
     * Update the data!
     */
    update: function() {
      var self = this;
      var url = MUNI_DATA_API + '/cubes/' + CUBE_NAME + '/aggregate?';

      if (this.filters.get('munis').length === 0) {
        this.cells.set({items: [], meta: {}});
        return;
      }

      var cells = [];
      this.cells.set('items', cells);

      _.each(this.filters.get('munis'), function(muni_id) {
        var parts = {
          // TODO: field to sum over ?
          aggregates: ['amount.sum'],
          cut: [],
          // TODO: determine
          drilldown: ['demarcation.code', 'demarcation.label', 'item.code', 'item.label', 'item.return_form_structure', 'item.position_in_return_form'],
          order: 'item.position_in_return_form:asc',
        };

        // TODO: set filter for municipality
        parts.cut.push('demarcation.code:"' + muni_id + '"');
        parts.cut.push('financial_year_end.year:' + self.filters.get('year'));

        // TODO: paginate
        // make the URL
        url += _.map(parts, function(value, key) {
          if (_.isArray(value)) value = value.join('|');
          return key + '=' + encodeURIComponent(value);
        }).join('&');

        console.log(url);

        spinnerStart();
        $.get(url, function(data) {
          self.cells.set('items', self.cells.get('items').concat(data.cells));
        }).always(spinnerStop);
      });
    },

    render: function() {
      if (this.rowHeadings) {
        this.renderValues();
      }
    },

    renderRowHeadings: function() {
      // render row headings table
      var table = this.$('.row-headings')[0];

      table.insertRow().insertCell().innerHTML = ' ';

      for (var i = 0; i < this.rowHeadings.length; i++) {
        var item = this.rowHeadings[i];
        var tr = table.insertRow();
        var td;

        $(tr).addClass('item-' + item['item.return_form_structure']);

        td = tr.insertCell();
        td.innerText = item['item.code'];
        td = tr.insertCell();
        td.innerText = item['item.label'];
      }
    },

    renderValues: function() {
      var table = this.$('.values').empty()[0];
      var cells = this.cells.get('items');
      var self = this;

      // group by code then municipality
      cells = _.groupBy(cells, 'item.code');
      _.each(cells, function(items, code) {
        cells[code] = _.indexBy(items, 'demarcation.code');
      });

      // municipality headings
      var tr = table.insertRow();
      var muni_ids = this.filters.get('munis');
      for (var i = 0; i < muni_ids.length; i++) {
        var th = document.createElement('th');
        th.innerText = municipalities[muni_ids[i]].name;
        tr.appendChild(th);
      }

      // values
      if (!_.isEmpty(cells)) {
        for (i = 0; i < this.rowHeadings.length; i++) {
          var row = this.rowHeadings[i];
          tr = table.insertRow();
          $(tr).addClass('item-' + row['item.return_form_structure']);

          for (var j = 0; j < muni_ids.length; j++) {
            var cell = cells[row['item.code']][muni_ids[j]];
            var v = (cell ? cell['amount.sum'] : null);

            tr.insertCell().innerText = v ? self.format(v / this.scale) : "-";
          }
        }
      }
    },
  });

  /** Overall table view on this page
   */
  var MainView = Backbone.View.extend({
    initialize: function() {
      this.filters = new Filters();
      this.cells = new Cells();

      this.filterView = new FilterView({filters: this.filters});
      this.tableView = new TableView({filters: this.filters, cells: this.cells});
    }
  });

  exports.view = new MainView();
})(window);
<commit_msg>Limit to financial year.<commit_after>(function(exports) {
  "use strict";

  // progress indicators
  var spinning = 0;

  function spinnerStart() {
    spinning++;

    // this stops us showing a spinner for cached queries which
    // return very quickly
    _.delay(function() {
      if (spinning > 0) $('#spinner').show();
    }, 200);
  }

  function spinnerStop() {
    spinning--;
    if (spinning === 0) {
      $('#spinner').hide();
    }
  }

  var Filters = Backbone.Model.extend({
    defaults: {
      munis: [],
    }
  });
  var Cells = Backbone.Model.extend({
    defaults: {
      items: [],
    }
  });
  var municipalities;

  /** The filters the user can choose
   */
  var FilterView = Backbone.View.extend({
    el: '.table-controls',
    events: {
      'click .del': 'muniRemoved',
      'click input[name=year]': 'yearChanged',
    },

    initialize: function(opts) {
      this.filters = opts.filters;
      this.filters.on('change', this.render, this);

      this.munis = [];
      this.preload();
    },

    preload: function() {
      var self = this;

      spinnerStart();
      $.get(MUNI_DATA_API + '/cubes/municipalities/facts', function(resp) {
        var munis = _.map(resp.data, function(muni) {
          // change municipality.foo to foo
          _.each(_.keys(muni), function(key) {
            if (key.startsWith("municipality.")) {
              muni[key.substring(13)] = muni[key];
              delete muni[key];
            }
          });
          return muni;
        });

        municipalities = _.indexBy(munis, 'demarcation_code');
        self.filters.trigger('change');
      }).always(spinnerStop);

      spinnerStart();
      $.get(MUNI_DATA_API + '/cubes/' + CUBE_NAME + '/members/financial_year_end.year', function(data) {
        self.years = _.pluck(data.data, "financial_year_end.year").sort().reverse();
        self.renderYears();
      }).always(spinnerStop);
    },

    render: function() {
      var self = this;

      if (municipalities && !this.$muniChooser) {
        this.renderMunis();
      }

      var munis = _.sortBy(
        _.map(this.filters.get('munis'), function(id) { return municipalities[id]; }),
        'long_name');
      var $list = this.$('.chosen-munis').empty();

      if (munis.length === 0) {
        $list.append('
').html('Choose a municipality below.');

      } else {
        _.each(munis, function(muni) {
          $list.append($('
')
            .text(muni.long_name)
            .data('id', muni.demarcation_code)
            .prepend(' ')
          );
        });
      }
    },

    renderMunis: function() {
      function formatMuni(item) {
        if (item.info) {
          return $("
" + item.info.name + " (" + item.id + ")
" + item.info.province_name + "
");
        } else {
          return item.text;
        }
      }

      var munis = _.map(municipalities, function(muni) {
        return {
          id: muni.demarcation_code,
          text: muni.long_name + " " + muni.demarcation_code,
          info: muni,
        };
      });

      this.$muniChooser = this.$('.muni-chooser').select2({
        data: munis,
        placeholder: "Find a municipality",
        allowClear: true,
        templateResult: formatMuni,
      })
        .on('select2:select', _.bind(this.muniSelected, this));
    },

    renderYears: function() {
      var $chooser = this.$('.year-chooser');

      for (var i = 0; i < this.years.length; i++) {
        var year = this.years[i];
        $chooser.append($('
<input type="radio" name="year" value="' + year + '"> ' + year + '
'));
      }

      $chooser.find('input:first').prop('checked', true).trigger('click');
    },

    muniSelected: function(e) {
      var munis = this.filters.get('munis');
      var id = e.params.data.id;

      if (id && _.indexOf(munis, id) === -1) {
        munis.push(id);
        this.filters.trigger('change');
      }

      this.$muniChooser.val(null).trigger('change');
    },

    muniRemoved: function(e) {
      e.preventDefault();
      var id = $(e.target).closest('li').data('id');
      this.filters.set('munis', _.without(this.filters.get('munis'), id));
    },

    yearChanged: function(e) {
      this.filters.set('year', Number.parseInt(this.$('input[name=year]:checked').val()));
    },
  });

  /** The data table portion of the page.
   */
  var TableView = Backbone.View.extend({
    el: '#table-view',

    events: {
      'click .scale': 'changeScale',
    },

    initialize: function(opts) {
      this.format = d3_format
        .formatLocale({decimal: ".", thousands: " ", grouping: [3], currency: "R"})
        .format(",d");
      this.scale = 1000;

      this.filters = opts.filters;
      this.filters.on('change', this.render, this);
      this.filters.on('change', this.update, this);

      this.cells = opts.cells;
      this.cells.on('change', this.render, this);

      this.preload();
    },

    preload: function() {
      var self = this;

      // TODO does this work for all cubes?
      spinnerStart();
      $.get(MUNI_DATA_API + '/cubes/' + CUBE_NAME + '/members/item', function(data) {
        self.rowHeadings = data.data;
        self.renderRowHeadings();
      }).always(spinnerStop);
    },

    changeScale: function() {
      var zeroes = this.$('.scale input:checked').attr('value');
      this.scale = Math.pow(10, Number.parseInt(zeroes));
      this.render();
    },

    /**
     * Update the data!
     */
    update: function() {
      var self = this;
      var url = MUNI_DATA_API + '/cubes/' + CUBE_NAME + '/aggregate?';

      if (this.filters.get('munis').length === 0) {
        this.cells.set({items: [], meta: {}});
        return;
      }

      var cells = [];
      this.cells.set('items', cells);

      _.each(this.filters.get('munis'), function(muni_id) {
        var parts = {
          // TODO: field to sum over ?
          aggregates: ['amount.sum'],
          cut: [],
          // TODO: determine
          drilldown: ['demarcation.code', 'demarcation.label', 'item.code', 'item.label', 'item.return_form_structure', 'item.position_in_return_form'],
          order: 'item.position_in_return_form:asc',
        };

        parts.cut.push('demarcation.code:"' + muni_id + '"');
        parts.cut.push('financial_year_end.year:' + self.filters.get('year'));
        parts.cut.push('financial_period.period:' + self.filters.get('year'));

        // TODO: paginate
        // make the URL
        url += _.map(parts, function(value, key) {
          if (_.isArray(value)) value = value.join('|');
          return key + '=' + encodeURIComponent(value);
        }).join('&');

        console.log(url);

        spinnerStart();
        $.get(url, function(data) {
          self.cells.set('items', self.cells.get('items').concat(data.cells));
        }).always(spinnerStop);
      });
    },

    render: function() {
      if (this.rowHeadings) {
        this.renderValues();
      }
    },

    renderRowHeadings: function() {
      // render row headings table
      var table = this.$('.row-headings')[0];

      table.insertRow().insertCell().innerHTML = ' ';

      for (var i = 0; i < this.rowHeadings.length; i++) {
        var item = this.rowHeadings[i];
        var tr = table.insertRow();
        var td;

        $(tr).addClass('item-' + item['item.return_form_structure']);

        td = tr.insertCell();
        td.innerText = item['item.code'];
        td = tr.insertCell();
        td.innerText = item['item.label'];
      }
    },

    renderValues: function() {
      var table = this.$('.values').empty()[0];
      var cells = this.cells.get('items');
      var self = this;

      // group by code then municipality
      cells = _.groupBy(cells, 'item.code');
      _.each(cells, function(items, code) {
        cells[code] = _.indexBy(items, 'demarcation.code');
      });

      // municipality headings
      var tr = table.insertRow();
      var muni_ids = this.filters.get('munis');
      for (var i = 0; i < muni_ids.length; i++) {
        var th = document.createElement('th');
        th.innerText = municipalities[muni_ids[i]].name;
        tr.appendChild(th);
      }

      // values
      if (!_.isEmpty(cells)) {
        for (i = 0; i < this.rowHeadings.length; i++) {
          var row = this.rowHeadings[i];
          tr = table.insertRow();
          $(tr).addClass('item-' + row['item.return_form_structure']);

          for (var j = 0; j < muni_ids.length; j++) {
            var cell = cells[row['item.code']][muni_ids[j]];
            var v = (cell ? cell['amount.sum'] : null);

            tr.insertCell().innerText = v ? self.format(v / this.scale) : "-";
          }
        }
      }
    },
  });

  /** Overall table view on this page
   */
  var MainView = Backbone.View.extend({
    initialize: function() {
      this.filters = new Filters();
      this.cells = new Cells();

      this.filterView = new FilterView({filters: this.filters});
      this.tableView = new TableView({filters: this.filters, cells: this.cells});
    }
  });

  exports.view = new MainView();
})(window);
<|endoftext|>


<commit_before>'use strict';

module.exports = function(grunt) {
	var app = 'app/wp-content/themes/<%= themeName %>/';
	var dist = 'dist/wp-content/themes/<%= themeName %>/';

	grunt.initConfig({
		watch: {
			css: {
				files: [<% if (includeLESS) { %>
					app + '/assets/less/*.less',
					app + '/assets/less/site/*.less'<% } if (includeSASS) { %>
					app + '/assets/sass/*.scss',
					app + '/assets/sass/site/*.scss'<% } %>
				],
				tasks: [<% if (includeLESS) { %>
					'less:development'<% } if (includeSASS) { %>
					'sass:development'<% } %>
				],
				options: {
					livereload: true
				}
			},
			js: {
				files: [
					app + '/assets/js/*.js',
					'Gruntfile.js'
				],
				tasks: ['jshint'],
				options: {
					livereload: true,
				}
			}
		},
		browser_sync: {
			files: {
				src : [
					app + '*.css',
					app + 'assets/img/*',
					app + 'assets/js/*.js',
					app + '{,*/}*.php'
				],
			},
			options: {
				watchTask: true
				host: '<%= themeName %>',
				port: 8888
			}
		}, <% if (includeLESS) { %>
		less: {
			development: {
				options: {
					sourceMap: true,
					sourceMapFilename: app + '/style.css.map',
					sourceMapURL: '/wp-content/themes/<%= themeName %> /style.css.map',
					sourceMapBasepath: 'public',
					sourceMapRootpath: '/'
				},
				files: {
					'app/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/less/style.less'
				}
			},
			dist: {
				options: {
					paths: app,
					sourceMap: false,
					cleancss: true,
					compress: true
				},
				files: {
					'dist/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/less/style.less'
				}
			}
		},<% } if (includeSASS) { %>
		sass: {
			development: {
				options: {
					sourceMap: true,
					sourceMapFilename: app + 'style.css.map',
					sourceMapURL: '/wp-content/themes/<%= themeName %> /style.css.map',
					sourceMapBasepath: 'public',
					sourceMapRootpath: '/'
				},
				files: {
					'app/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/sass/style.scss'
				}
			},
			dist: {
				options: {
					style: 'compressed',
					sourceMap: false
				},
				files: {
					'dist/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/sass/style.scss'
				}
			}
		},<% } %>
		clean: {
			dist: {
				files: [{
					dot: true,
					src: [
						'dist/*',
						'dist/.git*'
					]
				}]
			}
		},
		jshint: {
			options: {
				jshintrc: '.jshintrc'
			},
			all: [
				'Gruntfile.js',
				app + 'assets/js/{,*/}*.js'
			]
		},<% if (includeSASS) { %>
		// Configuration needs to be completed
		compass: {
			options: {
				sassDir: app,
				cssDir: app,
				generatedImagesDir: app + 'img',
				imagesDir: app + 'img',
				javascriptsDir: app + 'js',
				fontsDir: app + 'css/fonts',
				httpImagesPath: app + 'img',
				httpGeneratedImagesPath: app + 'img',
				httpFontsPath: app + 'fonts',
				relativeAssets: false
			},
			dist: {
				options: {
					generatedImagesDir: dist + 'img/generated'
				}
			}
		},<% } if (includeRequireJS) { %>
		requirejs: {
			dist: {
				// Options: https://github.com/jrburke/r.js/blob/master/build/example.build.js
				options: {
					// `name` and `out` is set by grunt-usemin
					baseUrl: app + 'assets/js',
					mainConfigFile: app + 'assets/js/main.js',
					paths: {
						jquery: 'empty:',
						underscore: 'empty:',
						app: 'app'
					},
					dir: dist + 'assets/js',
					shim: {
						underscore: {
							deps: ['jquery'],
							exports: '_'
						},
						app: {
							deps: ['jquery', 'underscore']
						}
					}
				}
			}
		},<% } %>
		imagemin: {
			dist: {
				files: [{
					expand: true,
					cwd: app + 'assets/images',
					src: '**/*.{png,jpg,jpeg}',
					dest: dist + 'assets/images'
				}],
				options: {
					cache: false
				}
			}
		},
		svgmin: {
			dist: {
				files: [{
					expand: true,
					cwd: app + 'assets/images',
					src: '**/*.svg',
					dest: dist + 'assets/images'
				}]
			}
		},
		preprocess: {
			dev: {
				options: {
					context: {
						NODE_ENV: 'DEVELOPMENT'
					},
				},
				files: {
					'app/wp-content/themes/<%= themeName %>/base.php': 'app/wp-content/themes/<%= themeName %>/base-template.html'
				},
			},
			dist: {
				options: {
					context: {
						NODE_ENV: 'PRODUCTION'
					},
				},
				files: {
					'dist/wp-content/themes/<%= themeName %>/base.php': 'app/wp-content/themes/<%= themeName %>/base-template.html'
				},
			},
		},
		// Put files not handled in other tasks here
		copy: {
			dist: {
				files: [{
					expand: true,
					dot: true,
					cwd: 'app',
					dest: 'dist',
					src: [
						'*.{ico,png,txt,php}',
						'.htaccess',
						'wp-admin/*',
						'wp-includes/*',
						'wp-content/plugins/*',
						'wp-content/themes/<%= themeName %>/*.{php,md,png,css}',
						'wp-content/themes/<%= themeName %>/templates/*',
						'wp-content/themes/<%= themeName %>/lib/*',
						'wp-content/themes/<%= themeName %>/lang/*',
						'wp-content/themes/<%= themeName %>/assets/fonts/{,*/}*.*'
					]
				}]
			}
		},
		hashres: {
			options: {
				encoding: 'utf8',
				fileNameFormat: '${name}.${ext}?${hash}',
				renameFiles: false
			},
			css: {
				src: [
					dist + 'style.css'
				],
				dest: dist + 'templates/head.php',
			}
		},
		concurrent: {
			dev: ['clean:dist', 'preprocess:dev'],
			build1: ['imagemin:dist', 'copy:dist', <% if (includeLESS) { %> 'less:dist' <% } %>, if (includeSASS) { %>'sass:dist'<% } %>],
			build2: ['preprocess:dist', 'svgmin:dist']
		}
	});

	// Load the Grunt plugins.
	<% if (includeLESS) { %>
	grunt.loadNpmTasks('grunt-contrib-less');<% } if (includeSASS) { %>
	grunt.loadNpmTasks('grunt-contrib-sass');<% } %>
	grunt.loadNpmTasks('grunt-contrib-watch');
	grunt.loadNpmTasks('grunt-contrib-uglify');
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-browser-sync');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-imagemin');
	grunt.loadNpmTasks('grunt-svgmin');
	grunt.loadNpmTasks('grunt-preprocess');
	grunt.loadNpmTasks('grunt-concurrent');
	grunt.loadNpmTasks('grunt-hashres'); <% if (includeRequireJS) { %>
	grunt.loadNpmTasks('grunt-contrib-requirejs'); <% } %>

	grunt.registerTask('build', [
		'clean:dist',
		'concurrent:build1',
		'concurrent:build2',
		'requirejs',
		'hashres'
	]);

	grunt.registerTask('dev', [
		'concurrent:dev',
		'browser_sync',
		'watch'
	]);
};
<commit_msg>fixing Barrow's hackjob<commit_after>'use strict';

module.exports = function(grunt) {
	var app = 'app/wp-content/themes/<%= themeName %>/';
	var dist = 'dist/wp-content/themes/<%= themeName %>/';

	grunt.initConfig({
		watch: {
			css: {
				files: [<% if (includeLESS) { %>
					app + '/assets/less/*.less',
					app + '/assets/less/site/*.less',<% } if (includeSASS) { %>
					app + '/assets/sass/*.scss',
					app + '/assets/sass/site/*.scss'<% } %>
				],
				tasks: [<% if (includeLESS) { %>
					'less:development'<% } if (includeSASS) { %>
					'sass:development'<% } %>
				],
				options: {
					livereload: true
				}
			},
			js: {
				files: [
					app + '/assets/js/*.js',
					'Gruntfile.js'
				],
				tasks: ['jshint'],
				options: {
					livereload: true,
				}
			}
		},
		browser_sync: {
			files: {
				src : [
					app + '*.css',
					app + 'assets/img/*',
					app + 'assets/js/*.js',
					app + '{,*/}*.php'
				],
			},
			options: {
				watchTask: true,
				host: '<%= themeName %>',
				port: 8888
			}
		}, <% if (includeLESS) { %>
		less: {
			development: {
				options: {
					sourceMap: true,
					sourceMapFilename: app + '/style.css.map',
					sourceMapURL: '/wp-content/themes/<%= themeName %> /style.css.map',
					sourceMapBasepath: 'public',
					sourceMapRootpath: '/'
				},
				files: {
					'app/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/less/style.less'
				}
			},
			dist: {
				options: {
					paths: app,
					sourceMap: false,
					cleancss: true,
					compress: true
				},
				files: {
					'dist/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/less/style.less'
				}
			}
		},<% } if (includeSASS) { %>
		sass: {
			development: {
				options: {
					sourceMap: true,
					sourceMapFilename: app + 'style.css.map',
					sourceMapURL: '/wp-content/themes/<%= themeName %> /style.css.map',
					sourceMapBasepath: 'public',
					sourceMapRootpath: '/'
				},
				files: {
					'app/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/sass/style.scss'
				}
			},
			dist: {
				options: {
					style: 'compressed',
					sourceMap: false
				},
				files: {
					'dist/wp-content/themes/<%= themeName %>/style.css': 'app/wp-content/themes/<%= themeName %>/assets/sass/style.scss'
				}
			}
		},<% } %>
		clean: {
			dist: {
				files: [{
					dot: true,
					src: [
						'dist/*',
						'dist/.git*'
					]
				}]
			}
		},
		jshint: {
			options: {
				jshintrc: '.jshintrc'
			},
			all: [
				'Gruntfile.js',
				app + 'assets/js/{,*/}*.js'
			]
		},<% if (includeSASS) { %>
		// Configuration needs to be completed
		compass: {
			options: {
				sassDir: app,
				cssDir: app,
				generatedImagesDir: app + 'img',
				imagesDir: app + 'img',
				javascriptsDir: app + 'js',
				fontsDir: app + 'css/fonts',
				httpImagesPath: app + 'img',
				httpGeneratedImagesPath: app + 'img',
				httpFontsPath: app + 'fonts',
				relativeAssets: false
			},
			dist: {
				options: {
					generatedImagesDir: dist + 'img/generated'
				}
			}
		},<% } if (includeRequireJS) { %>
		requirejs: {
			dist: {
				// Options: https://github.com/jrburke/r.js/blob/master/build/example.build.js
				options: {
					// `name` and `out` is set by grunt-usemin
					baseUrl: app + 'assets/js',
					mainConfigFile: app + 'assets/js/main.js',
					paths: {
						jquery: 'empty:',
						underscore: 'empty:',
						app: 'app'
					},
					dir: dist + 'assets/js',
					shim: {
						underscore: {
							deps: ['jquery'],
							exports: '_'
						},
						app: {
							deps: ['jquery', 'underscore']
						}
					}
				}
			}
		},<% } %>
		imagemin: {
			dist: {
				files: [{
					expand: true,
					cwd: app + 'assets/images',
					src: '**/*.{png,jpg,jpeg}',
					dest: dist + 'assets/images'
				}],
				options: {
					cache: false
				}
			}
		},
		svgmin: {
			dist: {
				files: [{
					expand: true,
					cwd: app + 'assets/images',
					src: '**/*.svg',
					dest: dist + 'assets/images'
				}]
			}
		},
		preprocess: {
			dev: {
				options: {
					context: {
						NODE_ENV: 'DEVELOPMENT'
					},
				},
				files: {
					'app/wp-content/themes/<%= themeName %>/base.php': 'app/wp-content/themes/<%= themeName %>/base-template.html'
				},
			},
			dist: {
				options: {
					context: {
						NODE_ENV: 'PRODUCTION'
					},
				},
				files: {
					'dist/wp-content/themes/<%= themeName %>/base.php': 'app/wp-content/themes/<%= themeName %>/base-template.html'
				},
			},
		},
		// Put files not handled in other tasks here
		copy: {
			dist: {
				files: [{
					expand: true,
					dot: true,
					cwd: 'app',
					dest: 'dist',
					src: [
						'*.{ico,png,txt,php}',
						'.htaccess',
						'wp-admin/*',
						'wp-includes/*',
						'wp-content/plugins/*',
						'wp-content/themes/<%= themeName %>/*.{php,md,png,css}',
						'wp-content/themes/<%= themeName %>/templates/*',
						'wp-content/themes/<%= themeName %>/lib/*',
						'wp-content/themes/<%= themeName %>/lang/*',
						'wp-content/themes/<%= themeName %>/assets/fonts/{,*/}*.*'
					]
				}]
			}
		},
		hashres: {
			options: {
				encoding: 'utf8',
				fileNameFormat: '${name}.${ext}?${hash}',
				renameFiles: false
			},
			css: {
				src: [
					dist + 'style.css'
				],
				dest: dist + 'templates/head.php',
			}
		},
		concurrent: {
			dev: ['clean:dist', 'preprocess:dev'],
			build1: ['imagemin:dist', 'copy:dist', <% if (includeLESS) { %> 'less:dist' <% } %>, if (includeSASS) { %>'sass:dist'<% } %>],
			build2: ['preprocess:dist', 'svgmin:dist']
		}
	});

	// Load the Grunt plugins.
	<% if (includeLESS) { %>
	grunt.loadNpmTasks('grunt-contrib-less');<% } if (includeSASS) { %>
	grunt.loadNpmTasks('grunt-contrib-sass');<% } %>
	grunt.loadNpmTasks('grunt-contrib-watch');
	grunt.loadNpmTasks('grunt-contrib-uglify');
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-browser-sync');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-imagemin');
	grunt.loadNpmTasks('grunt-svgmin');
	grunt.loadNpmTasks('grunt-preprocess');
	grunt.loadNpmTasks('grunt-concurrent');
	grunt.loadNpmTasks('grunt-hashres'); <% if (includeRequireJS) { %>
	grunt.loadNpmTasks('grunt-contrib-requirejs'); <% } %>

	grunt.registerTask('build', [
		'clean:dist',
		'concurrent:build1',
		'concurrent:build2',
		'requirejs',
		'hashres'
	]);

	grunt.registerTask('dev', [
		'concurrent:dev',
		'browser_sync',
		'watch'
	]);
};
<|endoftext|>


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

  require('time-grunt')(grunt);

  require('jit-grunt')(grunt,  {
    includereplace: 'grunt-include-replace',
    useminPrepare: 'grunt-usemin',
    validation: 'grunt-html-validation',
    replace: 'grunt-text-replace'
  });

  // Project configuration.
  grunt.option('force', true);

  grunt.initConfig({

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

    // Configs
    xh: {
      src: 'src',
      dist: 'dist',
      build: ['head.html', 'scripts.html']
    },

    useminPrepare: {
      html: {
        src: '<%%= xh.build %>',
        cwd: '<%%= xh.src %>/includes/',
        expand: true
      },

      options: {
        dest: '<%%= xh.dist %>',
        root: '<%%= xh.src %>',
        flow: {
          steps: {'js': ['concat'], 'css': ['concat'] },
          post: {}
        }
      }
    },

    usemin: {
      html: {
        src: '<%%= xh.build %>',
        cwd: '<%%= xh.src %>/includes/',
        expand: true
      },

      options: {
        assetsDirs: ['<%%= xh.src %>/includes/']
      }
    },

    clean: {
      tmp: { src: ['.tmp'] },
      dist: { src: ['<%%= xh.dist %>/*.html', '<%%= xh.dist %>/css', '<%%= xh.dist %>/js', '<%%= xh.dist %>/fonts'] }
    },

    // HTML Includes
    includereplace: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%%= xh.src %>',
          src: ['*.html', '!template.html'],
          dest: '<%%= xh.dist %>',
          ext: '.html'
        }]
      }
    },

    jsbeautifier: {
      options : {
        html: {
          indentSize: 2
        },
        js: {
          indentSize: 2
        }
      },

      html: {
        src: '<%%= xh.dist %>/*.html'
      },

      js: {
        src: '<%%= xh.dist %>/js/main.js'
      }
    },

    validation: {
      src: ['<%%= xh.dist %>/*.html'],
      options: {
        reset: true,
        relaxerror: [
          'Bad value X-UA-Compatible for attribute http-equiv on element meta.',
          'The frameborder attribute on the iframe element is obsolete. Use CSS instead.'
        ]
      }
    },

    // CSS
    <% if (cssPreprocessor === 'SCSS') { %>
    sass: {
      dist: {
        options: {
          style: 'expanded',
          sourcemap: true,
          loadPath: 'src/bower_components/'
        },
        files: {
          '<%%= xh.dist %>/css/main.css': '<%%= xh.src %>/scss/main.scss'
        }
      }
    },<% } %> <% if (cssPreprocessor === 'LESS') { %>
    less: {
      dist: {
        options: {
          path: 'src/bower_components/'
        },
        files: {
          '<%%= xh.dist %>/css/main.css': '<%%= xh.src %>/less/main.less'
        }
      }
    },<% } %>

    autoprefixer: {
      main: {
        src: '<%%= xh.dist %>/css/main.css',
        dest: '<%%= xh.dist %>/css/main.css'
      }
    },

    cssbeautifier: {
      files: ['<%%= xh.dist %>/css/*.css', '!<%%= xh.dist %>/css/libraries.min.css'],
      options : {
        indent: '  '
      }
    },

    // JS
    copy: {
      normalize: {
        src: '<%%= xh.src %>/bower_components/normalize.css/normalize.css',<% if (cssPreprocessor === 'SCSS') { %>
        dest: '<%%= xh.src %>/bower_components/normalize.css/normalize.scss'<% } %><% if (cssPreprocessor === 'LESS') { %>
        dest: '<%%= xh.src %>/bower_components/normalize.css/normalize.less'<% } %>
      },

      jquery: {
        expand: true,
        cwd: '<%%= xh.src %>/bower_components/jquery/dist/',
        src: 'jquery.min.js',
        dest: '<%%= xh.dist %>/js/'
      },<% if (!useModernizr) { %>

      shiv: {
        expand: true,
        cwd: '<%%= xh.src %>/bower_components/html5shiv/dist/',
        src: 'html5shiv.min.js',
        dest: '<%%= xh.dist %>/js/'
      },<% } %>

      assets: {
        files: [
          {
            expand: true,
            cwd: '<%%= xh.src %>/img/',
            src: ['**/*.*', '!do_not_delete_me.png'],
            dest: '<%%= xh.dist %>/img/'
          },
          {
            expand: true,
            cwd: '<%%= xh.src %>/media/',
            src: ['**/*.*', '!do_not_delete_me.png'],
            dest: '<%%= xh.dist %>/media/'
          },
          {
            expand: true,
            cwd: '<%%= xh.src %>/fonts/',
            src: ['**/*.*', '!do_not_delete_me.png'],
            dest: '<%%= xh.dist %>/fonts/'
          },
          {
            expand: true,
            cwd: '<%%= xh.src %>/xprecise/',
            src: ['**/*.*', '!do_not_delete_me.png'],
            dest: '<%%= xh.dist %>/xprecise/'
          }
        ]
      },

      js: {
        expand: true,
        cwd: '<%%= xh.src %>/js/',
        src: ['main.js'],
        dest: '<%%= xh.dist %>/js/'
      },<% if (isWP) { %>

      wp: {
        expand: true,
        cwd: '<%%= xh.dist %>/',
        src: ['**', '!**/xprecise/**', '!*.html'],
        dest: '<%= wpThemeFolder  %>'
      },<% } %>

      // Backup include files
      backup: {
        expand: true,
        cwd: '<%%= xh.src %>/includes/',
        src: '<%%= xh.build %>',
        dest: '.tmp'
      },

      // Restore include files
      restore: {
        expand: true,
        cwd: '.tmp',
        src: '<%%= xh.build %>',
        dest: '<%%= xh.src %>/includes/'
      }
    },

    jshint: {
      options: {
        jshintrc: true,
        force: true
      },
      dist: {
        src: ['<%%= xh.src %>/js/main.js', '<%%= xh.dist %>/js/main.js'],
      }
    },<% if (useModernizr) { %>

    uglify: {
      modernizr: {
        files: {
          '<%%= xh.dist %>/js/modernizr.min.js': ['src/bower_components/modernizr/modernizr.js']
        }
      }
    },<% } %>

    // Replacements in main.css and main.js
    replace: {
      css: {
        src: ['<%%= xh.dist %>/css/main.css'],
        overwrite: true,
        replacements: [{
          from: '@@timestamp',
          to: '<%%= grunt.template.today() %>'
        },
        // Table of contents in main.css
        {
          from: '@@toc',
          to: function () {

            if (!grunt.file.exists('csstoc.json')) {
              return '';
            }

            var toc_file = grunt.file.readJSON('csstoc.json')
            var files = toc_file.results;
            var toc = '';
            var i = 1;
            var match;

            function capitalize(s) {
              return s[0].toUpperCase() + s.slice(1);
            }

            for (var key in files) {
              if (files.hasOwnProperty(key)) {

                var results = files[key];

                for (var key in results) {
                  if (results.hasOwnProperty(key)) {

                    match = results[key]['match'];
                    match = match.replace(/"|'|@import|;|.scss|.less/gi, "").trim();
                    match = match.split('/').pop();
                    match = capitalize(match);

                    if (match !== 'Variables' && match !== 'Mixins') {
                      toc += '\n    ' + i + '. ' + match;
                      i++;
                    }
                  }
                }
              }
            }
            return toc;
          }
        },
        // Add empty line after section & subsection comment
        {
          from: /=== \*\//g,
          to: '=== */\n'
        },
        // Add empty line after rule if it doesn't have one already
        {
          from: /}(?!\n\n)/gi,
          to: '}\n'
        }]
      },

      js: {
        src: ['<%%= xh.dist %>/js/main.js'],
        overwrite: true,
        replacements: [{
          from: '@@timestamp',
          to: '<%%= grunt.template.today() %>'
        }]
      },

      xprecise: {
        src: ['<%%= xh.src %>/includes/scripts.html'],
        overwrite: true,
        replacements: [{
          from: '<script src="http://xhtmlized.github.io/x-precise/xprecise.min.js"></script>',
          to: ''
        }]
      }
    },

    // Create list of @imports
    search: {
      imports: {
        files: {<% if (cssPreprocessor === 'SCSS') { %>
          src: ['<%%= xh.src %>/scss/main.scss']<% } %><% if (cssPreprocessor === 'LESS') { %>
          src: ['<%%= xh.src %>/less/main.less']<% } %>
        },
        options: {
          searchString: /@import[ \("']*([^;]+)[;\)"']*/g,
          logFormat: "json",
          logFile: "csstoc.json"
        }
      }
    }<% if (reloader === 'BrowserSync') { %>,

    browserSync: {
      src: {
        bsFiles: {
          src: [
            '<%%= xh.dist %>/css/*.css',
            '<%%= xh.src %>/js/*.js',
            '<%%= xh.src %>/img/*.*',
            '<%%= xh.src %>/media/*.*',
            '<%%= xh.src %>/fonts/*.*',
            '<%%= xh.src %>/xprecise/*.*',
            '<%%= xh.src %>/**/*.html'
          ]
        },

        options: {
          watchTask: true,
          server: {
            baseDir: "./"
          }
        }
      }
    }<% } %>,

    // Watch
    watch: {
      options: {
        spawn: false
      },

      compileCSS: {
        files: [<% if (cssPreprocessor === 'SCSS') { %>'<%%= xh.src %>/scss/**/*.scss'<% } %><% if (cssPreprocessor === 'LESS') { %>'<%%= xh.src %>/less/**/*.less'<% } %>],
        tasks: ['build-css'<% if (isWP) { %>, 'copy:wp'<% } %>]
      }<% if (reloader === 'LiveReload') { %>,

      css: {
        files: ['<%%= xh.dist %>/css/*.css'],
        options: {
          livereload: true
        }
      }<% } %>,

      html: {
        files: ['<%%= xh.src %>/*.html', '<%%= xh.src %>/includes/*.html'],
        tasks: ['build-html']<% if (reloader === 'LiveReload') { %>,
        options: {
          livereload: true
        }<% } %>
      },

      js: {
        files: ['<%%= xh.src %>/js/*.js'],
        tasks: ['build-js'<% if (isWP) { %>, 'copy:wp'<% } %>]<% if (reloader === 'LiveReload') { %>,
        options: {
          livereload: true
        }<% } %>
      },

      assets: {
        files: ['<%%= xh.src %>/{img,media,fonts,xprecise}/**/*'],
        tasks: ['build-assets'<% if (isWP) { %>, 'copy:wp'<% } %>]<% if (reloader === 'LiveReload') { %>,
        options: {
          livereload: true
        }<% } %>
      }
    }

  });

  grunt.registerTask('build-html', [
    'useminPrepare',
    'concat',
    'copy:backup',
    'usemin',
    'includereplace',
    'copy:restore',
    'jsbeautifier:html',
    'clean:tmp'
  ]);

  grunt.registerTask('build-assets', [
    'copy:assets'
  ]);

  grunt.registerTask('build-css', [<% if (cssPreprocessor === 'SCSS') { %>
    'sass',<% } %><% if (cssPreprocessor === 'LESS') { %>
    'less',<% } %>
    'autoprefixer',
    'cssbeautifier',
    'search',
    'replace:css'
  ]);

  grunt.registerTask('build-js', [
    'copy:js',
    'jsbeautifier:js',
    'replace:js',
    'jshint'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'postinstall',

    'build-html',
    'build-assets',
    'build-css',
    'build-js',<% if (isWP) { %>

    'copy:wp',<% } %>
  ]);

  grunt.registerTask('validate', [
    'validation'
  ]);

  grunt.registerTask('qa', [
    'replace:xprecise',
    'build',
    'validate',
    'jshint'
  ]);

  grunt.registerTask('postinstall', [<% if (!useBootstrap) { %>
    'copy:normalize',<% } %><% if (useModernizr) { %>
    'uglify:modernizr',<% } else { %>'copy:shiv',<% } %>
    'copy:jquery'
  ]);

  grunt.registerTask('default', [
    'postinstall'<% if (reloader === 'BrowserSync') { %>,
    'browserSync'<% } %>,
    'watch'
  ]);
};
<commit_msg>Final updates to browser-sync module and bug fixed Fixes #31<commit_after>module.exports = function(grunt) {

  require('time-grunt')(grunt);

  require('jit-grunt')(grunt,  {
    includereplace: 'grunt-include-replace',
    useminPrepare: 'grunt-usemin',
    validation: 'grunt-html-validation',
    replace: 'grunt-text-replace'
  });

  // Project configuration.
  grunt.option('force', true);

  grunt.initConfig({

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

    // Configs
    xh: {
      src: 'src',
      dist: 'dist',
      build: ['head.html', 'scripts.html']
    },

    useminPrepare: {
      html: {
        src: '<%%= xh.build %>',
        cwd: '<%%= xh.src %>/includes/',
        expand: true
      },

      options: {
        dest: '<%%= xh.dist %>',
        root: '<%%= xh.src %>',
        flow: {
          steps: {'js': ['concat'], 'css': ['concat'] },
          post: {}
        }
      }
    },

    usemin: {
      html: {
        src: '<%%= xh.build %>',
        cwd: '<%%= xh.src %>/includes/',
        expand: true
      },

      options: {
        assetsDirs: ['<%%= xh.src %>/includes/']
      }
    },

    clean: {
      tmp: { src: ['.tmp'] },
      dist: { src: ['<%%= xh.dist %>/*.html', '<%%= xh.dist %>/css', '<%%= xh.dist %>/js', '<%%= xh.dist %>/fonts'] }
    },

    // HTML Includes
    includereplace: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%%= xh.src %>',
          src: ['*.html', '!template.html'],
          dest: '<%%= xh.dist %>',
          ext: '.html'
        }]
      }
    },

    jsbeautifier: {
      options : {
        html: {
          indentSize: 2
        },
        js: {
          indentSize: 2
        }
      },

      html: {
        src: '<%%= xh.dist %>/*.html'
      },

      js: {
        src: '<%%= xh.dist %>/js/main.js'
      }
    },

    validation: {
      src: ['<%%= xh.dist %>/*.html'],
      options: {
        reset: true,
        relaxerror: [
          'Bad value X-UA-Compatible for attribute http-equiv on element meta.',
          'The frameborder attribute on the iframe element is obsolete. Use CSS instead.'
        ]
      }
    },

    // CSS
    <% if (cssPreprocessor === 'SCSS') { %>
    sass: {
      dist: {
        options: {
          style: 'expanded',
          sourcemap: true,
          loadPath: 'src/bower_components/'
        },
        files: {
          '<%%= xh.dist %>/css/main.css': '<%%= xh.src %>/scss/main.scss'
        }
      }
    },<% } %> <% if (cssPreprocessor === 'LESS') { %>
    less: {
      dist: {
        options: {
          path: 'src/bower_components/'
        },
        files: {
          '<%%= xh.dist %>/css/main.css': '<%%= xh.src %>/less/main.less'
        }
      }
    },<% } %>

    autoprefixer: {
      main: {
        src: '<%%= xh.dist %>/css/main.css',
        dest: '<%%= xh.dist %>/css/main.css'
      }
    },

    cssbeautifier: {
      files: ['<%%= xh.dist %>/css/*.css', '!<%%= xh.dist %>/css/libraries.min.css'],
      options : {
        indent: '  '
      }
    },

    // JS
    copy: {
      normalize: {
        src: '<%%= xh.src %>/bower_components/normalize.css/normalize.css',<% if (cssPreprocessor === 'SCSS') { %>
        dest: '<%%= xh.src %>/bower_components/normalize.css/normalize.scss'<% } %><% if (cssPreprocessor === 'LESS') { %>
        dest: '<%%= xh.src %>/bower_components/normalize.css/normalize.less'<% } %>
      },

      jquery: {
        expand: true,
        cwd: '<%%= xh.src %>/bower_components/jquery/dist/',
        src: 'jquery.min.js',
        dest: '<%%= xh.dist %>/js/'
      },<% if (!useModernizr) { %>

      shiv: {
        expand: true,
        cwd: '<%%= xh.src %>/bower_components/html5shiv/dist/',
        src: 'html5shiv.min.js',
        dest: '<%%= xh.dist %>/js/'
      },<% } %>

      assets: {
        files: [
          {
            expand: true,
            cwd: '<%%= xh.src %>/img/',
            src: ['**/*.*', '!do_not_delete_me.png'],
            dest: '<%%= xh.dist %>/img/'
          },
          {
            expand: true,
            cwd: '<%%= xh.src %>/media/',
            src: ['**/*.*', '!do_not_delete_me.png'],
            dest: '<%%= xh.dist %>/media/'
          },
          {
            expand: true,
            cwd: '<%%= xh.src %>/fonts/',
            src: ['**/*.*', '!do_not_delete_me.png'],
            dest: '<%%= xh.dist %>/fonts/'
          },
          {
            expand: true,
            cwd: '<%%= xh.src %>/xprecise/',
            src: ['**/*.*', '!do_not_delete_me.png'],
            dest: '<%%= xh.dist %>/xprecise/'
          }
        ]
      },

      js: {
        expand: true,
        cwd: '<%%= xh.src %>/js/',
        src: ['main.js'],
        dest: '<%%= xh.dist %>/js/'
      },<% if (isWP) { %>

      wp: {
        expand: true,
        cwd: '<%%= xh.dist %>/',
        src: ['**', '!**/xprecise/**', '!*.html'],
        dest: '<%= wpThemeFolder  %>'
      },<% } %>

      // Backup include files
      backup: {
        expand: true,
        cwd: '<%%= xh.src %>/includes/',
        src: '<%%= xh.build %>',
        dest: '.tmp'
      },

      // Restore include files
      restore: {
        expand: true,
        cwd: '.tmp',
        src: '<%%= xh.build %>',
        dest: '<%%= xh.src %>/includes/'
      }
    },

    jshint: {
      options: {
        jshintrc: true,
        force: true
      },
      dist: {
        src: ['<%%= xh.src %>/js/main.js', '<%%= xh.dist %>/js/main.js'],
      }
    },<% if (useModernizr) { %>

    uglify: {
      modernizr: {
        files: {
          '<%%= xh.dist %>/js/modernizr.min.js': ['src/bower_components/modernizr/modernizr.js']
        }
      }
    },<% } %>

    // Replacements in main.css and main.js
    replace: {
      css: {
        src: ['<%%= xh.dist %>/css/main.css'],
        overwrite: true,
        replacements: [{
          from: '@@timestamp',
          to: '<%%= grunt.template.today() %>'
        },
        // Table of contents in main.css
        {
          from: '@@toc',
          to: function () {

            if (!grunt.file.exists('csstoc.json')) {
              return '';
            }

            var toc_file = grunt.file.readJSON('csstoc.json')
            var files = toc_file.results;
            var toc = '';
            var i = 1;
            var match;

            function capitalize(s) {
              return s[0].toUpperCase() + s.slice(1);
            }

            for (var key in files) {
              if (files.hasOwnProperty(key)) {

                var results = files[key];

                for (var key in results) {
                  if (results.hasOwnProperty(key)) {

                    match = results[key]['match'];
                    match = match.replace(/"|'|@import|;|.scss|.less/gi, "").trim();
                    match = match.split('/').pop();
                    match = capitalize(match);

                    if (match !== 'Variables' && match !== 'Mixins') {
                      toc += '\n    ' + i + '. ' + match;
                      i++;
                    }
                  }
                }
              }
            }
            return toc;
          }
        },
        // Add empty line after section & subsection comment
        {
          from: /=== \*\//g,
          to: '=== */\n'
        },
        // Add empty line after rule if it doesn't have one already
        {
          from: /}(?!\n\n)/gi,
          to: '}\n'
        }]
      },

      js: {
        src: ['<%%= xh.dist %>/js/main.js'],
        overwrite: true,
        replacements: [{
          from: '@@timestamp',
          to: '<%%= grunt.template.today() %>'
        }]
      },

      xprecise: {
        src: ['<%%= xh.src %>/includes/scripts.html'],
        overwrite: true,
        replacements: [{
          from: '<script src="http://xhtmlized.github.io/x-precise/xprecise.min.js"></script>',
          to: ''
        }]
      }
    },

    // Create list of @imports
    search: {
      imports: {
        files: {<% if (cssPreprocessor === 'SCSS') { %>
          src: ['<%%= xh.src %>/scss/main.scss']<% } %><% if (cssPreprocessor === 'LESS') { %>
          src: ['<%%= xh.src %>/less/main.less']<% } %>
        },
        options: {
          searchString: /@import[ \("']*([^;]+)[;\)"']*/g,
          logFormat: "json",
          logFile: "csstoc.json"
        }
      }
    }<% if (reloader === 'BrowserSync') { %>,

    browserSync: {
      src: {
        bsFiles: {
          src: [
            '<%= xh.dist %>/css/*.css',
            '<%= xh.dist %>/js/*.js',
            '<%= xh.dist %>/{img,media,fonts,xprecise}/**/*.*',
            '<%= xh.dist %>/**/*.html'
          ]
        },

        options: {
          watchTask: true,
          server: {
            baseDir: "./"
          },
          notify: false
        }
      }
    }<% } %>,

    // Watch
    watch: {
      options: {
        spawn: false
      },

      compileCSS: {
        files: [<% if (cssPreprocessor === 'SCSS') { %>'<%%= xh.src %>/scss/**/*.scss'<% } %><% if (cssPreprocessor === 'LESS') { %>'<%%= xh.src %>/less/**/*.less'<% } %>],
        tasks: ['build-css'<% if (isWP) { %>, 'copy:wp'<% } %>]
      }<% if (reloader === 'LiveReload') { %>,

      css: {
        files: ['<%%= xh.dist %>/css/*.css'],
        options: {
          livereload: true
        }
      }<% } %>,

      html: {
        files: ['<%%= xh.src %>/*.html', '<%%= xh.src %>/includes/*.html'],
        tasks: ['build-html']<% if (reloader === 'LiveReload') { %>,
        options: {
          livereload: true
        }<% } %>
      },

      js: {
        files: ['<%%= xh.src %>/js/*.js'],
        tasks: ['build-js'<% if (isWP) { %>, 'copy:wp'<% } %>]<% if (reloader === 'LiveReload') { %>,
        options: {
          livereload: true
        }<% } %>
      },

      assets: {
        files: ['<%%= xh.src %>/{img,media,fonts,xprecise}/**/*'],
        tasks: ['build-assets'<% if (isWP) { %>, 'copy:wp'<% } %>]<% if (reloader === 'LiveReload') { %>,
        options: {
          livereload: true
        }<% } %>
      }
    }

  });

  grunt.registerTask('build-html', [
    'useminPrepare',
    'concat',
    'copy:backup',
    'usemin',
    'includereplace',
    'copy:restore',
    'jsbeautifier:html',
    'clean:tmp'
  ]);

  grunt.registerTask('build-assets', [
    'copy:assets'
  ]);

  grunt.registerTask('build-css', [<% if (cssPreprocessor === 'SCSS') { %>
    'sass',<% } %><% if (cssPreprocessor === 'LESS') { %>
    'less',<% } %>
    'autoprefixer',
    'cssbeautifier',
    'search',
    'replace:css'
  ]);

  grunt.registerTask('build-js', [
    'copy:js',
    'jsbeautifier:js',
    'replace:js',
    'jshint'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'postinstall',

    'build-html',
    'build-assets',
    'build-css',
    'build-js',<% if (isWP) { %>

    'copy:wp',<% } %>
  ]);

  grunt.registerTask('validate', [
    'validation'
  ]);

  grunt.registerTask('qa', [
    'replace:xprecise',
    'build',
    'validate',
    'jshint'
  ]);

  grunt.registerTask('postinstall', [<% if (!useBootstrap) { %>
    'copy:normalize',<% } %><% if (useModernizr) { %>
    'uglify:modernizr',<% } else { %>'copy:shiv',<% } %>
    'copy:jquery'
  ]);

  grunt.registerTask('default', [
    'postinstall'<% if (reloader === 'BrowserSync') { %>,
    'browserSync'<% } %>,
    'watch'
  ]);
};
<|endoftext|>


<commit_before>(function() {
  "use strict";

  module.exports = function(grunt) {
    grunt.initConfig({
      clean: {
        coverage: [ "coverage" ]
      },

      mkdir: {
        all: {
          options: {
            create: [ "coverage" ]
          }
        }
      },

      jshint: {
        options: grunt.file.readJSON(".jshintrc"),

        gruntfile: {
          files: {
            src: "Gruntfile.js"
          }
        },

        src: {
          files: {
            src: "src/**/*.js"
          }
        },

        test: {
          files: {
            src: "test/**/*.js"
          },

          options: {
            globals: {
              describe: true,
              it: true
            }
          }
        }
      },

      watch: {
        gruntfile: {
          files: "<%= jshint.gruntfile.files.src %>",
          tasks: [
            "jshint:gruntfile"
          ]
        },

        src: {
          files: "<%= jshint.src.files.src %>",
          tasks: [
            "jshint:src",
            "mochaTest"
          ]
        },

        test: {
          files: "<%= jshint.test.files.src %>",
          tasks: [
            "jshint:test",
            "mochaTest"
          ]
        }
      },

      mochaTest: {
        test: {
          options: {
            reporter: "spec"
          },

          src: [
            "test/**/*.js"
          ]
        }
      },

      exec: {
        coverage: {
          command: "istanbul cover _mocha -- -u exports -R spec",
          stdout: true
        }
      }

    });

    grunt.loadNpmTasks("grunt-contrib-clean");
    grunt.loadNpmTasks("grunt-contrib-jshint");
    grunt.loadNpmTasks("grunt-contrib-watch");

    grunt.loadNpmTasks("grunt-exec");
    grunt.loadNpmTasks("grunt-mkdir");
    grunt.loadNpmTasks("grunt-mocha-test");

    grunt.registerTask("default", [ "clean", "mkdir", "jshint", "mochaTest", "exec:coverage" ]);
  };

} ());<commit_msg>Updating integration Mocha and Istanbul inside Grunt configuration.<commit_after>(function() {
  "use strict";

  module.exports = function(grunt) {
    grunt.initConfig({
      clean: {
        coverage: [ "coverage" ]
      },

      mkdir: {
        all: {
          options: {
            create: [ "coverage" ]
          }
        }
      },

      jshint: {
        options: grunt.file.readJSON(".jshintrc"),

        gruntfile: {
          files: {
            src: "Gruntfile.js"
          }
        },

        src: {
          files: {
            src: "src/**/*.js"
          }
        },

        test: {
          files: {
            src: "test/**/*.js"
          },

          options: {
            globals: {
              describe: true,
              it: true
            }
          }
        }
      },

      watch: {
        gruntfile: {
          files: "<%= jshint.gruntfile.files.src %>",
          tasks: [
            "jshint:gruntfile"
          ]
        },

        src: {
          files: "<%= jshint.src.files.src %>",
          tasks: [
            "jshint:src",
            "mochaTest"
          ]
        },

        test: {
          files: "<%= jshint.test.files.src %>",
          tasks: [
            "jshint:test",
            "mochaTest"
          ]
        }
      },

      mochaTest: {
        test: {
          options: {
            reporter: "spec"
          },

          src: [
            "test/**/*.js"
          ]
        }
      },

      exec: {
        coverage: {
          command: "istanbul cover node_modules/.bin/_mocha -- -u exports -R spec",
          stdout: true
        }
      }

    });

    grunt.loadNpmTasks("grunt-contrib-clean");
    grunt.loadNpmTasks("grunt-contrib-jshint");
    grunt.loadNpmTasks("grunt-contrib-watch");

    grunt.loadNpmTasks("grunt-exec");
    grunt.loadNpmTasks("grunt-mkdir");
    grunt.loadNpmTasks("grunt-mocha-test");

    grunt.registerTask("default", [ "clean", "mkdir", "jshint", "mochaTest", "exec:coverage" ]);
  };

} ());
<|endoftext|>


<commit_before>const fs = require("fs");
jest.mock("child_process");

const BehatStepsParser = require("../src/BehatStepsParser");

const project_path = "/project";
const config_file = "behat.yml";

let instance = new BehatStepsParser(project_path, config_file);

const equals = (actual, expected) => expect(actual).toBe(expected);
const equalsObject = (actual, expect) => {
    Object.keys(expect).map(key => equals(actual[key], expect[key]));
}

describe("paths and config file", () => {
    test("should get correct behat command and config file", () => {
        equals(instance.behatCMD, `php ${project_path}/vendor/bin/behat`);
        equals(instance.configFile, `${project_path}/${config_file}`);
    });

    test("should update command and config file", () => {
        let project_path = "/my/new/path";
        let config_file = "config/custom_behat.yml";

        instance.updateConfig(project_path, config_file);
        equals(instance.behatCMD, `php ${project_path}/vendor/bin/behat`);
        equals(instance.configFile, `${project_path}/${config_file}`);
    });

    test("should get correct cmd", () => {
        instance.updateConfig("/app", "b.yml");
        equals(instance.getCmdListSteps(), "php /app/vendor/bin/behat -c /app/b.yml -di /app/");
    });
});

describe("make regex", () => {
    test("should make steps regex", () => {
        let exampleData = [
            ["simple step", "^simple step$"],
            ["/simple step/", "simple step"],
            ["/^simple step/", "^simple step"],
            ["/simple step$/", "simple step$"],
            ["simple :arg1", '^simple "?([^"]*)"?$'],
            ["simple :arg1 :arg2", '^simple "?([^"]*)"? "?([^"]*)"?$'],
            ["simple :simple1", '^simple "?([^"]*)"?$'],
            ["/^simple (\d+)$/", "^simple (\d+)$"],
            ["/^simple (?:|optional )$/", "^simple (?:|optional )$"],
            ["/simple (?:|optional | opt )$/", "simple (?:|optional | opt )$"],
            ["/^simple (options|choices)/", "^simple (options|choices)"],
            ['/^simple "(?P<theuglyargument>.*)"$/', '^simple "(.*)"$'],
        ];

        exampleData.map(config => {
            equals(instance.makeStepRegex(config[0]), config[1]);
        });
    });

    test("shoud throw an error when the regex is invalid", () => {
        try {
            instance.makeStepRegex("/^simple (yopa$/");
            throw "This call should throw an error";
        } catch(e) {
            equals(true, true);
        }
    });
});

describe("extract context", () => {
    test("should extract the class and method", () => {
        equalsObject(instance.extractContext("   | at `Class::method()`"), {className: "Class", methodName: "method"});
    });

    test("should extract the class and method with namespace", () => {
        equalsObject(instance.extractContext("   | at `App\Class::method()`"), {className: "App\Class", methodName: "method"});
    });

    test("should extract the class and method with underline", () => {
        equalsObject(instance.extractContext("   | at `Class_xpto::method_foo()`"), {className: "Class_xpto", methodName: "method_foo"});
    });

    test("should extract class and method with accents", () => {
        equalsObject(instance.extractContext("   | at `Cláss::méthodã()`"), {className: "Cláss", methodName: "méthodã"});
    });
});

test("extract suite and regex", () => {
    let response = instance.extractSuiteAndRegex("default | [When|*] simple step");
    equals(response.suite, "default");
    equals(response.regex.keyword, "When|*");
    equals(response.regex.originalStep, "simple step");
    equals(response.regex.step, "^simple step$");
});

describe("parse step", () => {
    test("parse step", () => {
        let step = `suite | [When|*] step with arguments :arg1 :name1
                        | Example: When step with arguments 1 "two"
                        | at \`Class::method()\``;

        let response = instance.parseStep(step);
        equals(response.suite, "suite");
        equals(response.regex.keyword, "When|*");
        equals(response.regex.originalStep, "step with arguments :arg1 :name1");
        equals(response.regex.step, '^step with arguments "?([^"]*)"? "?([^"]*)"?$');
        equals(response.context.className, "Class");
        equals(response.context.methodName, "method");
    });

    test("shoud throw an error on invalid step", () => {
        try {
            instance.parseStep("invalid step");
            throw "This call should throw an error";
        } catch(e) {
            equals(true, true);
        }
    });

    test("shoud throw an error on empty step", () => {
        try {
            instance.parseStep("");
            throw "This call should throw an error";
        } catch(e) {
            equals(true, true);
        }
    });
});

test("update cache", () => {
    let test_steps = fs.readFileSync(__dirname + "/test_steps.txt").toString();
    require("child_process").__setMockSteps(test_steps);

    let instance = new BehatStepsParser(project_path, config_file);

    // the 9th is invalid
    equals(instance.steps.length, 12);

    // fix the problem
    test_steps = test_steps.replace(/\(yopa/, "");
    require("child_process").__setMockSteps(test_steps);
    instance.updateStepsCache();
    equals(instance.steps.length, 13);

    require("child_process").__setMockSteps("");
    instance.updateStepsCache();
    equals(instance.steps.length, 0);
});
<commit_msg>fix test, to be compatible with the path.resolve usage<commit_after>const fs = require("fs");
jest.mock("child_process");

const BehatStepsParser = require("../src/BehatStepsParser");

const project_path = "/project";
const config_file = "behat.yml";

let instance = new BehatStepsParser(project_path, config_file);

const equals = (actual, expected) => expect(actual).toBe(expected);
const equalsObject = (actual, expect) => {
    Object.keys(expect).map(key => equals(actual[key], expect[key]));
}

describe("paths and config file", () => {
    test("should get correct behat command and config file", () => {
        equals(instance.behatCMD, `php ${project_path}/vendor/bin/behat`);
        equals(instance.configFile, `${project_path}/${config_file}`);
    });

    test("should update command and config file", () => {
        let project_path = "/my/new/path";
        let config_file = "config/custom_behat.yml";

        instance.updateConfig(project_path, config_file);
        equals(instance.behatCMD, `php ${project_path}/vendor/bin/behat`);
        equals(instance.configFile, `${project_path}/${config_file}`);
    });

    test("should get correct cmd", () => {
        instance.updateConfig("/app", "b.yml");
        equals(instance.getCmdListSteps(), "php /app/vendor/bin/behat -c /app/b.yml -di /app");
    });
});

describe("make regex", () => {
    test("should make steps regex", () => {
        let exampleData = [
            ["simple step", "^simple step$"],
            ["/simple step/", "simple step"],
            ["/^simple step/", "^simple step"],
            ["/simple step$/", "simple step$"],
            ["simple :arg1", '^simple "?([^"]*)"?$'],
            ["simple :arg1 :arg2", '^simple "?([^"]*)"? "?([^"]*)"?$'],
            ["simple :simple1", '^simple "?([^"]*)"?$'],
            ["/^simple (\d+)$/", "^simple (\d+)$"],
            ["/^simple (?:|optional )$/", "^simple (?:|optional )$"],
            ["/simple (?:|optional | opt )$/", "simple (?:|optional | opt )$"],
            ["/^simple (options|choices)/", "^simple (options|choices)"],
            ['/^simple "(?P<theuglyargument>.*)"$/', '^simple "(.*)"$'],
        ];

        exampleData.map(config => {
            equals(instance.makeStepRegex(config[0]), config[1]);
        });
    });

    test("shoud throw an error when the regex is invalid", () => {
        try {
            instance.makeStepRegex("/^simple (yopa$/");
            throw "This call should throw an error";
        } catch(e) {
            equals(true, true);
        }
    });
});

describe("extract context", () => {
    test("should extract the class and method", () => {
        equalsObject(instance.extractContext("   | at `Class::method()`"), {className: "Class", methodName: "method"});
    });

    test("should extract the class and method with namespace", () => {
        equalsObject(instance.extractContext("   | at `App\Class::method()`"), {className: "App\Class", methodName: "method"});
    });

    test("should extract the class and method with underline", () => {
        equalsObject(instance.extractContext("   | at `Class_xpto::method_foo()`"), {className: "Class_xpto", methodName: "method_foo"});
    });

    test("should extract class and method with accents", () => {
        equalsObject(instance.extractContext("   | at `Cláss::méthodã()`"), {className: "Cláss", methodName: "méthodã"});
    });
});

test("extract suite and regex", () => {
    let response = instance.extractSuiteAndRegex("default | [When|*] simple step");
    equals(response.suite, "default");
    equals(response.regex.keyword, "When|*");
    equals(response.regex.originalStep, "simple step");
    equals(response.regex.step, "^simple step$");
});

describe("parse step", () => {
    test("parse step", () => {
        let step = `suite | [When|*] step with arguments :arg1 :name1
                        | Example: When step with arguments 1 "two"
                        | at \`Class::method()\``;

        let response = instance.parseStep(step);
        equals(response.suite, "suite");
        equals(response.regex.keyword, "When|*");
        equals(response.regex.originalStep, "step with arguments :arg1 :name1");
        equals(response.regex.step, '^step with arguments "?([^"]*)"? "?([^"]*)"?$');
        equals(response.context.className, "Class");
        equals(response.context.methodName, "method");
    });

    test("shoud throw an error on invalid step", () => {
        try {
            instance.parseStep("invalid step");
            throw "This call should throw an error";
        } catch(e) {
            equals(true, true);
        }
    });

    test("shoud throw an error on empty step", () => {
        try {
            instance.parseStep("");
            throw "This call should throw an error";
        } catch(e) {
            equals(true, true);
        }
    });
});

test("update cache", () => {
    let test_steps = fs.readFileSync(__dirname + "/test_steps.txt").toString();
    require("child_process").__setMockSteps(test_steps);

    let instance = new BehatStepsParser(project_path, config_file);

    // the 9th is invalid
    equals(instance.steps.length, 12);

    // fix the problem
    test_steps = test_steps.replace(/\(yopa/, "");
    require("child_process").__setMockSteps(test_steps);
    instance.updateStepsCache();
    equals(instance.steps.length, 13);

    require("child_process").__setMockSteps("");
    instance.updateStepsCache();
    equals(instance.steps.length, 0);
});
<|endoftext|>