<commit_before>// Require React
React = require('react/addons');
var $ = require('jquery-browserify');
var Loader = require('react-loader');

// import material UI
import mui from 'material-ui';
let List = mui.List;
let Colors = mui.Styles.Colors;
let ThemeManager = mui.Styles.ThemeManager;
let LightRawTheme = mui.Styles.LightRawTheme;

// Dependent component
import Member from './member.es6.js'
import Search from './search.es6.js'
import NoContent from './no_content.es6.js'
import Pagination from './pagination.es6.js'
import EmptyList from './empty_list.es6.js'

// Define component
const MembersList = React.createClass({

  getInitialState () {
    return {
      members: [],
      rels: [],
      path: this.props.path,
      featured: this.props.featured,
      loaded: false,
      muiTheme: ThemeManager.getMuiTheme(LightRawTheme)
    };
  },

  childContextTypes: {
    muiTheme: React.PropTypes.object
  },

  componentWillMount() {
    let newMuiTheme = ThemeManager.modifyRawThemePalette(this.state.muiTheme, {
      accent1Color: Colors.deepOrange500
    });
    this.setState({muiTheme: newMuiTheme});
  },

  getChildContext() {
    return {
      muiTheme: this.state.muiTheme,
    };
  },

  componentDidMount() {
    if(this.isMounted()){
      var query = decodeURIComponent(document.location.search.replace('?', ''));
      var path = !query? this.state.path : this.state.path + '?' + query
      this._fetchMembers(path, {});
    }
  },

  setChecked(e, checked) {
    this.setState({loaded: false});
    this._fetchMembers(this.state.path, {hireable: checked});
  },

  render() {

    let containerStyle = {
      paddingTop: '50px'
    };

    let subHeaderStyles = {
      fontSize: '25px',
      marginBottom: '20px',
      padding: '0',
      display: 'inline-block',
      marginRight: '30px'
    };

    let checkboxStyles = {
      display: 'inline-block',
      width: 'auto',
      marginRight: '20px',
      marginTop: '5px',
      height: '20px',
      width: '50%'
    };

    return (

            <Search action={"/members"} />

        <Loader loaded={this.state.loaded}>
          {this.state.loaded && this.state.members.length > 0 ?
            <List subheader={this.state.featured? 'Featured members' : 'Result'} subheaderStyle={subHeaderStyles} className="container" style={containerStyle}>
            {this.state.members.map(member => (
              <Member member={member} key={member.id} meta={this.props.meta} />
            ))}
          </List> : <EmptyList />}
        </Loader>

        {this.state.rels.length > 0 && this.state.members.length > 0 ?
          <Pagination links={this.state.rels} />
          : <NoContent />
        }

    );
  },

  _fetchMembers(path, params) {
    // Setup cache false
    $.ajaxSetup({
      cache: false
    });

    // Get initial members
    $.getJSON(path, params, function(json, textStatus) {
      this.setState({
        members: json.members,
        rels: json.rels,
        loaded: true
      });

      // Pre fetch paginations
      setTimeout(function(){
        json.rels.map(function(link) {
          $.get('?' + decodeURIComponent(link.url), function(data) {
          }, "html");
        }.bind(this));
      }.bind(this), 1000);

    }.bind(this));
  }

});

module.exports = MembersList;
<commit_msg>Fix bug related to empty rels<commit_after>// Require React
React = require('react/addons');
var $ = require('jquery-browserify');
var Loader = require('react-loader');

// import material UI
import mui from 'material-ui';
let List = mui.List;
let Colors = mui.Styles.Colors;
let ThemeManager = mui.Styles.ThemeManager;
let LightRawTheme = mui.Styles.LightRawTheme;

// Dependent component
import Member from './member.es6.js'
import Search from './search.es6.js'
import NoContent from './no_content.es6.js'
import Pagination from './pagination.es6.js'
import EmptyList from './empty_list.es6.js'

// Define component
const MembersList = React.createClass({

  getInitialState () {
    return {
      members: [],
      rels: [],
      path: this.props.path,
      featured: this.props.featured,
      loaded: false,
      muiTheme: ThemeManager.getMuiTheme(LightRawTheme)
    };
  },

  childContextTypes: {
    muiTheme: React.PropTypes.object
  },

  componentWillMount() {
    let newMuiTheme = ThemeManager.modifyRawThemePalette(this.state.muiTheme, {
      accent1Color: Colors.deepOrange500
    });
    this.setState({muiTheme: newMuiTheme});
  },

  getChildContext() {
    return {
      muiTheme: this.state.muiTheme,
    };
  },

  componentDidMount() {
    if(this.isMounted()){
      var query = decodeURIComponent(document.location.search.replace('?', ''));
      var path = !query? this.state.path : this.state.path + '?' + query
      this._fetchMembers(path, {});
    }
  },

  setChecked(e, checked) {
    this.setState({loaded: false});
    this._fetchMembers(this.state.path, {hireable: checked});
  },

  render() {

    let containerStyle = {
      paddingTop: '50px'
    };

    let subHeaderStyles = {
      fontSize: '25px',
      marginBottom: '20px',
      padding: '0',
      display: 'inline-block',
      marginRight: '30px'
    };

    let checkboxStyles = {
      display: 'inline-block',
      width: 'auto',
      marginRight: '20px',
      marginTop: '5px',
      height: '20px',
      width: '50%'
    };

    return (

            <Search action={"/members"} />

        <Loader loaded={this.state.loaded}>
          {this.state.loaded && this.state.members.length > 0 ?
            <List subheader={this.state.featured? 'Featured members' : 'Result'} subheaderStyle={subHeaderStyles} className="container" style={containerStyle}>
            {this.state.members.map(member => (
              <Member member={member} key={member.id} meta={this.props.meta} />
            ))}
          </List> : <EmptyList />}
        </Loader>

        {this.state.rels != null && this.state.members.length > 0 ?
          <Pagination links={this.state.rels} />
          : <NoContent />
        }

    );
  },

  _fetchMembers(path, params) {
    // Setup cache false
    $.ajaxSetup({
      cache: false
    });

    // Get initial members
    $.getJSON(path, params, function(json, textStatus) {
      this.setState({
        members: json.members,
        rels: json.rels,
        loaded: true
      });

      // Pre fetch paginations
      if(json.rels != null) {
        setTimeout(function(){
          json.rels.map(function(link) {
            $.get('?' + decodeURIComponent(link.url), function(data) {
            }, "html");
          }.bind(this));
        }.bind(this), 500);
      }

    }.bind(this));
  }

});

module.exports = MembersList;
<|endoftext|>


<commit_before>// Generated on 2014-06-10 using generator-angular 0.9.0-0
'use strict';

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

module.exports = function (grunt) {

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

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

  function connectAngularMiddleware (connect, options) {
    // based on http://stackoverflow.com/a/20553608/2486196
    var middlewares = [];

    // enable Angular's HTML5 mode
    middlewares.push(function (req, res, next) {
      var exists = false;
      var file = req.url.split('?')[0];

      for(var i = 0; i < options.base.length; i++) {
        if(require('fs').existsSync(options.base[i] + file)) {
          exists = true;
          break;
        }
      }

      if(!exists) {
        res.setHeader('Location', '/');
        req.url = '/';
      }

      next();
    });

    if (!Array.isArray(options.base)) {
      options.base = [options.base];
    }
    options.base.forEach(function(base) {
      // Serve static files.
      middlewares.push(connect.static(base));
    });

    return middlewares;
  }

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

    // Project settings
    yeoman: {
      // configurable paths
      app: require('./bower.json').appPath || 'app',
      dist: 'dist'
    },

    // Watches files for changes and runs tasks based on the changed files
    watch: {
      bower: {
        files: ['bower.json'],
        tasks: ['wiredep']
      },
      js: {
        files: ['<%= yeoman.app %>/components/{,*/}*.js'],
        tasks: ['newer:jshint:all'],
        options: {
          livereload: '<%= connect.options.livereload %>'
        }
      },
      jsTest: {
        files: ['test/spec/{,*/}*.js'],
        tasks: ['newer:jshint:test', 'karma']
      },
      compass: {
        files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
        tasks: ['compass:server', 'autoprefixer']
      },
      gruntfile: {
        files: ['Gruntfile.js']
      },
      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          '<%= yeoman.app %>/*.html',
          '<%= yeoman.app %>/components/{,*/}*.html',
          '.tmp/styles/{,*/}*.css',
          '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
        ]
      }
    },

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

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

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

    // Add vendor prefixed styles
    autoprefixer: {
      options: {
        browsers: ['last 1 version']
      },
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/styles/',
          src: '{,*/}*.css',
          dest: '.tmp/styles/'
        }]
      }
    },

    // Automatically inject Bower components into the app
    wiredep: {
      app: {
        src: ['<%= yeoman.app %>/index.html'],
        exclude: [ /handlebars/, /fira/ ],
        ignorePath: new RegExp('^<%= yeoman.app %>/')
      },
      sass: {
        src: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
        ignorePath: '<%= yeoman.app %>/bower_components/'
      }
    },

    // Compiles Sass to CSS and generates necessary files if requested
    compass: {
      options: {
        sassDir: '<%= yeoman.app %>/styles',
        cssDir: '.tmp/styles',
        generatedImagesDir: '.tmp/images/generated',
        imagesDir: '<%= yeoman.app %>/images',
        javascriptsDir: '<%= yeoman.app %>/scripts',
        fontsDir: '<%= yeoman.app %>/styles/fonts',
        importPath: '<%= yeoman.app %>/bower_components',
        httpImagesPath: '/images',
        httpGeneratedImagesPath: '/images/generated',
        httpFontsPath: '/styles/fonts',
        relativeAssets: false,
        assetCacheBuster: false,
        raw: 'Sass::Script::Number.precision = 10\n'
      },
      dist: {
        options: {
          generatedImagesDir: '<%= yeoman.dist %>/images/generated'
        }
      },
      server: {
        options: {
          debugInfo: true
        }
      }
    },

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

    // Reads HTML for usemin blocks to enable smart builds that automatically
    // concat, minify and revision files. Creates configurations in memory so
    // additional tasks can operate on them
    useminPrepare: {
      html: ['<%= yeoman.app %>/*.html', '<%= yeoman.app %>/components/{,*/}*.html'],
      options: {
        dest: '<%= yeoman.dist %>',
        flow: {
          html: {
            steps: {
              js: ['concat', 'uglifyjs'],
              css: ['cssmin']
            },
            post: {}
          }
        }
      }
    },

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

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

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

    svgmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/images',
          src: '{,*/}*.svg',
          dest: '<%= yeoman.dist %>/images'
        }]
      }
    },

    htmlmin: {
      dist: {
        options: {
          collapseWhitespace: true,
          conservativeCollapse: true,
          collapseBooleanAttributes: true,
          removeCommentsFromCDATA: true,
          removeOptionalTags: true
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: ['{,*/}*.html'],
          dest: '<%= yeoman.dist %>'
        }]
      }
    },

    // ngmin tries to make the code safe for minification automatically by
    // using the Angular long form for dependency injection. It doesn't work on
    // things like resolve or inject so those have to be done manually.
    ngmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/concat/scripts',
          src: '*.js',
          dest: '.tmp/concat/scripts'
        }]
      }
    },

    // Replace Google CDN references
    cdnify: {
      dist: {
        html: ['<%= yeoman.dist %>/*.html']
      }
    },

    nunjucks: {
      osftemplates: {
        baseDir: '<%= yeoman.app %>/bower_components/osf-export-templates/tpls',
        src: '**/*.tpl',
        dest: '.tmp/scripts/osf-templates.js',
        options: {
          name: function(filename) {
            var format = filename.substr(0, filename.length - 4);
            return 'osf_' + format;
          }
        }
      }
    },

    // Copies remaining files to places other tasks can use
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>',
          dest: '<%= yeoman.dist %>',
          src: [
            '*.{ico,png,txt}',
            '.htaccess',
            '*.html',
            'components/{,*/}*.html',
            'images/{,*/}*.{webp}',
            'fonts/**/*'
          ]
        }, {
          expand: true,
          cwd: '.tmp/images',
          dest: '<%= yeoman.dist %>/images',
          src: ['generated/*']
        }, {
          cwd: '<%= yeoman.app %>/bower_components/fira',
          dest: '<%= yeoman.dist %>/fonts/fira',
          expand: true,
          src: [ '**/*.{eot,otf,ttf,woff}', ]
        }]
      },
      fonts: {
        files: [{
          cwd: '<%= yeoman.app %>/bower_components/fira',
          dest: '.tmp/fonts/fira',
          expand: true,
          src: [ '**/*.{eot,otf,ttf,woff}', ]
        }]
      },
      styles: {
        expand: true,
        cwd: '<%= yeoman.app %>/styles',
        dest: '.tmp/styles/',
        src: '{,*/}*.css'
      }
    },

    // Run some tasks in parallel to speed up the build process
    concurrent: {
      server: [
        'compass:server'
      ],
      test: [
        'compass'
      ],
      dist: [
        'compass:dist',
        'imagemin',
        'svgmin'
      ]
    },

    // Test settings
    karma: {
      unit: {
        configFile: 'test/karma.conf.js',
        singleRun: true
      }
    }
  });

  grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'connect:dist:keepalive']);
    }

    grunt.task.run([
      'clean:server',
      'copy:fonts',
      'nunjucks:osftemplates',
      'wiredep',
      'concurrent:server',
      'autoprefixer',
      'connect:livereload',
      'watch'
    ]);
  });

  grunt.registerTask('test', [
    'clean:server',
    'concurrent:test',
    'autoprefixer',
    'connect:test',
    'karma'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'wiredep',
    'useminPrepare',
    'concurrent:dist',
    'autoprefixer',
    'concat',
    'ngmin',
    'nunjucks:osftemplates',
    'copy:dist',
    'cdnify',
    'cssmin',
    'uglify',
    'filerev',
    'usemin',
    'htmlmin'
  ]);

  grunt.registerTask('default', [
    'newer:jshint',
    'test',
    'build'
  ]);
};
<commit_msg>gruntfile compile all HTML files (not just one level)<commit_after>// Generated on 2014-06-10 using generator-angular 0.9.0-0
'use strict';

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

module.exports = function (grunt) {

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

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

  function connectAngularMiddleware (connect, options) {
    // based on http://stackoverflow.com/a/20553608/2486196
    var middlewares = [];

    // enable Angular's HTML5 mode
    middlewares.push(function (req, res, next) {
      var exists = false;
      var file = req.url.split('?')[0];

      for(var i = 0; i < options.base.length; i++) {
        if(require('fs').existsSync(options.base[i] + file)) {
          exists = true;
          break;
        }
      }

      if(!exists) {
        res.setHeader('Location', '/');
        req.url = '/';
      }

      next();
    });

    if (!Array.isArray(options.base)) {
      options.base = [options.base];
    }
    options.base.forEach(function(base) {
      // Serve static files.
      middlewares.push(connect.static(base));
    });

    return middlewares;
  }

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

    // Project settings
    yeoman: {
      // configurable paths
      app: require('./bower.json').appPath || 'app',
      dist: 'dist'
    },

    // Watches files for changes and runs tasks based on the changed files
    watch: {
      bower: {
        files: ['bower.json'],
        tasks: ['wiredep']
      },
      js: {
        files: ['<%= yeoman.app %>/components/**/*.js'],
        tasks: ['newer:jshint:all'],
        options: {
          livereload: '<%= connect.options.livereload %>'
        }
      },
      jsTest: {
        files: ['test/spec/{,*/}*.js'],
        tasks: ['newer:jshint:test', 'karma']
      },
      compass: {
        files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
        tasks: ['compass:server', 'autoprefixer']
      },
      gruntfile: {
        files: ['Gruntfile.js']
      },
      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          '<%= yeoman.app %>/*.html',
          '<%= yeoman.app %>/components/**/*.html',
          '.tmp/styles/{,*/}*.css',
          '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
        ]
      }
    },

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

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

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

    // Add vendor prefixed styles
    autoprefixer: {
      options: {
        browsers: ['last 1 version']
      },
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/styles/',
          src: '{,*/}*.css',
          dest: '.tmp/styles/'
        }]
      }
    },

    // Automatically inject Bower components into the app
    wiredep: {
      app: {
        src: ['<%= yeoman.app %>/index.html'],
        exclude: [ /handlebars/, /fira/ ],
        ignorePath: new RegExp('^<%= yeoman.app %>/')
      },
      sass: {
        src: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
        ignorePath: '<%= yeoman.app %>/bower_components/'
      }
    },

    // Compiles Sass to CSS and generates necessary files if requested
    compass: {
      options: {
        sassDir: '<%= yeoman.app %>/styles',
        cssDir: '.tmp/styles',
        generatedImagesDir: '.tmp/images/generated',
        imagesDir: '<%= yeoman.app %>/images',
        javascriptsDir: '<%= yeoman.app %>/scripts',
        fontsDir: '<%= yeoman.app %>/styles/fonts',
        importPath: '<%= yeoman.app %>/bower_components',
        httpImagesPath: '/images',
        httpGeneratedImagesPath: '/images/generated',
        httpFontsPath: '/styles/fonts',
        relativeAssets: false,
        assetCacheBuster: false,
        raw: 'Sass::Script::Number.precision = 10\n'
      },
      dist: {
        options: {
          generatedImagesDir: '<%= yeoman.dist %>/images/generated'
        }
      },
      server: {
        options: {
          debugInfo: true
        }
      }
    },

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

    // Reads HTML for usemin blocks to enable smart builds that automatically
    // concat, minify and revision files. Creates configurations in memory so
    // additional tasks can operate on them
    useminPrepare: {
      html: ['<%= yeoman.app %>/*.html', '<%= yeoman.app %>/components/**/*.html'],
      options: {
        dest: '<%= yeoman.dist %>',
        flow: {
          html: {
            steps: {
              js: ['concat', 'uglifyjs'],
              css: ['cssmin']
            },
            post: {}
          }
        }
      }
    },

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

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

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

    svgmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/images',
          src: '{,*/}*.svg',
          dest: '<%= yeoman.dist %>/images'
        }]
      }
    },

    htmlmin: {
      dist: {
        options: {
          collapseWhitespace: true,
          conservativeCollapse: true,
          collapseBooleanAttributes: true,
          removeCommentsFromCDATA: true,
          removeOptionalTags: true
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: ['{,*/}*.html'],
          dest: '<%= yeoman.dist %>'
        }]
      }
    },

    // ngmin tries to make the code safe for minification automatically by
    // using the Angular long form for dependency injection. It doesn't work on
    // things like resolve or inject so those have to be done manually.
    ngmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/concat/scripts',
          src: '*.js',
          dest: '.tmp/concat/scripts'
        }]
      }
    },

    // Replace Google CDN references
    cdnify: {
      dist: {
        html: ['<%= yeoman.dist %>/*.html']
      }
    },

    nunjucks: {
      osftemplates: {
        baseDir: '<%= yeoman.app %>/bower_components/osf-export-templates/tpls',
        src: '**/*.tpl',
        dest: '.tmp/scripts/osf-templates.js',
        options: {
          name: function(filename) {
            var format = filename.substr(0, filename.length - 4);
            return 'osf_' + format;
          }
        }
      }
    },

    // Copies remaining files to places other tasks can use
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>',
          dest: '<%= yeoman.dist %>',
          src: [
            '*.{ico,png,txt}',
            '.htaccess',
            '*.html',
            'components/**/*.html',
            'images/{,*/}*.{webp}',
            'fonts/**/*'
          ]
        }, {
          expand: true,
          cwd: '.tmp/images',
          dest: '<%= yeoman.dist %>/images',
          src: ['generated/*']
        }, {
          cwd: '<%= yeoman.app %>/bower_components/fira',
          dest: '<%= yeoman.dist %>/fonts/fira',
          expand: true,
          src: [ '**/*.{eot,otf,ttf,woff}', ]
        }]
      },
      fonts: {
        files: [{
          cwd: '<%= yeoman.app %>/bower_components/fira',
          dest: '.tmp/fonts/fira',
          expand: true,
          src: [ '**/*.{eot,otf,ttf,woff}', ]
        }]
      },
      styles: {
        expand: true,
        cwd: '<%= yeoman.app %>/styles',
        dest: '.tmp/styles/',
        src: '{,*/}*.css'
      }
    },

    // Run some tasks in parallel to speed up the build process
    concurrent: {
      server: [
        'compass:server'
      ],
      test: [
        'compass'
      ],
      dist: [
        'compass:dist',
        'imagemin',
        'svgmin'
      ]
    },

    // Test settings
    karma: {
      unit: {
        configFile: 'test/karma.conf.js',
        singleRun: true
      }
    }
  });

  grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'connect:dist:keepalive']);
    }

    grunt.task.run([
      'clean:server',
      'copy:fonts',
      'nunjucks:osftemplates',
      'wiredep',
      'concurrent:server',
      'autoprefixer',
      'connect:livereload',
      'watch'
    ]);
  });

  grunt.registerTask('test', [
    'clean:server',
    'concurrent:test',
    'autoprefixer',
    'connect:test',
    'karma'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'wiredep',
    'useminPrepare',
    'concurrent:dist',
    'autoprefixer',
    'concat',
    'ngmin',
    'nunjucks:osftemplates',
    'copy:dist',
    'cdnify',
    'cssmin',
    'uglify',
    'filerev',
    'usemin',
    'htmlmin'
  ]);

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


<commit_before>describe("Employees of <XYZ> Company:", function () {
    describe('Tax deducted for Indian Employees, ', function () {
        beforeEach(function () {
            this.myTaxableIncome = new TaxIndiaEmp();
        });
        afterEach(function () {
            this.myTaxableIncome = undefined;
        });
        it('Currency should be used INR', function () {
            var myCurrency = new Currency('INDIA');
            expect(myCurrency.currency).toBe('INR');
        });
        it('Should be duducted 10% if Gross Income is between RS 250,000/- AND RS 500,000/-', function () {
            //Let's assume the taxable income is RS 300,000/-
            this.myTaxableIncome.setIncome(300000);
            expect(this.myTaxableIncome.calculateTDS()).toEqual(5000);
        });
        it('Should be deducted 20% if Gross Income is between RS 500,000/- and RS 1,000,000/-', function () {
            //Let's assume the taxable income is RS 700,000/-
            this.myTaxableIncome.setIncome(700000);
            expect(this.myTaxableIncome.calculateTDS()).toEqual(40000);
        });
        it('Should be deducted 30% if Gross Income is >RS 10,000,00/-', function () {
            this.myTaxableIncome.setIncome(1300000);
            expect(this.myTaxableIncome.calculateTDS()).toEqual(90000);
        });
    });
    describe('Tax deducted for United Kingdom Employees', function () {
        it('Currency should be used GBP (Pound, UK£)', function () {
            var myCurrency = new Currency('UK');
            expect(myCurrency.currency).toBe('UK£');
        });
    });
    describe('Tax deducted for United States Employees', function () {
        it('Currency should be used USD (US$)', function () {
            var myCurrency = new Currency('US');
            expect(myCurrency.currency).toBe('US$');
        });
    });
});<commit_msg>refactor spec<commit_after>describe("Employees of <XYZ> Company:", function () {
    describe('TAX/TDS Currency', function () {
        var index = 0;
        var myRegion, myCurrency;
        beforeEach(function () {
            myRegion = ['INDIA', 'UK', 'US'];
            myCurrency = new Currency(myRegion[index]);
        });
        afterEach(function () {
            index += 1;
        });
        //Scenario -1
        it('Currency should be used INR', function () {
            expect(myCurrency.currency).toBe('INR');
        });
        //Scenario -2
        it('Currency should be used GBP (Pound, UK£)', function () {
            expect(myCurrency.currency).toBe('UK£');
        });
        //Scenario -3
        it('Currency should be used USD (US$)', function () {
            expect(myCurrency.currency).toBe('US$');
        });
    });
    describe('TAX/TDS', function () {
        describe('Tax deducted for Indian Employees, ', function () {
            var index = 0;
            var grossTaxableIncome = [300000, 700000, 1300000];
            var myTaxableIncome;
            beforeEach(function () {
                myTaxableIncome = new TaxIndiaEmp();
                myTaxableIncome.setIncome(grossTaxableIncome[index]);
            });
            afterEach(function () {
                index += 1;
            });

            //Scenario -4
            it('Should be duducted 10% if Gross Income is between RS 250,000/- AND RS 500,000/-', function () {
                //Let's assume the taxable income is RS 300,000/-
                expect(myTaxableIncome.calculateTDS()).toEqual(5000);
            });
            //Scenario -5
            it('Should be deducted 20% if Gross Income is between RS 500,000/- and RS 1,000,000/-', function () {
                //Let's assume the taxable income is RS 700,000/-
                expect(myTaxableIncome.calculateTDS()).toEqual(40000);
            });
            //Scenario -6
            it('Should be deducted 30% if Gross Income is >RS 10,000,00/-', function () {
                expect(myTaxableIncome.calculateTDS()).toEqual(90000);
            });
        });
        describe('Tax deducted for United Kingdom Employees', function () {

            xit('Should be deducted 20% if Gross Annual Income is between £10,000/- and £32,000', function () {

            });
        });
        describe('Tax deducted for United States Employees', function () {
            xit('Should be deducted 35% of Gross Taxable Income if employee status is SINGLE', function () {

            });
            xit('Should be deducted 30% of Gross Taxable Income if employee status is MARRIED', function () {

            });
        });
    });
});<|endoftext|>


<commit_before>/**
 * @file TableExamples.js
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, Fragment, createRef} from 'react';

// Components
import Table from 'src/Table';
import Switcher from 'src/Switcher';
import IconButton from 'src/IconButton';
import Widget from 'src/Widget';
import WidgetHeader from 'src/WidgetHeader';
import CircularLoading from 'src/CircularLoading';
import RaisedButton from 'src/RaisedButton';
import MaterialTextField from 'src/MaterialTextField';
import PropTypeDescTable from 'components/PropTypeDescTable';

// Statics
import doc from 'assets/propTypes/Table.json';

// Vendors
import classNames from 'classnames';
import round from 'lodash/round';
import Util from 'vendors/Util';

// Styles
import 'scss/containers/app/modules/layout/TableExamples.scss';

const LOADING_SYMBOL = Symbol('LOADING_SYMBOL');

class TableExamples extends Component {

    constructor(props) {

        super(props);

        this.tableRef = createRef();

        this.state = {
            data: this.generateData(),
            sorting: null,
            filter: '',
            headVisible: true,
            footVisible: true
        };

        this.columns = [{
            headRenderer: 'ID',
            bodyRenderer: rowDate => rowDate[LOADING_SYMBOL] ?
                <CircularLoading/> : rowDate.id,
            footRenderer: 'Total',
            sortable: true,
            sortingProp: 'id'
        }, {
            width: 300,
            noWrap: true,
            headRenderer: 'Name',
            bodyRenderer: rowDate => rowDate.firstName && rowDate.lastName ?
                `${rowDate.firstName} ${rowDate.lastName}` : '',
            sortable: true,
            sortingProp: 'firstName'
        }, {
            align: Table.Align.RIGHT,
            noWrap: true,
            headRenderer: 'Age',
            bodyRenderer: rowDate => rowDate.age,
            footRenderer: this.state.data && this.state.data.length > 0 ? () =>
                    <Fragment>

Average

{this.state.data.reduce((a, b) => a + b.age, 0) / this.state.data.length}

                    </Fragment>
                :
                null,
            sortable: true,
            sortingProp: 'age'
        }, {
            headRenderer: 'Other Column',
            headAlign: Table.Align.CENTER,
            children: [{
                width: 100,
                headRenderer: 'Other Column 1',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 1` : ''
            }, {
                width: 100,
                headRenderer: 'Other Column 2',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 2` : ''
            }, {
                width: 100,
                headRenderer: 'Other Column 3',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 3` : ''
            }, {
                width: 100,
                headRenderer: 'Other Column 4',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 4` : ''
            }]
        }, {
            align: Table.Align.RIGHT,
            noWrap: true,
            headRenderer: 'Deposit',
            bodyRenderer: rowDate => rowDate.deposit ? `$${rowDate.deposit}` : '',
            footRenderer: this.state.data && this.state.data.length > 0 ? () =>
                    <Fragment>

Sum

${this.state.data.reduce((a, b) => round(a + b.deposit, 2), 0)}

                    </Fragment>
                :
                null,
            sortable: true,
            sortingProp: 'deposit'
        }, {
            width: 64,
            align: Table.Align.CENTER,
            headRenderer: 'Status',
            bodyRenderer: rowData => rowData[LOADING_SYMBOL] ?
                null
                :
                <Switcher style={{display: 'inline-block', verticalAlign: 'middle'}}
                          value={!rowData.disabled}
                          size="small"
                          onClick={e => e.stopPropagation()}/>
        }, {
            width: 56,
            align: Table.Align.CENTER,
            headRenderer: 'Action',
            bodyRenderer: rowData => rowData[LOADING_SYMBOL] ?
                null
                :
                <IconButton iconCls="fas fa-trash-alt"
                            onClick={() => this.deleteRow(rowData.id)}/>
        }];

        this.pageSizes = [{
            value: 10,
            text: '10 / page'
        }, {
            value: 20,
            text: '20 / page'
        }, {
            value: 30,
            text: '30 / page'
        }, {
            value: 40,
            text: '40 / page'
        }, {
            value: 50,
            text: '50 / page'
        }];

    }

    getFixedColumns = () => {
        return this.columns.map(column => {
            if (['ID', 'Name'].includes(column.headRenderer)) {
                return {
                    fixed: Table.Fixed.LEFT,
                    ...column
                };
            } else if (['Status', 'Action'].includes(column.headRenderer)) {
                return {
                    fixed: Table.Fixed.RIGHT,
                    ...column
                };
            }
            return column;
        });
    };

    generateData = (size = 100, base = '', expanded = true) => {

        let data = [];
        for (let i = 0; i < size; i++) {

            const id = `${base ? `${base}-` : ''}${i}`,
                item = {
                    id,
                    firstName: `firstName${id}`,
                    lastName: `lastName${id}`,
                    age: Math.floor(Math.random() * 100),
                    deposit: round(Math.random() * 1000000, 2),
                    other: 'Other Content'
                };

            if (expanded && id.split('-').pop() === '0') {
                item.children = [{
                    [LOADING_SYMBOL]: true,
                    disabled: true
                }];
            }

            data.push(item);

        }

        return data;

    };

    deleteRow = id => {

        const {data} = this.state,
            newData = data.filter(item => item.id !== id);

        this.setState({
            data: newData
        });

    };

    handleSortChange = sorting => {
        this.setState({
            sorting
        });
        console.log('Sort Change Value: ', sorting);
    };

    handlePaginationChange = ({page, pageSize}) => {
        console.log(`page: ${page}, pageSize: ${pageSize}`);
    };

    handleSelect = (rowData, rowIndex, value) => {
        console.log('Select Value: ', rowData);
    };

    handleDeselect = (rowData, rowIndex, value) => {
        console.log('Deselect Value: ', rowData);
    };

    handleSelectAll = value => {
        console.log('Select All Value: ', value);
    };

    handleSeselectAll = value => {
        console.log('Deselect All Value: ', value);
    };

    handleChange = value => {
        console.log('Changed Value: ', value);
    };

    handleExpand = rowData => {

        console.log('Expand: ', rowData);

        const {data} = this.state;

        if (!rowData || !data || !rowData.children[0][LOADING_SYMBOL]) {
            return;
        }

        setTimeout(() => {

            Util.postOrderTraverse({
                children: data
            }, node => {
                if (node && node.id === rowData.id) {
                    node.children = this.generateData(10, node.id);
                    return false;
                }
            });

            this.setState({
                data
            });

        }, 1000);

    };

    handleCollapse = rowData => {
        console.log('Collapse: ', rowData);
    };

    collapseAllRows = () => {
        this.tableRef && this.tableRef.current && this.tableRef.current.collapseAllRows();
    };

    toggleHead = () => {
        this.setState({
            headVisible: !this.state.headVisible
        });
    };

    toggleFoot = () => {
        this.setState({
            footVisible: !this.state.footVisible
        });
    };

    handleFilter = filter => {
        this.setState({
            filter
        });
    };

    filterData = (data = this.state.data) => {

        const {filter} = this.state;

        if (!filter || !data) {
            return data;
        }

        return data.filter(item => item && (
            (item.firstName && item.firstName.toUpperCase().includes(filter.toUpperCase()))
            ||
            (item.lastName && item.lastName.toUpperCase().includes(filter.toUpperCase()))
        ));

    };

    render() {

        const {data, sorting, filter, headVisible, footVisible} = this.state,
            filteredLoadingData = this.filterData(data);

        return (

Table

                    Table
                     are used to display data and to organize it.

Examples

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Normal"/>

A simple Table example.

                            <Table className="example-table"
                                   columns={this.columns}
                                   data={data}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Fix Head & Foot"/>

                                You can config isHeadFixed to fix the Head,
                                and config isFootFixed to fix the Foot.

                            <Table className="example-table"
                                   columns={this.columns}
                                   data={data}
                                   isHeadFixed={true}
                                   isFootFixed={true}
                                   scroll={{
                                       maxHeight: 320
                                   }}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Fix Columns"/>

                                You can config fixed in columns to fix the column
                                Left or Right.

                            <Table className="example-table"
                                   columns={this.getFixedColumns()}
                                   data={data}
                                   scroll={{
                                       width: 1200
                                   }}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Fix Head, Foot and Columns"/>

                                <RaisedButton className="action-button"
                                              value="Collapse All Rows"
                                              onClick={this.collapseAllRows}/>
                                <RaisedButton className="action-button"
                                              value="Toggle Table Head"
                                              onClick={this.toggleHead}/>
                                <RaisedButton className="action-button"
                                              value="Toggle Table Foot"
                                              onClick={this.toggleFoot}/>
                                <MaterialTextField className="filter"
                                                   label="Filter"
                                                   value={filter}
                                                   onChange={this.handleFilter}/>

                                {
                                    filteredLoadingData ?
                                        <Table ref={this.tableRef}
                                               className={classNames('example-table border-collapse', {
                                                   'head-hidden': !headVisible,
                                                   'foot-hidden': !footVisible || !filteredLoadingData || filteredLoadingData.length < 1
                                               })}
                                               data={filteredLoadingData}
                                               columns={this.getFixedColumns()}
                                               sorting={sorting}
                                               selectMode={Table.SelectMode.MULTI_SELECT}
                                               isHeadFixed={true}
                                               isFootFixed={true}
                                               isHeadHidden={!headVisible}
                                               isFootHidden={!footVisible || !filteredLoadingData || filteredLoadingData.length < 1}
                                               scroll={{
                                                   width: 1200,
                                                   height: filteredLoadingData && filteredLoadingData.length > 0 ? 320 : 0
                                               }}
                                               useFullPagination={true}
                                               paginationTotalRenderer={total =>
                                                   Self Defined Total: {total}
                                               }
                                               onSortChange={this.handleSortChange}
                                               onPaginationChange={this.handlePaginationChange}
                                               onExpand={this.handleExpand}
                                               onCollapse={this.handleCollapse}
                                               onChange={this.handleChange}
                                               onSelect={this.handleSelect}
                                               onSelectAll={this.handleSelectAll}
                                               onDeselect={this.handleDeselect}
                                               onDeselectAll={this.handleSeselectAll}/>
                                        :
                                        <CircularLoading className="loading-table-loading"/>
                                }

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Dynamic Render"/>

                                <Table ref={this.tableRef}
                                       className="example-table"
                                       data={this.generateData(1000)}
                                       columns={this.columns}
                                       sorting={sorting}
                                       selectMode={Table.SelectMode.MULTI_SELECT}
                                       isHeadFixed={true}
                                       isFootFixed={true}
                                       scroll={{width: 1200}}
                                       isPaginated={false}
                                       useDynamicRender={true}
                                       onSortChange={this.handleSortChange}
                                       onExpand={this.handleExpand}
                                       onCollapse={this.handleCollapse}
                                       onChange={this.handleChange}
                                       onSelect={this.handleSelect}
                                       onSelectAll={this.handleSelectAll}
                                       onDeselect={this.handleDeselect}
                                       onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Resize Column Width"/>

                            <Table className="example-table border-collapse"
                                   columns={this.columns}
                                   data={data}
                                   isColumnResizable={true}
                                   isLayoutFixed={true}
                                   scroll={{
                                       width: 1000
                                   }}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="No Data"/>

No Data Table example.

                </Widget>

Properties

                <PropTypeDescTable data={doc}/>

        );
    }
}

export default TableExamples;
<commit_msg>update TableExamples<commit_after>/**
 * @file TableExamples.js
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, Fragment, createRef} from 'react';

// Components
import Table from 'src/Table';
import Switcher from 'src/Switcher';
import IconButton from 'src/IconButton';
import Widget from 'src/Widget';
import WidgetHeader from 'src/WidgetHeader';
import CircularLoading from 'src/CircularLoading';
import RaisedButton from 'src/RaisedButton';
import MaterialTextField from 'src/MaterialTextField';
import PropTypeDescTable from 'components/PropTypeDescTable';

// Statics
import doc from 'assets/propTypes/Table.json';

// Vendors
import classNames from 'classnames';
import round from 'lodash/round';
import Util from 'vendors/Util';

// Styles
import 'scss/containers/app/modules/layout/TableExamples.scss';

const LOADING_SYMBOL = Symbol('LOADING_SYMBOL');

class TableExamples extends Component {

    constructor(props) {

        super(props);

        this.tableRef = createRef();

        this.state = {
            data: this.generateData(),
            sorting: null,
            filter: '',
            headVisible: true,
            footVisible: true
        };

        this.columns = [{
            headRenderer: 'ID',
            bodyRenderer: rowDate => rowDate[LOADING_SYMBOL] ?
                <CircularLoading/> : rowDate.id,
            footRenderer: 'Total',
            sortable: true,
            sortingProp: 'id'
        }, {
            width: 300,
            noWrap: true,
            headRenderer: 'Name',
            headTitle: 'Name',
            bodyRenderer: rowDate => rowDate.firstName && rowDate.lastName ?
                `${rowDate.firstName} ${rowDate.lastName}` : null,
            bodyTitle: rowDate => rowDate.firstName && rowDate.lastName ?
                `${rowDate.firstName} ${rowDate.lastName}` : null,
            sortable: true,
            sortingProp: 'firstName'
        }, {
            align: Table.Align.RIGHT,
            noWrap: true,
            headRenderer: 'Age',
            bodyRenderer: rowDate => rowDate.age,
            footRenderer: this.state.data && this.state.data.length > 0 ? () =>
                    <Fragment>

Average

{this.state.data.reduce((a, b) => a + b.age, 0) / this.state.data.length}

                    </Fragment>
                :
                null,
            sortable: true,
            sortingProp: 'age'
        }, {
            headRenderer: 'Other Column',
            headAlign: Table.Align.CENTER,
            children: [{
                width: 100,
                headRenderer: 'Other Column 1',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 1` : ''
            }, {
                width: 100,
                headRenderer: 'Other Column 2',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 2` : ''
            }, {
                width: 100,
                headRenderer: 'Other Column 3',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 3` : ''
            }, {
                width: 100,
                headRenderer: 'Other Column 4',
                bodyRenderer: rowDate => rowDate.other ? `${rowDate.other} 4` : ''
            }]
        }, {
            align: Table.Align.RIGHT,
            noWrap: true,
            headRenderer: 'Deposit',
            bodyRenderer: rowDate => rowDate.deposit ? `$${rowDate.deposit}` : '',
            footRenderer: this.state.data && this.state.data.length > 0 ? () =>
                    <Fragment>

Sum

${this.state.data.reduce((a, b) => round(a + b.deposit, 2), 0)}

                    </Fragment>
                :
                null,
            sortable: true,
            sortingProp: 'deposit'
        }, {
            width: 64,
            align: Table.Align.CENTER,
            headRenderer: 'Status',
            bodyRenderer: rowData => rowData[LOADING_SYMBOL] ?
                null
                :
                <Switcher style={{display: 'inline-block', verticalAlign: 'middle'}}
                          value={!rowData.disabled}
                          size="small"
                          onClick={e => e.stopPropagation()}/>
        }, {
            width: 56,
            align: Table.Align.CENTER,
            headRenderer: 'Action',
            bodyRenderer: rowData => rowData[LOADING_SYMBOL] ?
                null
                :
                <IconButton iconCls="fas fa-trash-alt"
                            onClick={() => this.deleteRow(rowData.id)}/>
        }];

        this.pageSizes = [{
            value: 10,
            text: '10 / page'
        }, {
            value: 20,
            text: '20 / page'
        }, {
            value: 30,
            text: '30 / page'
        }, {
            value: 40,
            text: '40 / page'
        }, {
            value: 50,
            text: '50 / page'
        }];

    }

    getFixedColumns = () => {
        return this.columns.map(column => {
            if (['ID', 'Name'].includes(column.headRenderer)) {
                return {
                    fixed: Table.Fixed.LEFT,
                    ...column
                };
            } else if (['Status', 'Action'].includes(column.headRenderer)) {
                return {
                    fixed: Table.Fixed.RIGHT,
                    ...column
                };
            }
            return column;
        });
    };

    generateData = (size = 100, base = '', expanded = true) => {

        let data = [];
        for (let i = 0; i < size; i++) {

            const id = `${base ? `${base}-` : ''}${i}`,
                item = {
                    id,
                    firstName: `firstName${id}`,
                    lastName: `lastName${id}`,
                    age: Math.floor(Math.random() * 100),
                    deposit: round(Math.random() * 1000000, 2),
                    other: 'Other Content'
                };

            if (expanded && id.split('-').pop() === '0') {
                item.children = [{
                    [LOADING_SYMBOL]: true,
                    disabled: true
                }];
            }

            data.push(item);

        }

        return data;

    };

    deleteRow = id => {

        const {data} = this.state,
            newData = data.filter(item => item.id !== id);

        this.setState({
            data: newData
        });

    };

    handleSortChange = sorting => {
        this.setState({
            sorting
        });
        console.log('Sort Change Value: ', sorting);
    };

    handlePaginationChange = ({page, pageSize}) => {
        console.log(`page: ${page}, pageSize: ${pageSize}`);
    };

    handleSelect = (rowData, rowIndex, value) => {
        console.log('Select Value: ', rowData);
    };

    handleDeselect = (rowData, rowIndex, value) => {
        console.log('Deselect Value: ', rowData);
    };

    handleSelectAll = value => {
        console.log('Select All Value: ', value);
    };

    handleSeselectAll = value => {
        console.log('Deselect All Value: ', value);
    };

    handleChange = value => {
        console.log('Changed Value: ', value);
    };

    handleExpand = rowData => {

        console.log('Expand: ', rowData);

        const {data} = this.state;

        if (!rowData || !data || !rowData.children[0][LOADING_SYMBOL]) {
            return;
        }

        setTimeout(() => {

            Util.postOrderTraverse({
                children: data
            }, node => {
                if (node && node.id === rowData.id) {
                    node.children = this.generateData(10, node.id);
                    return false;
                }
            });

            this.setState({
                data
            });

        }, 1000);

    };

    handleCollapse = rowData => {
        console.log('Collapse: ', rowData);
    };

    collapseAllRows = () => {
        this.tableRef && this.tableRef.current && this.tableRef.current.collapseAllRows();
    };

    toggleHead = () => {
        this.setState({
            headVisible: !this.state.headVisible
        });
    };

    toggleFoot = () => {
        this.setState({
            footVisible: !this.state.footVisible
        });
    };

    handleFilter = filter => {
        this.setState({
            filter
        });
    };

    filterData = (data = this.state.data) => {

        const {filter} = this.state;

        if (!filter || !data) {
            return data;
        }

        return data.filter(item => item && (
            (item.firstName && item.firstName.toUpperCase().includes(filter.toUpperCase()))
            ||
            (item.lastName && item.lastName.toUpperCase().includes(filter.toUpperCase()))
        ));

    };

    render() {

        const {data, sorting, filter, headVisible, footVisible} = this.state,
            filteredLoadingData = this.filterData(data);

        return (

Table

                    Table
                     are used to display data and to organize it.

Examples

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Normal"/>

A simple Table example.

                            <Table className="example-table"
                                   columns={this.columns}
                                   data={data}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Fix Head & Foot"/>

                                You can config isHeadFixed to fix the Head,
                                and config isFootFixed to fix the Foot.

                            <Table className="example-table"
                                   columns={this.columns}
                                   data={data}
                                   isHeadFixed={true}
                                   isFootFixed={true}
                                   scroll={{
                                       maxHeight: 320
                                   }}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Fix Columns"/>

                                You can config fixed in columns to fix the column
                                Left or Right.

                            <Table className="example-table"
                                   columns={this.getFixedColumns()}
                                   data={data}
                                   scroll={{
                                       width: 1200
                                   }}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Fix Head, Foot and Columns"/>

                                <RaisedButton className="action-button"
                                              value="Collapse All Rows"
                                              onClick={this.collapseAllRows}/>
                                <RaisedButton className="action-button"
                                              value="Toggle Table Head"
                                              onClick={this.toggleHead}/>
                                <RaisedButton className="action-button"
                                              value="Toggle Table Foot"
                                              onClick={this.toggleFoot}/>
                                <MaterialTextField className="filter"
                                                   label="Filter"
                                                   value={filter}
                                                   onChange={this.handleFilter}/>

                                {
                                    filteredLoadingData ?
                                        <Table ref={this.tableRef}
                                               className={classNames('example-table border-collapse', {
                                                   'head-hidden': !headVisible,
                                                   'foot-hidden': !footVisible || !filteredLoadingData || filteredLoadingData.length < 1
                                               })}
                                               data={filteredLoadingData}
                                               columns={this.getFixedColumns()}
                                               sorting={sorting}
                                               selectMode={Table.SelectMode.MULTI_SELECT}
                                               isHeadFixed={true}
                                               isFootFixed={true}
                                               isHeadHidden={!headVisible}
                                               isFootHidden={!footVisible || !filteredLoadingData || filteredLoadingData.length < 1}
                                               scroll={{
                                                   width: 1200,
                                                   height: filteredLoadingData && filteredLoadingData.length > 0 ? 320 : 0
                                               }}
                                               useFullPagination={true}
                                               paginationTotalRenderer={total =>
                                                   Self Defined Total: {total}
                                               }
                                               onSortChange={this.handleSortChange}
                                               onPaginationChange={this.handlePaginationChange}
                                               onExpand={this.handleExpand}
                                               onCollapse={this.handleCollapse}
                                               onChange={this.handleChange}
                                               onSelect={this.handleSelect}
                                               onSelectAll={this.handleSelectAll}
                                               onDeselect={this.handleDeselect}
                                               onDeselectAll={this.handleSeselectAll}/>
                                        :
                                        <CircularLoading className="loading-table-loading"/>
                                }

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Dynamic Render"/>

                                <Table ref={this.tableRef}
                                       className="example-table"
                                       data={this.generateData(1000)}
                                       columns={this.columns}
                                       sorting={sorting}
                                       selectMode={Table.SelectMode.MULTI_SELECT}
                                       isHeadFixed={true}
                                       isFootFixed={true}
                                       scroll={{width: 1200}}
                                       isPaginated={false}
                                       useDynamicRender={true}
                                       onSortChange={this.handleSortChange}
                                       onExpand={this.handleExpand}
                                       onCollapse={this.handleCollapse}
                                       onChange={this.handleChange}
                                       onSelect={this.handleSelect}
                                       onSelectAll={this.handleSelectAll}
                                       onDeselect={this.handleDeselect}
                                       onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="Resize Column Width"/>

                            <Table className="example-table border-collapse"
                                   columns={this.columns}
                                   data={data}
                                   isColumnResizable={true}
                                   isLayoutFixed={true}
                                   scroll={{
                                       width: 1000
                                   }}
                                   onSortChange={this.handleSortChange}
                                   onPaginationChange={this.handlePaginationChange}
                                   onExpand={this.handleExpand}
                                   onCollapse={this.handleCollapse}
                                   onChange={this.handleChange}
                                   onSelect={this.handleSelect}
                                   onSelectAll={this.handleSelectAll}
                                   onDeselect={this.handleDeselect}
                                   onDeselectAll={this.handleSeselectAll}/>

                </Widget>

                <Widget>

                    <WidgetHeader className="example-header"
                                  title="No Data"/>

No Data Table example.

                </Widget>

Properties

                <PropTypeDescTable data={doc}/>

        );
    }
}

export default TableExamples;
<|endoftext|>


<commit_before>/* DO NOT MODIFY */
const createTemplate = module.parent.createTemplate;
/* END OF DO NOT MODIFY */

const templatePackage = createTemplate`
{
  "name": "${args => args.appName}",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "gluestick start",
    "test": "gluestick test",
    "flow": "flow",
    "lint": "eslint src"
  },
  "dependencies": {
    "babel-loader": "7.0.0",
    "babel-plugin-transform-decorators-legacy": "1.3.4",
    "babel-plugin-transform-flow-strip-types": "6.22.0",
    "babel-polyfill": "6.23.0",
    "babel-preset-es2015": "6.24.1",
    "babel-preset-react": "6.24.1",
    "babel-preset-stage-0": "6.24.1",
    "css-loader": "0.28.1",
    "extract-text-webpack-plugin": "2.1.0",
    "file-loader": "0.11.1",
    ${args =>
      Object.keys(args.gluestickDependencies)
        .reverse()
        .reduce(
          (prev, key, i, arr) =>
            prev.concat(
              `"${key}": "${args.gluestickDependencies[key]}",${i ===
              arr.length - 1
                ? ''
                : '\n    '}`,
            ),
          '',
        )}
    "image-webpack-loader": "3.3.1",
    "node-sass": "4.5.1",
    "normalize.css": "^5.0.0",
    "optimize-css-assets-webpack-plugin": "1.3.1",
    "postcss-calc": "5.3.1",
    "postcss-custom-properties": "5.0.2",
    "postcss-loader": "1.3.3",
    "react": "16.4.1",
    "react-dom": "16.4.1",
    "react-helmet": "5.2.0",
    "react-hot-loader": "^3.0.0-beta.6",
    "react-redux": "5.0.4",
    "react-router": "3.2.0",
    "react-router-scroll": "0.4.2",
    "redux": "3.6.0",
    "redux-thunk": "2.2.0",
    "sass-loader": "6.0.3",
    "style-loader": "0.16.1",
    "url-loader": "0.5.8"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-eslint": "7.1.1",
    "babel-jest": "18.0.0",
    "babel-plugin-react-transform": "2.0.2",
    "enzyme": "3.3.0",
    "enzyme-adapter-react-16": "1.1.1",
    "eslint": "3.14.1",
    "eslint-plugin-react": "6.9.0",
    "flow-bin": "0.45.0",
    "flow-typed": "^2.0.0",
    "react-addons-test-utils": "15.4.2",
    "redbox-react": "1.3.3"
  },
  "jest": {
    "setupTestFrameworkScriptFile": "./src/__tests__/configureEnzyme.js"
  }
}
`;

module.exports = ({ gluestickDependencies, appName }) => ({
  entries: [
    {
      path: '/',
      filename: 'package.json',
      template: templatePackage,
      args: {
        gluestickDependencies,
        appName,
      },
    },
  ],
});
<commit_msg>update enzyme-react-adapter to 1.5.0 (#1210)<commit_after>/* DO NOT MODIFY */
const createTemplate = module.parent.createTemplate;
/* END OF DO NOT MODIFY */

const templatePackage = createTemplate`
{
  "name": "${args => args.appName}",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "gluestick start",
    "test": "gluestick test",
    "flow": "flow",
    "lint": "eslint src"
  },
  "dependencies": {
    "babel-loader": "7.0.0",
    "babel-plugin-transform-decorators-legacy": "1.3.4",
    "babel-plugin-transform-flow-strip-types": "6.22.0",
    "babel-polyfill": "6.23.0",
    "babel-preset-es2015": "6.24.1",
    "babel-preset-react": "6.24.1",
    "babel-preset-stage-0": "6.24.1",
    "css-loader": "0.28.1",
    "extract-text-webpack-plugin": "2.1.0",
    "file-loader": "0.11.1",
    ${args =>
      Object.keys(args.gluestickDependencies)
        .reverse()
        .reduce(
          (prev, key, i, arr) =>
            prev.concat(
              `"${key}": "${args.gluestickDependencies[key]}",${i ===
              arr.length - 1
                ? ''
                : '\n    '}`,
            ),
          '',
        )}
    "image-webpack-loader": "3.3.1",
    "node-sass": "4.5.1",
    "normalize.css": "^5.0.0",
    "optimize-css-assets-webpack-plugin": "1.3.1",
    "postcss-calc": "5.3.1",
    "postcss-custom-properties": "5.0.2",
    "postcss-loader": "1.3.3",
    "react": "16.4.1",
    "react-dom": "16.4.1",
    "react-helmet": "5.2.0",
    "react-hot-loader": "^3.0.0-beta.6",
    "react-redux": "5.0.4",
    "react-router": "3.2.0",
    "react-router-scroll": "0.4.2",
    "redux": "3.6.0",
    "redux-thunk": "2.2.0",
    "sass-loader": "6.0.3",
    "style-loader": "0.16.1",
    "url-loader": "0.5.8"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-eslint": "7.1.1",
    "babel-jest": "18.0.0",
    "babel-plugin-react-transform": "2.0.2",
    "enzyme": "3.3.0",
    "enzyme-adapter-react-16": "1.5.1",
    "eslint": "3.14.1",
    "eslint-plugin-react": "6.9.0",
    "flow-bin": "0.45.0",
    "flow-typed": "^2.0.0",
    "react-addons-test-utils": "15.4.2",
    "redbox-react": "1.3.3"
  },
  "jest": {
    "setupTestFrameworkScriptFile": "./src/__tests__/configureEnzyme.js"
  }
}
`;

module.exports = ({ gluestickDependencies, appName }) => ({
  entries: [
    {
      path: '/',
      filename: 'package.json',
      template: templatePackage,
      args: {
        gluestickDependencies,
        appName,
      },
    },
  ],
});
<|endoftext|>


<commit_before>hqDefine('users/js/filtered_download', [
    'jquery',
    'underscore',
    'hqwebapp/js/initial_page_data',
    'hqwebapp/js/widgets',      // role selection
    'locations/js/widgets',     // location search
    'hqwebapp/js/components.ko',    // select toggle widget
], function (
    $,
    _,
    initialPageData
) {
    function getFilters() {
        return {
            'role_id': $("#id_role_id").val(),
            'search_string': $("#id_search_string").val(),
            'location_id': $("[name=location_id]").val(),
            'domains': $("#id_domains").val(),
        };
    }

    function countUsers(currentFilters) {
        var countUsersUrl = initialPageData.get('count_users_url');
        $.get({
            url: countUsersUrl,
            data: currentFilters,
            success: function (data) {
                var count = data.count;
                var template = count === 1 ? gettext("Download <%- count %> user") : gettext("Download <%- count %> users");
                $('.submit_button').text(_.template(template)({count: count}));
            },
            error: function () {
                alert("Error determining number of matching users");
            },
        });
    }

    $(function () {
        var prevFilters = getFilters();
        $("#user-filters").change(function () {
            var currentFilters = getFilters();
            if (!_.isEqual(currentFilters, prevFilters)) {
                countUsers(currentFilters);
            }
            prevFilters = currentFilters;
        });
        countUsers(getFilters());
    });
});
<commit_msg>Added spinner during count request<commit_after>hqDefine('users/js/filtered_download', [
    'jquery',
    'underscore',
    'hqwebapp/js/initial_page_data',
    'hqwebapp/js/widgets',      // role selection
    'locations/js/widgets',     // location search
    'hqwebapp/js/components.ko',    // select toggle widget
], function (
    $,
    _,
    initialPageData
) {
    function getFilters() {
        return {
            'role_id': $("#id_role_id").val(),
            'search_string': $("#id_search_string").val(),
            'location_id': $("[name=location_id]").val(),
            'domains': $("#id_domains").val(),
        };
    }

    function countUsers(currentFilters) {
        var countUsersUrl = initialPageData.get('count_users_url'),
            $submitButton = $('.submit_button');
        $submitButton.html("<i class='fa fa-spin fa-spinner'></i>");
        $.get({
            url: countUsersUrl,
            data: currentFilters,
            success: function (data) {
                var count = data.count;
                var template = count === 1 ? gettext("Download <%- count %> user") : gettext("Download <%- count %> users");
                $submitButton.text(_.template(template)({count: count}));
            },
            error: function () {
                alert(gettext("Error determining number of matching users"));
            },
        });
    }

    $(function () {
        var prevFilters = getFilters();
        $("#user-filters").change(function () {
            var currentFilters = getFilters();
            if (!_.isEqual(currentFilters, prevFilters)) {
                countUsers(currentFilters);
            }
            prevFilters = currentFilters;
        });
        countUsers(getFilters());
    });
});
<|endoftext|>


<commit_before>import Router from "vue-router";
import routeDefinitions from "./routeDefinitions";
import { toPromise } from "neutronium-vue-resultcommand-topromise";

function route({ name, children, component }) {
  return {
    exact: true,
    path: `/${name}`,
    name: name,
    children,
    component
  };
}

const routes = routeDefinitions.map(route);

const router = new Router({
  mode: 'hash',
  scrollBehavior: () => ({ y: 0 }),
  routes
});

const menu = routeDefinitions.filter(r => r.menu).map(({ name, menu }) => ({
  title: `Resource.Menu_${name}`,
  to: { name },
  icon: menu.icon
}));

function getRouterViewModel(router) {
  const app = router.app;
  if (!app) {
    return null;
  }

  const viewModel = app.ViewModel;
  if (!viewModel) {
    return null;
  }

  return viewModel.Router;
}

/*eslint no-unused-vars: ["error", { "args": "none" }]*/
router.beforeEach((to, from, next) => {
  const routerViewModel = getRouterViewModel(router);
  if (!routerViewModel) {
    next();
    return;
  }

  const navigator = routerViewModel.BeforeResolveCommand;
  if (!navigator) {
    next();
    return;
  }

  const promise = toPromise(navigator, to.name);
  promise.then(
    ok => {
      if (!ok.Continue) {
        next(false);
      } else if (ok.Redirect) {
        next({ name: ok.Redirect });
      } else {
        router.app.ViewModel.CurrentViewModel = ok.To;
        next();
      }
    },
    error => {
      next(error);
    }
  );
});

/*eslint no-unused-vars: ["error", { "args": "none" }]*/
router.afterEach((to, from, next) => {
  const routerViewModel = getRouterViewModel(router);
  if (!routerViewModel) {
    return;
  }

  const navigator = routerViewModel.AfterResolveCommand;
  if (!navigator) {
    return;
  }
  navigator.Execute(to.name);
});

export { router, menu };
<commit_msg>Using browser history<commit_after>import Router from "vue-router";
import routeDefinitions from "./routeDefinitions";
import { toPromise } from "neutronium-vue-resultcommand-topromise";

function route({ name, children, component }) {
  return {
    exact: true,
    path: `/${name}`,
    name: name,
    children,
    component
  };
}

const routes = routeDefinitions.map(route);

const router = new Router({
  mode: 'history',
  scrollBehavior: () => ({ y: 0 }),
  routes
});

const menu = routeDefinitions.filter(r => r.menu).map(({ name, menu }) => ({
  title: `Resource.Menu_${name}`,
  to: { name },
  icon: menu.icon
}));

function getRouterViewModel(router) {
  const app = router.app;
  if (!app) {
    return null;
  }

  const viewModel = app.ViewModel;
  if (!viewModel) {
    return null;
  }

  return viewModel.Router;
}

/*eslint no-unused-vars: ["error", { "args": "none" }]*/
router.beforeEach((to, from, next) => {
  const routerViewModel = getRouterViewModel(router);
  if (!routerViewModel) {
    next();
    return;
  }

  const navigator = routerViewModel.BeforeResolveCommand;
  if (!navigator) {
    next();
    return;
  }

  const promise = toPromise(navigator, to.name);
  promise.then(
    ok => {
      if (!ok.Continue) {
        next(false);
      } else if (ok.Redirect) {
        next({ name: ok.Redirect });
      } else {
        router.app.ViewModel.CurrentViewModel = ok.To;
        next();
      }
    },
    error => {
      next(error);
    }
  );
});

/*eslint no-unused-vars: ["error", { "args": "none" }]*/
router.afterEach((to, from, next) => {
  const routerViewModel = getRouterViewModel(router);
  if (!routerViewModel) {
    return;
  }

  const navigator = routerViewModel.AfterResolveCommand;
  if (!navigator) {
    return;
  }
  navigator.Execute(to.name);
});

export { router, menu };
<|endoftext|>


<commit_before>import API from '-/config/api.4chan';
import proxify from '../services/proxyUrls';

/**
 * Standardises a 4chan board.
 *
 * @param  {Object} board   - Directly from 4chan's API
 * @param  {String} boardID - ID used to request board with
 * @return {Array}          - Array of standardised objects
 */
export default function parseBoard( board, boardID ) {
    const _board = []
    const thumbUrl = API.thumbnail(boardID)
    const mediaUrl = API.media(boardID)

    log.app(`Parsing 4chan board ${boardID} ...`)

    try {
        for (let page in board) {
            if (!board.hasOwnProperty(page)) return false;
            board[page].threads.map( post => formatPost(post, page))
        }
    } catch (e) {
        log.error(e)
        log.error(board)
        throw new Error(board)
    }

    if (!_board.length) {
        throw new Error("4chan board was not parsed: No posts extracted")
    }

    log.app(`Created ${_board.length} board posts`)
    return _board;

    function formatPost(post, page) {
        let smImg = thumbUrl + post.tim + "s.jpg"
        let lgImg = mediaUrl + post.tim + post.ext

        _board.push({
            id: post.no,
            date: post.now,
            title: post.sub || "",
            comment: post.com,
            time: post.tim || post.time * 1000,
            page: page,
            media: {
                thumbnail: smImg,
                srcLarge: lgImg,
                width: post.w,
                height: post.h,
                filesize: post.fsize,
            },
            replies: {
                textCount: post.replies,
                imgCount: post.images,
            },
            last_modified: post.last_modified
        });
    }
}
<commit_msg>tweak(server): board parser<commit_after>import API from '-/config/api.4chan';
import proxify from '../services/proxyUrls';

/**
 * Standardises a 4chan board.
 *
 * @param  {Object} board   - Directly from 4chan's API
 * @param  {String} boardID - ID used to request board with
 * @return {Array}          - Array of standardised objects
 */
export default function parseBoard( board, boardID ) {
    const _board = []
    const thumbUrl = API.thumbnail(boardID)
    const mediaUrl = API.media(boardID)

    log.app(`Parsing 4chan board ${boardID} ...`)

    try {
        for (let page in board) {
            if (!board.hasOwnProperty(page)) return false;
            board[page].threads.map( post => formatPost(post, page))
        }
    } catch (e) {
        log.error(e)
        log.error(board)
        throw new Error(board)
    }

    if (!_board.length) {
        throw new Error("4chan board was not parsed: No posts extracted")
    }

    log.app(`Created ${_board.length} board posts`)
    return _board;

    function formatPost(post, page) {
        let smImg = thumbUrl + post.tim + "s.jpg"
        let lgImg = mediaUrl + post.tim + post.ext

        _board.push({
            id: post.no,
            date: post.now,
            title: post.sub || "",
            comment: post.com,
            time: post.tim || post.time * 1000,
            page: page,
            last_modified: post.last_modified,
            media: {
                thumbnail: smImg,
                srcLarge: lgImg,
                width: post.w,
                height: post.h,
                filesize: post.fsize,
            },
            replies: {
                textCount: post.replies,
                imgCount: post.images,
            },
        });
    }
}
<|endoftext|>


<commit_before>'use strict';

import {LEVELS, LEVELS_COUNT} from './../config';

// Game Controller
export default ['$scope', 'ResultModal', 'ModalData', function($scope, $modal, $data) {

    $scope.gameStarted = false;
    $scope.gameFinished = false;

    $scope.levelStarted = false;

    // Game total score
    $scope.totalScore = 0;
    // Currect level score
    $scope.score = 0;

    // Currect level time left
    $scope.timeLeft = null;
    // Currect level timer
    $scope.timer = null;

    // Currect level
    $scope.popMessage = null;

    $scope.level = null;
    $scope.levelNum = 0;

    $scope.startGame = () => {
        // Stop game
        if ($scope.gameStarted === true) {
            $scope.gameStarted = false;

            // End level if needed
            if ($scope.startLevel === true) {
                $scope.startLevel();
            }
        // Start game
        } else {
            $scope.gameStarted = true;
            $scope.gameFinished = false;

            $scope.totalScore = 0;
            $scope.levelNum = 0;
            $scope.loadLevel(LEVELS[$scope.levelNum]);
        }
    };

    $scope.loadLevel = (level) => {
        if (!level.hasOwnProperty('targetScore') || !level.hasOwnProperty('time')) {
            throw new Error(`Level configuration's damaged`);
        }

        $scope.level = level;

        $scope.timer = null;
        $scope.timeLeft = level.time * 1000;
    };

    $scope.goButtonLocked = false;
    $scope.startLevel = (level) => {
        if ($scope.goButtonLocked === true) {
            return;
        }

        // Stop level
        if ($scope.levelStarted === true) {
            $scope.goButtonLocked = true;
            $scope.levelStarted = false;

            clearInterval($scope.timer);

            $scope.clearGrid().then(() => {
                $scope.goButtonLocked = false;

                if ($scope.totalScore > 0 && $scope.score > 0) {
                    $scope.totalScore -= $scope.score;
                }
            });
        // Start level
        } else {
            $scope.levelStarted = true;

            $scope.loadLevel(level);
            $scope.generateLevel(level);

            $scope.timer = setInterval(() => {
                $scope.timeLeft -= 1000;

                if ($scope.timeLeft <= 0) {
                    clearInterval($scope.timer);

                    $scope.timer = null;
                    $scope.timeLeft = $scope.level.time;

                    $scope.levelStarted = false;
                    $scope.clearGrid().then(() => {
                        if ($scope.score >= $scope.level.targetScore) {
                            if ($scope.levelNum + 1 === LEVELS_COUNT) {
                                $data.message = `You won the game. Congratulations!`;
                                // Stop game
                                $scope.startGame();
                            } else {
                                $data.message = `Level's completed successfully!`;
                                $scope.loadLevel(LEVELS[++$scope.levelNum]);
                            }
                        } else {
                            $data.message = `Oops... not enough points.`;
                            $scope.totalScore -= $scope.score;
                        }

                        $data.score = $scope.score;
                        $data.targetScore = $scope.level.targetScore;
                        $data.totalScore = $scope.totalScore;

                        $scope.score = 0;

                        $modal.activate();
                    });
                }

                $scope.$digest();
            }, 1000);
        }
    };

    $scope.increaseScore = (value) => {
        $scope.totalScore += value;
        $scope.score += value;
        $scope.$digest();
    };

    // Helper function to show time
    $scope.getHumanTime = (time) => {
        let sign = 1;

        if (time < 0) {
            sign *= (-1);
        }

        time = Math.abs(time);

        let result = (sign > 0) ? '' : '- ';

        let seconds = Math.floor(time / 1000);
        let mins = Math.floor(seconds / 60);
        let hours = Math.floor(mins / 60);

        if (hours > 0) {
            result += hours.toString() + ' h. ';
        }

        mins = mins - hours * 60;
        if (mins > 0) {
            result += mins.toString() + ' m. ';
        }

        seconds = seconds - hours * 3600 - mins * 60;
        if (seconds > 0)  {
            result += seconds.toString() + ' s.';
        }

        return result;
    };

    $scope.getScorePercent = () => {
        return Math.floor(($scope.score / $scope.level.targetScore) * 100);
    };

    $scope.getDelimitedNumber = (n) => {
        return n.toString().replace(/./g, function(c, i, a) {
            return i && c !== '.' && ((a.length - i) % 3 === 0) ? ',' + c : c;
        });
    };

    $scope.$watch('timeLeft');
    $scope.$watch('totalScore');
    $scope.$watch('score');
}];<commit_msg>Score show changed<commit_after>'use strict';

import {LEVELS, LEVELS_COUNT} from './../config';

// Game Controller
export default ['$scope', 'ResultModal', 'ModalData', function($scope, $modal, $data) {

    $scope.gameStarted = false;
    $scope.gameFinished = false;

    $scope.levelStarted = false;

    // Game total score
    $scope.totalScore = 0;
    // Currect level score
    $scope.score = 0;

    // Currect level time left
    $scope.timeLeft = null;
    // Currect level timer
    $scope.timer = null;

    // Currect level
    $scope.popMessage = null;

    $scope.level = null;
    $scope.levelNum = 0;

    $scope.startGame = () => {
        // Stop game
        if ($scope.gameStarted === true) {
            $scope.gameStarted = false;

            // End level if needed
            if ($scope.startLevel === true) {
                $scope.startLevel();
            }
        // Start game
        } else {
            $scope.gameStarted = true;
            $scope.gameFinished = false;

            $scope.totalScore = 0;
            $scope.levelNum = 0;
            $scope.loadLevel(LEVELS[$scope.levelNum]);
        }
    };

    $scope.loadLevel = (level) => {
        if (!level.hasOwnProperty('targetScore') || !level.hasOwnProperty('time')) {
            throw new Error(`Level configuration's damaged`);
        }

        $scope.level = level;

        $scope.timer = null;
        $scope.timeLeft = level.time * 1000;
    };

    $scope.goButtonLocked = false;
    $scope.startLevel = (level) => {
        if ($scope.goButtonLocked === true) {
            return;
        }

        // Stop level
        if ($scope.levelStarted === true) {
            $scope.goButtonLocked = true;
            $scope.levelStarted = false;

            clearInterval($scope.timer);

            $scope.clearGrid().then(() => {
                $scope.goButtonLocked = false;

                if ($scope.totalScore > 0 && $scope.score > 0) {
                    $scope.totalScore -= $scope.score;
                }
            });
        // Start level
        } else {
            $scope.levelStarted = true;

            $scope.loadLevel(level);
            $scope.generateLevel(level);

            $scope.timer = setInterval(() => {
                $scope.timeLeft -= 1000;

                if ($scope.timeLeft <= 0) {
                    clearInterval($scope.timer);

                    $scope.timer = null;
                    $scope.timeLeft = $scope.level.time;

                    $scope.levelStarted = false;
                    $scope.clearGrid().then(() => {
                        $data.score = $scope.score;
                        $data.targetScore = $scope.level.targetScore;
                        $data.totalScore = $scope.totalScore;

                        if ($scope.score >= $scope.level.targetScore) {
                            if ($scope.levelNum + 1 === LEVELS_COUNT) {
                                $data.message = `You won the game. Congratulations!`;
                                // Stop game
                                $scope.startGame();
                            } else {
                                $data.message = `Level's completed successfully!`;
                                $scope.loadLevel(LEVELS[++$scope.levelNum]);
                            }
                        } else {
                            $data.message = `Oops... not enough points.`;
                            $scope.totalScore -= $scope.score;
                            $data.totalScore = $scope.totalScore;
                        }

                        $scope.score = 0;
                        $modal.activate();
                    });
                }

                $scope.$digest();
            }, 1000);
        }
    };

    $scope.increaseScore = (value) => {
        $scope.totalScore += value;
        $scope.score += value;
        $scope.$digest();
    };

    // Helper function to show time
    $scope.getHumanTime = (time) => {
        let sign = 1;

        if (time < 0) {
            sign *= (-1);
        }

        time = Math.abs(time);

        let result = (sign > 0) ? '' : '- ';

        let seconds = Math.floor(time / 1000);
        let mins = Math.floor(seconds / 60);
        let hours = Math.floor(mins / 60);

        if (hours > 0) {
            result += hours.toString() + ' h. ';
        }

        mins = mins - hours * 60;
        if (mins > 0) {
            result += mins.toString() + ' m. ';
        }

        seconds = seconds - hours * 3600 - mins * 60;
        if (seconds > 0)  {
            result += seconds.toString() + ' s.';
        }

        return result;
    };

    $scope.getScorePercent = () => {
        return Math.floor(($scope.score / $scope.level.targetScore) * 100);
    };

    $scope.getDelimitedNumber = (n) => {
        return n.toString().replace(/./g, function(c, i, a) {
            return i && c !== '.' && ((a.length - i) % 3 === 0) ? ',' + c : c;
        });
    };

    $scope.$watch('timeLeft');
    $scope.$watch('totalScore');
    $scope.$watch('score');
}];<|endoftext|>