<commit_before>import WebformBuilder from './WebformBuilder';
import Webform from './Webform';
import _ from 'lodash';

export default class WizardBuilder extends WebformBuilder {
  constructor() {
    let element, options;
    if (arguments[0] instanceof HTMLElement || arguments[1]) {
      element = arguments[0];
      options = arguments[1];
    }
    else {
      options = arguments[0];
    }
    // Reset skipInit in case PDFBuilder has set it.
    options.skipInit = false;

    super(element, options);

    this._form = {
      components: [
        this.getPageConfig(1),
      ],
    };

    this.page = 0;

    this.options.hooks.attachPanel = (element, component) => {
      if (component.refs.removeComponent) {
        this.addEventListener(component.refs.removeComponent, 'click', () => {
          const pageIndex = this.pages.findIndex((page) => page.key === component.key);
          const componentIndex = this._form.components.findIndex((comp) => comp.key === component.key);
          if (pageIndex !== -1) {
            this.removePage(pageIndex, componentIndex);
          }
        });
      }
    };

    const originalRenderComponentsHook = this.options.hooks.renderComponents;
    this.options.hooks.renderComponents = (html, { components, self }) => {
      if (self.type === 'form' && !self.root) {
        return html;
      }
      else {
        return originalRenderComponentsHook(html, { components, self });
      }
    };

    const originalAttachComponentsHook = this.options.hooks.attachComponents;
    this.options.hooks.attachComponents = (element, components, container, component) => {
      if (component.type === 'form' && !component.root) {
        return element;
      }

      return originalAttachComponentsHook(element, components, container, component);
    };

    // Wizard pages don't replace themselves in the right array. Do that here.
    this.on('saveComponent', (component, originalComponent) => {
      if (this._form.components.includes(originalComponent)) {
        this._form.components[this._form.components.indexOf(originalComponent)] = component;
        this.rebuild();
      }
    }, true);
  }

  get pages() {
    return _.filter(this._form.components, { type: 'panel' });
  }

  get currentPage() {
    const pages = this.pages;
    return (pages && (pages.length >= this.page)) ? pages[this.page] : null;
  }

  set form(value) {
    this._form = value;
    if (!this._form.components || !Array.isArray(this._form.components)) {
      this._form.components = [];
    }

    if (this.pages.length === 0) {
      const components = this._form.components.filter((component) => component.type !== 'button');
      this._form.components = [this.getPageConfig(1, components)];
    }
    this.rebuild();
  }

  get form() {
    return this._form;
  }

  get schema() {
    _.assign(this._form.components[this.page], this.webform._form.components[0]);
    const webform = new Webform();
    webform.form = this._form;
    return webform.schema;
  }

  render() {
    return this.renderTemplate('builderWizard', {
      sidebar: this.renderTemplate('builderSidebar', {
        scrollEnabled: this.sideBarScroll,
        groupOrder: this.groupOrder,
        groupId: `builder-sidebar-${this.id}`,
        groups: this.groupOrder.map((groupKey) => this.renderTemplate('builderSidebarGroup', {
          group: this.groups[groupKey],
          groupKey,
          groupId: `builder-sidebar-${this.id}`,
          subgroups: this.groups[groupKey].subgroups.map((group) => this.renderTemplate('builderSidebarGroup', {
            group,
            groupKey: group.key,
            groupId: `builder-sidebar-${groupKey}`,
            subgroups: []
          })),
        })),
      }),
      pages: this.pages,
      form: this.webform.render(),
    });
  }

  attach(element) {
    this.loadRefs(element, {
      addPage: 'multiple',
      gotoPage: 'multiple',
    });

    this.refs.addPage.forEach(link => {
      this.addEventListener(link, 'click', (event) => {
        event.preventDefault();
        this.addPage();
      });
    });

    this.refs.gotoPage.forEach((link, index) => {
      this.addEventListener(link, 'click', (event) => {
        event.preventDefault();
        this.setPage(index);
      });
    });

    return super.attach(element);
  }

  rebuild() {
    const page = this.currentPage;
    this.webform.form = {
      display: 'form',
      type: 'form',
      components: page ? [page] : [],
    };
    return this.redraw();
  }

  addPage() {
    const pageNum = (this.pages.length + 1);
    const newPage = this.getPageConfig(pageNum);
    this._form.components.push(newPage);
    this.emit('saveComponent', newPage);
    return this.rebuild();
  }

  removePage(pageIndex, componentIndex) {
    this._form.components.splice(componentIndex, 1);

    if (pageIndex === this.pages.length) {
      // If the last page is removed.
      if (pageIndex === 0) {
        this._form.components.push(this.getPageConfig(1));
        return this.rebuild();
      }
      else {
        return this.setPage(pageIndex - 1);
      }
    }
    else {
      return this.rebuild();
    }
  }

  setPage(index) {
    if (index === this.page) {
      return;
    }
    this.page = index;
    return this.rebuild();
  }

  getPageConfig(index, components = []) {
    return {
      title: `Page ${index}`,
      label: `Page ${index}`,
      type: 'panel',
      key: `page${index}`,
      components,
    };
  }
}
<commit_msg>Fixed WizardBuilder schema.<commit_after>import WebformBuilder from './WebformBuilder';
import Webform from './Webform';
import _ from 'lodash';

export default class WizardBuilder extends WebformBuilder {
  constructor() {
    let element, options;
    if (arguments[0] instanceof HTMLElement || arguments[1]) {
      element = arguments[0];
      options = arguments[1];
    }
    else {
      options = arguments[0];
    }
    // Reset skipInit in case PDFBuilder has set it.
    options.skipInit = false;

    super(element, options);

    this._form = {
      components: [
        this.getPageConfig(1),
      ],
    };

    this.page = 0;

    this.options.hooks.attachPanel = (element, component) => {
      if (component.refs.removeComponent) {
        this.addEventListener(component.refs.removeComponent, 'click', () => {
          const pageIndex = this.pages.findIndex((page) => page.key === component.key);
          const componentIndex = this._form.components.findIndex((comp) => comp.key === component.key);
          if (pageIndex !== -1) {
            this.removePage(pageIndex, componentIndex);
          }
        });
      }
    };

    const originalRenderComponentsHook = this.options.hooks.renderComponents;
    this.options.hooks.renderComponents = (html, { components, self }) => {
      if (self.type === 'form' && !self.root) {
        return html;
      }
      else {
        return originalRenderComponentsHook(html, { components, self });
      }
    };

    const originalAttachComponentsHook = this.options.hooks.attachComponents;
    this.options.hooks.attachComponents = (element, components, container, component) => {
      if (component.type === 'form' && !component.root) {
        return element;
      }

      return originalAttachComponentsHook(element, components, container, component);
    };

    // Wizard pages don't replace themselves in the right array. Do that here.
    this.on('saveComponent', (component, originalComponent) => {
      if (this._form.components.includes(originalComponent)) {
        this._form.components[this._form.components.indexOf(originalComponent)] = component;
        this.rebuild();
      }
    }, true);
  }

  get pages() {
    return _.filter(this._form.components, { type: 'panel' });
  }

  get currentPage() {
    const pages = this.pages;
    return (pages && (pages.length >= this.page)) ? pages[this.page] : null;
  }

  set form(value) {
    this._form = value;
    if (!this._form.components || !Array.isArray(this._form.components)) {
      this._form.components = [];
    }

    if (this.pages.length === 0) {
      const components = this._form.components.filter((component) => component.type !== 'button');
      this._form.components = [this.getPageConfig(1, components)];
    }
    this.rebuild();
  }

  get form() {
    return this._form;
  }

  get schema() {
    _.assign(this._form.components[this.page], this.webform._form.components[0]);
    const webform = new Webform(this.options);
    webform.form = this._form;
    return webform.schema;
  }

  render() {
    return this.renderTemplate('builderWizard', {
      sidebar: this.renderTemplate('builderSidebar', {
        scrollEnabled: this.sideBarScroll,
        groupOrder: this.groupOrder,
        groupId: `builder-sidebar-${this.id}`,
        groups: this.groupOrder.map((groupKey) => this.renderTemplate('builderSidebarGroup', {
          group: this.groups[groupKey],
          groupKey,
          groupId: `builder-sidebar-${this.id}`,
          subgroups: this.groups[groupKey].subgroups.map((group) => this.renderTemplate('builderSidebarGroup', {
            group,
            groupKey: group.key,
            groupId: `builder-sidebar-${groupKey}`,
            subgroups: []
          })),
        })),
      }),
      pages: this.pages,
      form: this.webform.render(),
    });
  }

  attach(element) {
    this.loadRefs(element, {
      addPage: 'multiple',
      gotoPage: 'multiple',
    });

    this.refs.addPage.forEach(link => {
      this.addEventListener(link, 'click', (event) => {
        event.preventDefault();
        this.addPage();
      });
    });

    this.refs.gotoPage.forEach((link, index) => {
      this.addEventListener(link, 'click', (event) => {
        event.preventDefault();
        this.setPage(index);
      });
    });

    return super.attach(element);
  }

  rebuild() {
    const page = this.currentPage;
    this.webform.form = {
      display: 'form',
      type: 'form',
      components: page ? [page] : [],
    };
    return this.redraw();
  }

  addPage() {
    const pageNum = (this.pages.length + 1);
    const newPage = this.getPageConfig(pageNum);
    this._form.components.push(newPage);
    this.emit('saveComponent', newPage);
    return this.rebuild();
  }

  removePage(pageIndex, componentIndex) {
    this._form.components.splice(componentIndex, 1);

    if (pageIndex === this.pages.length) {
      // If the last page is removed.
      if (pageIndex === 0) {
        this._form.components.push(this.getPageConfig(1));
        return this.rebuild();
      }
      else {
        return this.setPage(pageIndex - 1);
      }
    }
    else {
      return this.rebuild();
    }
  }

  setPage(index) {
    if (index === this.page) {
      return;
    }
    this.page = index;
    return this.rebuild();
  }

  getPageConfig(index, components = []) {
    return {
      title: `Page ${index}`,
      label: `Page ${index}`,
      type: 'panel',
      key: `page${index}`,
      components,
    };
  }
}
<|endoftext|>


<commit_before>var gulp = require('gulp');
var minifier = require('gulp-uglify/minifier');
var uglifyjs = require('uglify-js');
var reactify = require('reactify');
var source = require('vinyl-source-stream');
var browserify = require('browserify');
var watchify = require('watchify');
var streamify = require('gulp-streamify');
var htmlreplace = require('gulp-html-replace');
var gutil = require('gulp-util');
var _ = require('lodash');

var path = {
    HTML: ['index.html', 'home.html','signup.html'],
    FINAL_HTML: '../templates',
    ALL: ['js/*.js', 'js/**/*.js', 'home.html', 'signup.html'],
    REACT_JS: ['js/*.js', 'js/components/*.js'],
    JS_LIB: ['js/lib/*.js'],
    CSS: ['css/*'],
    OUT: 'build.js',
    MINIFIED_OUT: 'build.min.js',
    DEST_BUILD: 'public/static',
    DEST_BUILD_JS: 'public/static/js',
    DEST_FINAL_JS: '../static/js',
    DEST_BUILD_CSS: 'public/static/css',
    DEST_FINAL_CSS: '../static/css',
    DEST: 'public',
    ENTRIES: ['js/home.js', 'js/signup.js']
    };

gulp.task('copy', function(){
    gulp.src(path.HTML)
        .pipe(gulp.dest(path.DEST));
});

gulp.task('copy-prod', function(){
    gulp.src(path.HTML)
        .pipe(gulp.dest(path.FINAL_HTML));
});

gulp.task('css', function(){
    gulp.src(path.CSS)
        .pipe(gulp.dest(path.DEST_BUILD_CSS));
});

gulp.task('css-prod', function(){
    gulp.src(path.CSS)
        .pipe(gulp.dest(path.DEST_FINAL_CSS));
});

gulp.task('js', function() {
    gulp.src(path.JS_LIB)
        .pipe(gulp.dest(path.DEST_BUILD_JS));
});

gulp.task('js-prod', function() {
    gulp.src(path.JS_LIB)
        .pipe(gulp.dest(path.DEST_FINAL_JS));
});

gulp.task('watch', function(){
    gulp.watch(path.HTML, ['copy']);
    gulp.watch(path.JS_LIB, ['js']);

    _.each(path.ENTRIES, function(page) {

        var watcher = watchify(browserify({
            entries: [page],
            transform: [reactify],
            debug: true,
            cache: {}, packageCache: {}, fullPaths: true
        }));

        return watcher.on('update', function(){
            watcher.bundle()
                .pipe(source(page.split('/')[1].split('.')[0] + path.OUT))
                .pipe(gulp.dest(path.DEST_BUILD_JS));
                console.log('Updated');
            })
            .bundle()
            .pipe(source(page.split('/')[1].split('.')[0] + path.OUT))
            .pipe(gulp.dest(path.DEST_BUILD_JS));
        });
});

gulp.task('default', ['watch', 'copy', 'css', 'js']);

gulp.task('build', function(){
    browserify({
        entries: [path.ENTRY_POINT],
        transform: [reactify]
    })
    .bundle()
    .pipe(source(path.MINIFIED_OUT))
    .pipe(streamify(minifier({}, uglifyjs)))
    .pipe(gulp.dest(path.DEST_FINAL_JS));
});

// Remember use <!-- build:js --> and <!-- endbuild --> for stuff that needs replaced
gulp.task('replaceHTML', function(){
    gulp.src(path.HTML)
        .pipe(htmlreplace({
            'js': 'static/js/' + path.MINIFIED_OUT
        }))
        .pipe(gulp.dest(path.FINAL_HTML));
});

gulp.task('production', ['replaceHTML', 'build', 'css-prod', 'js-prod']);
<commit_msg>small change to gulpfile<commit_after>var gulp = require('gulp');
var minifier = require('gulp-uglify/minifier');
var uglifyjs = require('uglify-js');
var reactify = require('reactify');
var source = require('vinyl-source-stream');
var browserify = require('browserify');
var watchify = require('watchify');
var streamify = require('gulp-streamify');
var htmlreplace = require('gulp-html-replace');
var gutil = require('gulp-util');
var _ = require('lodash');

var path = {
    HTML: ['index.html', 'home.html','signup.html'],
    FINAL_HTML: '../templates',
    ALL: ['js/*.js', 'js/**/*.js', 'home.html', 'signup.html'],
    REACT_JS: ['js/*.js', 'js/components/*.js'],
    JS_LIB: ['js/lib/*.js'],
    CSS: ['css/*'],
    OUT: 'build.js',
    MINIFIED_OUT: 'build.min.js',
    DEST_BUILD: 'public/static',
    DEST_BUILD_JS: 'public/static/js',
    DEST_FINAL_JS: '../static/js',
    DEST_BUILD_CSS: 'public/static/css',
    DEST_FINAL_CSS: '../static/css',
    DEST: 'public',
    ENTRIES: ['js/home.js', 'js/signup.js']
    };

gulp.task('copy', function(){
    gulp.src(path.HTML)
        .pipe(gulp.dest(path.DEST));
});

gulp.task('copy-prod', function(){
    gulp.src(path.HTML)
        .pipe(gulp.dest(path.FINAL_HTML));
});

gulp.task('css', function(){
    gulp.src(path.CSS)
        .pipe(gulp.dest(path.DEST_BUILD_CSS));
});

gulp.task('css-prod', function(){
    gulp.src(path.CSS)
        .pipe(gulp.dest(path.DEST_FINAL_CSS));
});

gulp.task('js', function() {
    gulp.src(path.JS_LIB)
        .pipe(gulp.dest(path.DEST_BUILD_JS));
});

gulp.task('js-prod', function() {
    gulp.src(path.JS_LIB)
        .pipe(gulp.dest(path.DEST_FINAL_JS));
});

gulp.task('watch', function(){
    gulp.watch(path.HTML, ['copy']);
    gulp.watch(path.JS_LIB, ['js']);

    _.each(path.ENTRIES, function(page) {

        var watcher = watchify(browserify({
            entries: [page],
            transform: [reactify],
            debug: true,
            cache: {}, packageCache: {}, fullPaths: true
        }));

        return watcher.on('update', function(){
            watcher.bundle()
                .pipe(source(page.split('/')[1].split('.')[0] + path.OUT))
                .pipe(gulp.dest(path.DEST_BUILD_JS));
                console.log('Updated');
            })
            .bundle()
            .pipe(source(page.split('/')[1].split('.')[0] + path.OUT))
            .pipe(gulp.dest(path.DEST_BUILD_JS));
        });
});

gulp.task('default', ['watch', 'copy', 'css', 'js']);

gulp.task('build', function(){
    _.each(path.ENTRIES, function(page) {
        browserify({
            entries: [page],
            transform: [reactify]
        })
        .bundle()
        .pipe(source(page.split('/')[1].split('.')[0] + path.MINIFIED_OUT))
        .pipe(streamify(minifier({}, uglifyjs)))
        .pipe(gulp.dest(path.DEST_FINAL_JS));
    });
});

// Remember use <!-- build:js --> and <!-- endbuild --> for stuff that needs replaced
gulp.task('replaceHTML', function(){
    gulp.src(path.HTML)
        .pipe(htmlreplace({
            'js': 'static/js/' + path.MINIFIED_OUT
        }))
        .pipe(gulp.dest(path.FINAL_HTML));
});

gulp.task('production', ['replaceHTML', 'build', 'css-prod', 'js-prod']);
<|endoftext|>


<commit_before>const fs = require('fs');
const gulp = require('gulp');
const htmlmin = require('gulp-htmlmin');
const cleancss = require('gulp-clean-css');
const uglify = require('gulp-uglify');
const gzip = require('gulp-gzip');
const del = require('del');
const inline = require('gulp-inline');
const inlineImages = require('gulp-css-base64');
const favicon = require('gulp-base64-favicon');

const dataFolder = 'build/';

gulp.task('clean', function() {
    del([ dataFolder + '*']);
    return true;
});

gulp.task('buildfs_embeded', ['buildfs_inline'], function() {

    var source = dataFolder + 'index.html.gz';
    var destination = dataFolder + 'index.html.gz.h';

    var wstream = fs.createWriteStream(destination);
    wstream.on('error', function (err) {
        console.log(err);
    });

    var data = fs.readFileSync(source);

    wstream.write('#define index_html_gz_len ' + data.length + '\n');
    wstream.write('static const char index_html_gz[] PROGMEM = {')

    for (i=0; i<data.length; i++) {
        wstream.write(data[i].toString());
        if (i<data.length-1) wstream.write(',');
    }

    wstream.write('};')
    wstream.end();

    del();

});

gulp.task('buildfs_inline', ['clean'], function() {
    return gulp.src('src/*.html')
        // .pipe(favicon())
        .pipe(inline({
            base: 'src/',
            js: uglify,
            css: [cleancss, inlineImages],
            disabledTypes: ['svg', 'img']
        }))
        .pipe(htmlmin({
            collapseWhitespace: true,
            removeComments: true,
            minifyCSS: true,
            minifyJS: true
        }))
        .pipe(gzip({ gzipOptions: { level: 9 } }))
        .pipe(gulp.dest(dataFolder));
});

gulp.task('default', ['buildfs_embeded']);<commit_msg>web/gulpfile.js: remove superflous del()<commit_after>const fs = require('fs');
const gulp = require('gulp');
const htmlmin = require('gulp-htmlmin');
const cleancss = require('gulp-clean-css');
const uglify = require('gulp-uglify');
const gzip = require('gulp-gzip');
const del = require('del');
const inline = require('gulp-inline');
const inlineImages = require('gulp-css-base64');
const favicon = require('gulp-base64-favicon');

const dataFolder = 'build/';

gulp.task('clean', function() {
    del([ dataFolder + '*']);
    return true;
});

gulp.task('buildfs_embeded', ['buildfs_inline'], function() {

    var source = dataFolder + 'index.html.gz';
    var destination = dataFolder + 'index.html.gz.h';

    var wstream = fs.createWriteStream(destination);
    wstream.on('error', function (err) {
        console.log(err);
    });

    var data = fs.readFileSync(source);

    wstream.write('#define index_html_gz_len ' + data.length + '\n');
    wstream.write('static const char index_html_gz[] PROGMEM = {')

    for (i=0; i<data.length; i++) {
        wstream.write(data[i].toString());
        if (i<data.length-1) wstream.write(',');
    }

    wstream.write('};')
    wstream.end();

});

gulp.task('buildfs_inline', ['clean'], function() {
    return gulp.src('src/*.html')
        // .pipe(favicon())
        .pipe(inline({
            base: 'src/',
            js: uglify,
            css: [cleancss, inlineImages],
            disabledTypes: ['svg', 'img']
        }))
        .pipe(htmlmin({
            collapseWhitespace: true,
            removeComments: true,
            minifyCSS: true,
            minifyJS: true
        }))
        .pipe(gzip({ gzipOptions: { level: 9 } }))
        .pipe(gulp.dest(dataFolder));
});

gulp.task('default', ['buildfs_embeded']);
<|endoftext|>


<commit_before>var path = require('path');
var webpack = require('webpack');

// Webpack Plugins
var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
var autoprefixer = require('autoprefixer');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');

/**
 * Env
 * Get npm lifecycle event to identify the environment
 */
var ENV = process.env.MODE;
var isProd = ENV === 'build';

module.exports = function makeWebpackConfig() {
  /**
   * Config
   * Reference: http://webpack.github.io/docs/configuration.html
   * This is the object where all configuration gets set
   */
  var config = {};

  /**
   * Devtool
   * Reference: http://webpack.github.io/docs/configuration.html#devtool
   * Type of sourcemap to use per build type
   */
  if (isProd) {
    config.devtool = 'source-map';
  } else {
    config.devtool = 'eval-source-map';
  }

  // add debug messages
  config.debug = !isProd;

  /**
   * Entry
   * Reference: http://webpack.github.io/docs/configuration.html#entry
   */
  config.entry = {
    'polyfills': './demo/src/polyfills.ts',
    'vendor': './demo/src/vendor.ts',
    'app': './demo/src/main.ts' // our angular app
  };

  /**
   * Output
   * Reference: http://webpack.github.io/docs/configuration.html#output
   */
  config.output = {
    path: root('demo', 'dist'),
    publicPath: isProd ? '/' : 'http://localhost:9090/',
    filename: isProd ? 'js/[name].[hash].js' : 'js/[name].js',
    chunkFilename: isProd ? '[id].[hash].chunk.js' : '[id].chunk.js'
  };

  /**
   * Resolve
   * Reference: http://webpack.github.io/docs/configuration.html#resolve
   */
  config.resolve = {
    root: root('demo'),
    // only discover files that have those extensions
    extensions: ['', '.ts', '.js', '.json', '.css', '.scss', '.html'],

    alias: {
      '@ng-bootstrap/accordion': root('src/accordion/accordion.ts'),
      '@ng-bootstrap/alert': root('src/alert/alert.ts'),
      '@ng-bootstrap/buttons': root('src/buttons/radio.ts'),
      '@ng-bootstrap/carousel': root('src/carousel/carousel.ts'),
      '@ng-bootstrap/collapse': root('src/collapse/collapse.ts'),
      '@ng-bootstrap/dropdown': root('src/dropdown/dropdown.ts'),
      '@ng-bootstrap/progressbar': root('src/progressbar/progressbar.ts'),
      '@ng-bootstrap/tooltip': root('src/tooltip/tooltip.ts'),
      '@ng-bootstrap/popover': root('src/popover/popover.ts')
    }
  };

  /**
   * Loaders
   * Reference: http://webpack.github.io/docs/configuration.html#module-loaders
   * List: http://webpack.github.io/docs/list-of-loaders.html
   * This handles most of the magic responsible for converting modules
   */
  config.module = {
    loaders: [
      // Support for .ts files.
      {
        test: /\.ts$/,
        loader: 'ts',
        query: {
          'ignoreDiagnostics': [
            2403, // 2403 -> Subsequent variable declarations
            2300, // 2300 -> Duplicate identifier
            2374, // 2374 -> Duplicate number index signature
            2375, // 2375 -> Duplicate string index signature
            2502  // 2502 -> Referenced directly or indirectly
          ]
        },
        exclude: [/node_modules\/(?!(ng2-.+))/]
      },

      // copy those assets to output
      {test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/, loader: 'file?name=fonts/[name].[hash].[ext]?'},

      // Support for *.json files.
      {test: /\.json$/, loader: 'json'},

      // Support for CSS as raw text
      // use 'null' loader in test mode (https://github.com/webpack/null-loader)
      // all css in src/style will be bundled in an external css file
      {
        test: /\.css$/,
        exclude: root('demo', 'src', 'app'),
        loader: ExtractTextPlugin.extract('style', 'css?sourceMap!postcss')
      },
      // all css required in src/app files will be merged in js files
      {test: /\.css$/, include: root('demo', 'src', 'app'), loader: 'raw!postcss'},

      // support for .scss files
      // use 'null' loader in test mode (https://github.com/webpack/null-loader)
      // all css in src/style will be bundled in an external css file
      {
        test: /\.scss$/,
        exclude: root('src', 'app'),
        loader: ExtractTextPlugin.extract('style', 'css?sourceMap!postcss!sass')
      },
      // all css required in src/app files will be merged in js files
      {test: /\.scss$/, exclude: root('demo', 'src', 'style'), loader: 'raw!postcss!sass'},

      // support for .html as raw text
      // todo: change the loader to something that adds a hash to images
      {test: /\.html$/, loader: 'raw'},

      {test: /\.md$/, loader: 'html!markdown'}
    ],
    postLoaders: [],
    noParse: [/.+zone\.js\/dist\/.+/]
  };

  /**
   * Plugins
   * Reference: http://webpack.github.io/docs/configuration.html#plugins
   * List: http://webpack.github.io/docs/list-of-plugins.html
   */
  config.plugins = [
    // Define env variables to help with builds
    // Reference: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
    new webpack.DefinePlugin({
      // Environment helpers
      'process.env': {
        ENV: JSON.stringify(ENV)
      }
    }),

    new CommonsChunkPlugin({
      name: ['vendor', 'polyfills']
    }),

    // Inject script and link tags into html files
    // Reference: https://github.com/ampedandwired/html-webpack-plugin
    new HtmlWebpackPlugin({
      template: './demo/src/public/index.html',
      chunksSortMode: 'dependency'
    }),

    // Extract css files
    // Reference: https://github.com/webpack/extract-text-webpack-plugin
    // Disabled when in test mode or not in build mode
    new ExtractTextPlugin('css/[name].[hash].css', {disable: !isProd})
  ];

  // Add build specific plugins
  if (isProd) {
    config.plugins.push(
      // Reference: http://webpack.github.io/docs/list-of-plugins.html#noerrorsplugin
      // Only emit files when there are no errors
      new webpack.NoErrorsPlugin(),

      // Reference: http://webpack.github.io/docs/list-of-plugins.html#dedupeplugin
      // Dedupe modules in the output
      new webpack.optimize.DedupePlugin(),

      // Reference: http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
      // Minify all javascript, switch loaders to minimizing mode
      new webpack.optimize.UglifyJsPlugin({
        // Angular 2 is broken again, disabling mangle until beta 6 that should fix the thing
        // Todo: remove this with beta 6
        mangle: false
      }),

      // Copy assets from the public folder
      // Reference: https://github.com/kevlened/copy-webpack-plugin
      new CopyWebpackPlugin([{
        from: root('demo/src/public')
      }])
    );
  }

  /**
   * PostCSS
   * Reference: https://github.com/postcss/autoprefixer-core
   * Add vendor prefixes to your css
   */
  config.postcss = [
    autoprefixer({
      browsers: ['last 2 version']
    })
  ];

  /**
   * Dev server configuration
   * Reference: http://webpack.github.io/docs/configuration.html#devserver
   * Reference: http://webpack.github.io/docs/webpack-dev-server.html
   */
  config.devServer = {
    contentBase: './demo/src/public',
    historyApiFallback: true,
    stats: 'minimal' // none (or false), errors-only, minimal, normal (or true) and verbose
  };

  return config;
}();

// Helper functions
function root(args) {
  args = Array.prototype.slice.call(arguments, 0);
  return path.join.apply(path, [__dirname].concat(args));
}
<commit_msg>chore(build): add aliases to all demos (#353)<commit_after>var path = require('path');
var webpack = require('webpack');

// Webpack Plugins
var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
var autoprefixer = require('autoprefixer');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');

/**
 * Env
 * Get npm lifecycle event to identify the environment
 */
var ENV = process.env.MODE;
var isProd = ENV === 'build';

module.exports = function makeWebpackConfig() {
  /**
   * Config
   * Reference: http://webpack.github.io/docs/configuration.html
   * This is the object where all configuration gets set
   */
  var config = {};

  /**
   * Devtool
   * Reference: http://webpack.github.io/docs/configuration.html#devtool
   * Type of sourcemap to use per build type
   */
  if (isProd) {
    config.devtool = 'source-map';
  } else {
    config.devtool = 'eval-source-map';
  }

  // add debug messages
  config.debug = !isProd;

  /**
   * Entry
   * Reference: http://webpack.github.io/docs/configuration.html#entry
   */
  config.entry = {
    'polyfills': './demo/src/polyfills.ts',
    'vendor': './demo/src/vendor.ts',
    'app': './demo/src/main.ts' // our angular app
  };

  /**
   * Output
   * Reference: http://webpack.github.io/docs/configuration.html#output
   */
  config.output = {
    path: root('demo', 'dist'),
    publicPath: isProd ? '/' : 'http://localhost:9090/',
    filename: isProd ? 'js/[name].[hash].js' : 'js/[name].js',
    chunkFilename: isProd ? '[id].[hash].chunk.js' : '[id].chunk.js'
  };

  /**
   * Resolve
   * Reference: http://webpack.github.io/docs/configuration.html#resolve
   */
  config.resolve = {
    root: root('demo'),
    // only discover files that have those extensions
    extensions: ['', '.ts', '.js', '.json', '.css', '.scss', '.html'],

    alias: {
      '@ng-bootstrap/accordion': root('src/accordion/accordion.ts'),
      '@ng-bootstrap/alert': root('src/alert/alert.ts'),
      '@ng-bootstrap/buttons': root('src/buttons/radio.ts'),
      '@ng-bootstrap/carousel': root('src/carousel/carousel.ts'),
      '@ng-bootstrap/collapse': root('src/collapse/collapse.ts'),
      '@ng-bootstrap/dropdown': root('src/dropdown/dropdown.ts'),
      '@ng-bootstrap/modal': root('src/modal/modal.ts'),
      '@ng-bootstrap/pager': root('src/pager/pager.ts'),
      '@ng-bootstrap/pagination': root('src/pagination/pagination.ts'),
      '@ng-bootstrap/popover': root('src/popover/popover.ts'),
      '@ng-bootstrap/progressbar': root('src/progressbar/progressbar.ts'),
      '@ng-bootstrap/rating': root('src/rating/rating.ts'),
      '@ng-bootstrap/tabset': root('src/tabset/tabset.ts'),
      '@ng-bootstrap/tooltip': root('src/tooltip/tooltip.ts')
    }
  };

  /**
   * Loaders
   * Reference: http://webpack.github.io/docs/configuration.html#module-loaders
   * List: http://webpack.github.io/docs/list-of-loaders.html
   * This handles most of the magic responsible for converting modules
   */
  config.module = {
    loaders: [
      // Support for .ts files.
      {
        test: /\.ts$/,
        loader: 'ts',
        query: {
          'ignoreDiagnostics': [
            2403, // 2403 -> Subsequent variable declarations
            2300, // 2300 -> Duplicate identifier
            2374, // 2374 -> Duplicate number index signature
            2375, // 2375 -> Duplicate string index signature
            2502  // 2502 -> Referenced directly or indirectly
          ]
        },
        exclude: [/node_modules\/(?!(ng2-.+))/]
      },

      // copy those assets to output
      {test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/, loader: 'file?name=fonts/[name].[hash].[ext]?'},

      // Support for *.json files.
      {test: /\.json$/, loader: 'json'},

      // Support for CSS as raw text
      // use 'null' loader in test mode (https://github.com/webpack/null-loader)
      // all css in src/style will be bundled in an external css file
      {
        test: /\.css$/,
        exclude: root('demo', 'src', 'app'),
        loader: ExtractTextPlugin.extract('style', 'css?sourceMap!postcss')
      },
      // all css required in src/app files will be merged in js files
      {test: /\.css$/, include: root('demo', 'src', 'app'), loader: 'raw!postcss'},

      // support for .scss files
      // use 'null' loader in test mode (https://github.com/webpack/null-loader)
      // all css in src/style will be bundled in an external css file
      {
        test: /\.scss$/,
        exclude: root('src', 'app'),
        loader: ExtractTextPlugin.extract('style', 'css?sourceMap!postcss!sass')
      },
      // all css required in src/app files will be merged in js files
      {test: /\.scss$/, exclude: root('demo', 'src', 'style'), loader: 'raw!postcss!sass'},

      // support for .html as raw text
      // todo: change the loader to something that adds a hash to images
      {test: /\.html$/, loader: 'raw'},

      {test: /\.md$/, loader: 'html!markdown'}
    ],
    postLoaders: [],
    noParse: [/.+zone\.js\/dist\/.+/]
  };

  /**
   * Plugins
   * Reference: http://webpack.github.io/docs/configuration.html#plugins
   * List: http://webpack.github.io/docs/list-of-plugins.html
   */
  config.plugins = [
    // Define env variables to help with builds
    // Reference: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
    new webpack.DefinePlugin({
      // Environment helpers
      'process.env': {
        ENV: JSON.stringify(ENV)
      }
    }),

    new CommonsChunkPlugin({
      name: ['vendor', 'polyfills']
    }),

    // Inject script and link tags into html files
    // Reference: https://github.com/ampedandwired/html-webpack-plugin
    new HtmlWebpackPlugin({
      template: './demo/src/public/index.html',
      chunksSortMode: 'dependency'
    }),

    // Extract css files
    // Reference: https://github.com/webpack/extract-text-webpack-plugin
    // Disabled when in test mode or not in build mode
    new ExtractTextPlugin('css/[name].[hash].css', {disable: !isProd})
  ];

  // Add build specific plugins
  if (isProd) {
    config.plugins.push(
      // Reference: http://webpack.github.io/docs/list-of-plugins.html#noerrorsplugin
      // Only emit files when there are no errors
      new webpack.NoErrorsPlugin(),

      // Reference: http://webpack.github.io/docs/list-of-plugins.html#dedupeplugin
      // Dedupe modules in the output
      new webpack.optimize.DedupePlugin(),

      // Reference: http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
      // Minify all javascript, switch loaders to minimizing mode
      new webpack.optimize.UglifyJsPlugin({
        // Angular 2 is broken again, disabling mangle until beta 6 that should fix the thing
        // Todo: remove this with beta 6
        mangle: false
      }),

      // Copy assets from the public folder
      // Reference: https://github.com/kevlened/copy-webpack-plugin
      new CopyWebpackPlugin([{
        from: root('demo/src/public')
      }])
    );
  }

  /**
   * PostCSS
   * Reference: https://github.com/postcss/autoprefixer-core
   * Add vendor prefixes to your css
   */
  config.postcss = [
    autoprefixer({
      browsers: ['last 2 version']
    })
  ];

  /**
   * Dev server configuration
   * Reference: http://webpack.github.io/docs/configuration.html#devserver
   * Reference: http://webpack.github.io/docs/webpack-dev-server.html
   */
  config.devServer = {
    contentBase: './demo/src/public',
    historyApiFallback: true,
    stats: 'minimal' // none (or false), errors-only, minimal, normal (or true) and verbose
  };

  return config;
}();

// Helper functions
function root(args) {
  args = Array.prototype.slice.call(arguments, 0);
  return path.join.apply(path, [__dirname].concat(args));
}
<|endoftext|>


<commit_before>var request = require('request');
var async = require('async');
var util = require('util');
var mongoose = require('mongoose');

var Client = mongoose.model('Client');
var getter = require('./getter');
var mongoose = require('mongoose')

var adSchema = mongoose.model('Ad');

var _sent;

io.sockets.on('connection', function (socket) {

	getter.get(function (err, data){

		console.log(data);

		adSchema.find({})

			/*.where('temperature.max').lt(data.temperature)
			.where('temperature.min').gt(data.temperature)

			.where('humidity.max').lt(data.illuminance)
			.where('humidity.min').gt(data.illuminance)

			.where('illuminance.max').lt(data.relativeHumidity)
			.where('humidity.min').gt(data.relativeHumidity)*/

			.select('url')

		.exec(function (err, ads){

			async.map(ads, function (ad, cb){

				cb(null, ad.url);

			}, function (err, ads){

				socket.emit('ads', ads);

			});

			console.log(ads);

		});

	});

	socket.on('fid', function (data) {
		Client.list(function (err, clients) {
			Client.find({fid: data.fid}, function (er, client) {

				socket.emit('ads', {
					ads: client.ads
				});

			});
		});
	});
});

setInterval(function (){

	getter.get(function (err, data){

		adSchema.find({})

			.where('temperature.max').lt(Float(data.temperature))
			.where('temperature.min').gt(Float(data.temperature))

			.where('lux.max').lt(Float(data.illuminance))
			.where('lux.min').gt(Float(data.illuminance))

			.where('humidity.max').lt(Float(data.relativeHumidity))
			.where('humidity.min').gt(Float(data.relativeHumidity))

			.select('url')

		.exec(function (err, ads){

			async.map(ads, function (ad, cb){

				cb(null, ad.url);

			}, function (err, ads){

				io.sockets.emit('ads', ads);

				console.log(data, ads);

			});

		});

	});

}, 1000);<commit_msg>Testing socket algorithm output<commit_after>var request = require('request');
var async = require('async');
var util = require('util');
var mongoose = require('mongoose');

var Client = mongoose.model('Client');
var getter = require('./getter');
var mongoose = require('mongoose')

var adSchema = mongoose.model('Ad');

var _sent;

io.sockets.on('connection', function (socket) {

	getter.get(function (err, data){

		console.log(data);

		adSchema.find({})

			/*.where('temperature.max').lt(data.temperature)
			.where('temperature.min').gt(data.temperature)

			.where('humidity.max').lt(data.illuminance)
			.where('humidity.min').gt(data.illuminance)

			.where('illuminance.max').lt(data.relativeHumidity)
			.where('humidity.min').gt(data.relativeHumidity)*/

			.select('url')

		.exec(function (err, ads){

			async.map(ads, function (ad, cb){

				cb(null, ad.url);

			}, function (err, ads){

				socket.emit('ads', ads);

			});

			console.log(ads);

		});

	});

	socket.on('fid', function (data) {
		Client.list(function (err, clients) {
			Client.find({fid: data.fid}, function (er, client) {

				socket.emit('ads', {
					ads: client.ads
				});

			});
		});
	});
});

setInterval(function (){

	getter.get(function (err, data){

		adSchema.find({})

			.where('temperature.max').lt(Number(data.temperature))
			.where('temperature.min').gt(Number(data.temperature))

			.where('lux.max').lt(Number(data.illuminance))
			.where('lux.min').gt(Number(data.illuminance))

			.where('humidity.max').lt(Number(data.relativeHumidity))
			.where('humidity.min').gt(Number(data.relativeHumidity))

			.select('url')

		.exec(function (err, ads){

			async.map(ads, function (ad, cb){

				cb(null, ad.url);

			}, function (err, ads){

				io.sockets.emit('ads', ads);

				console.log(data, ads);

			});

		});

	});

}, 1000);<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////////////
//                                                                             //
//-----------------------------------------------------------------------------//
//                          ANGULAR DATALIST DIRECTIVE                         //
//-----------------------------------------------------------------------------//
//                                                                             //
/////////////////////////////////////////////////////////////////////////////////

/**------------------------------------------------------------------------------
 * @name ngDatalist
 * @author Przemysław Hardyn
 * @description Simple datalist directive.
 * @license MIT Licence <http://creativecommons.org/licenses/MIT/>
 ------------------------------------------------------------------------------*/

angular.module('ng-datalist', [])
  .directive('ngDatalist', ['$document', '$timeout', '$window', ngDatalist]);

function ngDatalist ($document, $timeout, $window) {
  return {
    restrict: 'E',
    replace: true,
    scope: {
      items: '=items',         /** @type {Array}   */
      currentItem: '=current', /** @type {string}  */
      fieldRequired: '=?req',   /** @type {boolean} */
      styling: '=styling',      /** @type {boolean} */
      placeholder: '@?placeholder',      /** @type {string} */
      inputClass: '@?inputClass'         /** @type {string} */
    },
    link: function (scope, elem) {
      // --------------------------------------------------------- //
      //                      SCOPE & VARIABLES                    //
      // --------------------------------------------------------- //
      // Functions binded to the template:
      scope.selectItem = selectItem;
      scope.showList = showList;
      scope.hideList = hideList;
      scope.highlightItem = highlightItem;
      scope.clearHighlightedItem = clearHighlightedItem;

      // Expose dependencies in the directive:
      var document = $document;
      var domReady = $timeout;

      // Set field to not required if attribute set to false
      // or not provided.
      if (scope.fieldRequired !== true) {
        scope.fieldRequired = false;
      }

      // Basic color config:
      var borderColor = '#DDDDDD';
      var highlightColor = '#DDDDDD';

      // --------------------------------------------------------- //
      //                           STYLES                          //
      // --------------------------------------------------------- //
      // Use default styles only if custom not set:
      if (scope.styling !== false) {
        // Container element styles:
        scope.containerStyle = {
          'display': 'inline-block',
          'position': 'relative',
          'box-sizing': 'border-box',
          'height': '32px'
        };

        // Input element styles:
        scope.inputStyle = {
          'box-sizing': 'border-box',
          'height': '32px',
          'padding': '5px',
          'margin': '0px'
        };

        // List element styles:
        scope.ulStyle = {
          'list-style-type': 'none',
          'padding': '0',
          'margin': '0',
          'display': 'none',
          'position': 'absolute',
          'top': '32px',
          'background-color': '#FFFFFF',
          'overflow-y': 'auto',
          'border-left': '1px solid '+borderColor,
          'border-bottom': '1px solid '+borderColor,
          'border-right': '1px solid '+borderColor,
          'z-index': 10
        };

        // List items styles:
        scope.liStyle = {
          'display': 'block',
          'padding': '5px',
          'cursor': 'pointer',
          'box-sizing': 'border-box'
        }
      }

      // --------------------------------------------------------- //
      //                          FUNCTIONS                        //
      // --------------------------------------------------------- //
      /**
       * @function selectItem
       * @description Copy data from selected list item to the model.
       * @param {Object} event Click event used to prevent bubbling.
       * @param {string} item  Text to be copied to the model.
       */
      function selectItem (event, item) {
        event.stopPropagation();
        scope.currentItem = item;
        elem.find('ul').css('display', 'none');
      }

      /**
       * @function showList
       * @description Show ul DOM element containing the list.
       * @param {Object} event Click event used to prevent bubbling.
       */
      function showList (event) {
        event.stopPropagation();
        var maxHeight = $window.innerHeight - event.target.getBoundingClientRect().top - 40;
        var ul = elem.find('ul');
        ul.css('max-height',  maxHeight + 'px')
        .css('display', 'block');
        scope.liStyle.width = event.target.clientWidth + 'px';
      }

      /**
       * @function hideList
       * @description Hide ul DOM element containing the list.
       * @param {Object} event Click event used to prevent bubbling.
       */
      function hideList (event) {
        event.stopPropagation();
        elem.find('ul').css('display', 'none');
      }

      /**
       * @function highlightItem
       * @description Highlight hovered list item.
       * @param {Object} event Mouseover event used to prevent bubbling.
       * @param {Number} index Used to locate current list item in the DOM tree.
       */
      function highlightItem (event) {
        event.stopPropagation();
        angular.element(event.currentTarget).css({
          'background-color': borderColor
        });
      }

      /**
       * @function clearHighlightedItem
       * @description Remove item highlight on mouseleave.
       * @param {Object} event Mouseleave event used to prevent bubbling.
       */
      function clearHighlightedItem (event) {
        event.stopPropagation();
        angular.element(event.currentTarget).css({
          'background-color': 'transparent'
        });
      }

      // --------------------------------------------------------- //
      //                           EVENTS                          //
      // --------------------------------------------------------- //
      // Bind click event to the document to hide list:
      domReady(function () {
        document.on('click', function (event) {
          var contains = false;
          if (window.jQuery) {
            contains = window.jQuery.contains(elem, event.target);
          } else {
            contains = elem.contains(event.target);
          }
          if (!contains) {
            scope.hideList(event);
          }
        })
      })

      // Remove document click event on destroy:
      elem.on('$destroy', function () {
        document.off('click');
      });
    },
    template:
    '
'+
      '<input type="text" '+
             'class="ng-datalist-input {{inputClass}}" '+
             'placeholder="{{placeholder}}" '+
             'ng-required="fieldRequired" '+
             'ng-model="currentItem" '+
             'ng-click="showList($event)" '+
             'ng-style="inputStyle" '+
             'ng-keydown="($event.keyCode == 13 || '+
                           '$event.keyCode == 9) && '+
                           'hideList($event)">'+
      '
'+
        '
{{ item }}
'+
      '
'+
    '
'
  }
}
<commit_msg>oninput時にng-modelの値を更新<commit_after>/////////////////////////////////////////////////////////////////////////////////
//                                                                             //
//-----------------------------------------------------------------------------//
//                          ANGULAR DATALIST DIRECTIVE                         //
//-----------------------------------------------------------------------------//
//                                                                             //
/////////////////////////////////////////////////////////////////////////////////

/**------------------------------------------------------------------------------
 * @name ngDatalist
 * @author Przemysław Hardyn
 * @description Simple datalist directive.
 * @license MIT Licence <http://creativecommons.org/licenses/MIT/>
 ------------------------------------------------------------------------------*/

angular.module('ng-datalist', [])
  .directive('ngDatalist', ['$document', '$timeout', '$window', ngDatalist]);

function ngDatalist ($document, $timeout, $window) {
  return {
    restrict: 'E',
    replace: true,
    scope: {
      items: '=items',         /** @type {Array}   */
      currentItem: '=current', /** @type {string}  */
      fieldRequired: '=?req',   /** @type {boolean} */
      styling: '=styling',      /** @type {boolean} */
      placeholder: '@?placeholder',      /** @type {string} */
      inputClass: '@?inputClass'         /** @type {string} */
    },
    link: function (scope, elem) {
      // --------------------------------------------------------- //
      //                      SCOPE & VARIABLES                    //
      // --------------------------------------------------------- //
      // Functions binded to the template:
      scope.selectItem = selectItem;
      scope.showList = showList;
      scope.hideList = hideList;
      scope.highlightItem = highlightItem;
      scope.clearHighlightedItem = clearHighlightedItem;

      elem.find('input').on('input propertychange', function() {
        scope.currentItem = this.value;
        scope.$evalAsync();
      });

      // Expose dependencies in the directive:
      var document = $document;
      var domReady = $timeout;

      // Set field to not required if attribute set to false
      // or not provided.
      if (scope.fieldRequired !== true) {
        scope.fieldRequired = false;
      }

      // Basic color config:
      var borderColor = '#DDDDDD';
      var highlightColor = '#DDDDDD';

      // --------------------------------------------------------- //
      //                           STYLES                          //
      // --------------------------------------------------------- //
      // Use default styles only if custom not set:
      if (scope.styling !== false) {
        // Container element styles:
        scope.containerStyle = {
          'display': 'inline-block',
          'position': 'relative',
          'box-sizing': 'border-box',
          'height': '32px'
        };

        // Input element styles:
        scope.inputStyle = {
          'box-sizing': 'border-box',
          'height': '32px',
          'padding': '5px',
          'margin': '0px'
        };

        // List element styles:
        scope.ulStyle = {
          'list-style-type': 'none',
          'padding': '0',
          'margin': '0',
          'display': 'none',
          'position': 'absolute',
          'top': '32px',
          'background-color': '#FFFFFF',
          'overflow-y': 'auto',
          'border-left': '1px solid '+borderColor,
          'border-bottom': '1px solid '+borderColor,
          'border-right': '1px solid '+borderColor,
          'z-index': 10
        };

        // List items styles:
        scope.liStyle = {
          'display': 'block',
          'padding': '5px',
          'cursor': 'pointer',
          'box-sizing': 'border-box'
        }
      }

      // --------------------------------------------------------- //
      //                          FUNCTIONS                        //
      // --------------------------------------------------------- //
      /**
       * @function selectItem
       * @description Copy data from selected list item to the model.
       * @param {Object} event Click event used to prevent bubbling.
       * @param {string} item  Text to be copied to the model.
       */
      function selectItem (event, item) {
        event.stopPropagation();
        scope.currentItem = item;
        elem.find('ul').css('display', 'none');
      }

      /**
       * @function showList
       * @description Show ul DOM element containing the list.
       * @param {Object} event Click event used to prevent bubbling.
       */
      function showList (event) {
        event.stopPropagation();
        var maxHeight = $window.innerHeight - event.target.getBoundingClientRect().top - 40;
        var ul = elem.find('ul');
        ul.css('max-height',  maxHeight + 'px')
        .css('display', 'block');
        scope.liStyle.width = event.target.clientWidth + 'px';
      }

      /**
       * @function hideList
       * @description Hide ul DOM element containing the list.
       * @param {Object} event Click event used to prevent bubbling.
       */
      function hideList (event) {
        event.stopPropagation();
        elem.find('ul').css('display', 'none');
      }

      /**
       * @function highlightItem
       * @description Highlight hovered list item.
       * @param {Object} event Mouseover event used to prevent bubbling.
       * @param {Number} index Used to locate current list item in the DOM tree.
       */
      function highlightItem (event) {
        event.stopPropagation();
        angular.element(event.currentTarget).css({
          'background-color': borderColor
        });
      }

      /**
       * @function clearHighlightedItem
       * @description Remove item highlight on mouseleave.
       * @param {Object} event Mouseleave event used to prevent bubbling.
       */
      function clearHighlightedItem (event) {
        event.stopPropagation();
        angular.element(event.currentTarget).css({
          'background-color': 'transparent'
        });
      }

      // --------------------------------------------------------- //
      //                           EVENTS                          //
      // --------------------------------------------------------- //
      // Bind click event to the document to hide list:
      domReady(function () {
        document.on('click', function (event) {
          var contains = false;
          if (window.jQuery) {
            contains = window.jQuery.contains(elem, event.target);
          } else {
            contains = elem.contains(event.target);
          }
          if (!contains) {
            scope.hideList(event);
          }
        })
      })

      // Remove document click event on destroy:
      elem.on('$destroy', function () {
        document.off('click');
      });
    },
    template:
    '
'+
      '<input type="text" '+
             'class="ng-datalist-input {{inputClass}}" '+
             'placeholder="{{placeholder}}" '+
             'ng-required="fieldRequired" '+
             'ng-model="currentItem" '+
             'ng-click="showList($event)" '+
             'ng-style="inputStyle" '+
             'ng-keydown="($event.keyCode == 13 || '+
                           '$event.keyCode == 9) && '+
                           'hideList($event)">'+
      '
'+
        '
{{ item }}
'+
      '
'+
    '
'
  }
}
<|endoftext|>


<commit_before>"use strict";

const Course = require('course');

// IO proxies
const ioutils = require('ioutils');
const json_io = ioutils.json_io;
const fs_io = ioutils.fs_io;
const http_io = ioutils.http_io;

// Utilities
const utils = require('utils');
const html2document = utils.html2document;
const html2text = utils.html2text;

// The Catalog

var Catalog = function(depts, courses, term) {
	// Index courses into the catalog object
	this.courses = {};
	this.sections = {};
	this.term = term;
	for (var dept in depts) {
		this.courses[dept] = {name:depts[dept]};
	}
	courses.forEach((course) => {
		// Index courses by code
		let dept = course.dept;
		if (!this.courses[dept]) {
			console.warn(`Dept ${dept} not indexed!`);
			this.courses[dept] = {name: dept};
		}
		this.courses[dept][course.number] = course;

		// Index sections by CRN
		for (var type in course.sections) {
			course.sections[type].forEach((section) => {
				this.sections[section.crn] = section;
				section.course = course;
			});
		}
	});

	this.fetchIO = new http_io("https://courses.illinois.edu");

	return this;
};

Catalog.prototype.getCourse = function(code) {
	var code = Catalog.parseCourseCode(code);
	if (!code || !this.courses[code.dept] || !this.courses[code.dept][code.number]) {
		return null;
	}
	return this.courses[code.dept][code.number];
}

Catalog.prototype.update = function(code) {
	return new Promise((resolve, reject) => {
		code = Catalog.parseCourseCode(code);
		if (!code) {
			reject("Invalid course code");
			return;
		}
		// TODO: embed base urls into data
		Course.fromURL("/schedule/"+this.term+"/"+code.dept+"/"+code.number, this.fetchIO).then(((course) => {
			var oldsections = this.courses[code.dept][code.number].sections;
			var oldcrns = [];
			for (var type in oldsections) {
				oldsections[type].forEach((section) => {
					oldcrns.push(section.crn);
				});
			}

			this.courses[code.dept][code.number] = course;
			if (this.storage) {
				this.storage.setItem(`${code.dept}_${code.number}`, JSON.stringify(course));
			}

			var newcrns = [];
			for (var type in course.sections) {
				course.sections[type].forEach((section) => {
					var idx = oldcrns.indexOf(section.crn);
					if (idx == -1) {
						newcrns.push(section.crn);
					} else {
						oldcrns.splice(idx, 1);
					}
					this.sections[section.crn] = section;
					section.course = course;
				});
			}
			resolve({course: course, added: newcrns, removed: oldcrns});
		}).bind(this), (err) => {
			console.error(err);
			reject(err);
		});
	});
}

// Dump to filesystem/localstorage
Catalog.prototype.save = function(storage) {
	if (!storage) {
		if (!this.storage) {
			return false;
		}
		storage = this.storage;
	}
	let index = [], dept_index = {};
	for (var dept_code in this.courses) {
		let dept = this.courses[dept_code];
		for (var idx in dept) {
			if (idx == 'name') {
				dept_index[dept_code] = dept[idx];
			} else {
				let course = dept[idx], filename = `${dept_code}_${course.number}`;
				index.push(filename);
				storage.setItem(filename, JSON.stringify(course));
			}
		}
	}
	storage.setItem("index", JSON.stringify(index));
	storage.setItem("depts", JSON.stringify(dept_index));
	storage.setItem("meta", JSON.stringify({term: this.term}));
}

// Online-fetch utilities
let getTerm = function(term, io, cb) {
	return new Promise((resolve, reject) => {
		io.getItem('schedule/'+term).then((val) => {
			let table = html2document(val).querySelector("table#term-dt tbody");
			if (!table) {
				throw `Cannot get dept list for term ${term}`;
			}

			var depts = {}, dept_list = [], courses = [], ptr = 0;

			var dept_promise = Promise.resolve();

			table.querySelectorAll("tr").forEach((dept) => {
				let tds = dept.querySelectorAll('td');
				if (tds.length != 2) {
					if (cb.console)
					var console = cb.console;
					console.warn(`Unexpected td length for ${dept}`);
					return;
				}
				let	dept_code = tds[0].innerText.trim().toUpperCase(),
					dept_name = tds[1].innerText.trim(),
					dept_link = dept.querySelector('a').getAttribute('href');
				if (!dept_link) {
					if (cb.console)
						var console = cb.console;
					console.warn(`No link to ${dept_code}, skipping...`);
					return
				}
				depts[dept_code] = dept_name;
				dept_list.push({dept_name, dept_link});

				dept_promise = dept_promise.then(() => {
					if (cb) cb.console.log("Loading courses for "+dept_list[ptr].dept_name+"...");
					return getCoursesForDept(dept_list[ptr].dept_link, io);
				}).then((val) => {
					courses = courses.concat(val);
					ptr++;
					if(cb) cb.completeOne();
				}, (err) => {
					if (cb.console)
						var console = cb.console;
					console.warn(`Course fetch failed for ${dept_list[ptr].dept_name}`);
					console.warn(err);
					ptr++;
				});
			});
			if(cb) cb.setTaskCount(dept_list.length);

			dept_promise.then(() => {
				resolve({courses, depts});
			});
		}).catch((err) => {
			reject(err);
		});
	});
};

let getCoursesForDept = function(url, io) {
	return new Promise((resolve, reject) => {
		io.getItem(url).then((val) => {
			let table = html2document(val).querySelector('table#default-dt tbody');
			// var q = [[],[],[],[]], ptr = 0; // 4 Concurrent connections
			// var promises = [Promise.resolve(), Promise.resolve(), Promise.resolve(), Promise.resolve()];
			// q.io = io;
			var courses = [];
			table.querySelectorAll("tr").forEach((trow) => {
				var code, title;
				[code, title] = trow.querySelectorAll("td");
				code = code.innerText.trim();
				title = title.innerText.trim();
				courses.push(Course.templateFromCode(code, title));
			});
			resolve(courses);
			/*
			table.querySelectorAll('a').forEach((item) => {
				q[ptr].push(item.getAttribute('href'));

				promises[ptr] = promises[ptr].then( ( (i)=>{
					return Course.fromURL(q[i].pop(), io);
				} ).bind(this, ptr) );
				promises[ptr] = promises[ptr].then((fetched_course) => {
					courses.push(fetched_course);
				}, (err) => {
					console.warn("Cannot process course");
					console.warn(err);
				});

				++ptr;
				ptr%=4;
			});
			Promise.all(promises).then(() => {
				// console.log(`Fetched ${courses.length} courses for ${url}`);
				resolve(courses);
			});
			*/
		});
	});
}

// Initialization class methods

Catalog.fromTerm = function(term, baseURL, cb) {
	if (baseURL) {
		var io = new http_io(baseURL);
	} else {
		var io = new http_io("https://courses.illinois.edu");
	}
	if (!term) {
		term = "DEFAULT/DEFAULT";
	}
	return new Promise((resolve, reject) => {
		getTerm(term, io, cb).then((val) => {
			try {
				var catalog = new Catalog(val.depts, val.courses, term);
				// catalog.resolveDependencies();
				resolve(catalog);
			} catch(e) {
				reject(e);
			}
		}, (err) => {
			reject(err);
		});
	});
};

Catalog.fromStorage = function(storage) {
	if (!storage) {
		throw "Storage object unavailable";
	}
	let index = JSON.parse(storage.getItem('index'));
	let depts = JSON.parse(storage.getItem('depts'));
	let meta = JSON.parse(storage.getItem('meta'));
	var courses = [];
	index.forEach((file) => {
		let data = JSON.parse(storage.getItem(file));
		courses.push(new Course(data));
	});

	let catalog = new Catalog(depts, courses, meta.term);
	catalog.storage = storage;
	return catalog;
}

Catalog.fromLocalStorage = Catalog.fromStorage.bind({}, window.localStorage);

Catalog.fromDirectory = function(dirname) {
	return Catalog.fromStorage(new fs_io(dirname));
}

// Utility methods

Catalog.parseCourseCode = function(courseid) {
	try {
		var number = parseInt(/\d+/.exec(courseid)[0]);
		if (number < 100) {
			throw "Course number too low";
		}
		var dept = /[A-Za-z]*/.exec(courseid)[0].toUpperCase();
		return {dept, number};
	} catch(e) {
		return null;
	}
}

Catalog.getDefaultTerm = function() {
	return Promise.resolve().then(() => {
		var io = new http_io("https://courses.illinois.edu/schedule");
		return io.getItem("DEFAULT/DEFAULT").then((data) => {
			var doc = html2document(data);
			var term = doc.querySelector("h1").innerText;
			term = term.trim().toLowerCase();
			return term.replace(/(\w+) (\d+)/, "$2/$1");
		});
	});
}

module.exports = Catalog;
window.Catalog = Catalog;
<commit_msg>Fix update message<commit_after>"use strict";

const Course = require('course');

// IO proxies
const ioutils = require('ioutils');
const json_io = ioutils.json_io;
const fs_io = ioutils.fs_io;
const http_io = ioutils.http_io;

// Utilities
const utils = require('utils');
const html2document = utils.html2document;
const html2text = utils.html2text;

// The Catalog

var Catalog = function(depts, courses, term) {
	// Index courses into the catalog object
	this.courses = {};
	this.sections = {};
	this.term = term;
	for (var dept in depts) {
		this.courses[dept] = {name:depts[dept]};
	}
	courses.forEach((course) => {
		// Index courses by code
		let dept = course.dept;
		if (!this.courses[dept]) {
			console.warn(`Dept ${dept} not indexed!`);
			this.courses[dept] = {name: dept};
		}
		this.courses[dept][course.number] = course;

		// Index sections by CRN
		for (var type in course.sections) {
			course.sections[type].forEach((section) => {
				this.sections[section.crn] = section;
				section.course = course;
			});
		}
	});

	this.fetchIO = new http_io("https://courses.illinois.edu");

	return this;
};

Catalog.prototype.getCourse = function(code) {
	var code = Catalog.parseCourseCode(code);
	if (!code || !this.courses[code.dept] || !this.courses[code.dept][code.number]) {
		return null;
	}
	return this.courses[code.dept][code.number];
}

Catalog.prototype.update = function(code) {
	return new Promise((resolve, reject) => {
		code = Catalog.parseCourseCode(code);
		if (!code) {
			reject("Invalid course code");
			return;
		}
		// TODO: embed base urls into data
		Course.fromURL("/schedule/"+this.term+"/"+code.dept+"/"+code.number, this.fetchIO).then(((course) => {
			var oldsections = this.courses[code.dept][code.number].sections;
			var oldcrns = [];
			for (var type in oldsections) {
				oldsections[type].forEach((section) => {
					oldcrns.push(section.crn);
				});
			}

			this.courses[code.dept][code.number] = course;
			if (this.storage) {
				this.storage.setItem(`${code.dept}_${code.number}`, JSON.stringify(course));
			}

			var newcrns = [];
			if (oldcrns.length != 0) {
				for (var type in course.sections) {
					course.sections[type].forEach((section) => {
						var idx = oldcrns.indexOf(section.crn);
						if (idx == -1) {
							newcrns.push(section.crn);
						} else {
							oldcrns.splice(idx, 1);
						}
						this.sections[section.crn] = section;
						section.course = course;
					});
				}
			}
			resolve({course: course, added: newcrns, removed: oldcrns});
		}).bind(this), (err) => {
			console.error(err);
			reject(err);
		});
	});
}

// Dump to filesystem/localstorage
Catalog.prototype.save = function(storage) {
	if (!storage) {
		if (!this.storage) {
			return false;
		}
		storage = this.storage;
	}
	let index = [], dept_index = {};
	for (var dept_code in this.courses) {
		let dept = this.courses[dept_code];
		for (var idx in dept) {
			if (idx == 'name') {
				dept_index[dept_code] = dept[idx];
			} else {
				let course = dept[idx], filename = `${dept_code}_${course.number}`;
				index.push(filename);
				storage.setItem(filename, JSON.stringify(course));
			}
		}
	}
	storage.setItem("index", JSON.stringify(index));
	storage.setItem("depts", JSON.stringify(dept_index));
	storage.setItem("meta", JSON.stringify({term: this.term}));
}

// Online-fetch utilities
let getTerm = function(term, io, cb) {
	return new Promise((resolve, reject) => {
		io.getItem('schedule/'+term).then((val) => {
			let table = html2document(val).querySelector("table#term-dt tbody");
			if (!table) {
				throw `Cannot get dept list for term ${term}`;
			}

			var depts = {}, dept_list = [], courses = [], ptr = 0;

			var dept_promise = Promise.resolve();

			table.querySelectorAll("tr").forEach((dept) => {
				let tds = dept.querySelectorAll('td');
				if (tds.length != 2) {
					if (cb.console)
					var console = cb.console;
					console.warn(`Unexpected td length for ${dept}`);
					return;
				}
				let	dept_code = tds[0].innerText.trim().toUpperCase(),
					dept_name = tds[1].innerText.trim(),
					dept_link = dept.querySelector('a').getAttribute('href');
				if (!dept_link) {
					if (cb.console)
						var console = cb.console;
					console.warn(`No link to ${dept_code}, skipping...`);
					return
				}
				depts[dept_code] = dept_name;
				dept_list.push({dept_name, dept_link});

				dept_promise = dept_promise.then(() => {
					if (cb) cb.console.log("Loading courses for "+dept_list[ptr].dept_name+"...");
					return getCoursesForDept(dept_list[ptr].dept_link, io);
				}).then((val) => {
					courses = courses.concat(val);
					ptr++;
					if(cb) cb.completeOne();
				}, (err) => {
					if (cb.console)
						var console = cb.console;
					console.warn(`Course fetch failed for ${dept_list[ptr].dept_name}`);
					console.warn(err);
					ptr++;
				});
			});
			if(cb) cb.setTaskCount(dept_list.length);

			dept_promise.then(() => {
				resolve({courses, depts});
			});
		}).catch((err) => {
			reject(err);
		});
	});
};

let getCoursesForDept = function(url, io) {
	return new Promise((resolve, reject) => {
		io.getItem(url).then((val) => {
			let table = html2document(val).querySelector('table#default-dt tbody');
			// var q = [[],[],[],[]], ptr = 0; // 4 Concurrent connections
			// var promises = [Promise.resolve(), Promise.resolve(), Promise.resolve(), Promise.resolve()];
			// q.io = io;
			var courses = [];
			table.querySelectorAll("tr").forEach((trow) => {
				var code, title;
				[code, title] = trow.querySelectorAll("td");
				code = code.innerText.trim();
				title = title.innerText.trim();
				courses.push(Course.templateFromCode(code, title));
			});
			resolve(courses);
			/*
			table.querySelectorAll('a').forEach((item) => {
				q[ptr].push(item.getAttribute('href'));

				promises[ptr] = promises[ptr].then( ( (i)=>{
					return Course.fromURL(q[i].pop(), io);
				} ).bind(this, ptr) );
				promises[ptr] = promises[ptr].then((fetched_course) => {
					courses.push(fetched_course);
				}, (err) => {
					console.warn("Cannot process course");
					console.warn(err);
				});

				++ptr;
				ptr%=4;
			});
			Promise.all(promises).then(() => {
				// console.log(`Fetched ${courses.length} courses for ${url}`);
				resolve(courses);
			});
			*/
		});
	});
}

// Initialization class methods

Catalog.fromTerm = function(term, baseURL, cb) {
	if (baseURL) {
		var io = new http_io(baseURL);
	} else {
		var io = new http_io("https://courses.illinois.edu");
	}
	if (!term) {
		term = "DEFAULT/DEFAULT";
	}
	return new Promise((resolve, reject) => {
		getTerm(term, io, cb).then((val) => {
			try {
				var catalog = new Catalog(val.depts, val.courses, term);
				// catalog.resolveDependencies();
				resolve(catalog);
			} catch(e) {
				reject(e);
			}
		}, (err) => {
			reject(err);
		});
	});
};

Catalog.fromStorage = function(storage) {
	if (!storage) {
		throw "Storage object unavailable";
	}
	let index = JSON.parse(storage.getItem('index'));
	let depts = JSON.parse(storage.getItem('depts'));
	let meta = JSON.parse(storage.getItem('meta'));
	var courses = [];
	index.forEach((file) => {
		let data = JSON.parse(storage.getItem(file));
		courses.push(new Course(data));
	});

	let catalog = new Catalog(depts, courses, meta.term);
	catalog.storage = storage;
	return catalog;
}

Catalog.fromLocalStorage = Catalog.fromStorage.bind({}, window.localStorage);

Catalog.fromDirectory = function(dirname) {
	return Catalog.fromStorage(new fs_io(dirname));
}

// Utility methods

Catalog.parseCourseCode = function(courseid) {
	try {
		var number = parseInt(/\d+/.exec(courseid)[0]);
		if (number < 100) {
			throw "Course number too low";
		}
		var dept = /[A-Za-z]*/.exec(courseid)[0].toUpperCase();
		return {dept, number};
	} catch(e) {
		return null;
	}
}

Catalog.getDefaultTerm = function() {
	return Promise.resolve().then(() => {
		var io = new http_io("https://courses.illinois.edu/schedule");
		return io.getItem("DEFAULT/DEFAULT").then((data) => {
			var doc = html2document(data);
			var term = doc.querySelector("h1").innerText;
			term = term.trim().toLowerCase();
			return term.replace(/(\w+) (\d+)/, "$2/$1");
		});
	});
}

module.exports = Catalog;
window.Catalog = Catalog;
<|endoftext|>