<commit_before>var gulp = require('gulp');
var clean = require('gulp-clean');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var minify = require('gulp-minify-css');
var autoprefixer = require('gulp-autoprefixer');
var rename = require('gulp-rename');
var sourcemaps = require('gulp-sourcemaps');
var stylus = require('gulp-stylus');
var jade = require('gulp-jade');
var nodemon = require('gulp-nodemon');
var jshint = require('gulp-jshint');
var jscs = require('gulp-jscs');
var noop = function () {};
var stylish = require('gulp-jscs-stylish');

var DIST_DIR = './public/dist';
var JS_DIR = DIST_DIR + '/js';
var CSS_DIR = DIST_DIR + '/css';
var VIEW_DIR = DIST_DIR + '/views';
var DIRECTIVES_DIR = DIST_DIR + '/directives-views';
var COMPILED_STYLUS_DIR = './public/css/';

var JS_SRC = ['./public/vendors/jquery/dist/jquery.min.js',
              './public/vendors/bootstrap/dist/js/bootstrap.min.js',
              './public/vendors/toastr/toastr.min.js',
              './public/vendors/angular/angular.js',
              './public/vendors/angular-resource/angular-resource.js',
              './public/vendors/angular-animate/angular-animate.js',
              './public/vendors/angular-route/angular-route.js',
              './public/vendors/angular-translate/angular-translate.min.js',
              './public/vendors/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js',
              './public/vendors/angular-local-storage/dist/angular-local-storage.min.js',
              './public/vendors/angular-ui-select/dist/select.js',
              './public/vendors/odometer/odometer.js',
              './public/vendors/angular-odometer-js/dist/angular-odometer.js',
              './public/vendors/Chart.js/Chart.min.js',
              './public/vendors/angular-chart.js/dist/angular-chart.min.js',
              './public/vendors/ngDialog/js/ngDialog.min.js',
              './public/vendors/angular-utils-pagination/dirPagination.js',
              './public/vendors/angular-hotkeys/build/hotkeys.min.js',
              './public/app/app.js',
              './public/app/config/**/*.js',
              './public/app/filters/**/*.js',
              './public/app/directives/**/*.js',
              './public/app/ui/**/*.js',
              './public/app/questions/**/*.js',
              './public/app/users/**/*.js',
              './public/app/admin/**/*.js'
              ];

var CSS_SRC = ['./public/css/socicon.css',
                './public/vendors/ngDialog/css/ngDialog.min.css',
                './public/vendors/ngDialog/css/ngDialog-theme-default.min.css',
                './public/vendors/angular-ui-select/dist/select.css',
                './public/vendors/odometer/themes/odometer-theme-minimal.css',
                './public/vendors/toastr/toastr.css',
                './public/vendors/angular-chart.js/dist/angular-chart.css',
                './public/vendors/angular-hotkeys/build/angular-hotkeys.min.css',
                './public/css/site.css',
                './public/css/mobile.css'];

var VIEW_SRC = ['./public/app/**/*.jade'];

// yvar DIRECTIVE_SRC = ['./public/app/directives/**/*.jade'];

var STYLUS_SRC = ['./public/css/*.styl'];

var TO_LINT_SRC = ['./public/app/**/*.js',
                   './server.js',
                   './server/**/*.js',
                  '!./public/**/bootstrap-tagsinput.js'];

gulp.task('default', function () {
  gulp.start('build');
});

gulp.task('build', function () {
  gulp.start('build-client');
});

gulp.task('clean-client-dist', function () {
  return gulp.src(DIST_DIR)
    .pipe(clean());
});

gulp.task('build-client', ['clean-client-dist'], function () {
  gulp.start('build-client-js');
  gulp.start('build-client-css');
  gulp.start('build-client-views');
});

gulp.task('build-client-js', function () {
  gulp.src(JS_SRC)
    .pipe(sourcemaps.init())
    .pipe(concat('dilemme.js'))
    .pipe(gulp.dest(JS_DIR))
    .pipe(uglify({mangle: false}))
    .pipe(rename({extname: '.min.js'}))
    .pipe(sourcemaps.write('maps'))
    .pipe(gulp.dest(JS_DIR));
});

gulp.task('build-client-stylus', function () {
  return gulp.src(STYLUS_SRC)
    .pipe(stylus())
    .pipe(gulp.dest(COMPILED_STYLUS_DIR));
});

gulp.task('build-client-css', ['build-client-stylus'], function () {
  gulp.src(CSS_SRC)
    .pipe(sourcemaps.init())
    .pipe(autoprefixer())
    .pipe(concat('dilemme.css'))
    .pipe(gulp.dest(CSS_DIR))
    .pipe(minify())
    .pipe(rename({extname: '.min.css'}))
    .pipe(sourcemaps.write('maps'))
    .pipe(gulp.dest(CSS_DIR));
});

gulp.task('build-client-views', function () {
  gulp.src(VIEW_SRC)
    .pipe(jade())
    .pipe(gulp.dest(VIEW_DIR));
  gulp.src(['./public/app/directives/**/*.jade'])
    .pipe(jade())
    .pipe(gulp.dest(DIRECTIVES_DIR));
});

gulp.task('watch', function () {
  gulp.start('watch-client');
  gulp.start('watch-server');
});

gulp.task('watch-client', function () {
  gulp.watch(JS_SRC, ['build-client-js']);
  gulp.watch(STYLUS_SRC, ['build-client-css']);
  gulp.watch(VIEW_SRC, ['build-client-views']);
});

gulp.task('watch-server', function () {
  nodemon({
    script: 'server.js',
    watch: './server'
  });
});

gulp.task('lint', function () {
  gulp.src(TO_LINT_SRC)
    .pipe(jshint())
    .pipe(jscs())
    .on('error', noop)
    .pipe(stylish.combineWithHintResults()) // combine with jshint results
    .pipe(jshint.reporter('jshint-stylish'));
});
<commit_msg>Fix style<commit_after>var gulp = require('gulp');
var clean = require('gulp-clean');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var minify = require('gulp-minify-css');
var autoprefixer = require('gulp-autoprefixer');
var rename = require('gulp-rename');
var sourcemaps = require('gulp-sourcemaps');
var stylus = require('gulp-stylus');
var jade = require('gulp-jade');
var nodemon = require('gulp-nodemon');
var jshint = require('gulp-jshint');
var jscs = require('gulp-jscs');
var noop = function() {};
var stylish = require('gulp-jscs-stylish');

var DIST_DIR = './public/dist';
var JS_DIR = DIST_DIR + '/js';
var CSS_DIR = DIST_DIR + '/css';
var VIEW_DIR = DIST_DIR + '/views';
var DIRECTIVES_DIR = DIST_DIR + '/directives-views';
var COMPILED_STYLUS_DIR = './public/css/';

var JS_SRC = ['./public/vendors/jquery/dist/jquery.min.js',
              './public/vendors/bootstrap/dist/js/bootstrap.min.js',
              './public/vendors/toastr/toastr.min.js',
              './public/vendors/angular/angular.js',
              './public/vendors/angular-resource/angular-resource.js',
              './public/vendors/angular-animate/angular-animate.js',
              './public/vendors/angular-route/angular-route.js',
              './public/vendors/angular-translate/angular-translate.min.js',
              './public/vendors/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js',
              './public/vendors/angular-local-storage/dist/angular-local-storage.min.js',
              './public/vendors/angular-ui-select/dist/select.js',
              './public/vendors/odometer/odometer.js',
              './public/vendors/angular-odometer-js/dist/angular-odometer.js',
              './public/vendors/Chart.js/Chart.min.js',
              './public/vendors/angular-chart.js/dist/angular-chart.min.js',
              './public/vendors/ngDialog/js/ngDialog.min.js',
              './public/vendors/angular-utils-pagination/dirPagination.js',
              './public/vendors/angular-hotkeys/build/hotkeys.min.js',
              './public/app/app.js',
              './public/app/config/**/*.js',
              './public/app/filters/**/*.js',
              './public/app/directives/**/*.js',
              './public/app/ui/**/*.js',
              './public/app/questions/**/*.js',
              './public/app/users/**/*.js',
              './public/app/admin/**/*.js'
              ];

var CSS_SRC = ['./public/css/socicon.css',
                './public/vendors/ngDialog/css/ngDialog.min.css',
                './public/vendors/ngDialog/css/ngDialog-theme-default.min.css',
                './public/vendors/angular-ui-select/dist/select.css',
                './public/vendors/odometer/themes/odometer-theme-minimal.css',
                './public/vendors/toastr/toastr.css',
                './public/vendors/angular-chart.js/dist/angular-chart.css',
                './public/vendors/angular-hotkeys/build/angular-hotkeys.min.css',
                './public/css/site.css',
                './public/css/mobile.css'];

var VIEW_SRC = ['./public/app/**/*.jade'];

// yvar DIRECTIVE_SRC = ['./public/app/directives/**/*.jade'];

var STYLUS_SRC = ['./public/css/*.styl'];

var TO_LINT_SRC = ['./public/app/**/*.js',
                   './server.js',
                   './server/**/*.js',
                  '!./public/**/bootstrap-tagsinput.js'];

gulp.task('default', function () {
  gulp.start('build');
});

gulp.task('build', function () {
  gulp.start('build-client');
});

gulp.task('clean-client-dist', function () {
  return gulp.src(DIST_DIR)
    .pipe(clean());
});

gulp.task('build-client', ['clean-client-dist'], function () {
  gulp.start('build-client-js');
  gulp.start('build-client-css');
  gulp.start('build-client-views');
});

gulp.task('build-client-js', function () {
  gulp.src(JS_SRC)
    .pipe(sourcemaps.init())
    .pipe(concat('dilemme.js'))
    .pipe(gulp.dest(JS_DIR))
    .pipe(uglify({mangle: false}))
    .pipe(rename({extname: '.min.js'}))
    .pipe(sourcemaps.write('maps'))
    .pipe(gulp.dest(JS_DIR));
});

gulp.task('build-client-stylus', function () {
  return gulp.src(STYLUS_SRC)
    .pipe(stylus())
    .pipe(gulp.dest(COMPILED_STYLUS_DIR));
});

gulp.task('build-client-css', ['build-client-stylus'], function () {
  gulp.src(CSS_SRC)
    .pipe(sourcemaps.init())
    .pipe(autoprefixer())
    .pipe(concat('dilemme.css'))
    .pipe(gulp.dest(CSS_DIR))
    .pipe(minify())
    .pipe(rename({extname: '.min.css'}))
    .pipe(sourcemaps.write('maps'))
    .pipe(gulp.dest(CSS_DIR));
});

gulp.task('build-client-views', function () {
  gulp.src(VIEW_SRC)
    .pipe(jade())
    .pipe(gulp.dest(VIEW_DIR));
  gulp.src(['./public/app/directives/**/*.jade'])
    .pipe(jade())
    .pipe(gulp.dest(DIRECTIVES_DIR));
});

gulp.task('watch', function () {
  gulp.start('watch-client');
  gulp.start('watch-server');
});

gulp.task('watch-client', function () {
  gulp.watch(JS_SRC, ['build-client-js']);
  gulp.watch(STYLUS_SRC, ['build-client-css']);
  gulp.watch(VIEW_SRC, ['build-client-views']);
});

gulp.task('watch-server', function () {
  nodemon({
    script: 'server.js',
    watch: './server'
  });
});

gulp.task('lint', function () {
  gulp.src(TO_LINT_SRC)
    .pipe(jshint())
    .pipe(jscs())
    .on('error', noop)
    .pipe(stylish.combineWithHintResults()) // combine with jshint results
    .pipe(jshint.reporter('jshint-stylish'));
});
<|endoftext|>


<commit_before>var gulp = require('gulp');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');
var nodemon = require('gulp-nodemon');
var watch = require('gulp-watch');
var rename = require('gulp-rename');
var karma = require('gulp-karma');
var mocha = require('gulp-mocha');

var publicDir = 'public/**/*.js';

//Backbone requires specific order for its dependencies
gulp.task('scripts', function(){
  return gulp.src(['./bower_components/jquery/dist/jquery.js',
                   './bower_components/underscore/underscore.js',
                   './bower_components/backbone/backbone.js',
                   './node_modules/socket.io-client/socket.io.js',
                   './public/client/**/*.js',
                   './public/client/app.js'])
          .pipe(concat('scripts.js'))
          .pipe(rename('scripts.min.js'))
          .pipe(uglify())
          .pipe(gulp.dest('./public/dist/'));
});

gulp.task('watch-public', function(){
  gulp.watch([publicDir, '!public/dist/*.js'], ['scripts']);
});

gulp.task('develop', function(){
  gulp.start('scripts');
  nodemon({
    script: './server.js',
    env: { 'NODE_ENV': 'development' },
    ignore: ['public/dist/']
  })
  //have nodemon run watch on start
  .on('start', ['watch-public']);
});

gulp.task('default', ['develop']);

gulp.task('test-server', function(){
  return gulp.src(['./test/server/server.js','./test/server/integration.js' ], {read: false})
    .pipe(mocha({reporter: 'nyan'}));
});

var testFiles = ['./test/client/unit.js',
  './test/client/integration.js'];

gulp.task('test-client', function() {

  return gulp.src(testFiles)
    .pipe(karma({
      configFile: 'karma.conf.js',
      reporters: ['progress', 'coverage'],
      action: 'run'
    }))
    .on('error', function(err) {
      throw err;
    });
});<commit_msg>Create an unminified and minified version of the scripts<commit_after>var gulp = require('gulp');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');
var nodemon = require('gulp-nodemon');
var watch = require('gulp-watch');
var rename = require('gulp-rename');
var karma = require('gulp-karma');
var mocha = require('gulp-mocha');

var publicDir = 'public/**/*.js';

//Backbone requires specific order for its dependencies
gulp.task('scripts', function(){
  return gulp.src(['./bower_components/jquery/dist/jquery.js',
                   './bower_components/underscore/underscore.js',
                   './bower_components/backbone/backbone.js',
                   './node_modules/socket.io-client/socket.io.js',
                   './public/client/**/*.js',
                   './public/client/app.js'])
          .pipe(concat('scripts.js'))
          .pipe(gulp.dest('./public/dist/'))
          .pipe(rename('scripts.min.js'))
          .pipe(uglify())
          .pipe(gulp.dest('./public/dist/'));
});

gulp.task('watch-public', function(){
  gulp.watch([publicDir, '!public/dist/*.js'], ['scripts']);
});

gulp.task('develop', function(){
  gulp.start('scripts');
  nodemon({
    script: './server.js',
    env: { 'NODE_ENV': 'development' },
    ignore: ['public/dist/']
  })
  //have nodemon run watch on start
  .on('start', ['watch-public']);
});

gulp.task('default', ['develop']);

gulp.task('test-server', function(){
  return gulp.src(['./test/server/server.js','./test/server/integration.js' ], {read: false})
    .pipe(mocha({reporter: 'nyan'}));
});

var testFiles = ['./test/client/unit.js',
  './test/client/integration.js'];

gulp.task('test-client', function() {

  return gulp.src(testFiles)
    .pipe(karma({
      configFile: 'karma.conf.js',
      reporters: ['progress', 'coverage'],
      action: 'run'
    }))
    .on('error', function(err) {
      throw err;
    });
});
<|endoftext|>


<commit_before>// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// @ts-nocheck
// TODO(crbug.com/1011811): Enable TypeScript compiler checks

import * as UI from '../ui/ui.js';

export class CSSOverviewSidebarPanel extends UI.Widget.VBox {
  static get ITEM_CLASS_NAME() {
    return 'overview-sidebar-panel-item';
  }

  static get SELECTED() {
    return 'selected';
  }

  constructor() {
    super(true);

    this.registerRequiredCSS('css_overview/cssOverviewSidebarPanel.css');
    this.contentElement.classList.add('overview-sidebar-panel');
    this.contentElement.addEventListener('click', this._onItemClick.bind(this));

    // Clear overview.
    const clearResultsButton = new UI.Toolbar.ToolbarButton(ls`Clear overview`, 'largeicon-clear');
    clearResultsButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, this._reset, this);

    // Toolbar.
    const toolbarElement = this.contentElement.createChild('div', 'overview-toolbar');
    const toolbar = new UI.Toolbar.Toolbar('', toolbarElement);
    toolbar.appendToolbarItem(clearResultsButton);
  }

  addItem(name, id) {
    const item = this.contentElement.createChild('div', CSSOverviewSidebarPanel.ITEM_CLASS_NAME);
    item.textContent = name;
    item.dataset.id = id;
  }

  _reset() {
    this.dispatchEventToListeners(SidebarEvents.Reset);
  }

  _deselectAllItems() {
    const items = this.contentElement.querySelectorAll(`.${CSSOverviewSidebarPanel.ITEM_CLASS_NAME}`);
    for (const item of items) {
      item.classList.remove(CSSOverviewSidebarPanel.SELECTED);
    }
  }

  _onItemClick(event) {
    const target = event.path[0];
    if (!target.classList.contains(CSSOverviewSidebarPanel.ITEM_CLASS_NAME)) {
      return;
    }

    const {id} = target.dataset;
    this.select(id);
    this.dispatchEventToListeners(SidebarEvents.ItemSelected, id);
  }

  select(id) {
    const target = this.contentElement.querySelector(`[data-id=${CSS.escape(id)}]`);
    if (!target) {
      return;
    }

    if (target.classList.contains(CSSOverviewSidebarPanel.SELECTED)) {
      return;
    }

    this._deselectAllItems();
    target.classList.add(CSSOverviewSidebarPanel.SELECTED);
  }
}

export const SidebarEvents = {
  ItemSelected: Symbol('ItemSelected'),
  Reset: Symbol('Reset')
};
<commit_msg>[ts] Typecheck css_overview/CSSOverviewSidebarPanel.js with TypeScript<commit_after>// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as UI from '../ui/ui.js';

export class CSSOverviewSidebarPanel extends UI.Widget.VBox {
  static get ITEM_CLASS_NAME() {
    return 'overview-sidebar-panel-item';
  }

  static get SELECTED() {
    return 'selected';
  }

  constructor() {
    super(true);

    this.registerRequiredCSS('css_overview/cssOverviewSidebarPanel.css');
    this.contentElement.classList.add('overview-sidebar-panel');
    this.contentElement.addEventListener('click', this._onItemClick.bind(this));

    // Clear overview.
    const clearResultsButton = new UI.Toolbar.ToolbarButton(ls`Clear overview`, 'largeicon-clear');
    clearResultsButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, this._reset, this);

    // Toolbar.
    const toolbarElement = this.contentElement.createChild('div', 'overview-toolbar');
    const toolbar = new UI.Toolbar.Toolbar('', toolbarElement);
    toolbar.appendToolbarItem(clearResultsButton);
  }

  /**
   * @param {string} name
   * @param {string} id
   */
  addItem(name, id) {
    const item = this.contentElement.createChild('div', CSSOverviewSidebarPanel.ITEM_CLASS_NAME);
    item.textContent = name;
    item.dataset.id = id;
  }

  _reset() {
    this.dispatchEventToListeners(SidebarEvents.Reset);
  }

  _deselectAllItems() {
    const items = this.contentElement.querySelectorAll(`.${CSSOverviewSidebarPanel.ITEM_CLASS_NAME}`);
    items.forEach(item => {
      item.classList.remove(CSSOverviewSidebarPanel.SELECTED);
    });
  }

  /** @param {!Event} event */
  _onItemClick(event) {
    const target = /** @type {!HTMLElement} */ (event.composedPath()[0]);
    if (!target.classList.contains(CSSOverviewSidebarPanel.ITEM_CLASS_NAME)) {
      return;
    }

    const {id} = target.dataset;
    if (!id) {
      return;
    }
    this.select(id);
    this.dispatchEventToListeners(SidebarEvents.ItemSelected, id);
  }

  /**
   * @param {string} id
   */
  select(id) {
    const target = this.contentElement.querySelector(`[data-id=${CSS.escape(id)}]`);
    if (!target) {
      return;
    }

    if (target.classList.contains(CSSOverviewSidebarPanel.SELECTED)) {
      return;
    }

    this._deselectAllItems();
    target.classList.add(CSSOverviewSidebarPanel.SELECTED);
  }
}

export const SidebarEvents = {
  ItemSelected: Symbol('ItemSelected'),
  Reset: Symbol('Reset')
};
<|endoftext|>


<commit_before>var browserify = require("browserify");
var browserSync = require('browser-sync').create();
var buffer = require("vinyl-buffer");
var cleanCSS = require('gulp-clean-css');
var del = require("del");
var gulp = require("gulp");
var htmlhint = require("gulp-htmlhint");
var htmlmin = require('gulp-htmlmin');
var sass = require("gulp-sass");
var sassLint = require("gulp-sass-lint");
var source = require("vinyl-source-stream");
var sourcemaps = require("gulp-sourcemaps");
var tsify = require("tsify");
var tslint = require("gulp-tslint");
var uglify = require("gulp-uglify");
var util = require("gulp-util");

var paths = {
    sources: {
        application: "application/**/*",
        html: ["src/*.html"],
        scss: ["src/scss/**/*"],
        typeScript: "src/typescript/**/*"
    },
    entrypoints: {
        scss: "src/scss/application.scss",
        typeScript: "src/typescript/application.ts"
    },
    destinations: {
        application: "application"
    }
};

var isProductionBuild = !!util.env.isProductionBuild;

gulp.task("build", gulp.series(
    cleanBuild,
    gulp.parallel(lintHtml, lintScss, lintTypeScript),
    gulp.parallel(buildHtml, buildCss, buildJavaScript)
));
gulp.task("test", gulp.series("build"));
gulp.task("default", gulp.series("build", watch));

function cleanBuild() {
    util.log("isProductionBuild: " + isProductionBuild);
    return del([paths.destinations.application]);
}

function buildHtml() {
    return gulp.src(paths.sources.html)
        .pipe(isProductionBuild ? htmlmin({collapseWhitespace: true}) : util.noop())
        .pipe(gulp.dest(paths.destinations.application));
}

function lintScss() {
    return gulp.src(paths.entrypoints.scss)
        .pipe(sassLint())
        .pipe(sassLint.format())
        .pipe(sassLint.failOnError());
}

function buildCss() {
    return gulp.src(paths.entrypoints.scss)
        .pipe(isProductionBuild ? util.noop() : sourcemaps.init())
        .pipe(sass().on("error", sass.logError))
        .pipe(isProductionBuild ? cleanCSS() : util.noop())
        .pipe(isProductionBuild ? util.noop() : sourcemaps.write("./"))
        .pipe(gulp.dest(paths.destinations.application));
}

function lintHtml() {
    return gulp.src(paths.sources.html)
        .pipe(htmlhint())
        .pipe(htmlhint.failReporter());
}

function lintTypeScript() {
    return gulp.src(paths.sources.typeScript)
        .pipe(tslint())
        .pipe(tslint.report());
}

function buildJavaScript() {
    return browserify()
        .add(paths.entrypoints.typeScript)
        .plugin(tsify)
        .bundle()
        .on("error", function (error) {
            console.error(error.toString());
        })
        .pipe(source("application.js"))
        .pipe(buffer())
        .pipe(isProductionBuild ? util.noop() : sourcemaps.init({loadMaps: true}))
        .pipe(isProductionBuild ? uglify() : util.noop())
        .pipe(isProductionBuild ? util.noop() : sourcemaps.write("./"))
        .pipe(gulp.dest(paths.destinations.application));
}

function reload(done) {
    browserSync.reload();
    done();
}

function watch() {
    browserSync.init({
        server: "./application"
    });

    gulp.watch(paths.sources.html, gulp.series(lintHtml, buildHtml, reload));
    gulp.watch(paths.sources.scss, gulp.series(lintScss, buildCss, reload));
    gulp.watch(paths.sources.typeScript, gulp.series(lintTypeScript, buildJavaScript, reload));
}
<commit_msg>Watch continues even on errors (closes #11)<commit_after>var browserify = require("browserify");
var browserSync = require('browser-sync').create();
var buffer = require("vinyl-buffer");
var cleanCSS = require('gulp-clean-css');
var del = require("del");
var gulp = require("gulp");
var htmlhint = require("gulp-htmlhint");
var htmlmin = require('gulp-htmlmin');
var sass = require("gulp-sass");
var sassLint = require("gulp-sass-lint");
var source = require("vinyl-source-stream");
var sourcemaps = require("gulp-sourcemaps");
var tsify = require("tsify");
var tslint = require("gulp-tslint");
var uglify = require("gulp-uglify");
var util = require("gulp-util");

var paths = {
    sources: {
        application: "application/**/*",
        html: ["src/*.html"],
        scss: ["src/scss/**/*"],
        typeScript: "src/typescript/**/*"
    },
    entrypoints: {
        scss: "src/scss/application.scss",
        typeScript: "src/typescript/application.ts"
    },
    destinations: {
        application: "application"
    }
};

var isProductionBuild = !!util.env.isProductionBuild;

gulp.task("build", gulp.series(
    cleanBuild,
    gulp.parallel(lintHtml, lintScss, lintTypeScript),
    gulp.parallel(buildHtml, buildCss, buildJavaScript)
));
gulp.task("test", gulp.series("build"));
gulp.task("default", gulp.series("build", watch));

function cleanBuild() {
    util.log("isProductionBuild: " + isProductionBuild);
    return del([paths.destinations.application]);
}

function buildHtml() {
    return gulp.src(paths.sources.html)
        .pipe(isProductionBuild ? htmlmin({collapseWhitespace: true}) : util.noop())
        .pipe(gulp.dest(paths.destinations.application));
}

function lintScss() {
    return gulp.src(paths.entrypoints.scss)
        .pipe(sassLint())
        .pipe(sassLint.format())
        .pipe(sassLint.failOnError());
}

function buildCss() {
    return gulp.src(paths.entrypoints.scss)
        .pipe(isProductionBuild ? util.noop() : sourcemaps.init())
        .pipe(sass().on("error", sass.logError))
        .pipe(isProductionBuild ? cleanCSS() : util.noop())
        .pipe(isProductionBuild ? util.noop() : sourcemaps.write("./"))
        .pipe(gulp.dest(paths.destinations.application));
}

function lintHtml() {
    return gulp.src(paths.sources.html)
        .pipe(htmlhint())
        .pipe(htmlhint.failReporter());
}

function lintTypeScript() {
    return gulp.src(paths.sources.typeScript)
        .pipe(tslint())
        .pipe(tslint.report({
            emitError: isProductionBuild
        }));
}

function buildJavaScript(done) {
    return browserify()
        .add(paths.entrypoints.typeScript)
        .plugin(tsify)
        .bundle()
        .on("error", function(error) {
            util.log(error);

            if (!isProductionBuild){
                done();
            }
        })
        .pipe(source("application.js"))
        .pipe(buffer())
        .pipe(isProductionBuild ? util.noop() : sourcemaps.init({loadMaps: true}))
        .pipe(isProductionBuild ? uglify() : util.noop())
        .pipe(isProductionBuild ? util.noop() : sourcemaps.write("./"))
        .pipe(gulp.dest(paths.destinations.application));
}

function reload(done) {
    browserSync.reload();
    done();
}

function watch() {
    browserSync.init({
        server: "./application"
    });

    gulp.watch(paths.sources.html, gulp.series(lintHtml, buildHtml, reload));
    gulp.watch(paths.sources.scss, gulp.series(lintScss, buildCss, reload));
    gulp.watch(paths.sources.typeScript, gulp.series(lintTypeScript, buildJavaScript, reload));
}
<|endoftext|>


<commit_before>var gulp = require('gulp');
var typescript = require('gulp-tsc');
var jasmine = require('gulp-jasmine-phantom');
var stripDebug = require('gulp-strip-debug');
var del = require('del');
var reporters = require('reporters');

gulp.task('default', ['compile:src'], function () {
});

gulp.task('scripts', function () {
    return gulp;
});

gulp.task('watch', function () {
    return gulp.watch('src/**/*.ts', ['compile:src'])
});

gulp.task('compile:src', function () {
    return gulp.src(['src/**/*.ts'])
        .pipe(typescript({out: 'm3.js', target:'ES5'}))
        .pipe(gulp.dest('bin/debug'))
        .pipe(stripDebug())
        .pipe(gulp.dest('bin/release/'))
});

gulp.task('compile:tests', ['compile:src'], function () {
    return gulp.src(['tests/**/*.ts'])
            .pipe(typescript({out: 'tests.js', target:'ES5'}))
        .pipe(gulp.dest('bin/'))
});

gulp.task('test', ['compile:tests'], function () {
    return gulp
        .src('bin/tests.js')
        .pipe(jasmine({integration: true,reporter: reporters('gulp-jasmine')}))
});

gulp.task('clean', function () {
    return del(['bin/**/*']);
});

<commit_msg>fail a failing test<commit_after>var gulp = require('gulp');
var typescript = require('gulp-tsc');
var jasmine = require('gulp-jasmine-phantom');
var stripDebug = require('gulp-strip-debug');
var del = require('del');
var reporters = require('reporters');

gulp.task('default', ['compile:src'], function () {
});

gulp.task('scripts', function () {
    return gulp;
});

gulp.task('watch', function () {
    return gulp.watch('src/**/*.ts', ['compile:src'])
});

gulp.task('compile:src', function () {
    return gulp.src(['src/**/*.ts'])
        .pipe(typescript({out: 'm3.js', target:'ES5'}))
        .pipe(gulp.dest('bin/debug'))
        .pipe(stripDebug())
        .pipe(gulp.dest('bin/release/'))
});

gulp.task('compile:tests', ['compile:src'], function () {
    return gulp.src(['tests/**/*.ts'])
            .pipe(typescript({out: 'tests.js', target:'ES5'}))
        .pipe(gulp.dest('bin/'))
});

gulp.task('test', ['compile:tests'], function () {
    return gulp
        .src('bin/tests.js')
        .pipe(jasmine({integration: true,abortOnFail:true}))
});

gulp.task('clean', function () {
    return del(['bin/**/*']);
});

<|endoftext|>


<commit_before>
var gulp = require('gulp'),
    connect = require('gulp-connect'),
    protractor = require("gulp-protractor").protractor;

gulp.task('connect', function () {
    connect.server({
        root: ['./', 'test/', 'node_modules/'],
        port: 8888,
        fallback: './test/testfixture.html'
    });
});

gulp.task('test', ['connect'], function(done) {
    var args = ['--baseUrl', 'http://127.0.0.1:8899'];
    gulp.src(["./spec.js"])
        .pipe(protractor({
            configFile: "protractor.conf.js",
            args: args
        }))
        .on('error', function(e) {     connect.serverClose(); throw e; })
        .on('end', function() {     connect.serverClose(); });

});<commit_msg>Run connect on port 8899<commit_after>
var gulp = require('gulp'),
    connect = require('gulp-connect'),
    protractor = require("gulp-protractor").protractor;

gulp.task('connect', function () {
    connect.server({
        root: ['./', 'test/', 'node_modules/'],
        port: 8899,
        fallback: './test/testfixture.html'
    });
});

gulp.task('test', ['connect'], function(done) {
    var args = ['--baseUrl', 'http://127.0.0.1:8899'];
    gulp.src(["./spec.js"])
        .pipe(protractor({
            configFile: "protractor.conf.js",
            args: args
        }))
        .on('error', function(e) {     connect.serverClose(); throw e; })
        .on('end', function() {     connect.serverClose(); });

});<|endoftext|>


<commit_before>'use strict';
const gulp = require('gulp'),
    gulpJsdoc2md = require('gulp-jsdoc-to-markdown'),
    rename = require('gulp-rename'),
    istanbul = require('gulp-istanbul'),
    istanbulHarmony = require('istanbul-harmony'),
    mocha = require('gulp-mocha'),
    eslint = require('gulp-eslint'),
    git = require('gulp-git');

const sockFiles = ['*.js', '!./gulpfile.js', '**/plugins/**/*.js', '!node_modules/**'],
    sockExterns = ['**/external/**/*.js'],
    sockDocs = ['README.md', 'docs/**/*.md'],
    sockTests = ['test/**/*.js'];

const JobNumber = process.env.TRAVIS_JOB_NUMBER,
    runDocs = !JobNumber || /[.]1$/.test(JobNumber);

/**
 * Pull git branch locally (solves detached head issue in CI)
 */
gulp.task('gitBranch', (done) => {
    let complete = false;
    const branch = process.env.TRAVIS_BRANCH;
    // Abort(successfully) early if not running in CI
    if (!(JobNumber && runDocs && branch)) {
        return done();
    }
    git.checkout(branch, () => {
        // Make sure we have full log history.
        git.pull('origin', branch, {}, () => {
            if (!complete) {
                done();
            }
            complete = true;
        });
    });
});

/**
 * Generate API documentation for all js files, place markup in the correct folder for readthedocs.org
 */
gulp.task('docs', ['gitBranch', 'lintExterns'], function (done) {
    // Abort(successfully) early if running in CI and not job #1
    if (!runDocs) {
        return done();
    }
    gulp.src(sockFiles.concat(sockExterns))
        .pipe(gulpJsdoc2md({}))
        .on('error', done)
        .pipe(rename((path) => {
            path.extname = '.md';
        }))
        .pipe(gulp.dest('docs/api'))
        .on('finish', done);
});

/**
 * Run all js files through eslint and report status.
 */
gulp.task('lintCore', (done) => {
    return gulp.src(sockFiles)
        .pipe(eslint())
        .pipe(eslint.format())
        .pipe(eslint.failAfterError());
});
/**
 * Run all js files through eslint and report status.
 */
gulp.task('lintExterns', (done) => {
    return gulp.src(sockExterns)
        .pipe(eslint())
        .pipe(eslint.format())
        .pipe(eslint.failAfterError());
});

/**
 * Run all tests through eslint and report status.
 */
gulp.task('lintTests', (done) => {
    return gulp.src(sockTests)
        .pipe(eslint())
        .pipe(eslint.format())
        .pipe(eslint.failAfterError());
});

/**
 * Set git username/email to CI user
 */
gulp.task('gitConfig', (done) => {
    // Abort(successfully) early if not running in CI
    if (!JobNumber) {
        return done();
    }
    git.exec({
        args: 'config user.name "Travis-CI"'
    }, () => {
        git.exec({
            args: 'config user.email "Travis-CI@servercooties.com"'
        }, () => {
            done();
        });
    });
});

/**
 * Commit generated documentation to be picked up by readthedocs.org
 *
 * Add CI tag to commit to prevent CI jobs from being created by checking in docs
 */
gulp.task('commitDocs', ['gitConfig'], (done) => {
    gulp.src(sockDocs)
        .pipe(git.add())
        .pipe(git.commit('Automatically push updated documentation [ci skip]'))
        .on('error', () => 0)
        .on('finish', done);
});

/**
 * Commit and push docs to github to be picked up by readthedocs.org
 */
gulp.task('pushDocs', ['gitConfig', 'commitDocs'], (done) => {
    //Abort(successfully) early if running in CI and not job #1
    if (!runDocs) {
        return done();
    }
    git.addRemote('github', 'https://github.com/SockDrawer/SockBot.git', (e) => {
        if (e) {
            done();
        } else {
            git.push('github', 'HEAD', {
                args: ['-q']
            }, () => {
                done();
            });
        }
    });
});

/**
 * Run code coverage instrumented tests
 */
gulp.task('test', ['lintCore', 'lintTests'], (done) => {
    gulp.src(sockFiles)
        // Instrument code files with istanbulHarmony
        .pipe(istanbul({
            instrumenter: istanbulHarmony.Instrumenter
        }))
        // hook require function for complete code coverage
        .pipe(istanbul.hookRequire())
        .on('finish', () => {
            // Run all tests
            gulp.src(sockTests)
                .pipe(mocha({
                    reporter: 'dot'
                }))
                .on('error', done)
                // Write code coverage reports
                .pipe(istanbul.writeReports())
                .on('finish', done);
        });
});

// Meta tasks
gulp.task('buildDocs', ['docs'], () => 0);
gulp.task('preBuild', ['buildDocs'], () => 0);
gulp.task('postBuild', ['pushDocs'], () => 0);
gulp.task('default', ['lint'], () => 0);
gulp.task('lint', ['lintCore', 'lintTests', 'lintExterns'], () => 0);<commit_msg>Restrict docgen to JS files changed since the last docgen<commit_after>'use strict';
const gulp = require('gulp'),
    gulpJsdoc2md = require('gulp-jsdoc-to-markdown'),
    rename = require('gulp-rename'),
    istanbul = require('gulp-istanbul'),
    istanbulHarmony = require('istanbul-harmony'),
    mocha = require('gulp-mocha'),
    eslint = require('gulp-eslint'),
    git = require('gulp-git');

const sockFiles = ['*.js', '!./gulpfile.js', '**/plugins/**/*.js', '!node_modules/**'],
    sockExterns = ['**/external/**/*.js'],
    sockDocs = ['README.md', 'docs/**/*.md'],
    sockTests = ['test/**/*.js'];

const JobNumber = process.env.TRAVIS_JOB_NUMBER,
    CommitRange = process.env.TRAVIS_COMMIT_RANGE,
    runDocs = !JobNumber || /[.]1$/.test(JobNumber);

/**
 * Construct the array of file globs for gulpJsdoc2md
 */
function getFilesForDocGen() {
    let files = [];
    if (CommitRange) {
        git.exec({
            args: 'show --pretty="format:" --name-only ' + CommitRange
        }, (err, stdout) => {
            if (err) {
                console.log('Error fetching files in commit range\n' + err);
                return;
            }
            stdout.split(/\r?\n/).foreach((file) => {
                if (file && file.length > 3 && file.endsWith('.js')){
                    files.push('./' + file);
                }
                console.log(file);
            });
        });
    }
    return files.length > 0 ? files : sockFiles.concat(sockExterns);
}

/**
 * Pull git branch locally (solves detached head issue in CI)
 */
gulp.task('gitBranch', (done) => {
    let complete = false;
    const branch = process.env.TRAVIS_BRANCH;
    // Abort(successfully) early if not running in CI
    if (!(JobNumber && runDocs && branch)) {
        return done();
    }
    git.checkout(branch, () => {
        // Make sure we have full log history.
        git.pull('origin', branch, {}, () => {
            if (!complete) {
                done();
            }
            complete = true;
        });
    });
});

/**
 * Generate API documentation for all js files, place markup in the correct folder for readthedocs.org
 */
gulp.task('docs', ['gitBranch', 'lintExterns'], function (done) {
    // Abort(successfully) early if running in CI and not job #1
    if (!runDocs) {
        return done();
    }
    gulp.src(getFilesForDocGen())
        .pipe(gulpJsdoc2md({}))
        .on('error', done)
        .pipe(rename((path) => {
            path.extname = '.md';
        }))
        .pipe(gulp.dest('docs/api'))
        .on('finish', done);
});

/**
 * Run all js files through eslint and report status.
 */
gulp.task('lintCore', (done) => {
    return gulp.src(sockFiles)
        .pipe(eslint())
        .pipe(eslint.format())
        .pipe(eslint.failAfterError());
});
/**
 * Run all js files through eslint and report status.
 */
gulp.task('lintExterns', (done) => {
    return gulp.src(sockExterns)
        .pipe(eslint())
        .pipe(eslint.format())
        .pipe(eslint.failAfterError());
});

/**
 * Run all tests through eslint and report status.
 */
gulp.task('lintTests', (done) => {
    return gulp.src(sockTests)
        .pipe(eslint())
        .pipe(eslint.format())
        .pipe(eslint.failAfterError());
});

/**
 * Set git username/email to CI user
 */
gulp.task('gitConfig', (done) => {
    // Abort(successfully) early if not running in CI
    if (!JobNumber) {
        return done();
    }
    git.exec({
        args: 'config user.name "Travis-CI"'
    }, () => {
        git.exec({
            args: 'config user.email "Travis-CI@servercooties.com"'
        }, () => {
            done();
        });
    });
});

/**
 * Commit generated documentation to be picked up by readthedocs.org
 *
 * Add CI tag to commit to prevent CI jobs from being created by checking in docs
 */
gulp.task('commitDocs', ['gitConfig'], (done) => {
    gulp.src(sockDocs)
        .pipe(git.add())
        .pipe(git.commit('Automatically push updated documentation [ci skip]'))
        .on('error', () => 0)
        .on('finish', done);
});

/**
 * Commit and push docs to github to be picked up by readthedocs.org
 */
gulp.task('pushDocs', ['gitConfig', 'commitDocs'], (done) => {
    //Abort(successfully) early if running in CI and not job #1
    if (!runDocs) {
        return done();
    }
    git.addRemote('github', 'https://github.com/SockDrawer/SockBot.git', (e) => {
        if (e) {
            done();
        } else {
            git.push('github', 'HEAD', {
                args: ['-q']
            }, () => {
                done();
            });
        }
    });
});

/**
 * Run code coverage instrumented tests
 */
gulp.task('test', ['lintCore', 'lintTests'], (done) => {
    gulp.src(sockFiles)
        // Instrument code files with istanbulHarmony
        .pipe(istanbul({
            instrumenter: istanbulHarmony.Instrumenter
        }))
        // hook require function for complete code coverage
        .pipe(istanbul.hookRequire())
        .on('finish', () => {
            // Run all tests
            gulp.src(sockTests)
                .pipe(mocha({
                    reporter: 'dot'
                }))
                .on('error', done)
                // Write code coverage reports
                .pipe(istanbul.writeReports())
                .on('finish', done);
        });
});

// Meta tasks
gulp.task('buildDocs', ['docs'], () => 0);
gulp.task('preBuild', ['buildDocs'], () => 0);
gulp.task('postBuild', ['pushDocs'], () => 0);
gulp.task('default', ['lint'], () => 0);
gulp.task('lint', ['lintCore', 'lintTests', 'lintExterns'], () => 0);<|endoftext|>


<commit_before>import React, { useEffect, useState } from 'react';
import projectApi from '../../store/project/api';
import PropTypes from 'prop-types';
import {
    TextField,
    CircularProgress,
    Grid,
    Button,
    InputAdornment,
} from '@material-ui/core';
import { Search } from '@material-ui/icons';
import Autocomplete from '@material-ui/lab/Autocomplete';
import { Alert } from '@material-ui/lab';
import ProjectRoleSelect from './ProjectAccess/ProjectRoleSelect/ProjectRoleSelect';

function AddUserComponent({ roles, addUserToRole }) {
    const [user, setUser] = useState();
    const [role, setRole] = useState({});
    const [options, setOptions] = useState([]);
    const [loading, setLoading] = useState(false);
    const [select, setSelect] = useState(false);

    useEffect(() => {
        if (roles.length > 0) {
            const regularRole = roles.find(
                r => r.name.toLowerCase() === 'regular'
            );
            setRole(regularRole || roles[0]);
        }
    }, [roles]);

    const search = async q => {
        if (q.length > 1) {
            setLoading(true);
            // TODO: Do not hard-code fetch here.
            const users = await projectApi.searchProjectUser(q);
            setOptions([...users]);
        } else {
            setOptions([]);
        }
        setLoading(false);
    };

    const handleQueryUpdate = evt => {
        const q = evt.target.value;
        search(q);
        if (options.length === 1) {
            setSelect(true);
            return;
        }
        setSelect(false);
    };

    const handleSelectUser = (evt, value) => {
        setOptions([]);
        setUser(value);
    };

    const handleRoleChange = evt => {
        const roleId = +evt.target.value;
        const role = roles.find(r => r.id === roleId);
        setRole(role);
    };

    const handleSubmit = async evt => {
        evt.preventDefault();
        await addUserToRole(user.id, role.id);
        setUser(undefined);
        setOptions([]);
    };

    return (
        <>
            <Alert severity="info" style={{ marginBottom: '20px' }}>
                The user must have an Unleash root role before added to the
                project.
            </Alert>
            <Grid container spacing={3} alignItems="flex-end">
                <Grid item>
                    <Autocomplete
                        id="add-user-component"
                        style={{ width: 300 }}
                        noOptionsText="No users found."
                        onChange={handleSelectUser}
                        autoSelect={select}
                        value={user || ''}
                        freeSolo
                        getOptionSelected={() => true}
                        filterOptions={o => o}
                        getOptionLabel={option => {
                            if (option) {
                                return `${option.name || '(Empty name)'} <${
                                    option.email || option.username
                                }>`;
                            } else return '';
                        }}
                        options={options}
                        loading={loading}
                        renderInput={params => (
                            <TextField
                                {...params}
                                label="User"
                                variant="outlined"
                                size="small"
                                name="search"
                                onChange={handleQueryUpdate}
                                InputProps={{
                                    ...params.InputProps,
                                    startAdornment: (
                                        <InputAdornment position="start">
                                            <Search />
                                        </InputAdornment>
                                    ),
                                    endAdornment: (
                                        <React.Fragment>
                                            {loading ? (
                                                <CircularProgress
                                                    color="inherit"
                                                    size={20}
                                                />
                                            ) : null}
                                            {params.InputProps.endAdornment}
                                        </React.Fragment>
                                    ),
                                }}
                            />
                        )}
                    />
                </Grid>
                <Grid item>
                    <ProjectRoleSelect
                        labelId="add-user-select-role-label"
                        id="add-user-select-role"
                        placeholder="Project role"
                        value={role.id || ''}
                        onChange={handleRoleChange}
                        roles={roles}
                    />
                </Grid>
                <Grid item>
                    <Button
                        variant="contained"
                        color="primary"
                        disabled={!user}
                        onClick={handleSubmit}
                    >
                        Add user
                    </Button>
                </Grid>
            </Grid>
        </>
    );
}

AddUserComponent.propTypes = {
    roles: PropTypes.array.isRequired,
    addUserToRole: PropTypes.func.isRequired,
};

export default AddUserComponent;
<commit_msg>fix: race condition when adding users<commit_after>import React, { useEffect, useState } from 'react';
import projectApi from '../../store/project/api';
import PropTypes from 'prop-types';
import {
    TextField,
    CircularProgress,
    Grid,
    Button,
    InputAdornment,
} from '@material-ui/core';
import { Search } from '@material-ui/icons';
import Autocomplete from '@material-ui/lab/Autocomplete';
import { Alert } from '@material-ui/lab';
import ProjectRoleSelect from './ProjectAccess/ProjectRoleSelect/ProjectRoleSelect';

function AddUserComponent({ roles, addUserToRole }) {
    const [user, setUser] = useState();
    const [role, setRole] = useState({});
    const [options, setOptions] = useState([]);
    const [loading, setLoading] = useState(false);
    const [select, setSelect] = useState(false);

    useEffect(() => {
        if (roles.length > 0) {
            const regularRole = roles.find(
                r => r.name.toLowerCase() === 'regular'
            );
            setRole(regularRole || roles[0]);
        }
    }, [roles]);

    const search = async q => {
        if (q.length > 1) {
            setLoading(true);
            // TODO: Do not hard-code fetch here.
            const users = await projectApi.searchProjectUser(q);
            setOptions([...users]);
        } else {
            setOptions([]);
        }
        setLoading(false);
    };

    const handleQueryUpdate = evt => {
        const q = evt.target.value;
        search(q);
        if (options.length === 1) {
            setSelect(true);
            return;
        }
        setSelect(false);
    };

    const handleSelectUser = (evt, selectedUser) => {
        setOptions([]);
        if(selectedUser.id) {
            setUser(selectedUser);
        }
    };

    const handleRoleChange = evt => {
        const roleId = +evt.target.value;
        const role = roles.find(r => r.id === roleId);
        setRole(role);
    };

    const handleSubmit = async evt => {
        debugger;
        evt.preventDefault();
        await addUserToRole(user.id, role.id);
        setUser(undefined);
        setOptions([]);
    };

    return (
        <>
            <Alert severity="info" style={{ marginBottom: '20px' }}>
                The user must have an Unleash root role before added to the
                project.
            </Alert>
            <Grid container spacing={3} alignItems="flex-end">
                <Grid item>
                    <Autocomplete
                        id="add-user-component"
                        style={{ width: 300 }}
                        noOptionsText="No users found."
                        onChange={handleSelectUser}
                        autoSelect={select}
                        value={user || ''}
                        freeSolo
                        getOptionSelected={() => true}
                        filterOptions={o => o}
                        getOptionLabel={option => {
                            if (option) {
                                return `${option.name || '(Empty name)'} <${
                                    option.email || option.username
                                }>`;
                            } else return '';
                        }}
                        options={options}
                        loading={loading}
                        renderInput={params => (
                            <TextField
                                {...params}
                                label="User"
                                variant="outlined"
                                size="small"
                                name="search"
                                onChange={handleQueryUpdate}
                                InputProps={{
                                    ...params.InputProps,
                                    startAdornment: (
                                        <InputAdornment position="start">
                                            <Search />
                                        </InputAdornment>
                                    ),
                                    endAdornment: (
                                        <React.Fragment>
                                            {loading ? (
                                                <CircularProgress
                                                    color="inherit"
                                                    size={20}
                                                />
                                            ) : null}
                                            {params.InputProps.endAdornment}
                                        </React.Fragment>
                                    ),
                                }}
                            />
                        )}
                    />
                </Grid>
                <Grid item>
                    <ProjectRoleSelect
                        labelId="add-user-select-role-label"
                        id="add-user-select-role"
                        placeholder="Project role"
                        value={role.id || ''}
                        onChange={handleRoleChange}
                        roles={roles}
                    />
                </Grid>
                <Grid item>
                    <Button
                        variant="contained"
                        color="primary"
                        disabled={!user}
                        onClick={handleSubmit}
                    >
                        Add user
                    </Button>
                </Grid>
            </Grid>
        </>
    );
}

AddUserComponent.propTypes = {
    roles: PropTypes.array.isRequired,
    addUserToRole: PropTypes.func.isRequired,
};

export default AddUserComponent;
<|endoftext|>


<commit_before>test('It is hello world!', () => {
  expect('hello world!').toBe('hello world!');
});

test('It is failing', () => {
  expect('hello world!').toBe('not hello world!');
});<commit_msg>test(frontend): remove failing test<commit_after>test('It is hello world!', () => {
  expect('hello world!').toBe('hello world!');
});
<|endoftext|>


<commit_before>/* eslint-disable react/no-multi-comp */

import React from 'react'
import { compose } from 'redux'
import PropTypes from 'prop-types'
import { asField } from 'informed'
import styled, { withTheme } from 'styled-components'
import { styles } from 'styled-system'
import system from '@rebass/components'
import { Flex } from 'rebass'
import Search from 'components/Icon/Search'
import { withInputValidation } from 'hocs'
import Message from './Message'
import Label from './Label'
import Span from './Span'
import Text from './Text'
import Tooltip from './Tooltip'

function isFieldValid({ value, error, touched }) {
  return value && !error && touched
}

function mapDefaultBorderColor(props) {
  const {
    isDisabled,
    isReadOnly,
    fieldState,
    fieldState: { error, asyncError },
    theme: {
      colors: { gray, superGreen, superRed },
    },
  } = props
  let borderColor = gray

  if (!props.highlightOnValid) {
    return borderColor
  }

  if (isReadOnly || isDisabled) {
    borderColor = gray
  } else if (error || asyncError) {
    borderColor = superRed
  } else if (isFieldValid(fieldState)) {
    borderColor = superGreen
  }
  return borderColor
}

function mapFocusBorderColor(props) {
  const {
    fieldState,
    theme: {
      colors: { lightningOrange, superGreen },
    },
  } = props

  if (!props.highlightOnValid) {
    return lightningOrange
  }

  return fieldState.touched && isFieldValid(fieldState) ? superGreen : lightningOrange
}

const SearchIcon = styled(Search)`
  margin-right: -${props => props.width}px;
  width: ${props => props.width}px;
  height: 15px;
  color: ${props => props.color || props.theme.colors.gray};
`

// Create an html input element that accepts all style props from styled-system.
const SystemInput = styled(
  system(
    {
      as: 'input',
      border: 1,
      borderColor: 'gray',
      borderRadius: 5,
      bg: 'transparent',
      color: 'primaryText',
      fontFamily: 'sans',
      fontSize: 'm',
      fontWeight: 'light',
      p: 3,
      width: 1,
    },
    'space',
    'color',
    'borders',
    'borderColor',
    'borderRadius',
    'fontFamily',
    'textAlign',
    'fontSize',
    'fontWeight',
    'width'
  )
)`
  opacity: ${props => (props.isDisabled || props.isReadOnly ? '0.6' : 'inherit')};
  outline: none;
  border-color: ${mapDefaultBorderColor};
  &:not([readOnly]):not([disabled]):focus {
    border-color: ${mapFocusBorderColor};
  }
  ::-webkit-search-decoration:hover,
  ::-webkit-search-cancel-button:hover {
    cursor: pointer;
  }
`

/**
 * @render react
 * @name Input
 * @example
 * <Input />
 */
class Input extends React.Component {
  static displayName = 'Input'

  static propTypes = {
    children: PropTypes.node,
    className: PropTypes.string,
    description: PropTypes.node,
    field: PropTypes.string.isRequired,
    fieldApi: PropTypes.object.isRequired,
    fieldState: PropTypes.object.isRequired,
    forwardedRef: PropTypes.object,
    hasMessage: PropTypes.bool,
    highlightOnValid: PropTypes.bool,
    iconSize: PropTypes.number,
    initialValue: PropTypes.string,
    isDisabled: PropTypes.bool,
    isReadOnly: PropTypes.bool,
    isRequired: PropTypes.bool,
    justifyContent: PropTypes.string,
    label: PropTypes.node,
    maxLength: PropTypes.number,
    minLength: PropTypes.number,
    onBlur: PropTypes.func,
    onChange: PropTypes.func,
    onFocus: PropTypes.func,
    theme: PropTypes.object.isRequired,
    tooltip: PropTypes.string,
    type: PropTypes.string,
    variant: PropTypes.string,
    willAutoFocus: PropTypes.bool,
  }

  static defaultProps = {
    isRequired: false,
    isReadOnly: false,
    isDisabled: false,
    hasMessage: true,
    willAutoFocus: false,
    highlightOnValid: true,
    iconSize: 46,
    tooltip: null,
    initialValue: '',
  }

  state = {
    hasFocus: false,
  }

  constructor(props) {
    super(props)
    const { forwardedRef } = this.props
    this.inputRef = forwardedRef || React.createRef()
  }

  componentDidMount() {
    const { willAutoFocus } = this.props
    if (willAutoFocus) {
      this.inputRef.current.focus()
    }
  }

  render() {
    const {
      description,
      onChange,
      onBlur,
      onFocus,
      forwardedRef,
      label,
      isDisabled,
      isReadOnly,
      isRequired,
      maxLength,
      minLength,
      theme,
      type,
      field,
      fieldApi,
      fieldState,
      iconSize,
      justifyContent,
      hasMessage,
      variant,
      className,
      tooltip,
      children,
      initialValue,
      ...rest
    } = this.props
    const { hasFocus } = this.state
    const { setValue, setTouched } = fieldApi
    const { value } = fieldState

    // Extract any styled-system space props so that we can apply them directly to the wrapper.
    const spaceProps = {}
    Object.keys(rest).forEach(key => {
      /*eslint-disable react/forbid-foreign-prop-types*/
      if ([...Object.keys(styles.space.propTypes), 'width'].includes(key)) {
        spaceProps[key] = rest[key]
        delete rest[key]
      }
    })

    const getValue = () => {
      if (typeof value === 'undefined') {
        return initialValue
      }
      const { fieldState } = this.props
      const { maskedValue } = fieldState
      return !maskedValue && maskedValue !== 0 ? '' : maskedValue
    }

    return (
      <Flex
        flexDirection="column"
        justifyContent={justifyContent}
        {...spaceProps}
        className={className}
      >
        {label && (
          <Flex mb={2}>
            <Label htmlFor={field}>
              {label}
              {isRequired && (
                <Span
                  css={`
                    vertical-align: top;
                  `}
                  fontSize="s"
                >
                  {' '}
                  *
                </Span>
              )}
            </Label>
            {tooltip && <Tooltip ml={1}>{tooltip}</Tooltip>}
          </Flex>
        )}

        <Flex alignItems="center">
          {type === 'search' && <SearchIcon width={iconSize} />}
          <SystemInput
            p={variant === 'thin' ? 2 : 3}
            {...rest}
            ref={this.inputRef}
            disabled={isDisabled}
            field={field}
            fieldState={fieldState}
            maxLength={maxLength}
            minLength={minLength}
            onBlur={e => {
              // set touched to true to enforce validity highlight
              setTouched(true)
              // Make the state aware that the element is no longer focused.
              this.setState({ hasFocus: false })
              if (onBlur) {
                onBlur(e)
              }
            }}
            onChange={e => {
              setValue(e.target.value)
              if (onChange) {
                onChange(e)
              }
            }}
            onFocus={e => {
              // Make the state aware that the element is now focused.
              this.setState({ hasFocus: true })
              if (onFocus) {
                onFocus(e)
              }
            }}
            pl={type === 'search' ? 35 : null}
            readOnly={isReadOnly}
            theme={theme}
            type={type}
            value={getValue()}
          />
          {children}
        </Flex>

        {type !== 'hidden' && description && (
          <Text color="gray" fontSize="s" mt={1}>
            {description}
          </Text>
        )}
        {type !== 'hidden' && hasMessage && fieldState.error && (
          <Message mt={1} variant={hasFocus ? 'warning' : 'error'}>
            {fieldState.error}
          </Message>
        )}
      </Flex>
    )
  }
}

const BasicInput = withTheme(Input)

export { BasicInput }

export default compose(
  withInputValidation,
  asField
)(BasicInput)
<commit_msg>fix(ui): always highlight inputs with an error<commit_after>/* eslint-disable react/no-multi-comp */

import React from 'react'
import { compose } from 'redux'
import PropTypes from 'prop-types'
import { asField } from 'informed'
import styled, { withTheme } from 'styled-components'
import { styles } from 'styled-system'
import system from '@rebass/components'
import { Flex } from 'rebass'
import Search from 'components/Icon/Search'
import { withInputValidation } from 'hocs'
import Message from './Message'
import Label from './Label'
import Span from './Span'
import Text from './Text'
import Tooltip from './Tooltip'

function isFieldValid({ value, error, touched }) {
  return value && !error && touched
}

function mapDefaultBorderColor(props) {
  const {
    isDisabled,
    isReadOnly,
    fieldState,
    fieldState: { error, asyncError },
    theme: {
      colors: { gray, superGreen, superRed },
    },
  } = props
  let borderColor = gray

  if (isFieldValid(fieldState) && !props.highlightOnValid) {
    return borderColor
  }

  if (isReadOnly || isDisabled) {
    borderColor = gray
  } else if (error || asyncError) {
    borderColor = superRed
  } else if (isFieldValid(fieldState)) {
    borderColor = superGreen
  }
  return borderColor
}

function mapFocusBorderColor(props) {
  const {
    fieldState,
    theme: {
      colors: { lightningOrange, superGreen },
    },
  } = props

  if (!props.highlightOnValid) {
    return lightningOrange
  }

  return fieldState.touched && isFieldValid(fieldState) ? superGreen : lightningOrange
}

const SearchIcon = styled(Search)`
  margin-right: -${props => props.width}px;
  width: ${props => props.width}px;
  height: 15px;
  color: ${props => props.color || props.theme.colors.gray};
`

// Create an html input element that accepts all style props from styled-system.
const SystemInput = styled(
  system(
    {
      as: 'input',
      border: 1,
      borderColor: 'gray',
      borderRadius: 5,
      bg: 'transparent',
      color: 'primaryText',
      fontFamily: 'sans',
      fontSize: 'm',
      fontWeight: 'light',
      p: 3,
      width: 1,
    },
    'space',
    'color',
    'borders',
    'borderColor',
    'borderRadius',
    'fontFamily',
    'textAlign',
    'fontSize',
    'fontWeight',
    'width'
  )
)`
  opacity: ${props => (props.isDisabled || props.isReadOnly ? '0.6' : 'inherit')};
  outline: none;
  border-color: ${mapDefaultBorderColor};
  &:not([readOnly]):not([disabled]):focus {
    border-color: ${mapFocusBorderColor};
  }
  ::-webkit-search-decoration:hover,
  ::-webkit-search-cancel-button:hover {
    cursor: pointer;
  }
`

/**
 * @render react
 * @name Input
 * @example
 * <Input />
 */
class Input extends React.Component {
  static displayName = 'Input'

  static propTypes = {
    children: PropTypes.node,
    className: PropTypes.string,
    description: PropTypes.node,
    field: PropTypes.string.isRequired,
    fieldApi: PropTypes.object.isRequired,
    fieldState: PropTypes.object.isRequired,
    forwardedRef: PropTypes.object,
    hasMessage: PropTypes.bool,
    highlightOnValid: PropTypes.bool,
    iconSize: PropTypes.number,
    initialValue: PropTypes.string,
    isDisabled: PropTypes.bool,
    isReadOnly: PropTypes.bool,
    isRequired: PropTypes.bool,
    justifyContent: PropTypes.string,
    label: PropTypes.node,
    maxLength: PropTypes.number,
    minLength: PropTypes.number,
    onBlur: PropTypes.func,
    onChange: PropTypes.func,
    onFocus: PropTypes.func,
    theme: PropTypes.object.isRequired,
    tooltip: PropTypes.string,
    type: PropTypes.string,
    variant: PropTypes.string,
    willAutoFocus: PropTypes.bool,
  }

  static defaultProps = {
    isRequired: false,
    isReadOnly: false,
    isDisabled: false,
    hasMessage: true,
    willAutoFocus: false,
    highlightOnValid: true,
    iconSize: 46,
    tooltip: null,
    initialValue: '',
  }

  state = {
    hasFocus: false,
  }

  constructor(props) {
    super(props)
    const { forwardedRef } = this.props
    this.inputRef = forwardedRef || React.createRef()
  }

  componentDidMount() {
    const { willAutoFocus } = this.props
    if (willAutoFocus) {
      this.inputRef.current.focus()
    }
  }

  render() {
    const {
      description,
      onChange,
      onBlur,
      onFocus,
      forwardedRef,
      label,
      isDisabled,
      isReadOnly,
      isRequired,
      maxLength,
      minLength,
      theme,
      type,
      field,
      fieldApi,
      fieldState,
      iconSize,
      justifyContent,
      hasMessage,
      variant,
      className,
      tooltip,
      children,
      initialValue,
      ...rest
    } = this.props
    const { hasFocus } = this.state
    const { setValue, setTouched } = fieldApi
    const { value } = fieldState

    // Extract any styled-system space props so that we can apply them directly to the wrapper.
    const spaceProps = {}
    Object.keys(rest).forEach(key => {
      /*eslint-disable react/forbid-foreign-prop-types*/
      if ([...Object.keys(styles.space.propTypes), 'width'].includes(key)) {
        spaceProps[key] = rest[key]
        delete rest[key]
      }
    })

    const getValue = () => {
      if (typeof value === 'undefined') {
        return initialValue
      }
      const { fieldState } = this.props
      const { maskedValue } = fieldState
      return !maskedValue && maskedValue !== 0 ? '' : maskedValue
    }

    return (
      <Flex
        flexDirection="column"
        justifyContent={justifyContent}
        {...spaceProps}
        className={className}
      >
        {label && (
          <Flex mb={2}>
            <Label htmlFor={field}>
              {label}
              {isRequired && (
                <Span
                  css={`
                    vertical-align: top;
                  `}
                  fontSize="s"
                >
                  {' '}
                  *
                </Span>
              )}
            </Label>
            {tooltip && <Tooltip ml={1}>{tooltip}</Tooltip>}
          </Flex>
        )}

        <Flex alignItems="center">
          {type === 'search' && <SearchIcon width={iconSize} />}
          <SystemInput
            p={variant === 'thin' ? 2 : 3}
            {...rest}
            ref={this.inputRef}
            disabled={isDisabled}
            field={field}
            fieldState={fieldState}
            maxLength={maxLength}
            minLength={minLength}
            onBlur={e => {
              // set touched to true to enforce validity highlight
              setTouched(true)
              // Make the state aware that the element is no longer focused.
              this.setState({ hasFocus: false })
              if (onBlur) {
                onBlur(e)
              }
            }}
            onChange={e => {
              setValue(e.target.value)
              if (onChange) {
                onChange(e)
              }
            }}
            onFocus={e => {
              // Make the state aware that the element is now focused.
              this.setState({ hasFocus: true })
              if (onFocus) {
                onFocus(e)
              }
            }}
            pl={type === 'search' ? 35 : null}
            readOnly={isReadOnly}
            theme={theme}
            type={type}
            value={getValue()}
          />
          {children}
        </Flex>

        {type !== 'hidden' && description && (
          <Text color="gray" fontSize="s" mt={1}>
            {description}
          </Text>
        )}
        {type !== 'hidden' && hasMessage && fieldState.error && (
          <Message mt={1} variant={hasFocus ? 'warning' : 'error'}>
            {fieldState.error}
          </Message>
        )}
      </Flex>
    )
  }
}

const BasicInput = withTheme(Input)

export { BasicInput }

export default compose(
  withInputValidation,
  asField
)(BasicInput)
<|endoftext|>


<commit_before>const countDays = (startDate, endDate) => {
  console.log({startDate, endDate});
  const yearInDays = []
  let currentDate = startDate
  console.log({currentDate, 'typeof': typeof currentDate});
  // let currentDate = new Date()
  while (currentDate <= endDate) {
    yearInDays.push(currentDate)
    currentDate = currentDate.setDate(currentDate.getDate() + 1)
  }

  return yearInDays.reduce((counter, day) => {
      counter[day] ? counter[day]++ : counter[day] = 1
      return counter
    }, {})
}

const now = new Date()
const thisYear = now.getFullYear()
const [startDate, endDate] = [new Date(`01/01/${thisYear}`), new Date(`12/31/${thisYear}`)]

export default countDays(startDate, endDate) // returns an object with keys corresponding to each day of the week, and respective values which count how many of those occur during the specified date range, in our case thisYear.
<commit_msg>make CountDays provide correct array<commit_after>const countDays = (startDate, endDate) => {
  const yearInDays = []
  let currentDate = startDate
  // let currentDate = new Date()
  while (currentDate <= endDate) {
    currentDate = new Date(currentDate)
    yearInDays.push(currentDate.getDay())
    currentDate = currentDate.setDate(currentDate.getDate() + 1)
  }

  return yearInDays.reduce((counter, day) => {
      counter[day] ? counter[day]++ : counter[day] = 1
      return counter
    }, {})
}

const now = new Date()
const thisYear = now.getFullYear()
const [startDate, endDate] = [new Date(`01/01/${thisYear}`), new Date(`12/31/${thisYear}`)]

export default countDays(startDate, endDate) // returns an object with keys corresponding to each day of the week, and respective values which count how many of those occur during the specified date range, in our case thisYear.
<|endoftext|>


<commit_before>
/*
    Utilities for testing jQuery-based JavaScript code.
*/
tests = {};

tests.waitFor = function(checkCondition, config) {
    /*
        Wait for a condition before doing anything else.

        Good for making async tests fast on fast machines.
        Use it like this::

          tests.waitFor(function() {
              return (thing == 'done);
          }).thenDo(function() {
              equals(1,1);
              ok(stuff());
          });

        You can pass in a config object as the second argument
        with these possible attributes:

        **config.interval**
          milliseconds to wait between polling condition
        **config.timeout**
          milliseconds to wait before giving up on condition
    */
    if (typeof(config) === 'undefined') {
        config = {};
    }
    var interval = config.interval || 5,
        timeout = config.timeout || 300,
        run,
        runWhenReady,
        timeSpent = 0;

    run = function() {
        if (timeSpent > timeout) {
            var cond = checkCondition.toString()
            ok(false, "Spent too long waiting for: " + cond);
            start();
        }
        timeSpent += interval;
        var ready = checkCondition();
        if (!ready) {
            setTimeout(run, interval);
        } else {
            if (typeof runWhenReady === 'function') {
                runWhenReady();
            }
        }
    };
    setTimeout(run, interval);
    return {
        thenDo: function(fn) {
            runWhenReady = fn;
        }
    }
};

tests._sbCounter = 0;

tests.createSandbox = function(tmpl) {
    /*
        Returns a jQuery object for a temporary, unique div filled with html
        from a template.

        **tmpl**
          An optional jQuery locator from which to copy html.  This would
          typically be the ID of a div in your test runner HTML (e.g. qunit.html)

        Example::

            module('Group of tests', {
                setup: function() {
                    this.sandbox = tests.createSandbox('#foobar-template');
                },
                teardown: function() {
                    this.sandbox.remove();
                }
            });

            test('some test', function() {
                this.sandbox.append('...');
            });
    */
    tests._sbCounter++;
    var sb = $('

');
    if (tmpl) {
        sb.append($(tmpl).html());
    }
    $('#sandbox').append(sb);
    return sb;
};

tests.StubOb = function(Orig, overrides) {
    /*
        Returns a class-like replacement for Orig.

        **Orig**
          object you want to replace.
        **overrides**
          object containing properties to override in the original.

        All properties in the overrides object will replace those of Orig's
        prototype when you create an instance of the class.  This is useful
        for stubbing out certain methods.  For example::

            z.FileData = tests.StubOb(z.FormData, {
                send: function() {}
            });

        This allows the creation of a FormData object that behaves just like
        the original except that send() does not actually post data during
        a test::

            var fileData = new z.FileData();
            fileData.send(); // does nothing

        Be sure to assign the original class back when you're done testing.
    */
    return function() {
        var ob = {}
        Orig.apply(ob, this.arguments);
        for (k in overrides) {
            ob[k] = overrides[k];
        }
        return ob;
    }
};

tests.hasClass = function($sel, cls) {
    /*
        Asserts that jQuery selector $sel has CSS class cls.

        Otherwise, an instructive error is raised.
    */
    equals($sel.hasClass(cls), true,
           'Expecting ' + cls + ', got: ' + $sel.attr('class'));
}

tests.lacksClass = function($sel, cls) {
    /*
        Asserts that jQuery selector $sel does not have CSS class cls.

        Otherwise, an instructive error is raised.
    */
    equals($sel.hasClass(cls), false,
           'Should not have ' + cls + ', got: ' + $sel.attr('class'));
};
<commit_msg>Eases the polling hammer after test failures (@washort is right about polling)<commit_after>
/*
    Utilities for testing jQuery-based JavaScript code.
*/
tests = {};

tests.waitFor = function(checkCondition, config) {
    /*
        Wait for a condition before doing anything else.

        Good for making async tests fast on fast machines.
        Use it like this::

          tests.waitFor(function() {
              return (thing == 'done);
          }).thenDo(function() {
              equals(1,1);
              ok(stuff());
          });

        You can pass in a config object as the second argument
        with these possible attributes:

        **config.interval**
          milliseconds to wait between polling condition
        **config.timeout**
          milliseconds to wait before giving up on condition
    */
    if (typeof(config) === 'undefined') {
        config = {};
    }
    var interval = config.interval || 20,
        timeout = config.timeout || 1000,
        run,
        runWhenReady,
        timeSpent = 0;

    run = function() {
        if (timeSpent > timeout) {
            var cond = checkCondition.toString()
            ok(false, "Spent too long waiting for: " + cond);
            start();
        }
        timeSpent += interval;
        var ready = checkCondition();
        if (!ready) {
            setTimeout(run, interval);
        } else {
            if (typeof runWhenReady === 'function') {
                runWhenReady();
            }
        }
    };
    setTimeout(run, interval);
    return {
        thenDo: function(fn) {
            runWhenReady = fn;
        }
    }
};

tests._sbCounter = 0;

tests.createSandbox = function(tmpl) {
    /*
        Returns a jQuery object for a temporary, unique div filled with html
        from a template.

        **tmpl**
          An optional jQuery locator from which to copy html.  This would
          typically be the ID of a div in your test runner HTML (e.g. qunit.html)

        Example::

            module('Group of tests', {
                setup: function() {
                    this.sandbox = tests.createSandbox('#foobar-template');
                },
                teardown: function() {
                    this.sandbox.remove();
                }
            });

            test('some test', function() {
                this.sandbox.append('...');
            });
    */
    tests._sbCounter++;
    var sb = $('

');
    if (tmpl) {
        sb.append($(tmpl).html());
    }
    $('#sandbox').append(sb);
    return sb;
};

tests.StubOb = function(Orig, overrides) {
    /*
        Returns a class-like replacement for Orig.

        **Orig**
          object you want to replace.
        **overrides**
          object containing properties to override in the original.

        All properties in the overrides object will replace those of Orig's
        prototype when you create an instance of the class.  This is useful
        for stubbing out certain methods.  For example::

            z.FileData = tests.StubOb(z.FormData, {
                send: function() {}
            });

        This allows the creation of a FormData object that behaves just like
        the original except that send() does not actually post data during
        a test::

            var fileData = new z.FileData();
            fileData.send(); // does nothing

        Be sure to assign the original class back when you're done testing.
    */
    return function() {
        var ob = {}
        Orig.apply(ob, this.arguments);
        for (k in overrides) {
            ob[k] = overrides[k];
        }
        return ob;
    }
};

tests.hasClass = function($sel, cls) {
    /*
        Asserts that jQuery selector $sel has CSS class cls.

        Otherwise, an instructive error is raised.
    */
    equals($sel.hasClass(cls), true,
           'Expecting ' + cls + ', got: ' + $sel.attr('class'));
}

tests.lacksClass = function($sel, cls) {
    /*
        Asserts that jQuery selector $sel does not have CSS class cls.

        Otherwise, an instructive error is raised.
    */
    equals($sel.hasClass(cls), false,
           'Should not have ' + cls + ', got: ' + $sel.attr('class'));
};
<|endoftext|>


<commit_before>(function(doc, $) {
    'use strict';

    /*
        Track clientside errors
    */
    mdn.analytics.trackClientErrors();

    /*
        Main menu
    */
    (function() {
        var $mainItems = $('#main-nav > ul > li');
        $mainItems.find('> a').mozMenu({
            brickOnClick: function(e) { return e.target.tagName == 'I'; }
        });
        $mainItems.find('.submenu').mozKeyboardNav();
    })();

    /*
        Open Auth Login Heading widget
    */
    (function() {
        var $container = $('.oauth-login-container');
        var activeClass = 'active';
        var fadeSpeed = 300;

        $container.find('.oauth-login-options').mozMenu({
            fadeInSpeed: fadeSpeed,
            fadeOutSpeed: fadeSpeed,
            onOpen: function() {
                $container.addClass(activeClass);
            },
            onClose: function() {
                $container.removeClass(activeClass);
            }
        });

        $('.login-link').on('click', function(e) {
            // Track event of which was clicked
            var serviceUsed = $(this).data('service'); // "Persona" or "GitHub"

            mdn.analytics.trackEvent({
                category: 'Sign-in',
                action: 'Start',
                label: serviceUsed.toLowerCase()
            });

            // We use data-optimizely-hook and associated Optimizely element
            // targeting for most click goals, but if we are maintaining this
            // selector for Google Analytics anyway, we might as well use it.
            mdn.optimizely.push(['trackEvent', 'click-login-button-' + serviceUsed.toLowerCase()]);
        });
    })();

    /*
        Search animation
    */
    (function() {
        var $nav = $('#main-nav');
        var $navItems = $nav.find('ul > li:not(:last-child)');
        var $mainNavSearch = $nav.find('.main-nav-search');
        var $searchWrap = $nav.find('.search-wrap');
        var $input = $searchWrap.find('input');
        var $searchTrigger = $searchWrap.find('.search-trigger');
        var placeholder = $input.attr('placeholder');

        $searchTrigger.on('click', function(e) {
            $input.get(0).focus();
        });

        var timeout;
        var createExpander = function(delay, isAdd) {
            return function(e) {
                // If we're on mobile, just let everything be
                if($mainNavSearch.css('display') == 'block') {
                    return;
                }

                e && e.preventDefault();
                timeout && clearTimeout(timeout);
                timeout = setTimeout(function() {
                    if(isAdd) {
                        $navItems.fadeOut(100, function() {
                            $navItems.css('display', 'none');
                            $searchWrap.addClass('expanded');
                            $nav.addClass('expand');
                            setTimeout(function() {
                                $input.attr('placeholder', $input.attr('data-placeholder'));
                                $input.val($input.attr('data-value'));
                            }, 100);
                        });
                    }
                    else {
                        $nav.removeClass('expand');
                        $input.attr('placeholder', '');
                        $input.attr('data-value', $input.val());
                        $input.val('');
                        timeout = setTimeout(function() {
                            $searchWrap.removeClass('expanded');
                            $navItems.fadeIn(400);
                        } , 500);
                    }
                }, delay);
            };
        };

        $input.
            on('focus', createExpander(200, true)).
            on('blur', createExpander(600));
    })();

    /*
        Account for the footer language change dropdown and other dropdowns marked as autosubmit
    */
    $('select.autosubmit').on('change', function(){
        this.form.submit();
    });

    /*
        Disable forms when submitted
    */
    (function() {
        var disabled = 'disabled';

        $('form').on('submit', function(ev) {
            var $this = $(this);

            // Allow for a special CSS class to prevent this functionality
            if($this.hasClass('nodisable')) return;

            if ($this.data(disabled)) {
                ev.preventDefault();
            } else {
                $this.data(disabled, true).addClass(disabled);
            }

            $this.ajaxComplete(function(){
                $this.data(disabled, false).removeClass(disabled);
                $this.unbind('ajaxComplete');
            });
        });
    })();

    /*
        Send Django CSRF with all AJAX requests
    */
    $(doc).ajaxSend(function(event, xhr, settings) {
        function getCookie(name) {
            var cookieValue = null;
            if (doc.cookie && doc.cookie != '') {
                var cookies = doc.cookie.split(';');
                for (var i = 0; i < cookies.length; i++) {
                    var cookie = jQuery.trim(cookies[i]);
                    // Does this cookie string begin with the name we want?
                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue;
        }
        function sameOrigin(url) {
            // url could be relative or scheme relative or absolute
            var host = doc.location.host; // host + port
            var protocol = doc.location.protocol;
            var sr_origin = '//' + host;
            var origin = protocol + sr_origin;
            // Allow absolute or scheme relative URLs to same origin
            return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
                (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
                // or any other URL that isn't scheme relative or absolute i.e relative.
                !(/^(\/\/|http:|https:).*/.test(url));
        }
        function safeMethod(method) {
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }

        if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
            xhr.setRequestHeader('X-CSRFToken', getCookie('csrftoken'));
        }
    });

    /*
        Skip to search and is better done with JS because it's sometimes hidden and shown
        Skip to main is also better done with JS as it is configurable on the server side
    */
    $('#skip-search').on('click', function(e) {
        e.preventDefault();
        $('input[name=q]').last().get(0).focus();
    });
    $('#skip-main').each(function() { // Only one, so using each as closure
        var id = this.href.split('#')[1];
        id && $('#' + id).attr('role', 'main');
    });

    /*
    Skip to select language doesn't work in fx without js
    */
    $('#skip-language').on('click', function(e) {
        e.preventDefault();
        $('#language').get(0).focus();
    });

    /*
        Create advanced and language menus
    */
    (function() {
        var $menus = $('#advanced-menu, #languages-menu');
        $menus.mozMenu();
        $menus.parent().find('.submenu').mozKeyboardNav();
    })();

    /*
        Tabzilla :/
    */
    (function() {
        var $tabzilla = $('#tabzilla');

        $tabzilla.length && $.ajax({
            url: '//mozorg.cdn.mozilla.net/en-US/tabzilla/tabzilla.js',
            dataType: 'script',
            cache: true
        });
    })();

})(document, jQuery);
<commit_msg>Add JS logic to place messages in correct places<commit_after>(function(doc, $) {
    'use strict';

    /*
        Track clientside errors
    */
    mdn.analytics.trackClientErrors();

    /*
        Main menu
    */
    (function() {
        var $mainItems = $('#main-nav > ul > li');
        $mainItems.find('> a').mozMenu({
            brickOnClick: function(e) { return e.target.tagName == 'I'; }
        });
        $mainItems.find('.submenu').mozKeyboardNav();
    })();

    /*
        Open Auth Login Heading widget
    */
    (function() {
        var $container = $('.oauth-login-container');
        var activeClass = 'active';
        var fadeSpeed = 300;

        $container.find('.oauth-login-options').mozMenu({
            fadeInSpeed: fadeSpeed,
            fadeOutSpeed: fadeSpeed,
            onOpen: function() {
                $container.addClass(activeClass);
            },
            onClose: function() {
                $container.removeClass(activeClass);
            }
        });

        $('.login-link').on('click', function(e) {
            // Track event of which was clicked
            var serviceUsed = $(this).data('service'); // "Persona" or "GitHub"

            mdn.analytics.trackEvent({
                category: 'Sign-in',
                action: 'Start',
                label: serviceUsed.toLowerCase()
            });

            // We use data-optimizely-hook and associated Optimizely element
            // targeting for most click goals, but if we are maintaining this
            // selector for Google Analytics anyway, we might as well use it.
            mdn.optimizely.push(['trackEvent', 'click-login-button-' + serviceUsed.toLowerCase()]);
        });
    })();

    /*
        Search animation
    */
    (function() {
        var $nav = $('#main-nav');
        var $navItems = $nav.find('ul > li:not(:last-child)');
        var $mainNavSearch = $nav.find('.main-nav-search');
        var $searchWrap = $nav.find('.search-wrap');
        var $input = $searchWrap.find('input');
        var $searchTrigger = $searchWrap.find('.search-trigger');
        var placeholder = $input.attr('placeholder');

        $searchTrigger.on('click', function(e) {
            $input.get(0).focus();
        });

        var timeout;
        var createExpander = function(delay, isAdd) {
            return function(e) {
                // If we're on mobile, just let everything be
                if($mainNavSearch.css('display') == 'block') {
                    return;
                }

                e && e.preventDefault();
                timeout && clearTimeout(timeout);
                timeout = setTimeout(function() {
                    if(isAdd) {
                        $navItems.fadeOut(100, function() {
                            $navItems.css('display', 'none');
                            $searchWrap.addClass('expanded');
                            $nav.addClass('expand');
                            setTimeout(function() {
                                $input.attr('placeholder', $input.attr('data-placeholder'));
                                $input.val($input.attr('data-value'));
                            }, 100);
                        });
                    }
                    else {
                        $nav.removeClass('expand');
                        $input.attr('placeholder', '');
                        $input.attr('data-value', $input.val());
                        $input.val('');
                        timeout = setTimeout(function() {
                            $searchWrap.removeClass('expanded');
                            $navItems.fadeIn(400);
                        } , 500);
                    }
                }, delay);
            };
        };

        $input.
            on('focus', createExpander(200, true)).
            on('blur', createExpander(600));
    })();

    /*
        Account for the footer language change dropdown and other dropdowns marked as autosubmit
    */
    $('select.autosubmit').on('change', function(){
        this.form.submit();
    });

    /*
        Disable forms when submitted
    */
    (function() {
        var disabled = 'disabled';

        $('form').on('submit', function(ev) {
            var $this = $(this);

            // Allow for a special CSS class to prevent this functionality
            if($this.hasClass('nodisable')) return;

            if ($this.data(disabled)) {
                ev.preventDefault();
            } else {
                $this.data(disabled, true).addClass(disabled);
            }

            $this.ajaxComplete(function(){
                $this.data(disabled, false).removeClass(disabled);
                $this.unbind('ajaxComplete');
            });
        });
    })();

    /*
        Send Django CSRF with all AJAX requests
    */
    $(doc).ajaxSend(function(event, xhr, settings) {
        function getCookie(name) {
            var cookieValue = null;
            if (doc.cookie && doc.cookie != '') {
                var cookies = doc.cookie.split(';');
                for (var i = 0; i < cookies.length; i++) {
                    var cookie = jQuery.trim(cookies[i]);
                    // Does this cookie string begin with the name we want?
                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue;
        }
        function sameOrigin(url) {
            // url could be relative or scheme relative or absolute
            var host = doc.location.host; // host + port
            var protocol = doc.location.protocol;
            var sr_origin = '//' + host;
            var origin = protocol + sr_origin;
            // Allow absolute or scheme relative URLs to same origin
            return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
                (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
                // or any other URL that isn't scheme relative or absolute i.e relative.
                !(/^(\/\/|http:|https:).*/.test(url));
        }
        function safeMethod(method) {
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }

        if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
            xhr.setRequestHeader('X-CSRFToken', getCookie('csrftoken'));
        }
    });

    /*
        Skip to search and is better done with JS because it's sometimes hidden and shown
        Skip to main is also better done with JS as it is configurable on the server side
    */
    $('#skip-search').on('click', function(e) {
        e.preventDefault();
        $('input[name=q]').last().get(0).focus();
    });
    $('#skip-main').each(function() { // Only one, so using each as closure
        var id = this.href.split('#')[1];
        id && $('#' + id).attr('role', 'main');
    });

    /*
    Skip to select language doesn't work in fx without js
    */
    $('#skip-language').on('click', function(e) {
        e.preventDefault();
        $('#language').get(0).focus();
    });

    /*
        Create advanced and language menus
    */
    (function() {
        var $menus = $('#advanced-menu, #languages-menu');
        $menus.mozMenu();
        $menus.parent().find('.submenu').mozKeyboardNav();
    })();

    /*
        Messages / Notifications -- show the initial ones
    */
    (function() {
        // Find where we should put notifications
        var insertLocation;

        $.each([
            { selector: '#wikiArticle', method: 'prependTo' },
            { selector: '#home', method: 'prependTo' },
            { selector: 'h1', method: 'insertAfter' }
        ], function() {
            if(!insertLocation && $(this.selector).length) {
                insertLocation = this;
            }
        });

        if(!insertLocation) {
            insertLocation = { selector: 'body', method: 'prependTo' };
        }

        // Inject notifications
        $.each(mdn.notifications || [], function() {
            // Make it so
            $('
' + this.message + '
')[insertLocation.method](insertLocation.selector);
        });
    })();

    /*
        Tabzilla
    */
    (function() {
        $('#tabzilla').length && $.ajax({
            url: '//mozorg.cdn.mozilla.net/en-US/tabzilla/tabzilla.js',
            dataType: 'script',
            cache: true
        });
    })();

})(document, jQuery);
<|endoftext|>