<commit_before>var gulp = require('gulp');
var minifyHTML = require('gulp-minify-html');
var uglify = require('gulp-uglify');
var jshint = require('gulp-jshint');
var changed = require('gulp-changed');
var imagemin = require('gulp-imagemin');
var autoprefix = require('gulp-autoprefixer');
var minifyCSS = require('gulp-minify-css');
var del = require('del');
var concat = require('gulp-concat');
var refresh = require('gulp-livereload');
var modRewrite = require('connect-modrewrite');
var RevAll = require('gulp-rev-all');
var runSequence = require('run-sequence');
var sourcemaps = require('gulp-sourcemaps');
var sass = require('gulp-sass');
var gutil = require('gulp-util');
var plumber = require('gulp-plumber');

var paths = {
    dist: 'dist',
    jshint: [
        'app/scripts/**/*.js',
        'app/theme/**/*.js'
    ],
    html: 'app/**/*.html',
    misc: 'app/*.{txt,htaccess,ico}',
    scripts: [
        'app/scripts/config.js',
        'app/scripts/main.js',
        'app/scripts/**/init.js',
        'app/scripts/**/*.js'
    ],
    theme: {
        dist: 'dist/theme',
        css: 'app/theme/styles/**/*.css',
        images: 'app/theme/**/*.{png,gif,jpg,jpeg,ico,svg,mp4}',
        fonts: 'app/theme/fonts/**/*',
        scripts: [
            'app/theme/lib/**/*.js',
            'app/theme/**/*.js'
        ]
    },
    lib: {
        dist: 'dist/lib',
        scripts: [
            'app/lib/jquery.min.js',
            'app/lib/angular.min.js',
            'app/lib/*.js' // NOTE: no folder glob, or it would clobber .ie
        ],
        ie: 'app/lib/ie/*.js'
    }
};

var handleError = function(err) {
    gutil.log(gutil.colors.red('# Error in ' + err.plugin));
    gutil.log('File: %s:%s', err.fileName, err.lineNumber);
    gutil.log('Error Message: %s', err.message);
    gutil.beep();
}

var host = {
    port: '8080',
    lrPort: '35729'
};

var env = process.env.NODE_ENV || 'development';

// Empties folders to start fresh
gulp.task('clean', function (cb) {
    return del(['dist/*', '!dist/media'], cb);
});

gulp.task('jshint', function () {
    return gulp.src(paths.jshint)
        .pipe(jshint())
        .pipe(jshint.reporter(require('jshint-stylish')));
});

gulp.task('html', function () {
    return gulp.src(paths.html)
        .pipe(changed(paths.dist))
        .pipe(minifyHTML({
            collapseWhitespace: true,
            collapseBooleanAttributes: true,
            removeCommentsFromCDATA: true,
            removeOptionalTags: true,
            conditionals: true,
            quotes: true,
            empty: true
        }))
        .pipe(gulp.dest(paths.dist));
});

gulp.task('misc', function () {
    return gulp.src(paths.misc)
        .pipe(gulp.dest(paths.dist));
});

gulp.task('scripts', function () {
    return gulp.src(paths.scripts)
        .pipe(sourcemaps.init())
        .pipe(plumber(handleError))
        .pipe(uglify({
            mangle: false
        }))
        .pipe(plumber.stop())
        .pipe(concat('main.js'))
        .pipe(sourcemaps.write('./maps'))
        .pipe(gulp.dest(paths.dist + '/scripts'))
        .pipe(refresh());
});

gulp.task('theme.sass', function() {
    return gulp.src('app/theme/styles/bootstrap/bootstrap.scss')
    .pipe(sass({
        outputStyle: 'expanded',
        precision: 8
    }))
    .pipe(gulp.dest('app/theme/styles'));
})
gulp.task('theme.css', function () {
    return gulp.src(paths.theme.css)
        .pipe(sourcemaps.init())
        .pipe(autoprefix('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
        .pipe(minifyCSS())
        .pipe(sourcemaps.write('./maps'))
        .pipe(gulp.dest(paths.theme.dist + '/styles'))
        .pipe(refresh());
});

gulp.task('theme.fonts', function() {
    return gulp.src(paths.theme.fonts)
        .pipe(gulp.dest(paths.theme.dist + '/fonts'));
});

gulp.task('theme.scripts', function () {
    return gulp.src(paths.theme.scripts)
        .pipe(sourcemaps.init())
        .pipe(plumber(handleError))
        .pipe(uglify({
            mangle: false
        }))
        .pipe(plumber.stop())
        .pipe(concat('main.js'))
        .pipe(sourcemaps.write('./maps'))
        .pipe(gulp.dest(paths.theme.dist))
        .pipe(refresh());
});

gulp.task('theme.images', function () {
    return gulp.src(paths.theme.images)
        .pipe(changed(paths.theme.dist))
        .pipe(imagemin())
        .pipe(gulp.dest(paths.theme.dist));
});

gulp.task('lib.scripts', function () {
    return gulp.src(paths.lib.scripts)
        .pipe(concat('lib.js'))
        .pipe(gulp.dest(paths.lib.dist));
});

// IE libs can stick together, but need to be separate from other libs
gulp.task('lib.ie', function() {
    return gulp.src(paths.lib.ie)
        .pipe(concat('ie-libs.js'))
        .pipe(gulp.dest(paths.lib.dist));
});

gulp.task('watch',function(){
    refresh.listen({ basePath: paths.dist });

    gulp.start('livereload');

    gulp.watch(["app/**/*.html"],['html']);
    gulp.watch(["app/**/*.css"],['theme.css']);
    gulp.watch(["app/**/*.scss"],['theme.sass']);
    gulp.watch(["app/scripts/**/*.js"],['scripts']);
    gulp.watch(["app/theme/**/*.js"],['theme.scripts']);
});

gulp.task('livereload', function(){
    var path = require('path');
    var express = require('express');
    var app = express();
    var staticFolder = path.join(__dirname, 'dist');

    app.use(modRewrite([
        '!\\. /index.html [L]'
    ]))
        .use(express.static(staticFolder));

    app.listen( host.port, function() {
        console.log('server started: http://localhost:' + host.port);
        return gulp;
    });
});

gulp.task('revision', function(){
    if(env === 'production') {
        var revAll = new RevAll({
            dontUpdateReference: [/^((?!.js|.css).)*$/g],
            dontRenameFile: [/^((?!.js|.css).)*$/g]
        });
        gulp.src('dist/**')
            .pipe(revAll.revision())
            .pipe(gulp.dest('dist'));
    }
});

gulp.task('lib', ['lib.ie', 'lib.scripts']);
gulp.task('theme', [
    'theme.css',
    'theme.fonts',
    'theme.scripts',
    'theme.images'
]);

// For production
gulp.task('build', function(){
    // note: revision has a short circuit for dev
    runSequence('clean', 'theme.sass', [
        'html',
        'misc',
        'scripts',
        'theme',
        'lib'
    ], 'revision');
});

// For development
gulp.task('serve', ['default']);
gulp.task('default', ['build'], function(){
    gulp.start('watch');
});
<commit_msg>gulp additional media<commit_after>var gulp = require('gulp');
var minifyHTML = require('gulp-minify-html');
var uglify = require('gulp-uglify');
var jshint = require('gulp-jshint');
var changed = require('gulp-changed');
var imagemin = require('gulp-imagemin');
var autoprefix = require('gulp-autoprefixer');
var minifyCSS = require('gulp-minify-css');
var del = require('del');
var concat = require('gulp-concat');
var refresh = require('gulp-livereload');
var modRewrite = require('connect-modrewrite');
var RevAll = require('gulp-rev-all');
var runSequence = require('run-sequence');
var sourcemaps = require('gulp-sourcemaps');
var sass = require('gulp-sass');
var gutil = require('gulp-util');
var plumber = require('gulp-plumber');

var paths = {
    dist: 'dist',
    jshint: [
        'app/scripts/**/*.js',
        'app/theme/**/*.js'
    ],
    html: 'app/**/*.html',
    misc: 'app/*.{txt,htaccess,ico}',
    scripts: [
        'app/scripts/config.js',
        'app/scripts/main.js',
        'app/scripts/**/init.js',
        'app/scripts/**/*.js'
    ],
    theme: {
        dist: 'dist/theme',
        css: 'app/theme/styles/**/*.css',
        // images, videos, fonts
        media: 'app/theme/**/*.{png,gif,jpg,jpeg,ico,svg,mp4,ogv,webm,pdf,eot,ttf,woff}',
        scripts: [
            'app/theme/lib/**/*.js',
            'app/theme/**/*.js'
        ]
    },
    lib: {
        dist: 'dist/lib',
        scripts: [
            'app/lib/jquery.min.js',
            'app/lib/angular.min.js',
            'app/lib/*.js' // NOTE: no folder glob, or it would clobber .ie
        ],
        ie: 'app/lib/ie/*.js'
    }
};

var handleError = function(err) {
    gutil.log(gutil.colors.red('# Error in ' + err.plugin));
    gutil.log('File: %s:%s', err.fileName, err.lineNumber);
    gutil.log('Error Message: %s', err.message);
    gutil.beep();
}

var host = {
    port: '8080',
    lrPort: '35729'
};

var env = process.env.NODE_ENV || 'development';

// Empties folders to start fresh
gulp.task('clean', function (cb) {
    return del(['dist/*', '!dist/media'], cb);
});

gulp.task('jshint', function () {
    return gulp.src(paths.jshint)
        .pipe(jshint())
        .pipe(jshint.reporter(require('jshint-stylish')));
});

gulp.task('html', function () {
    return gulp.src(paths.html)
        .pipe(changed(paths.dist))
        .pipe(minifyHTML({
            collapseWhitespace: true,
            collapseBooleanAttributes: true,
            removeCommentsFromCDATA: true,
            removeOptionalTags: true,
            conditionals: true,
            quotes: true,
            empty: true
        }))
        .pipe(gulp.dest(paths.dist));
});

gulp.task('misc', function () {
    return gulp.src(paths.misc)
        .pipe(gulp.dest(paths.dist));
});

gulp.task('scripts', function () {
    return gulp.src(paths.scripts)
        .pipe(sourcemaps.init())
        .pipe(plumber(handleError))
        .pipe(uglify({
            mangle: false
        }))
        .pipe(plumber.stop())
        .pipe(concat('main.js'))
        .pipe(sourcemaps.write('./maps'))
        .pipe(gulp.dest(paths.dist + '/scripts'))
        .pipe(refresh());
});

gulp.task('theme.sass', function() {
    return gulp.src('app/theme/styles/bootstrap/bootstrap.scss')
    .pipe(sass({
        outputStyle: 'expanded',
        precision: 8
    }))
    .pipe(gulp.dest('app/theme/styles'));
})
gulp.task('theme.css', function () {
    return gulp.src(paths.theme.css)
        .pipe(sourcemaps.init())
        .pipe(autoprefix('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
        .pipe(minifyCSS())
        .pipe(sourcemaps.write('./maps'))
        .pipe(gulp.dest(paths.theme.dist + '/styles'))
        .pipe(refresh());
});

gulp.task('theme.scripts', function () {
    return gulp.src(paths.theme.scripts)
        .pipe(sourcemaps.init())
        .pipe(plumber(handleError))
        .pipe(uglify({
            mangle: false
        }))
        .pipe(plumber.stop())
        .pipe(concat('main.js'))
        .pipe(sourcemaps.write('./maps'))
        .pipe(gulp.dest(paths.theme.dist))
        .pipe(refresh());
});

gulp.task('theme.media', function () {
    return gulp.src(paths.theme.media)
        .pipe(changed(paths.theme.dist))
        .pipe(imagemin())
        .pipe(gulp.dest(paths.theme.dist));
});

gulp.task('lib.scripts', function () {
    return gulp.src(paths.lib.scripts)
        .pipe(concat('lib.js'))
        .pipe(gulp.dest(paths.lib.dist));
});

// IE libs can stick together, but need to be separate from other libs
gulp.task('lib.ie', function() {
    return gulp.src(paths.lib.ie)
        .pipe(concat('ie-libs.js'))
        .pipe(gulp.dest(paths.lib.dist));
});

gulp.task('watch',function(){
    refresh.listen({ basePath: paths.dist });

    gulp.start('livereload');

    gulp.watch(["app/**/*.html"],['html']);
    gulp.watch(["app/**/*.css"],['theme.css']);
    gulp.watch(["app/**/*.scss"],['theme.sass']);
    gulp.watch(["app/scripts/**/*.js"],['scripts']);
    gulp.watch(["app/theme/**/*.js"],['theme.scripts']);
});

gulp.task('livereload', function(){
    var path = require('path');
    var express = require('express');
    var app = express();
    var staticFolder = path.join(__dirname, 'dist');

    app.use(modRewrite([
        '!\\. /index.html [L]'
    ]))
        .use(express.static(staticFolder));

    app.listen( host.port, function() {
        console.log('server started: http://localhost:' + host.port);
        return gulp;
    });
});

gulp.task('revision', function(){
    if(env === 'production') {
        var revAll = new RevAll({
            dontUpdateReference: [/^((?!.js|.css).)*$/g],
            dontRenameFile: [/^((?!.js|.css).)*$/g]
        });
        gulp.src('dist/**')
            .pipe(revAll.revision())
            .pipe(gulp.dest('dist'));
    }
});

gulp.task('lib', ['lib.ie', 'lib.scripts']);
gulp.task('theme', [
    'theme.css',
    'theme.scripts',
    'theme.media'
]);

// For production
gulp.task('build', function(){
    // note: revision has a short circuit for dev
    runSequence('clean', 'theme.sass', [
        'html',
        'misc',
        'scripts',
        'theme',
        'lib'
    ], 'revision');
});

// For development
gulp.task('serve', ['default']);
gulp.task('default', ['build'], function(){
    gulp.start('watch');
});
<|endoftext|>


<commit_before>'use strict'

var cli = require('cli')
var csv = require('csv')
var fs = require('fs')
var local = {}

var MAX_LEVEL = 32

function main() {
  // parse command arguments
  cli.parse({})

  if (cli.args.length === 2) {
    // load csv from file
    var srcFile = cli.args[0]
    var dstFile = cli.args[1]

    var data = fs.readFileSync(srcFile, {encoding: 'utf-8'})
    makeRuleJson(data, function(err, json) {
      if (err) {
        local.errorExit(-1, 'convert error:' + err)
      }
      else {
        // write converted file to dstFile
        fs.writeFileSync(dstFile, JSON.stringify(json), 0, 'utf-8')
      }
    })
  }
  else {
    // load csv file from stdin
    cli.withStdin(function(data) {
      makeRuleJson(data, function(err, json) {
        if (err) {
          local.errorExit(-1, 'convert error: ' + err)
        }
        else {
          // write converted file to stdout
          local.writeToConsole(JSON.stringify(json))
        }
      })
    })
  }
}

function makeRuleJson(csvString, callback) {
  csv.parse(csvString, {
    columns: true,
    skip_empty_lines: true,
    skip_lines_with_empty_values: true
  },
    function(err, csv, obj) {
      if (err) {
        callback(err)
      }
      var ruleJson = {}
      var parents = []

      csv.forEach(function(rec) {
        // depth level of this element
        var level = Array.apply(null, {length: MAX_LEVEL})
          .map(Function.call, Number)
          .filter(function(lv) {
            var colName = 'LV' + (lv + 1)
            return rec[colName] !== undefined && rec[colName] !== ''
          })
          .filter(function(elem, idx) {
            return idx === 0
          })[0]
        if (level === undefined) {
          callback(new Error('no elements found in any level'))
        }

        var elem = rec['LV' + (level + 1)]

        // add this object to JSON tree
        var obj = {}
        if (level === 0) {
          ruleJson[elem] = obj
        }
        else {
          parents[level - 1][elem] = obj
        }
        parents[level] = obj

        // add read/write
        if (rec.READ !== '') {
          obj['.read'] = rec.READ
        }
        if (rec.WRITE !== '') {
          obj['.write'] = rec.WRITE
        }

        // add type condition
        var typeCondition = ''
        if (rec.TYPE !== '') {
          switch (rec.TYPE) {
            case 'string':
              typeCondition = 'newData.isString()'
              break;
            case 'number':
              typeCondition = 'newData.isNumber()'
              break;
            case 'boolean':
              typeCondition = 'newData.isBoolean()'
              break;
            default:
              callback(new Error('invalid type "' + rec.TYPE + ': ' + elem))
              break;
          }
        }
        var userCondition = rec.CONDITION
        var condition = ''
        if (typeCondition !== '' && userCondition !== '') {
          condition = '(' + typeCondition + ') && (' + userCondition + ')'
        }
        else if (typeCondition !== '' && userCondition === '') {
          condition = typeCondition
        }
        else if (userCondition !== '') {
          condition = userCondition
        }
        if (condition !== '') {
            obj['.validate'] = condition
        }

        // add index
        if  (rec.INDEX) {
          if (level === 0) {
            callback(new Error('INDEX element must not be at the top level: ' + elem))
          }
          else {
            if (!parents[level - 1]['.indexOn']) {
              parents[level - 1]['.indexOn'] = []
            }
            parents[level - 1]['.indexOn'].push(elem)
          }
        }
      })
      callback(null, { rules: ruleJson })
    })
}

// exit with exit code and error message
local.errorExit = function(exitCode, message) {
  if (message) console.error(message)
  process.exit(exitCode)
}

// write message to console
local.writeToConsole = function(message) {
  console.log(message)
}

module.exports = {
  main: main,
  makeRuleJson: makeRuleJson,
  test: local
}
<commit_msg>changed exit code on error<commit_after>'use strict'

var cli = require('cli')
var csv = require('csv')
var fs = require('fs')
var local = {}

var MAX_LEVEL = 32

function main() {
  // parse command arguments
  cli.parse({})

  if (cli.args.length === 2) {
    // load csv from file
    var srcFile = cli.args[0]
    var dstFile = cli.args[1]

    var data = fs.readFileSync(srcFile, {encoding: 'utf-8'})
    makeRuleJson(data, function(err, json) {
      if (err) {
        local.errorExit(1, 'convert error:' + err)
      }
      else {
        // write converted file to dstFile
        fs.writeFileSync(dstFile, JSON.stringify(json), 0, 'utf-8')
      }
    })
  }
  else {
    // load csv file from stdin
    cli.withStdin(function(data) {
      makeRuleJson(data, function(err, json) {
        if (err) {
          local.errorExit(1, 'convert error: ' + err)
        }
        else {
          // write converted file to stdout
          local.writeToConsole(JSON.stringify(json))
        }
      })
    })
  }
}

function makeRuleJson(csvString, callback) {
  csv.parse(csvString, {
    columns: true,
    skip_empty_lines: true,
    skip_lines_with_empty_values: true
  },
    function(err, csv, obj) {
      if (err) {
        callback(err)
      }
      var ruleJson = {}
      var parents = []

      csv.forEach(function(rec) {
        // depth level of this element
        var level = Array.apply(null, {length: MAX_LEVEL})
          .map(Function.call, Number)
          .filter(function(lv) {
            var colName = 'LV' + (lv + 1)
            return rec[colName] !== undefined && rec[colName] !== ''
          })
          .filter(function(elem, idx) {
            return idx === 0
          })[0]
        if (level === undefined) {
          callback(new Error('no elements found in any level'))
        }

        var elem = rec['LV' + (level + 1)]

        // add this object to JSON tree
        var obj = {}
        if (level === 0) {
          ruleJson[elem] = obj
        }
        else {
          parents[level - 1][elem] = obj
        }
        parents[level] = obj

        // add read/write
        if (rec.READ !== '') {
          obj['.read'] = rec.READ
        }
        if (rec.WRITE !== '') {
          obj['.write'] = rec.WRITE
        }

        // add type condition
        var typeCondition = ''
        if (rec.TYPE !== '') {
          switch (rec.TYPE) {
            case 'string':
              typeCondition = 'newData.isString()'
              break;
            case 'number':
              typeCondition = 'newData.isNumber()'
              break;
            case 'boolean':
              typeCondition = 'newData.isBoolean()'
              break;
            default:
              callback(new Error('invalid type "' + rec.TYPE + ': ' + elem))
              break;
          }
        }
        var userCondition = rec.CONDITION
        var condition = ''
        if (typeCondition !== '' && userCondition !== '') {
          condition = '(' + typeCondition + ') && (' + userCondition + ')'
        }
        else if (typeCondition !== '' && userCondition === '') {
          condition = typeCondition
        }
        else if (userCondition !== '') {
          condition = userCondition
        }
        if (condition !== '') {
            obj['.validate'] = condition
        }

        // add index
        if  (rec.INDEX) {
          if (level === 0) {
            callback(new Error('INDEX element must not be at the top level: ' + elem))
          }
          else {
            if (!parents[level - 1]['.indexOn']) {
              parents[level - 1]['.indexOn'] = []
            }
            parents[level - 1]['.indexOn'].push(elem)
          }
        }
      })
      callback(null, { rules: ruleJson })
    })
}

// exit with exit code and error message
local.errorExit = function(exitCode, message) {
  if (message) console.error(message)
  process.exit(exitCode)
}

// write message to console
local.writeToConsole = function(message) {
  console.log(message)
}

module.exports = {
  main: main,
  makeRuleJson: makeRuleJson,
  test: local
}
<|endoftext|>


<commit_before>import React from 'react';
import { TransitionGroup } from 'react-transition-group';
import { shallow, mount } from 'enzyme';

import Node from '../../Node';
import Link from '../../Link';
import Tree from '../index';

describe('<Tree />', () => {
  const mockData = [
    {
      name: 'Top Level',
      parent: 'null',
      attributes: {
        keyA: 'val A',
        keyB: 'val B',
        keyC: 'val C',
      },
      children: [
        {
          name: 'Level 2: A',
          parent: 'Top Level',
          attributes: {
            keyA: 'val A',
            keyB: 'val B',
            keyC: 'val C',
          },
        },
        {
          name: 'Level 2: B',
          parent: 'Top Level',
        },
      ],
    },
  ];

  // Clear method spies on prototype before each test
  afterEach(() => jest.clearAllMocks());

  it('builds a tree on each render', () => {
    jest.spyOn(Tree.prototype, 'generateTree');
    const renderedComponent = shallow(
      <Tree data={mockData} />
    );
    expect(renderedComponent.instance().generateTree).toHaveBeenCalled();
  });

  it('maps every node onto a <Node />', () => {
    const nodeCount = 3; // 1 top level node + 2 child nodes in mockData
    const renderedComponent = shallow(
      <Tree data={mockData} />
    );

    expect(renderedComponent.find(Node).length).toBe(nodeCount);
  });

  it('maps every parent-child relation onto a <Link />', () => {
    const linkCount = 2;
    const renderedComponent = shallow(
      <Tree data={mockData} />
    );

    expect(renderedComponent.find(Link).length).toBe(linkCount);
  });

  it('applies the `translate` prop when specified', () => {
    const fixture = { x: 123, y: 321 };
    const expected = `translate(${fixture.x},${fixture.y})`;
    const renderedComponent = shallow(
      <Tree
        data={mockData}
        translate={fixture}
      />
    );
    expect(renderedComponent.find(TransitionGroup).prop('transform')).toBe(expected);
  });

  it('passes `props.orientation` to its <Node /> and <Link /> children', () => {
    const fixture = 'vertical';
    const renderedComponent = shallow(
      <Tree
        data={mockData}
        orientation={fixture}
      />
    );

    expect(renderedComponent.find(Node).everyWhere((n) =>
      n.prop('orientation') === fixture)
    ).toBe(true);
    expect(renderedComponent.find(Link).everyWhere((n) =>
      n.prop('orientation') === fixture)
    ).toBe(true);
  });

  it('passes `handleNodeToggle()` to its <Node /> children as onClick prop', () => {
    const renderedComponent = shallow(
      <Tree data={mockData} />
    );

    expect(renderedComponent.find(Node).everyWhere((n) =>
      n.prop('onClick') === renderedComponent.instance().handleNodeToggle)
    ).toBe(true);
  });

  it('collapses a node\'s children when it is clicked in an expanded state', () => {
    jest.spyOn(Tree.prototype, 'handleNodeToggle');
    jest.spyOn(Tree.prototype, 'collapseNode');
    const renderedComponent = mount(
      <Tree data={mockData} />
    );
    renderedComponent.find(Node).first().simulate('click'); // collapse

    expect(Tree.prototype.handleNodeToggle).toHaveBeenCalledTimes(1);
    expect(Tree.prototype.collapseNode).toHaveBeenCalled();
  });

  it('expands a node\'s children when it is clicked in a collapsed state', () => {
    jest.spyOn(Tree.prototype, 'handleNodeToggle');
    jest.spyOn(Tree.prototype, 'collapseNode');
    jest.spyOn(Tree.prototype, 'expandNode');
    const renderedComponent = mount(
      <Tree data={mockData} />
    );
    renderedComponent.find(Node).first().simulate('click'); // collapse
    renderedComponent.find(Node).first().simulate('click'); // re-expand

    expect(Tree.prototype.handleNodeToggle).toHaveBeenCalledTimes(2);
    expect(Tree.prototype.collapseNode).toHaveBeenCalled();
    expect(Tree.prototype.expandNode).toHaveBeenCalled();
  });

  it('does not collapse a node if `props.collapsible` is false', () => {
    jest.spyOn(Tree.prototype, 'handleNodeToggle');
    jest.spyOn(Tree.prototype, 'collapseNode');
    const renderedComponent = mount(
      <Tree
        data={mockData}
        collapsible={false}
      />
    );
    renderedComponent.find(Node).first().simulate('click');

    expect(Tree.prototype.handleNodeToggle).toHaveBeenCalledTimes(1);
    expect(Tree.prototype.collapseNode).toHaveBeenCalledTimes(0);
  });

  it('sets tree depth to `props.initialDepth` if specified', () => {
    jest.spyOn(Tree.prototype, 'setInitialTreeDepth');
    mount(
      <Tree
        data={mockData}
        initialDepth={1}
      />
    );

    expect(Tree.prototype.setInitialTreeDepth).toHaveBeenCalled();
  });

  it('allows zooming in/out according to `props.scaleExtent` if `props.zoomable`', () => {
    const zoomableComponent = mount(
      <Tree
        data={mockData}
      />
    );
    const nonZoomableComponent = mount(
      <Tree
        data={mockData}
        zoomable={false}
      />
    );

    zoomableComponent.find('svg').simulate('touchmove');

    expect(zoomableComponent.find('svg').prop('transform')).toBeDefined();
    expect(nonZoomableComponent.find('svg').prop('transform')).toBeUndefined();
  });
});
<commit_msg>Comments out bindZoomListener test until relevant<commit_after>import React from 'react';
import { TransitionGroup } from 'react-transition-group';
import { shallow, mount } from 'enzyme';

import Node from '../../Node';
import Link from '../../Link';
import Tree from '../index';

describe('<Tree />', () => {
  const mockData = [
    {
      name: 'Top Level',
      parent: 'null',
      attributes: {
        keyA: 'val A',
        keyB: 'val B',
        keyC: 'val C',
      },
      children: [
        {
          name: 'Level 2: A',
          parent: 'Top Level',
          attributes: {
            keyA: 'val A',
            keyB: 'val B',
            keyC: 'val C',
          },
        },
        {
          name: 'Level 2: B',
          parent: 'Top Level',
        },
      ],
    },
  ];

  // Clear method spies on prototype before each test
  afterEach(() => jest.clearAllMocks());

  it('builds a tree on each render', () => {
    jest.spyOn(Tree.prototype, 'generateTree');
    const renderedComponent = shallow(
      <Tree data={mockData} />
    );
    expect(renderedComponent.instance().generateTree).toHaveBeenCalled();
  });

  it('maps every node onto a <Node />', () => {
    const nodeCount = 3; // 1 top level node + 2 child nodes in mockData
    const renderedComponent = shallow(
      <Tree data={mockData} />
    );

    expect(renderedComponent.find(Node).length).toBe(nodeCount);
  });

  it('maps every parent-child relation onto a <Link />', () => {
    const linkCount = 2;
    const renderedComponent = shallow(
      <Tree data={mockData} />
    );

    expect(renderedComponent.find(Link).length).toBe(linkCount);
  });

  it('applies the `translate` prop when specified', () => {
    const fixture = { x: 123, y: 321 };
    const expected = `translate(${fixture.x},${fixture.y})`;
    const renderedComponent = shallow(
      <Tree
        data={mockData}
        translate={fixture}
      />
    );
    expect(renderedComponent.find(TransitionGroup).prop('transform')).toBe(expected);
  });

  it('passes `props.orientation` to its <Node /> and <Link /> children', () => {
    const fixture = 'vertical';
    const renderedComponent = shallow(
      <Tree
        data={mockData}
        orientation={fixture}
      />
    );

    expect(renderedComponent.find(Node).everyWhere((n) =>
      n.prop('orientation') === fixture)
    ).toBe(true);
    expect(renderedComponent.find(Link).everyWhere((n) =>
      n.prop('orientation') === fixture)
    ).toBe(true);
  });

  it('passes `handleNodeToggle()` to its <Node /> children as onClick prop', () => {
    const renderedComponent = shallow(
      <Tree data={mockData} />
    );

    expect(renderedComponent.find(Node).everyWhere((n) =>
      n.prop('onClick') === renderedComponent.instance().handleNodeToggle)
    ).toBe(true);
  });

  it('collapses a node\'s children when it is clicked in an expanded state', () => {
    jest.spyOn(Tree.prototype, 'handleNodeToggle');
    jest.spyOn(Tree.prototype, 'collapseNode');
    const renderedComponent = mount(
      <Tree data={mockData} />
    );
    renderedComponent.find(Node).first().simulate('click'); // collapse

    expect(Tree.prototype.handleNodeToggle).toHaveBeenCalledTimes(1);
    expect(Tree.prototype.collapseNode).toHaveBeenCalled();
  });

  it('expands a node\'s children when it is clicked in a collapsed state', () => {
    jest.spyOn(Tree.prototype, 'handleNodeToggle');
    jest.spyOn(Tree.prototype, 'collapseNode');
    jest.spyOn(Tree.prototype, 'expandNode');
    const renderedComponent = mount(
      <Tree data={mockData} />
    );
    renderedComponent.find(Node).first().simulate('click'); // collapse
    renderedComponent.find(Node).first().simulate('click'); // re-expand

    expect(Tree.prototype.handleNodeToggle).toHaveBeenCalledTimes(2);
    expect(Tree.prototype.collapseNode).toHaveBeenCalled();
    expect(Tree.prototype.expandNode).toHaveBeenCalled();
  });

  it('does not collapse a node if `props.collapsible` is false', () => {
    jest.spyOn(Tree.prototype, 'handleNodeToggle');
    jest.spyOn(Tree.prototype, 'collapseNode');
    const renderedComponent = mount(
      <Tree
        data={mockData}
        collapsible={false}
      />
    );
    renderedComponent.find(Node).first().simulate('click');

    expect(Tree.prototype.handleNodeToggle).toHaveBeenCalledTimes(1);
    expect(Tree.prototype.collapseNode).toHaveBeenCalledTimes(0);
  });

  it('sets tree depth to `props.initialDepth` if specified', () => {
    jest.spyOn(Tree.prototype, 'setInitialTreeDepth');
    mount(
      <Tree
        data={mockData}
        initialDepth={1}
      />
    );

    expect(Tree.prototype.setInitialTreeDepth).toHaveBeenCalled();
  });

  // it('allows zooming in/out according to `props.scaleExtent` if `props.zoomable`', () => {
  //   const zoomableComponent = mount(
  //     <Tree
  //       data={mockData}
  //     />
  //   );
  //   const nonZoomableComponent = mount(
  //     <Tree
  //       data={mockData}
  //       zoomable={false}
  //     />
  //   );
  //
  //   zoomableComponent.find('svg').simulate('touchmove');
  //
  //   expect(zoomableComponent.find('svg').prop('transform')).toBeDefined();
  //   expect(nonZoomableComponent.find('svg').prop('transform')).toBeUndefined();
  // });
});
<|endoftext|>


<commit_before>var gulp = require('gulp'),
	sass = require('gulp-sass'),
	autoprefixer = require('gulp-autoprefixer'),
	uglify = require('gulp-uglify'),
	rename = require('gulp-rename'),
	notify = require('gulp-notify'),
	del = require('del'),
	csso = require('gulp-csso');

// Development tasks
// ----------------------------------------------------------------------

gulp.task('styles', function() {
	gulp.src('source/css/modaal.scss')
		.pipe(sass({
						style: 'expanded',
						sourcemap: false
				})
					.on('error', sass.logError))
		.pipe(gulp.dest('source/css'))
		.pipe(notify({
			message: 'Modaal styles task complete'
		}));
});

// For demo website only, can be removed
gulp.task('demo-styles', function() {
	gulp.src('demo/css/demo.scss')
		.pipe(sass({
						style: 'expanded',
						sourcemap: false
				})
					.on('error', sass.logError))
		.pipe(gulp.dest('demo/css'))
		.pipe(notify({
			message: 'Demo styles task complete'
		}));
});

gulp.task('watch', function() {
	gulp.watch('source/css/*.scss', ['styles']);
	// for demo site only, can be removed
	gulp.watch('demo/css/*.scss', ['demo-styles']);
});

// Distribute tasks
// ----------------------------------------------------------------------

gulp.task('min-modaal', function() {
	gulp.src(['source/js/modaal.js'])
		.pipe(uglify({
			preserveComments: 'some'
		}))
		.pipe(rename({
			suffix: '.min',
			extname: '.js'
		}))
		.pipe(gulp.dest('dist/js/'))
		.pipe(notify({
			message: 'Successfully uglified Modaal.'
		}));

	gulp.src('source/css/modaal.css')
				.pipe(csso())
				.pipe(rename('modaal.min.css'))
		.pipe(gulp.dest('dist/css/'))
		.pipe(notify({
			message: 'Min copy created.'
		}));
});

gulp.task('copy-to-dist', function() {
	// copy other files to dist folder
	gulp.src('source/js/modaal.js')
		.pipe(gulp.dest('dist/js/'));

	gulp.src('source/css/modaal.scss')
		.pipe(gulp.dest('dist/css/'));

	gulp.src('source/css/modaal.css')
		.pipe(gulp.dest('dist/css/'))
		.pipe(notify({
			message: 'Moved to dist.'
		}));
});

// Now run in order
gulp.task('dist', ['min-modaal', 'copy-to-dist']);
<commit_msg>Added autoprefixer into watch tasks<commit_after>var gulp = require('gulp'),
	sass = require('gulp-sass'),
	autoprefixer = require('gulp-autoprefixer'),
	uglify = require('gulp-uglify'),
	rename = require('gulp-rename'),
	notify = require('gulp-notify'),
	del = require('del'),
	csso = require('gulp-csso');

// Development tasks
// ----------------------------------------------------------------------

gulp.task('styles', function() {
	gulp.src('source/css/modaal.scss')
		.pipe(sass({
			style: 'expanded',
			sourcemap: false
		})
			.on('error', sass.logError))
		.pipe(autoprefixer({
			browsers: ['last 2 version', 'ie 8', 'ie 9']
		}))
		.pipe(gulp.dest('source/css'))
		.pipe(notify({
			message: 'Modaal styles task complete'
		}));
});

// For demo website only, can be removed
gulp.task('demo-styles', function() {
	gulp.src('demo/css/demo.scss')
		.pipe(sass({
			style: 'expanded',
			sourcemap: false
		})
			.on('error', sass.logError))
		.pipe(autoprefixer({
			browsers: ['last 2 version', 'ie 8', 'ie 9']
		}))
		.pipe(gulp.dest('demo/css'))
		.pipe(notify({
			message: 'Demo styles task complete'
		}));
});

gulp.task('watch', function() {
	gulp.watch('source/css/*.scss', ['styles']);
	// for demo site only, can be removed
	gulp.watch('demo/css/*.scss', ['demo-styles']);
});

// Distribute tasks
// ----------------------------------------------------------------------

gulp.task('min-modaal', function() {
	gulp.src(['source/js/modaal.js'])
		.pipe(uglify({
			preserveComments: 'some'
		}))
		.pipe(rename({
			suffix: '.min',
			extname: '.js'
		}))
		.pipe(gulp.dest('dist/js/'))
		.pipe(notify({
			message: 'Successfully uglified Modaal.'
		}));

	gulp.src('source/css/modaal.css')
		.pipe(csso())
		.pipe(rename('modaal.min.css'))
		.pipe(gulp.dest('dist/css/'))
		.pipe(notify({
			message: 'Min copy created.'
		}));
});

gulp.task('copy-to-dist', function() {
	// copy other files to dist folder
	gulp.src('source/js/modaal.js')
		.pipe(gulp.dest('dist/js/'));

	gulp.src('source/css/modaal.scss')
		.pipe(gulp.dest('dist/css/'));

	gulp.src('source/css/modaal.css')
		.pipe(gulp.dest('dist/css/'))
		.pipe(notify({
			message: 'Moved to dist.'
		}));
});

// Now run in order
gulp.task('dist', ['min-modaal', 'copy-to-dist']);
<|endoftext|>


<commit_before>(function(global) {

  'use strict';

  var fabric = global.fabric || (global.fabric = { }),
      pi = Math.PI,
      extend = fabric.util.object.extend;

  if (fabric.Circle) {
    fabric.warn('fabric.Circle is already defined.');
    return;
  }

  /**
   * Circle class
   * @class fabric.Circle
   * @extends fabric.Object
   * @see {@link fabric.Circle#initialize} for constructor definition
   */
  fabric.Circle = fabric.util.createClass(fabric.Object, /** @lends fabric.Circle.prototype */ {

    /**
     * Type of an object
     * @type String
     * @default
     */
    type: 'circle',

    /**
     * Radius of this circle
     * @type Number
     * @default
     */
    radius: 0,

    /**
     * Start angle of the circle, moving clockwise
     * @type Number
     * @default 0
     */
    startAngle: 0,

    /**
     * End angle of the circle
     * @type Number
     * @default 2Pi
     */
     endAngle: pi * 2,

    /**
     * Constructor
     * @param {Object} [options] Options object
     * @return {fabric.Circle} thisArg
     */
    initialize: function(options) {
      options = options || { };

      this.callSuper('initialize', options);
      this.set('radius', options.radius || 0);
      this.startAngle = options.startAngle || this.startAngle;
      this.endAngle = options.endAngle || this.endAngle;
    },

    /**
     * @private
     * @param {String} key
     * @param {Any} value
     * @return {fabric.Circle} thisArg
     */
    _set: function(key, value) {
      this.callSuper('_set', key, value);

      if (key === 'radius') {
        this.setRadius(value);
      }

      return this;
    },

    /**
     * Returns object representation of an instance
     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
     * @return {Object} object representation of an instance
     */
    toObject: function(propertiesToInclude) {
      return extend(this.callSuper('toObject', propertiesToInclude), {
        radius: this.get('radius'),
        startAngle: this.startAngle,
        endAngle: this.endAngle
      });
    },

    /* _TO_SVG_START_ */
    /**
     * Returns svg representation of an instance
     * @param {Function} [reviver] Method for further parsing of svg representation.
     * @return {String} svg representation of an instance
     */
    toSVG: function(reviver) {
      var markup = this._createBaseSVGMarkup(), x = 0, y = 0,
      angle = (this.endAngle - this.startAngle) % ( 2 * pi);

      if (angle === 0) {
        if (this.group && this.group.type === 'path-group') {
          x = this.left + this.radius;
          y = this.top + this.radius;
        }
        markup.push(
          '<circle ',
            'cx="' + x + '" cy="' + y + '" ',
            'r="', this.radius,
            '" style="', this.getSvgStyles(),
            '" transform="', this.getSvgTransform(),
            ' ', this.getSvgTransformMatrix(),
          '"/>\n'
        );
      } else {
        var startX = Math.cos(this.startAngle) * this.radius,
            startY = Math.sin(this.startAngle) * this.radius,
            endX = Math.cos(this.endAngle) * this.radius,
            endY = Math.sin(this.endAngle) * this.radius,
            largeFlag = angle > pi ? '1' : '0';

        markup.push(
          '<path d="M ' + startX + ' ' + startY,
          ' A ' + this.radius + ' ' + this.radius,
          ' 0 ', + largeFlag + ' 1', ' ' + endX + ' ' + endY,
          '" style="', this.getSvgStyles(),
          '" transform="', this.getSvgTransform(),
          ' ', this.getSvgTransformMatrix(),
          '"/>\n'
        );
      }

      return reviver ? reviver(markup.join('')) : markup.join('');
    },
    /* _TO_SVG_END_ */

    /**
     * @private
     * @param {CanvasRenderingContext2D} ctx context to render on
     * @param {Boolean} [noTransform] When true, context is not transformed
     */
    _render: function(ctx, noTransform) {
      ctx.beginPath();
      ctx.arc(noTransform ? this.left + this.radius : 0, noTransform ? this.top + this.radius : 0, this.radius, this.startAngle, this.endAngle, false);
      this._renderFill(ctx);
      this._renderStroke(ctx);
    },

    /**
     * Returns horizontal radius of an object (according to how an object is scaled)
     * @return {Number}
     */
    getRadiusX: function() {
      return this.get('radius') * this.get('scaleX');
    },

    /**
     * Returns vertical radius of an object (according to how an object is scaled)
     * @return {Number}
     */
    getRadiusY: function() {
      return this.get('radius') * this.get('scaleY');
    },

    /**
     * Sets radius of an object (and updates width accordingly)
     * @return {Number}
     */
    setRadius: function(value) {
      this.radius = value;
      this.set('width', value * 2).set('height', value * 2);
    },

    /**
     * Returns complexity of an instance
     * @return {Number} complexity of this instance
     */
    complexity: function() {
      return 1;
    }
  });

  /* _FROM_SVG_START_ */
  /**
   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Circle.fromElement})
   * @static
   * @memberOf fabric.Circle
   * @see: http://www.w3.org/TR/SVG/shapes.html#CircleElement
   */
  fabric.Circle.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy r'.split(' '));

  /**
   * Returns {@link fabric.Circle} instance from an SVG element
   * @static
   * @memberOf fabric.Circle
   * @param {SVGElement} element Element to parse
   * @param {Object} [options] Options object
   * @throws {Error} If value of `r` attribute is missing or invalid
   * @return {fabric.Circle} Instance of fabric.Circle
   */
  fabric.Circle.fromElement = function(element, options) {
    options || (options = { });

    var parsedAttributes = fabric.parseAttributes(element, fabric.Circle.ATTRIBUTE_NAMES);

    if (!isValidRadius(parsedAttributes)) {
      throw new Error('value of `r` attribute is required and can not be negative');
    }

    parsedAttributes.left = parsedAttributes.left || 0;
    parsedAttributes.top = parsedAttributes.top || 0;

    var obj = new fabric.Circle(extend(parsedAttributes, options));

    obj.left -= obj.radius;
    obj.top -= obj.radius;
    return obj;
  };

  /**
   * @private
   */
  function isValidRadius(attributes) {
    return (('radius' in attributes) && (attributes.radius > 0));
  }
  /* _FROM_SVG_END_ */

  /**
   * Returns {@link fabric.Circle} instance from an object representation
   * @static
   * @memberOf fabric.Circle
   * @param {Object} object Object to create an instance from
   * @return {Object} Instance of fabric.Circle
   */
  fabric.Circle.fromObject = function(object) {
    return new fabric.Circle(object);
  };

})(typeof exports !== 'undefined' ? exports : this);
<commit_msg>Update circle.class.js<commit_after>(function(global) {

  'use strict';

  var fabric = global.fabric || (global.fabric = { }),
      pi = Math.PI,
      extend = fabric.util.object.extend;

  if (fabric.Circle) {
    fabric.warn('fabric.Circle is already defined.');
    return;
  }

  /**
   * Circle class
   * @class fabric.Circle
   * @extends fabric.Object
   * @see {@link fabric.Circle#initialize} for constructor definition
   */
  fabric.Circle = fabric.util.createClass(fabric.Object, /** @lends fabric.Circle.prototype */ {

    /**
     * Type of an object
     * @type String
     * @default
     */
    type: 'circle',

    /**
     * Radius of this circle
     * @type Number
     * @default
     */
    radius: 0,

    /**
     * Start angle of the circle, moving clockwise
     * @type Number
     * @default 0
     */
    startAngle: 0,

    /**
     * End angle of the circle
     * @type Number
     * @default 2Pi
     */
    endAngle: pi * 2,

    /**
     * Constructor
     * @param {Object} [options] Options object
     * @return {fabric.Circle} thisArg
     */
    initialize: function(options) {
      options = options || { };

      this.callSuper('initialize', options);
      this.set('radius', options.radius || 0);
      this.startAngle = options.startAngle || this.startAngle;
      this.endAngle = options.endAngle || this.endAngle;
    },

    /**
     * @private
     * @param {String} key
     * @param {Any} value
     * @return {fabric.Circle} thisArg
     */
    _set: function(key, value) {
      this.callSuper('_set', key, value);

      if (key === 'radius') {
        this.setRadius(value);
      }

      return this;
    },

    /**
     * Returns object representation of an instance
     * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
     * @return {Object} object representation of an instance
     */
    toObject: function(propertiesToInclude) {
      return extend(this.callSuper('toObject', propertiesToInclude), {
        radius: this.get('radius'),
        startAngle: this.startAngle,
        endAngle: this.endAngle
      });
    },

    /* _TO_SVG_START_ */
    /**
     * Returns svg representation of an instance
     * @param {Function} [reviver] Method for further parsing of svg representation.
     * @return {String} svg representation of an instance
     */
    toSVG: function(reviver) {
      var markup = this._createBaseSVGMarkup(), x = 0, y = 0,
      angle = (this.endAngle - this.startAngle) % ( 2 * pi);

      if (angle === 0) {
        if (this.group && this.group.type === 'path-group') {
          x = this.left + this.radius;
          y = this.top + this.radius;
        }
        markup.push(
          '<circle ',
            'cx="' + x + '" cy="' + y + '" ',
            'r="', this.radius,
            '" style="', this.getSvgStyles(),
            '" transform="', this.getSvgTransform(),
            ' ', this.getSvgTransformMatrix(),
          '"/>\n'
        );
      }
      else {
        var startX = Math.cos(this.startAngle) * this.radius,
            startY = Math.sin(this.startAngle) * this.radius,
            endX = Math.cos(this.endAngle) * this.radius,
            endY = Math.sin(this.endAngle) * this.radius,
            largeFlag = angle > pi ? '1' : '0';

        markup.push(
          '<path d="M ' + startX + ' ' + startY,
          ' A ' + this.radius + ' ' + this.radius,
          ' 0 ', + largeFlag + ' 1', ' ' + endX + ' ' + endY,
          '" style="', this.getSvgStyles(),
          '" transform="', this.getSvgTransform(),
          ' ', this.getSvgTransformMatrix(),
          '"/>\n'
        );
      }

      return reviver ? reviver(markup.join('')) : markup.join('');
    },
    /* _TO_SVG_END_ */

    /**
     * @private
     * @param {CanvasRenderingContext2D} ctx context to render on
     * @param {Boolean} [noTransform] When true, context is not transformed
     */
    _render: function(ctx, noTransform) {
      ctx.beginPath();
      ctx.arc(noTransform ? this.left + this.radius : 0, noTransform ? this.top + this.radius : 0, this.radius, this.startAngle, this.endAngle, false);
      this._renderFill(ctx);
      this._renderStroke(ctx);
    },

    /**
     * Returns horizontal radius of an object (according to how an object is scaled)
     * @return {Number}
     */
    getRadiusX: function() {
      return this.get('radius') * this.get('scaleX');
    },

    /**
     * Returns vertical radius of an object (according to how an object is scaled)
     * @return {Number}
     */
    getRadiusY: function() {
      return this.get('radius') * this.get('scaleY');
    },

    /**
     * Sets radius of an object (and updates width accordingly)
     * @return {Number}
     */
    setRadius: function(value) {
      this.radius = value;
      this.set('width', value * 2).set('height', value * 2);
    },

    /**
     * Returns complexity of an instance
     * @return {Number} complexity of this instance
     */
    complexity: function() {
      return 1;
    }
  });

  /* _FROM_SVG_START_ */
  /**
   * List of attribute names to account for when parsing SVG element (used by {@link fabric.Circle.fromElement})
   * @static
   * @memberOf fabric.Circle
   * @see: http://www.w3.org/TR/SVG/shapes.html#CircleElement
   */
  fabric.Circle.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy r'.split(' '));

  /**
   * Returns {@link fabric.Circle} instance from an SVG element
   * @static
   * @memberOf fabric.Circle
   * @param {SVGElement} element Element to parse
   * @param {Object} [options] Options object
   * @throws {Error} If value of `r` attribute is missing or invalid
   * @return {fabric.Circle} Instance of fabric.Circle
   */
  fabric.Circle.fromElement = function(element, options) {
    options || (options = { });

    var parsedAttributes = fabric.parseAttributes(element, fabric.Circle.ATTRIBUTE_NAMES);

    if (!isValidRadius(parsedAttributes)) {
      throw new Error('value of `r` attribute is required and can not be negative');
    }

    parsedAttributes.left = parsedAttributes.left || 0;
    parsedAttributes.top = parsedAttributes.top || 0;

    var obj = new fabric.Circle(extend(parsedAttributes, options));

    obj.left -= obj.radius;
    obj.top -= obj.radius;
    return obj;
  };

  /**
   * @private
   */
  function isValidRadius(attributes) {
    return (('radius' in attributes) && (attributes.radius > 0));
  }
  /* _FROM_SVG_END_ */

  /**
   * Returns {@link fabric.Circle} instance from an object representation
   * @static
   * @memberOf fabric.Circle
   * @param {Object} object Object to create an instance from
   * @return {Object} Instance of fabric.Circle
   */
  fabric.Circle.fromObject = function(object) {
    return new fabric.Circle(object);
  };

})(typeof exports !== 'undefined' ? exports : this);
<|endoftext|>


<commit_before>'use strict';

const gulp = require('gulp');
const browserSync = require('browser-sync');
const reload = browserSync.reload;

const IS_DEVELOPMENT = process.env.NODE_ENV === 'development';
const TASK_ENV = IS_DEVELOPMENT ? 'dev' : 'dist';

gulp.task('sass:dev', require('./tasks/sass').dev);
gulp.task('sass:dist', require('./tasks/sass').dist);
gulp.task('pug:dev', require('./tasks/pug').dev);
gulp.task('pug:dist', require('./tasks/pug').dist);

// Bundle all our webpack modules.
// Will handle which ENV in the bundler.
gulp.task('bundle', require('./tasks/bundler'));

gulp.task('build', [`sass:${TASK_ENV}`, 'bundle', `pug:${TASK_ENV}`], () => {
  if (IS_DEVELOPMENT) {
    gulp.src('dist/**/*')
      .pipe(gulp.dest('docs/dist'));
  }
});

gulp.task('serve', ['build'], () => {
  browserSync.init({
    browser: 'google chrome',
    server: {
      baseDir: ['.tmp', 'src']
    }
  });

  gulp.watch(['src/**/*.scss'], ['sass:dev'])
  gulp.watch(['docs/**/*.pug'], ['pug:dev', reload]);
});
<commit_msg>chore(build): copy dist assets to docs<commit_after>'use strict';

const gulp = require('gulp');
const browserSync = require('browser-sync');
const reload = browserSync.reload;

const IS_DEVELOPMENT = process.env.NODE_ENV === 'development';
const TASK_ENV = IS_DEVELOPMENT ? 'dev' : 'dist';

gulp.task('sass:dev', require('./tasks/sass').dev);
gulp.task('sass:dist', require('./tasks/sass').dist);
gulp.task('pug:dev', require('./tasks/pug').dev);
gulp.task('pug:dist', require('./tasks/pug').dist);

// Bundle all our webpack modules.
// Will handle which ENV in the bundler.
gulp.task('bundle', require('./tasks/bundler'));

gulp.task('build', [`sass:${TASK_ENV}`, 'bundle', `pug:${TASK_ENV}`], () => {
  if (!IS_DEVELOPMENT) {
    gulp.src([
      'dist/js/formed.min.js',
      'dist/js/formed.min.js.map'])
      .pipe(gulp.dest('docs/dist/js'));

    gulp.src('dist/css/*')
      .pipe(gulp.dest('docs/dist/css'));
  }
});

gulp.task('serve', ['build'], () => {
  browserSync.init({
    browser: 'google chrome',
    server: {
      baseDir: ['.tmp', 'src']
    }
  });

  gulp.watch(['src/**/*.scss'], ['sass:dev'])
  gulp.watch(['docs/**/*.pug'], ['pug:dev', reload]);
});
<|endoftext|>


<commit_before>var json = require('./json').json;
var stringify = require('./json').stringify;
var documents = require('./doc');

module.exports = function help(keepalive, req, next, stream/*, converter*/) {
  var conf = this.configure()
    , converter
    , alias = this.finder.getCommandByName;
  var style = typeof keepalive === 'string'
    ? keepalive : process.env.CLI_TOOLKIT_HELP_STYLE || conf.help.style;
  stream = stream || process.stdout;
  var cmd;
  //console.dir(req.unparsed);
  if(req && req.unparsed && req.unparsed.length) {
    cmd = alias(req.unparsed[0], this.commands())
  }
  // NOTE: this handles --help <cmd> syntax
  if(cmd && !process.env.CLI_TOOLKIT_HELP_CMD) {
    //console.log('got unparsed cmd %s', cmd.names());
    process.env.CLI_TOOLKIT_HELP_CMD = req.unparsed[0];
  }
  if(typeof next !== 'function' && !stream) {
    stream = next;
  }
  if(style) {
    converter = documents[style];
    if(converter) {
      converter = converter(this);
    }
  }
  if(!converter) {
    converter = documents.gnu(this);
  }
  converter.style = style;
  var data = json.call(this);
  var listeners = this.listeners('help');
  if(listeners.length) {
    this.emit('help', data, converter, stream || process.stdout);
  }else{
    converter.write(data, stream);
  }

  process.env.CLI_TOOLKIT_HELP_CMD = '';
  this.emit('help:trailers', converter, data, stream);
  if(conf.exit && keepalive !== true) {
    process.exit();
  }
  if((keepalive === true || typeof keepalive === 'string')
     && typeof next === 'function') {
    next();
  }
  return false;
}

module.exports.fmt = require('./doc/formats');
module.exports.documents = documents;
module.exports.json = json;
module.exports.stringify = stringify;
module.exports.styles = Object.keys(documents);

// utilities
module.exports.pad = documents.gnu.pad;
module.exports.repeat = documents.gnu.repeat;
module.exports.longest = documents.gnu.longest;
module.exports.section = documents.gnu.section;
<commit_msg>Easily suppress output in test env.<commit_after>var json = require('./json').json;
var stringify = require('./json').stringify;
var documents = require('./doc');

module.exports = function help(keepalive, req, next, stream/*, converter*/) {
  if(process.env.NODE_ENV === 'test' && !process.env.DEBUG) {
    return;
  }
  var conf = this.configure()
    , converter
    , alias = this.finder.getCommandByName;
  var style = typeof keepalive === 'string'
    ? keepalive : process.env.CLI_TOOLKIT_HELP_STYLE || conf.help.style;
  stream = stream || process.stdout;
  var cmd;
  //console.dir(req.unparsed);
  if(req && req.unparsed && req.unparsed.length) {
    cmd = alias(req.unparsed[0], this.commands())
  }
  // NOTE: this handles --help <cmd> syntax
  if(cmd && !process.env.CLI_TOOLKIT_HELP_CMD) {
    //console.log('got unparsed cmd %s', cmd.names());
    process.env.CLI_TOOLKIT_HELP_CMD = req.unparsed[0];
  }
  if(typeof next !== 'function' && !stream) {
    stream = next;
  }
  if(style) {
    converter = documents[style];
    if(converter) {
      converter = converter(this);
    }
  }
  if(!converter) {
    converter = documents.gnu(this);
  }
  converter.style = style;
  var data = json.call(this);
  var listeners = this.listeners('help');
  if(listeners.length) {
    this.emit('help', data, converter, stream || process.stdout);
  }else{
    converter.write(data, stream);
  }

  process.env.CLI_TOOLKIT_HELP_CMD = '';
  this.emit('help:trailers', converter, data, stream);
  if(conf.exit && keepalive !== true) {
    process.exit();
  }
  if((keepalive === true || typeof keepalive === 'string')
     && typeof next === 'function') {
    next();
  }
  return false;
}

module.exports.fmt = require('./doc/formats');
module.exports.documents = documents;
module.exports.json = json;
module.exports.stringify = stringify;
module.exports.styles = Object.keys(documents);

// utilities
module.exports.pad = documents.gnu.pad;
module.exports.repeat = documents.gnu.repeat;
module.exports.longest = documents.gnu.longest;
module.exports.section = documents.gnu.section;
<|endoftext|>


<commit_before>/**
 * @file TreeSelect component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, createRef} from 'react';
import PropTypes from 'prop-types';
import isArray from 'lodash/isArray';
import classNames from 'classnames';

import Dropdown from '../Dropdown';
import Tree from '../Tree';
import Theme from '../Theme';
import TextField from '../TextField';

import SelectMode from '../_statics/SelectMode';
import VirtualRoot from '../_statics/VirtualRoot';
import Position from '../_statics/Position';

import Util from '../_vendors/Util';
import TreeCalculation from '../_vendors/TreeCalculation';
import ComponentUtil from '../_vendors/ComponentUtil';
import Checkbox from '../Checkbox';

class TreeSelect extends Component {

    static SelectMode = SelectMode;
    static Theme = Theme;
    static Position = Position;
    static TipPosition = Position;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.dropdown = createRef();
        this.dropdownInstance = null;
        this.filter = createRef();

        this.state = {
            filter: '',
            value: props.value,
            popupVisible: false,
            path: props.selectMode === SelectMode.SINGLE_SELECT ?
                TreeCalculation.calPath(props.value, props.data, props) : undefined
        };

    }

    /**
     * public
     */
    startRipple = (e, props) => {
        this.dropdownInstance && this.dropdownInstance.startRipple(e, props);
    };

    /**
     * public
     */
    endRipple = () => {
        this.dropdownInstance && this.dropdownInstance.endRipple();
    };

    /**
     * public
     */
    triggerRipple = (e, props) => {
        this.dropdownInstance && this.dropdownInstance.triggerRipple(e, props);
    };

    /**
     * public
     */
    resetPopupPosition = () => {
        this.dropdownInstance && this.dropdownInstance.resetPosition();
    };

    /**
     * public
     */
    openPopup = () => {
        this.dropdownInstance && this.dropdownInstance.openPopup();
    };

    /**
     * public
     */
    closePopup = () => {
        this.dropdownInstance && this.dropdownInstance.closePopup();
    };

    getTriggerValue = (props = this.props) => {

        const {data, selectMode, placeholder, triggerRenderer, renderer, displayField, valueField} = props,
            {value, path} = this.state,
            isMultiSelect = selectMode === SelectMode.MULTI_SELECT;

        if (triggerRenderer) {
            return typeof triggerRenderer === 'function' ? triggerRenderer(value, path) : triggerRenderer;
        }

        if (!value) {
            return placeholder;
        }

        if (isMultiSelect) {
            return value.length > 0 ?
                value.length + ' selected'
                :
                placeholder;
        }

        let result = [];

        function addNode(node, i) {
            result.push(
                renderer ?

                        {renderer(node, path && path.slice(0, i + 1))}

                    :
                    Util.getTextByDisplayField(node, displayField, valueField)
            );
        }

        addNode(data, -1);

        if (path) {
            for (let i = 0, len = path.length; i < len; i++) {

                result.push(

                );

                addNode(path[i].node, i);

            }
        }

        return result;

    };

    handleNodeSelect = (value, path) => {

        if (this.props.selectMode !== SelectMode.SINGLE_SELECT) {
            return;
        }

        this.setState({
            path
        });

    };

    handleChange = value => {

        const {autoClose} = this.props;
        if (autoClose) {
            this.closePopup();
        }

        this.setState({
            value
        }, () => {
            const {onChange} = this.props;
            onChange && onChange(value);
        });

    };

    handlePopupOpen = e => {

        const {useFilter, onOpenPopup} = this.props;

        if (useFilter) {
            this.filter && this.filter.current && this.filter.current.focus();
        }

        onOpenPopup && onOpenPopup(e);

    };

    handlePopupClosed = e => {
        this.setState({
            popupVisible: false
        }, () => {
            const {onClosePopup} = this.props;
            onClosePopup && onClosePopup(e);
        });
    };

    handleFilterChange = filter => {
        this.setState({
            filter
        }, () => {
            this.dropdownInstance && this.dropdownInstance.resetPopupPosition();
        });
    };

    handleSelectAllClick = () => {

        const {data} = this.props,
            {value} = this.state;

        if (value && value.length > 0 && value.length === this.total) {
            this.handleChange([]);
            return;
        }

        let result = [];
        TreeCalculation.addRecursiveValue(isArray(data) ? {children: data} : data, result, this.props);
        this.handleChange(TreeCalculation.updateValue(result, this.props));

    };

    isEmpty = (filter = this.state.filter, data = this.props.data) => {

        if (!filter) {
            return !data;
        }

        const {displayField} = this.props;
        let result = true;

        Util.preOrderTraverse(isArray(data) ? {[VirtualRoot]: true, children: data} : data, node => {
            if (node && !!node[displayField]
                && node[displayField].toString().toUpperCase().includes(filter.toUpperCase())) {
                return result = false;
            }
        });

        return result;

    };

    componentDidMount() {
        this.dropdownInstance = this.dropdown && this.dropdown.current;
    }

    static getDerivedStateFromProps(props, state) {
        return {
            prevProps: props,
            value: ComponentUtil.getDerivedState(props, state, 'value')
        };
    }

    render() {

        const {

                className, triggerClassName, popupClassName, style, name, data, popupTheme, renderer,
                selectMode, valueField, displayField, descriptionField, triggerRenderer,
                useFilter, filterIconCls, filterPlaceholder, useSelectAll, selectAllText, isSelectRecursive,
                allowCollapse, collapsed, indentWidth,
                onNodeClick, popupChildren, noMatchedMsg,
                collapsedIconCls, expandedIconCls, radioUncheckedIconCls, radioCheckedIconCls,
                checkboxUncheckedIconCls, checkboxCheckedIconCls, checkboxIndeterminateIconCls,

                // not passing down these props
                onChange,

                ...restProps

            } = this.props,
            {value, filter, popupVisible} = this.state,

            isMultiSelect = selectMode === SelectMode.MULTI_SELECT;

        this.total = TreeCalculation.getTotalCount(data);

        return (

                {
                    name ?
                        <input type="hidden"
                               name={name}
                               value={Util.getValueByValueField(value, valueField, displayField)}/>
                        :
                        null
                }

                <Dropdown {...restProps}
                          ref={this.dropdown}
                          triggerClassName={classNames({
                              activated: popupVisible,
                              empty: !triggerRenderer && (!value || value.length < 1),
                              [triggerClassName]: triggerClassName
                          })}
                          popupClassName={classNames('tree-select-popup', {
                              [popupClassName]: popupClassName
                          })}
                          popupTheme={popupTheme}
                          triggerValue={this.getTriggerValue()}
                          onOpenPopup={this.handlePopupOpen}
                          onClosePopup={this.handlePopupClosed}>

                        {
                            useFilter ?
                                <TextField ref={this.filter}
                                           className="tree-select-filter"
                                           value={filter}
                                           placeholder={filterPlaceholder}
                                           rightIconCls={filterIconCls}
                                           onChange={this.handleFilterChange}/>
                                :
                                null
                        }

                        {
                            isMultiSelect && useSelectAll ?
                                <div className="tree-node tree-select-all-wrapper"
                                     style={{padding: `0 ${indentWidth}px`}}
                                     onClick={this.handleSelectAllClick}>

                                        <Checkbox className="tree-node-select"
                                                  checked={value && value.length === this.total}
                                                  indeterminate={value && value.length > 0 && value.length < this.total}
                                                  uncheckedIconCls={checkboxUncheckedIconCls}
                                                  checkedIconCls={checkboxCheckedIconCls}
                                                  indeterminateIconCls={checkboxIndeterminateIconCls}/>
                                        {selectAllText}

                                :
                                null
                        }

                        {
                            useFilter ?

                                :
                                null
                        }

                        {
                            isMultiSelect && useSelectAll ?

                                :
                                null
                        }

                        {
                            this.isEmpty() ?

                                    {
                                        noMatchedMsg ?
                                            noMatchedMsg
                                            :

                                                No matched value.

                                    }

                                :
                                <Tree className="tree-select-list"
                                      theme={popupTheme}
                                      selectMode={selectMode}
                                      data={data}
                                      filter={filter}
                                      value={value}
                                      valueField={valueField}
                                      displayField={displayField}
                                      descriptionField={descriptionField}
                                      isSelectRecursive={isSelectRecursive}
                                      allowCollapse={allowCollapse}
                                      collapsed={collapsed}
                                      indentWidth={indentWidth}
                                      collapsedIconCls={collapsedIconCls}
                                      expandedIconCls={expandedIconCls}
                                      radioUncheckedIconCls={radioUncheckedIconCls}
                                      radioCheckedIconCls={radioCheckedIconCls}
                                      checkboxUncheckedIconCls={checkboxUncheckedIconCls}
                                      checkboxCheckedIconCls={checkboxCheckedIconCls}
                                      checkboxIndeterminateIconCls={checkboxIndeterminateIconCls}
                                      renderer={renderer}
                                      onNodeClick={onNodeClick}
                                      onNodeSelect={this.handleNodeSelect}
                                      onChange={this.handleChange}/>
                        }

                    {popupChildren}

                </Dropdown>

        );

    }
}

TreeSelect.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * The CSS class name of the trigger element.
     */
    triggerClassName: PropTypes.string,

    /**
     * The class name of the popup element.
     */
    popupClassName: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * Override the styles of the popup element.
     */
    popupStyle: PropTypes.object,

    /**
     * The theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * The theme.
     */
    popupTheme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    position: PropTypes.oneOf(Util.enumerateValue(Position)),

    /**
     * The name of the dropDownSelect.
     */
    name: PropTypes.string,

    /**
     * The value of the dropDownSelect.
     */
    value: PropTypes.any,

    /**
     * The placeholder of the dropDownSelect.
     */
    placeholder: PropTypes.string,

    title: PropTypes.string,
    tip: PropTypes.string,
    tipPosition: PropTypes.oneOf(Util.enumerateValue(Position)),
    triggerValue: PropTypes.string,
    rightIconCls: PropTypes.string,

    /**
     * The options data.
     */
    data: PropTypes.oneOfType([PropTypes.shape({

        /**
         * The CSS class name of the tree node.
         */
        className: PropTypes.string,

        /**
         * Override the styles of the tree node.
         */
        style: PropTypes.object,

        /**
         * The theme of the tree button.
         */
        theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

        /**
         * The text value of the tree button.Type can be string or number.
         */
        value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The tree node's display text. Type can be string, number or bool.
         */
        text: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The desc value of the tree node. Type can be string or number.
         */
        desc: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * If true,the tree node will be disabled.
         */
        disabled: PropTypes.bool,

        /**
         * If true,the button will be have loading effect.
         */
        isLoading: PropTypes.bool,

        /**
         * Use this property to display an icon. It will display on the left.
         */
        iconCls: PropTypes.string,

        /**
         * Use this property to display an icon. It will display on the right.
         */
        rightIconCls: PropTypes.string,

        /**
         * The message of tip.
         */
        title: PropTypes.string,

        children: PropTypes.array,

        /**
         * You can create a complicated renderer callback instead of value and desc prop.
         */
        itemRenderer: PropTypes.func,

        /**
         * Callback function fired when a tree node touch-tapped.
         */
        onClick: PropTypes.func

    }), PropTypes.array]),

    /**
     * The invalid message of dropDownSelect.
     */
    invalidMsg: PropTypes.string,

    /**
     * If true,the dropDownSelect will be disabled.
     */
    disabled: PropTypes.bool,

    /**
     * The select mode of listItem.Can be normal,checkbox.
     */
    selectMode: PropTypes.oneOf(Util.enumerateValue(SelectMode)),

    /**
     * The value field name in data. (default: "value")
     */
    valueField: PropTypes.string,

    /**
     * The display field name in data. (default: "text")
     */
    displayField: PropTypes.string,

    /**
     * The description field name in data. (default: "desc")
     */
    descriptionField: PropTypes.string,

    /**
     * The message of the dropDownSelect.
     */
    infoMsg: PropTypes.string,

    /**
     * Use this function to format the options's text.
     */
    textFormat: PropTypes.func,

    /**
     * If true,the drop-down box automatically closed after selection.
     */
    autoClose: PropTypes.bool,

    useFilter: PropTypes.bool,
    filterIconCls: PropTypes.string,
    filterPlaceholder: PropTypes.string,
    useSelectAll: PropTypes.bool,
    selectAllText: PropTypes.string,
    noMatchedMsg: PropTypes.string,
    isSelectRecursive: PropTypes.bool,
    allowCollapse: PropTypes.bool,
    collapsed: PropTypes.bool,
    autoPopupWidth: PropTypes.bool,
    collapsedIconCls: PropTypes.string,
    expandedIconCls: PropTypes.string,
    radioUncheckedIconCls: PropTypes.string,
    radioCheckedIconCls: PropTypes.string,
    checkboxUncheckedIconCls: PropTypes.string,
    checkboxCheckedIconCls: PropTypes.string,
    checkboxIndeterminateIconCls: PropTypes.string,

    popupChildren: PropTypes.any,

    resetPopPositionWait: PropTypes.number,
    indentWidth: PropTypes.number,

    renderer: PropTypes.func,

    triggerRenderer: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.func]),

    /**
     * Callback function fired when the button is touch-tapped.
     */
    onNodeClick: PropTypes.func,

    /**
     * Callback function fired when the popup is closed.
     */
    onClosePopup: PropTypes.func,

    /**
     * Callback function fired when a menu item is selected.
     */
    onChange: PropTypes.func,

    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    onMouseOver: PropTypes.func,
    onMouseOut: PropTypes.func,
    onOpenPopup: PropTypes.func

};

TreeSelect.defaultProps = {

    theme: Theme.DEFAULT,
    popupTheme: Theme.DEFAULT,

    placeholder: 'Please select ...',
    rightIconCls: 'fas fa-angle-down',
    disabled: false,
    selectMode: SelectMode.SINGLE_SELECT,
    tipPosition: Position.BOTTOM,

    valueField: 'value',
    displayField: 'text',
    descriptionField: 'desc',

    autoClose: true,
    useFilter: false,
    filterIconCls: 'fas fa-search',
    filterPlaceholder: 'Search ...',
    useSelectAll: false,
    selectAllText: 'Select All',

    isSelectRecursive: false,
    allowCollapse: true,
    collapsed: false,
    autoPopupWidth: true,
    resetPopPositionWait: 250,
    indentWidth: 20

};

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

import React, {Component, createRef} from 'react';
import PropTypes from 'prop-types';
import isArray from 'lodash/isArray';
import classNames from 'classnames';

import Dropdown from '../Dropdown';
import Tree from '../Tree';
import Theme from '../Theme';
import TextField from '../TextField';

import SelectMode from '../_statics/SelectMode';
import VirtualRoot from '../_statics/VirtualRoot';
import Position from '../_statics/Position';

import Util from '../_vendors/Util';
import TreeCalculation from '../_vendors/TreeCalculation';
import ComponentUtil from '../_vendors/ComponentUtil';
import Checkbox from '../Checkbox';

class TreeSelect extends Component {

    static SelectMode = SelectMode;
    static Theme = Theme;
    static Position = Position;
    static TipPosition = Position;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.dropdown = createRef();
        this.dropdownInstance = null;
        this.filter = createRef();

        this.state = {
            filter: '',
            value: props.value,
            popupVisible: false,
            path: props.selectMode === SelectMode.SINGLE_SELECT ?
                TreeCalculation.calPath(props.value, props.data, props) : undefined
        };

    }

    /**
     * public
     */
    startRipple = (e, props) => {
        this.dropdownInstance && this.dropdownInstance.startRipple(e, props);
    };

    /**
     * public
     */
    endRipple = () => {
        this.dropdownInstance && this.dropdownInstance.endRipple();
    };

    /**
     * public
     */
    triggerRipple = (e, props) => {
        this.dropdownInstance && this.dropdownInstance.triggerRipple(e, props);
    };

    /**
     * public
     */
    resetPopupPosition = () => {
        this.dropdownInstance && this.dropdownInstance.resetPosition();
    };

    /**
     * public
     */
    openPopup = () => {
        this.dropdownInstance && this.dropdownInstance.openPopup();
    };

    /**
     * public
     */
    closePopup = () => {
        this.dropdownInstance && this.dropdownInstance.closePopup();
    };

    getTriggerValue = (props = this.props) => {

        const {data, selectMode, placeholder, triggerRenderer, renderer, displayField, valueField} = props,
            {value, path} = this.state,
            isMultiSelect = selectMode === SelectMode.MULTI_SELECT;

        if (triggerRenderer) {
            return typeof triggerRenderer === 'function' ? triggerRenderer(value, path) : triggerRenderer;
        }

        if (!value) {
            return placeholder;
        }

        if (isMultiSelect) {
            return value.length > 0 ?
                value.length + ' selected'
                :
                placeholder;
        }

        let result = [];

        function addNode(node, i) {
            result.push(
                renderer ?

                        {renderer(node, path && path.slice(0, i + 1))}

                    :
                    Util.getTextByDisplayField(node, displayField, valueField)
            );
        }

        addNode(data, -1);

        if (path) {
            for (let i = 0, len = path.length; i < len; i++) {

                result.push(

                );

                addNode(path[i].node, i);

            }
        }

        return result;

    };

    handleNodeSelect = (value, path) => {

        if (this.props.selectMode !== SelectMode.SINGLE_SELECT) {
            return;
        }

        this.setState({
            path
        });

    };

    handleChange = value => {

        const {autoClose} = this.props;
        if (autoClose) {
            this.closePopup();
        }

        this.setState({
            value
        }, () => {
            const {onChange} = this.props;
            onChange && onChange(value);
        });

    };

    handlePopupOpen = e => {

        const {useFilter, onOpenPopup} = this.props;

        if (useFilter) {
            this.filter && this.filter.current && this.filter.current.focus();
        }

        onOpenPopup && onOpenPopup(e);

    };

    handlePopupClosed = e => {
        this.setState({
            popupVisible: false
        }, () => {
            const {onClosePopup} = this.props;
            onClosePopup && onClosePopup(e);
        });
    };

    handleFilterChange = filter => {
        this.setState({
            filter
        }, () => {
            this.dropdownInstance && this.dropdownInstance.resetPopupPosition();
        });
    };

    handleSelectAllClick = () => {

        const {data} = this.props,
            {value} = this.state;

        if (value && value.length > 0 && value.length === this.total) {
            this.handleChange([]);
            return;
        }

        let result = [];
        TreeCalculation.addRecursiveValue(isArray(data) ? {children: data} : data, result, this.props);
        this.handleChange(TreeCalculation.updateValue(result, this.props));

    };

    isEmpty = (filter = this.state.filter, data = this.props.data) => {

        if (!filter) {
            return !data;
        }

        const {displayField} = this.props;
        let result = true;

        Util.preOrderTraverse(isArray(data) ? {[VirtualRoot]: true, children: data} : data, node => {
            if (node && !!node[displayField]
                && node[displayField].toString().toUpperCase().includes(filter.toUpperCase())) {
                return result = false;
            }
        });

        return result;

    };

    componentDidMount() {
        this.dropdownInstance = this.dropdown && this.dropdown.current;
    }

    static getDerivedStateFromProps(props, state) {
        return {
            prevProps: props,
            value: ComponentUtil.getDerivedState(props, state, 'value')
        };
    }

    render() {

        const {

                className, triggerClassName, popupClassName, style, name, data, popupTheme, renderer,
                selectMode, valueField, displayField, descriptionField, triggerRenderer,
                useFilter, filterIconCls, filterPlaceholder, useSelectAll, selectAllText, isSelectRecursive,
                allowCollapse, collapsed, indentWidth,
                onNodeClick, popupChildren, noMatchedMsg, isNodeCollapsed,
                collapsedIconCls, expandedIconCls, radioUncheckedIconCls, radioCheckedIconCls,
                checkboxUncheckedIconCls, checkboxCheckedIconCls, checkboxIndeterminateIconCls,

                // not passing down these props
                onChange,

                ...restProps

            } = this.props,
            {value, filter, popupVisible} = this.state,

            isMultiSelect = selectMode === SelectMode.MULTI_SELECT;

        this.total = TreeCalculation.getTotalCount(data);

        return (

                {
                    name ?
                        <input type="hidden"
                               name={name}
                               value={Util.getValueByValueField(value, valueField, displayField)}/>
                        :
                        null
                }

                <Dropdown {...restProps}
                          ref={this.dropdown}
                          triggerClassName={classNames({
                              activated: popupVisible,
                              empty: !triggerRenderer && (!value || value.length < 1),
                              [triggerClassName]: triggerClassName
                          })}
                          popupClassName={classNames('tree-select-popup', {
                              [popupClassName]: popupClassName
                          })}
                          popupTheme={popupTheme}
                          triggerValue={this.getTriggerValue()}
                          onOpenPopup={this.handlePopupOpen}
                          onClosePopup={this.handlePopupClosed}>

                        {
                            useFilter ?
                                <TextField ref={this.filter}
                                           className="tree-select-filter"
                                           value={filter}
                                           placeholder={filterPlaceholder}
                                           rightIconCls={filterIconCls}
                                           onChange={this.handleFilterChange}/>
                                :
                                null
                        }

                        {
                            isMultiSelect && useSelectAll ?
                                <div className="tree-node tree-select-all-wrapper"
                                     style={{padding: `0 ${indentWidth}px`}}
                                     onClick={this.handleSelectAllClick}>

                                        <Checkbox className="tree-node-select"
                                                  checked={value && value.length === this.total}
                                                  indeterminate={value && value.length > 0 && value.length < this.total}
                                                  uncheckedIconCls={checkboxUncheckedIconCls}
                                                  checkedIconCls={checkboxCheckedIconCls}
                                                  indeterminateIconCls={checkboxIndeterminateIconCls}/>
                                        {selectAllText}

                                :
                                null
                        }

                        {
                            useFilter ?

                                :
                                null
                        }

                        {
                            isMultiSelect && useSelectAll ?

                                :
                                null
                        }

                        {
                            this.isEmpty() ?

                                    {
                                        noMatchedMsg ?
                                            noMatchedMsg
                                            :

                                                No matched value.

                                    }

                                :
                                <Tree className="tree-select-list"
                                      theme={popupTheme}
                                      selectMode={selectMode}
                                      data={data}
                                      filter={filter}
                                      value={value}
                                      valueField={valueField}
                                      displayField={displayField}
                                      descriptionField={descriptionField}
                                      isSelectRecursive={isSelectRecursive}
                                      allowCollapse={allowCollapse}
                                      collapsed={collapsed}
                                      indentWidth={indentWidth}
                                      collapsedIconCls={collapsedIconCls}
                                      expandedIconCls={expandedIconCls}
                                      radioUncheckedIconCls={radioUncheckedIconCls}
                                      radioCheckedIconCls={radioCheckedIconCls}
                                      checkboxUncheckedIconCls={checkboxUncheckedIconCls}
                                      checkboxCheckedIconCls={checkboxCheckedIconCls}
                                      checkboxIndeterminateIconCls={checkboxIndeterminateIconCls}
                                      renderer={renderer}
                                      isNodeCollapsed={isNodeCollapsed}
                                      onNodeClick={onNodeClick}
                                      onNodeSelect={this.handleNodeSelect}
                                      onChange={this.handleChange}/>
                        }

                    {popupChildren}

                </Dropdown>

        );

    }
}

TreeSelect.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * The CSS class name of the trigger element.
     */
    triggerClassName: PropTypes.string,

    /**
     * The class name of the popup element.
     */
    popupClassName: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * Override the styles of the popup element.
     */
    popupStyle: PropTypes.object,

    /**
     * The theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * The theme.
     */
    popupTheme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    position: PropTypes.oneOf(Util.enumerateValue(Position)),

    /**
     * The name of the dropDownSelect.
     */
    name: PropTypes.string,

    /**
     * The value of the dropDownSelect.
     */
    value: PropTypes.any,

    /**
     * The placeholder of the dropDownSelect.
     */
    placeholder: PropTypes.string,

    title: PropTypes.string,
    tip: PropTypes.string,
    tipPosition: PropTypes.oneOf(Util.enumerateValue(Position)),
    triggerValue: PropTypes.string,
    rightIconCls: PropTypes.string,

    /**
     * The options data.
     */
    data: PropTypes.oneOfType([PropTypes.shape({

        /**
         * The CSS class name of the tree node.
         */
        className: PropTypes.string,

        /**
         * Override the styles of the tree node.
         */
        style: PropTypes.object,

        /**
         * The theme of the tree button.
         */
        theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

        /**
         * The text value of the tree button.Type can be string or number.
         */
        value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The tree node's display text. Type can be string, number or bool.
         */
        text: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The desc value of the tree node. Type can be string or number.
         */
        desc: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * If true,the tree node will be disabled.
         */
        disabled: PropTypes.bool,

        /**
         * If true,the button will be have loading effect.
         */
        isLoading: PropTypes.bool,

        /**
         * Use this property to display an icon. It will display on the left.
         */
        iconCls: PropTypes.string,

        /**
         * Use this property to display an icon. It will display on the right.
         */
        rightIconCls: PropTypes.string,

        /**
         * The message of tip.
         */
        title: PropTypes.string,

        children: PropTypes.array,

        /**
         * You can create a complicated renderer callback instead of value and desc prop.
         */
        itemRenderer: PropTypes.func,

        /**
         * Callback function fired when a tree node touch-tapped.
         */
        onClick: PropTypes.func

    }), PropTypes.array]),

    /**
     * The invalid message of dropDownSelect.
     */
    invalidMsg: PropTypes.string,

    /**
     * If true,the dropDownSelect will be disabled.
     */
    disabled: PropTypes.bool,

    /**
     * The select mode of listItem.Can be normal,checkbox.
     */
    selectMode: PropTypes.oneOf(Util.enumerateValue(SelectMode)),

    /**
     * The value field name in data. (default: "value")
     */
    valueField: PropTypes.string,

    /**
     * The display field name in data. (default: "text")
     */
    displayField: PropTypes.string,

    /**
     * The description field name in data. (default: "desc")
     */
    descriptionField: PropTypes.string,

    /**
     * The message of the dropDownSelect.
     */
    infoMsg: PropTypes.string,

    /**
     * Use this function to format the options's text.
     */
    textFormat: PropTypes.func,

    /**
     * If true,the drop-down box automatically closed after selection.
     */
    autoClose: PropTypes.bool,

    useFilter: PropTypes.bool,
    filterIconCls: PropTypes.string,
    filterPlaceholder: PropTypes.string,
    useSelectAll: PropTypes.bool,
    selectAllText: PropTypes.string,
    noMatchedMsg: PropTypes.string,
    isSelectRecursive: PropTypes.bool,
    allowCollapse: PropTypes.bool,
    collapsed: PropTypes.bool,
    autoPopupWidth: PropTypes.bool,
    collapsedIconCls: PropTypes.string,
    expandedIconCls: PropTypes.string,
    radioUncheckedIconCls: PropTypes.string,
    radioCheckedIconCls: PropTypes.string,
    checkboxUncheckedIconCls: PropTypes.string,
    checkboxCheckedIconCls: PropTypes.string,
    checkboxIndeterminateIconCls: PropTypes.string,

    popupChildren: PropTypes.any,

    resetPopPositionWait: PropTypes.number,
    indentWidth: PropTypes.number,

    renderer: PropTypes.func,

    triggerRenderer: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.func]),

    /**
     * Callback function fired when the button is touch-tapped.
     */
    onNodeClick: PropTypes.func,

    /**
     * Callback function fired when the popup is closed.
     */
    onClosePopup: PropTypes.func,

    /**
     * Callback function fired when a menu item is selected.
     */
    onChange: PropTypes.func,

    isNodeCollapsed: PropTypes.func,
    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    onMouseOver: PropTypes.func,
    onMouseOut: PropTypes.func,
    onOpenPopup: PropTypes.func

};

TreeSelect.defaultProps = {

    theme: Theme.DEFAULT,
    popupTheme: Theme.DEFAULT,

    placeholder: 'Please select ...',
    rightIconCls: 'fas fa-angle-down',
    disabled: false,
    selectMode: SelectMode.SINGLE_SELECT,
    tipPosition: Position.BOTTOM,

    valueField: 'value',
    displayField: 'text',
    descriptionField: 'desc',

    autoClose: true,
    useFilter: false,
    filterIconCls: 'fas fa-search',
    filterPlaceholder: 'Search ...',
    useSelectAll: false,
    selectAllText: 'Select All',

    isSelectRecursive: false,
    allowCollapse: true,
    collapsed: false,
    autoPopupWidth: true,
    resetPopPositionWait: 250,
    indentWidth: 20

};

export default TreeSelect;
<|endoftext|>


<commit_before>var utils = {};

// 使い方
// utils.getCurrentLocation()
//     .done(function(location) {
// 	// success
//     })
//     .fail(function() {
// 	// faile
//     });
utils.getCurrentLocation = function() {
    var dfd = $.Deferred();

    if(!navigator.geolocation) {
	alert('Geolocation API is unavalable.');
	dfd.reject();
    }

    navigator.geolocation.getCurrentPosition(function(position) {
	console.log(position.coords);
	var location = {"latitude" : position.coords.latitude,
			"longitude": position.coords.longitude};
	dfd.resolve(location);
    }, function(error) {
	alert('ERROR(' + error.code + '): ' + error.message);
	dfd.reject();
    });

    return dfd.promise();
};<commit_msg>Minor change<commit_after>var utils = {};

// 使い方
// utils.getCurrentLocation()
//     .done(function(location) {
// 	// success
//     })
//     .fail(function() {
// 	// faile
//     });
utils.getCurrentLocation = function() {
    var dfd = $.Deferred();

    if(!navigator.geolocation) {
	alert('Geolocation API is unavalable.');
	dfd.reject();
    }

    navigator.geolocation.getCurrentPosition(function(position) {
	var location = {"latitude" : position.coords.latitude,
			"longitude": position.coords.longitude};
	dfd.resolve(location);
    }, function(error) {
	alert('ERROR(' + error.code + '): ' + error.message);
	dfd.reject();
    });

    return dfd.promise();
};<|endoftext|>