<commit_before>var assert = require("assert");
var path = require("path");
var fs = require("fs");
var createHash = require("crypto").createHash;
var hasOwn = Object.hasOwnProperty;
var defaultHandler = require.extensions[".js"];
var convertSourceMap = require("convert-source-map");

var config = {
  version: require("./package.json").version,
  cacheDir: process.env.BABEL_CACHE_DIR ||
    path.join(
      process.env.HOME || process.env.USERPROFILE || __dirname,
      ".babel-cache"
    ),
  babelOptions: require("./options").getDefaults()
};

exports = module.exports = function reconfigure(newConfig) {
  Object.keys(newConfig).forEach(function (key) {
    config[key] = newConfig[key];
  });
};

require.extensions[".js"] = function(module, filename) {
  if (shouldNotTransform(filename)) {
    defaultHandler(module, filename);
  } else {
    module._compile(
      getBabelResult(filename).code,
      filename
    );
  }
};

exports.retrieveSourceMap = function(filename) {
  if (shouldNotTransform(filename)) {
    return null;
  }

  var result = getBabelResult(filename);
  var converted = result && convertSourceMap.fromSource(result.code);
  var map = converted && converted.toJSON();

  return map && {
    url: map.file,
    map: map
  } || null;
};

function shouldNotTransform(filename) {
  if (path.resolve(filename) !==
      path.normalize(filename)) {
    // If the filename is not absolute, then it's a file in a core Node
    // module, and should not be transformed.
    return true;
  }

  var relPath = path.relative(__dirname, filename);
  var firstPart = relPath.split(path.sep, 1)[0];
  var isExternal = firstPart === "..";

  if (isExternal) {
    // If the file is outside the meteor-babel directory, then ignore it
    // if it is contained by any node_modules ancestor directory.
    return filename.split(path.sep).indexOf("node_modules") >= 0;
  }

  // If the file is inside the meteor-babel directory, then ignore it only
  // if it is contained by the local meteor-babel/node_modules directory.
  return firstPart === "node_modules";
}

function getCache() {
  var cacheDir = config.cacheDir;

  if (! hasOwn.call(getCache, cacheDir)) {
    mkdirp(cacheDir);
    var cache = getCache[cacheDir] = {};

    fs.readdirSync(cacheDir).forEach(function (cacheFile) {
      if (/\.json$/.test(cacheFile)) {
        // Avoid actually reading the files until we know we need their
        // contents, but record the filename so that we can quickly check
        // whether a cached file exists on disk or not.
        cache[cacheFile] = true;
      }
    });
  }

  return getCache[cacheDir];
}

function mkdirp(dir) {
  if (! fs.existsSync(dir)) {
    var parentDir = path.dirname(dir);
    if (parentDir !== dir) {
      mkdirp(parentDir);
    }

    try {
      fs.mkdirSync(dir);
    } catch (error) {
      if (error.code !== "EEXIST") {
        throw error;
      }
    }
  }

  return dir;
}

function getBabelResult(filename) {
  var source = fs.readFileSync(filename, "utf8");
  var cache = getCache();
  var cacheFile = deepHash([
    // Though it's tempting to include babel.version in this hash, we
    // don't want to call require("babel") unless we really have to, and
    // the package version should be good enough, especially if we make it
    // identical to babel.version.
    config.version,
    config.babelOptions,
    filename,
    source
  ]) + ".json";
  var result;

  if (hasOwn.call(cache, cacheFile)) {
    result = cache[cacheFile];
    if (result === true) {
      try {
        result = cache[cacheFile] =
          require(path.join(config.cacheDir, cacheFile));
      } catch (error) {
        console.error(error.stack);
        // Fall through to re-transform the file below.
      }
    }
  }

  if (! result) {
    if (config.babelOptions.sourceMap) {
      config.babelOptions.filename = filename;
      config.babelOptions.sourceFileName = filename;
      config.babelOptions.sourceMapName = filename + ".map";
    }

    result = cache[cacheFile] =
      require("babel-core").transform(source, config.babelOptions);

    // Use the asynchronous version of fs.writeFile so that we don't slow
    // down require by waiting for cache files to be written.
    fs.writeFile(
      path.join(config.cacheDir, cacheFile),
      JSON.stringify(result) + "\n",
      { encoding: "utf8", flag: "wx" },
      function (error) {
        if (! error || error.code === "EEXIST") {
          // Opening the file with the exclusive (x) flag failed because
          // the file already existed, which is not a problem.
          return;
        }

        // Errors encountered while persisting cache files to disk will
        // not prevent the program from working, so should not be fatal.
        console.error(error.stack);
      }
    );
  }

  var usedHelpers = result.metadata.usedHelpers;
  if (usedHelpers && usedHelpers.length > 0) {
    require("babel-core/external-helpers");
  }

  return result;
}

// Borrowed from another MIT-licensed project that I wrote:
// https://github.com/reactjs/commoner/blob/235d54a12c/lib/util.js#L136-L168
function deepHash(val) {
  var hash = createHash("sha1");
  var type = typeof val;

  if (val === null) {
    type = "null";
  }

  switch (type) {
  case "object":
    var keys = Object.keys(val);

    // Array keys will already be sorted.
    if (! Array.isArray(val)) {
      keys.sort();
    }

    keys.forEach(function(key) {
      if (typeof val[key] === "function") {
        // Silently ignore nested methods, but nevertheless complain below
        // if the root value is a function.
        return;
      }

      hash.update(key + "\0").update(deepHash(val[key]));
    });

    break;

  case "function":
    assert.ok(false, "cannot hash function objects");
    break;

  default:
    hash.update("" + val);
    break;
  }

  return hash.digest("hex");
}
<commit_msg>Handle not-completely-written cache files more gracefully.<commit_after>var assert = require("assert");
var path = require("path");
var fs = require("fs");
var createHash = require("crypto").createHash;
var hasOwn = Object.hasOwnProperty;
var defaultHandler = require.extensions[".js"];
var convertSourceMap = require("convert-source-map");

var config = {
  version: require("./package.json").version,
  cacheDir: process.env.BABEL_CACHE_DIR ||
    path.join(
      process.env.HOME || process.env.USERPROFILE || __dirname,
      ".babel-cache"
    ),
  babelOptions: require("./options").getDefaults()
};

exports = module.exports = function reconfigure(newConfig) {
  Object.keys(newConfig).forEach(function (key) {
    config[key] = newConfig[key];
  });
};

require.extensions[".js"] = function(module, filename) {
  if (shouldNotTransform(filename)) {
    defaultHandler(module, filename);
  } else {
    module._compile(
      getBabelResult(filename).code,
      filename
    );
  }
};

exports.retrieveSourceMap = function(filename) {
  if (shouldNotTransform(filename)) {
    return null;
  }

  var result = getBabelResult(filename);
  var converted = result && convertSourceMap.fromSource(result.code);
  var map = converted && converted.toJSON();

  return map && {
    url: map.file,
    map: map
  } || null;
};

function shouldNotTransform(filename) {
  if (path.resolve(filename) !==
      path.normalize(filename)) {
    // If the filename is not absolute, then it's a file in a core Node
    // module, and should not be transformed.
    return true;
  }

  var relPath = path.relative(__dirname, filename);
  var firstPart = relPath.split(path.sep, 1)[0];
  var isExternal = firstPart === "..";

  if (isExternal) {
    // If the file is outside the meteor-babel directory, then ignore it
    // if it is contained by any node_modules ancestor directory.
    return filename.split(path.sep).indexOf("node_modules") >= 0;
  }

  // If the file is inside the meteor-babel directory, then ignore it only
  // if it is contained by the local meteor-babel/node_modules directory.
  return firstPart === "node_modules";
}

function getCache() {
  var cacheDir = config.cacheDir;

  if (! hasOwn.call(getCache, cacheDir)) {
    mkdirp(cacheDir);
    var cache = getCache[cacheDir] = {};

    fs.readdirSync(cacheDir).forEach(function (cacheFile) {
      if (/\.json$/.test(cacheFile)) {
        // Avoid actually reading the files until we know we need their
        // contents, but record the filename so that we can quickly check
        // whether a cached file exists on disk or not.
        cache[cacheFile] = true;
      }
    });
  }

  return getCache[cacheDir];
}

function mkdirp(dir) {
  if (! fs.existsSync(dir)) {
    var parentDir = path.dirname(dir);
    if (parentDir !== dir) {
      mkdirp(parentDir);
    }

    try {
      fs.mkdirSync(dir);
    } catch (error) {
      if (error.code !== "EEXIST") {
        throw error;
      }
    }
  }

  return dir;
}

function getBabelResult(filename) {
  var source = fs.readFileSync(filename, "utf8");
  var cache = getCache();
  var cacheFile = deepHash([
    // Though it's tempting to include babel.version in this hash, we
    // don't want to call require("babel") unless we really have to, and
    // the package version should be good enough, especially if we make it
    // identical to babel.version.
    config.version,
    config.babelOptions,
    filename,
    source
  ]) + ".json";
  var fullCacheFile = path.join(config.cacheDir, cacheFile);
  var result;

  if (hasOwn.call(cache, cacheFile)) {
    result = cache[cacheFile];
    if (result === true) {
      try {
        result = cache[cacheFile] = require(fullCacheFile);
      } catch (error) {
        fs.unlinkSync(fullCacheFile);
        result = cache[cacheFile] = false;

        if (error.message.indexOf("Unexpected end of input") >= 0) {
          // The cache file was not written completely, probably because
          // we use the asynchronous version of fs.writeFile, and the
          // program exited too soon. Fall through to transform again.
        } else {
          // Some other problem occurred that we should know about.
          console.error(error.stack);
        }
      }
    }
  }

  if (typeof result !== "object") {
    if (config.babelOptions.sourceMap) {
      config.babelOptions.filename = filename;
      config.babelOptions.sourceFileName = filename;
      config.babelOptions.sourceMapName = filename + ".map";
    }

    result = cache[cacheFile] =
      require("babel-core").transform(source, config.babelOptions);

    // Use the asynchronous version of fs.writeFile so that we don't slow
    // down require by waiting for cache files to be written.
    fs.writeFile(
      fullCacheFile,
      JSON.stringify(result) + "\n",
      { encoding: "utf8", flag: "wx" },
      function (error) {
        if (! error || error.code === "EEXIST") {
          // Opening the file with the exclusive (x) flag failed because
          // the file already existed, which is not a problem.
          return;
        }

        // Errors encountered while persisting cache files to disk will
        // not prevent the program from working, so should not be fatal.
        console.error(error.stack);
      }
    );
  }

  var usedHelpers = result.metadata.usedHelpers;
  if (usedHelpers && usedHelpers.length > 0) {
    require("babel-core/external-helpers");
  }

  return result;
}

// Borrowed from another MIT-licensed project that I wrote:
// https://github.com/reactjs/commoner/blob/235d54a12c/lib/util.js#L136-L168
function deepHash(val) {
  var hash = createHash("sha1");
  var type = typeof val;

  if (val === null) {
    type = "null";
  }

  switch (type) {
  case "object":
    var keys = Object.keys(val);

    // Array keys will already be sorted.
    if (! Array.isArray(val)) {
      keys.sort();
    }

    keys.forEach(function(key) {
      if (typeof val[key] === "function") {
        // Silently ignore nested methods, but nevertheless complain below
        // if the root value is a function.
        return;
      }

      hash.update(key + "\0").update(deepHash(val[key]));
    });

    break;

  case "function":
    assert.ok(false, "cannot hash function objects");
    break;

  default:
    hash.update("" + val);
    break;
  }

  return hash.digest("hex");
}
<|endoftext|>


<commit_before>/**
 * build-examples.js
 * --------
 * Searches for each example's `js/app.es6` file.
 * Creates a new watchify instance for each `app.es6`.
 * Changes to Uppy's source will trigger rebundling.
 *
 * Run as:
 *
 * build-examples.js        # to build all examples one-off
 * build-examples.js watch  # to keep rebuilding examples with an internal watchify
 * build-examples.js <path> # to build just one example app.es6
 *
 * Note:
 * Since each example is dependent on Uppy's source,
 * changing one source file causes the 'file changed'
 * notification to fire multiple times. To stop this,
 * files are added to a 'muted' array that is checked
 * before announcing a changed file.  It's removed from
 * the array when it has been bundled.
 */
var createStream = require('fs').createWriteStream;
var glob = require('multi-glob').glob;
var chalk = require('chalk');
var path = require('path');
var mkdirp = require('mkdirp');
var notifier = require('node-notifier');
var babelify = require('babelify');
var browserify = require('browserify');
var watchify = require('watchify');

var webRoot = __dirname;
var uppyRoot = path.dirname(webRoot);

var srcPattern = webRoot + '/src/examples/**/js/app.es6';
var dstPattern = webRoot + '/public/examples/**/js/app.js';

var watchifyEnabled = process.argv[2] === 'watch';
var browserifyPlugins = [];
if (watchifyEnabled) {
  browserifyPlugins.push(watchify);
}

// Instead of 'watch', build-examples.js can also take a path as cli argument.
// In this case we'll only bundle the specified path/pattern
if (!watchifyEnabled && process.argv[2]) {
  srcPattern = process.argv[2];
}

// Find each app.es6 file with glob.
glob(srcPattern, function(err, files) {
  if (err) throw new Error(err);

  if (watchifyEnabled) {
    console.log('--> Watching examples..');
  }

  var muted = [];

  // Create a new watchify instance for each file.
  files.forEach(function(file) {
    var browseFy = browserify(file, {
      cache       : {},
      packageCache: {},
      plugin      : browserifyPlugins
    })

    // Aliasing for using `require('uppy')`, etc.
    browseFy
      .require(uppyRoot + '/src/index.js', { expose: 'uppy' })
      .require(uppyRoot + '/src/core/index.js', { expose: 'uppy/core' })
      .require(uppyRoot + '/src/plugins/index.js', { expose: 'uppy/plugins' })
      .transform(babelify);

    // Listeners for changes, errors, and completion.
    browseFy
      .on('update', bundle)
      .on('error', onError)
      .on('log', function(msg) {

      })
      .on('file', function(file, id, parent) {
        // When file completes, unmute it.
        muted = muted.filter(function(mutedId) {
          return id !== mutedId;
        });
      });

    // Call bundle() manually to start watch processes.
    bundle();

    /**
     * Creates bundle and writes it to static and public folders.
     * Changes to
     * @param  {[type]} ids [description]
     * @return {[type]}     [description]
     */
    function bundle(ids) {
      ids = ids || [];
      ids.forEach(function(id) {
        if (!isMuted(id, muted)) {
          console.info(chalk.cyan('change:'), id);
          muted.push(id);
        }
      });

      var exampleName = path.basename(path.dirname(path.dirname(file)));
      var output      = dstPattern.replace('**', exampleName);
      var parentDir   = path.dirname(output);

      mkdirp.sync(parentDir);

      console.info(chalk.green('✓ building:'), chalk.green(path.relative(process.cwd(), output)));

      var bundle = browseFy.bundle()
        .on('error', onError)

      bundle.pipe(createStream(output));
    }
  });
});

/**
 * Logs to console and shows desktop notification on error.
 * Calls `this.emit(end)` to stop bundling.
 * @param  {object} err Error object
 */
function onError(err) {
  console.error(chalk.red('✗ error:'), chalk.red(err.message));
  notifier.notify({
    'title': 'Build failed:',
    'message': err.message
  })
  this.emit('end');
}

/**
 * Checks if a file has been added to muted list.
 * This stops single changes from logging multiple times.
 * @param  {string}  id   Name of changed file
 * @param  {Array<string>}  list Muted files array
 * @return {Boolean}      True if file is muted
 */
function isMuted(id, list) {
  return list.reduce(function(prev, curr) {
    return prev || (curr === id);
  }, false);
}
<commit_msg>Remove unused event handler<commit_after>/**
 * build-examples.js
 * --------
 * Searches for each example's `js/app.es6` file.
 * Creates a new watchify instance for each `app.es6`.
 * Changes to Uppy's source will trigger rebundling.
 *
 * Run as:
 *
 * build-examples.js        # to build all examples one-off
 * build-examples.js watch  # to keep rebuilding examples with an internal watchify
 * build-examples.js <path> # to build just one example app.es6
 *
 * Note:
 * Since each example is dependent on Uppy's source,
 * changing one source file causes the 'file changed'
 * notification to fire multiple times. To stop this,
 * files are added to a 'muted' array that is checked
 * before announcing a changed file.  It's removed from
 * the array when it has been bundled.
 */
var createStream = require('fs').createWriteStream;
var glob = require('multi-glob').glob;
var chalk = require('chalk');
var path = require('path');
var mkdirp = require('mkdirp');
var notifier = require('node-notifier');
var babelify = require('babelify');
var browserify = require('browserify');
var watchify = require('watchify');

var webRoot = __dirname;
var uppyRoot = path.dirname(webRoot);

var srcPattern = webRoot + '/src/examples/**/js/app.es6';
var dstPattern = webRoot + '/public/examples/**/js/app.js';

var watchifyEnabled = process.argv[2] === 'watch';
var browserifyPlugins = [];
if (watchifyEnabled) {
  browserifyPlugins.push(watchify);
}

// Instead of 'watch', build-examples.js can also take a path as cli argument.
// In this case we'll only bundle the specified path/pattern
if (!watchifyEnabled && process.argv[2]) {
  srcPattern = process.argv[2];
}

// Find each app.es6 file with glob.
glob(srcPattern, function(err, files) {
  if (err) throw new Error(err);

  if (watchifyEnabled) {
    console.log('--> Watching examples..');
  }

  var muted = [];

  // Create a new watchify instance for each file.
  files.forEach(function(file) {
    var browseFy = browserify(file, {
      cache       : {},
      packageCache: {},
      plugin      : browserifyPlugins
    })

    // Aliasing for using `require('uppy')`, etc.
    browseFy
      .require(uppyRoot + '/src/index.js', { expose: 'uppy' })
      .require(uppyRoot + '/src/core/index.js', { expose: 'uppy/core' })
      .require(uppyRoot + '/src/plugins/index.js', { expose: 'uppy/plugins' })
      .transform(babelify);

    // Listeners for changes, errors, and completion.
    browseFy
      .on('update', bundle)
      .on('error', onError)
      .on('file', function(file, id, parent) {
        // When file completes, unmute it.
        muted = muted.filter(function(mutedId) {
          return id !== mutedId;
        });
      });

    // Call bundle() manually to start watch processes.
    bundle();

    /**
     * Creates bundle and writes it to static and public folders.
     * Changes to
     * @param  {[type]} ids [description]
     * @return {[type]}     [description]
     */
    function bundle(ids) {
      ids = ids || [];
      ids.forEach(function(id) {
        if (!isMuted(id, muted)) {
          console.info(chalk.cyan('change:'), id);
          muted.push(id);
        }
      });

      var exampleName = path.basename(path.dirname(path.dirname(file)));
      var output      = dstPattern.replace('**', exampleName);
      var parentDir   = path.dirname(output);

      mkdirp.sync(parentDir);

      console.info(chalk.green('✓ building:'), chalk.green(path.relative(process.cwd(), output)));

      var bundle = browseFy.bundle()
        .on('error', onError)

      bundle.pipe(createStream(output));
    }
  });
});

/**
 * Logs to console and shows desktop notification on error.
 * Calls `this.emit(end)` to stop bundling.
 * @param  {object} err Error object
 */
function onError(err) {
  console.error(chalk.red('✗ error:'), chalk.red(err.message));
  notifier.notify({
    'title': 'Build failed:',
    'message': err.message
  })
  this.emit('end');
}

/**
 * Checks if a file has been added to muted list.
 * This stops single changes from logging multiple times.
 * @param  {string}  id   Name of changed file
 * @param  {Array<string>}  list Muted files array
 * @return {Boolean}      True if file is muted
 */
function isMuted(id, list) {
  return list.reduce(function(prev, curr) {
    return prev || (curr === id);
  }, false);
}
<|endoftext|>


<commit_before>export const ALERT_BANNER_ACTIVE = true
// https://github.com/hashicorp/web-components/tree/master/packages/alert-banner
export default {
  tag: 'ANNOUNCEMENT',
  url: 'https://www.hashicorp.com/blog/announcing-hashicorp-nomad-1-2',
  text:
    'Nomad 1.2.0 is now generally available, which includes 3 new major features and many improvements.',
  linkText: 'Learn more',
  // Set the expirationDate prop with a datetime string (e.g. '2020-01-31T12:00:00-07:00')
  // if you'd like the component to stop showing at or after a certain date
  expirationDate: '2021-11-23T00:00:00-07:00',
}
<commit_msg>Update the banner (#11656)<commit_after>export const ALERT_BANNER_ACTIVE = true
// https://github.com/hashicorp/web-components/tree/master/packages/alert-banner
export default {
  tag: 'Blog post',
  url: 'https://www.hashicorp.com/blog/a-new-chapter-for-hashicorp',
  text: 'HashiCorp shares have begun trading on the Nasdaq. Read the blog from our founders, Mitchell Hashimoto and Armon Dadgar.',
  linkText: 'Read the post',
  // Set the expirationDate prop with a datetime string (e.g. '2020-01-31T12:00:00-07:00')
  // if you'd like the component to stop showing at or after a certain date
  expirationDate: '2021-12-17T23:00:00-07:00',
}
<|endoftext|>


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

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';

import SubtreeContainer from '../_SubtreeContainer';
import Notification from '../_Notification';

import Util from '../_vendors/Util';

export default class Notifier extends Component {

    static NotificationType = Notification.Type;

    static Position = {

        TOP_LEFT: 'top-left',
        TOP: 'top',
        TOP_RIGHT: 'top-right',

        BOTTOM_LEFT: 'bottom-left',
        BOTTOM: 'bottom',
        BOTTOM_RIGHT: 'bottom-right'

    };

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.nextKey = 0;
        this.unrenderTimeout = null;

        this.state = {
            visible: false,
            notifications: []
        };

        this.isPositiveSequence = ::this.isPositiveSequence;
        this.clearUnrenderTimeout = ::this.clearUnrenderTimeout;
        this.addNotification = ::this.addNotification;
        this.removeNotification = ::this.removeNotification;

    }

    isPositiveSequence(position = this.props.position) {
        return position === Notifier.Position.TOP_LEFT
            || position === Notifier.Position.TOP
            || position === Notifier.Position.TOP_RIGHT;
    }

    clearUnrenderTimeout() {
        if (this.unrenderTimeout) {
            clearTimeout(this.unrenderTimeout);
            this.unrenderTimeout = null;
        }
    }

    addNotification(notification) {

        this.clearUnrenderTimeout();

        let notifications = this.state.notifications;

        if (this.isPositiveSequence()) {
            notifications.push({...notification, notificationId: this.nextKey++});
        } else {
            notifications.unshift({...notification, notificationId: this.nextKey++});
        }

        this.setState({
            notifications,
            visible: true
        });

    }

    removeNotification(notificationId) {

        let notifications = this.state.notifications;

        notifications.splice(notifications.findIndex(item => item.notificationId === notificationId), 1);

        this.setState({
            notifications
        }, () => {
            if (notifications.length < 1) {

                this.clearUnrenderTimeout();

                this.unrenderTimeout = setTimeout(() => {
                    this.setState({
                        visible: false
                    });
                }, 1250);

            }
        });

    }

    componentWillReceiveProps(nextProps) {

        if (nextProps.notifications && nextProps.notifications.length > 0) {

            this.clearUnrenderTimeout();

            let notifications = _.cloneDeep(nextProps.notifications);
            for (let i = 0, len = notifications.length; i < len; i++) {
                if (typeof notifications[i] !== 'object') {
                    notifications[i] = {
                        message: notifications[i]
                    };
                }
                notifications[i].notificationId = this.nextKey++;
            }

            if (this.isPositiveSequence()) {
                notifications = [...this.state.notifications, ...notifications];
            } else {
                notifications = [...notifications.reverse(), ...this.state.notifications];
            }

            this.setState({
                notifications,
                visible: true
            }, () => {
                this.props.onNotificationPop();
            });

        }

    }

    componentWillUnmount() {
        this.clearUnrenderTimeout();
    }

    render() {

        const {position} = this.props,
            {notifications, visible} = this.state;

        return (
            <SubtreeContainer className={'notifier' + (position ? ` notifier-position-${position}` : '')}
                              visible={visible}>
                {
                    notifications.length > 0 ?
                        (
                            notifications.map(options =>
                                <Notification {...options}
                                              key={options.notificationId}
                                              onRequestClose={this.removeNotification}/>
                            )
                        )
                        : null
                }
            </SubtreeContainer>
        );

    }

};

Notifier.propTypes = {

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

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

    /**
     * Children passed into the notifier.
     */
    notifications: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.shape({

        /**
         * The CSS class name of toast.
         */
        className: PropTypes.string,

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

        /**
         * The type of toast.
         */
        type: PropTypes.oneOf(Util.enumerateValue(Notification.Type)),

        /**
         * The title of toast.
         */
        title: PropTypes.string,

        /**
         * The message of toast.
         */
        message: PropTypes.string,

        /**
         * The icon class name of toast.
         */
        iconCls: PropTypes.string,

        /**
         * The duration of toast.
         */
        duration: PropTypes.number

    }), PropTypes.string, PropTypes.number])),

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

    /**
     * Callback function fired when the notifier pop.
     */
    onNotificationPop: PropTypes.func

};

Notifier.defaultProps = {

    className: '',
    style: null,

    position: Notifier.Position.BOTTOM_RIGHT

};<commit_msg>optimize Notifier<commit_after>/**
 * @file Notifier component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';

import SubtreeContainer from '../_SubtreeContainer';
import Notification from '../_Notification';

import Util from '../_vendors/Util';
import MsgType from '../_statics/MsgType';

export default class Notifier extends Component {

    static Type = MsgType;

    static Position = {

        TOP_LEFT: 'top-left',
        TOP: 'top',
        TOP_RIGHT: 'top-right',

        BOTTOM_LEFT: 'bottom-left',
        BOTTOM: 'bottom',
        BOTTOM_RIGHT: 'bottom-right'

    };

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.nextKey = 0;
        this.unrenderTimeout = null;

        this.state = {
            visible: false,
            notifications: []
        };

        this.isPositiveSequence = ::this.isPositiveSequence;
        this.clearUnrenderTimeout = ::this.clearUnrenderTimeout;
        this.addNotification = ::this.addNotification;
        this.removeNotification = ::this.removeNotification;

    }

    isPositiveSequence(position = this.props.position) {
        return position === Notifier.Position.TOP_LEFT
            || position === Notifier.Position.TOP
            || position === Notifier.Position.TOP_RIGHT;
    }

    clearUnrenderTimeout() {
        if (this.unrenderTimeout) {
            clearTimeout(this.unrenderTimeout);
            this.unrenderTimeout = null;
        }
    }

    addNotification(notification) {

        this.clearUnrenderTimeout();

        let notifications = this.state.notifications;

        if (this.isPositiveSequence()) {
            notifications.push({...notification, notificationId: this.nextKey++});
        } else {
            notifications.unshift({...notification, notificationId: this.nextKey++});
        }

        this.setState({
            notifications,
            visible: true
        });

    }

    removeNotification(notificationId) {

        let notifications = this.state.notifications;

        notifications.splice(notifications.findIndex(item => item.notificationId === notificationId), 1);

        this.setState({
            notifications
        }, () => {
            if (notifications.length < 1) {

                this.clearUnrenderTimeout();

                this.unrenderTimeout = setTimeout(() => {
                    this.setState({
                        visible: false
                    });
                }, 1250);

            }
        });

    }

    componentWillReceiveProps(nextProps) {

        if (nextProps.notifications && nextProps.notifications.length > 0) {

            this.clearUnrenderTimeout();

            let notifications = _.cloneDeep(nextProps.notifications);
            for (let i = 0, len = notifications.length; i < len; i++) {
                if (typeof notifications[i] !== 'object') {
                    notifications[i] = {
                        message: notifications[i]
                    };
                }
                notifications[i].notificationId = this.nextKey++;
            }

            if (this.isPositiveSequence()) {
                notifications = [...this.state.notifications, ...notifications];
            } else {
                notifications = [...notifications.reverse(), ...this.state.notifications];
            }

            this.setState({
                notifications,
                visible: true
            }, () => {
                this.props.onNotificationPop();
            });

        }

    }

    componentWillUnmount() {
        this.clearUnrenderTimeout();
    }

    render() {

        const {position} = this.props,
            {notifications, visible} = this.state;

        return (
            <SubtreeContainer className={'notifier' + (position ? ` notifier-position-${position}` : '')}
                              visible={visible}>
                {
                    notifications.length > 0 ?
                        (
                            notifications.map(options =>
                                <Notification {...options}
                                              key={options.notificationId}
                                              onRequestClose={this.removeNotification}/>
                            )
                        )
                        : null
                }
            </SubtreeContainer>
        );

    }

};

Notifier.propTypes = {

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

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

    /**
     * Children passed into the notifier.
     */
    notifications: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.shape({

        /**
         * The CSS class name of toast.
         */
        className: PropTypes.string,

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

        /**
         * The type of toast.
         */
        type: PropTypes.oneOf(Util.enumerateValue(MsgType)),

        /**
         * The title of toast.
         */
        title: PropTypes.string,

        /**
         * The message of toast.
         */
        message: PropTypes.string,

        /**
         * The icon class name of toast.
         */
        iconCls: PropTypes.string,

        /**
         * The duration of toast.
         */
        duration: PropTypes.number

    }), PropTypes.string, PropTypes.number])),

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

    /**
     * Callback function fired when the notifier pop.
     */
    onNotificationPop: PropTypes.func

};

Notifier.defaultProps = {

    className: '',
    style: null,

    position: Notifier.Position.BOTTOM_RIGHT

};<|endoftext|>


<commit_before>var $body = $("#inner-body"),
    Type,
    PhoneView = false,
    Title = "纸异兽",
    supportHistory = !!(window.history.pushState && window.history.replaceState);

//alert(!!navigator.userAgent.match(/mobile/i));

$(function () {
    doChanged();
    //load article list and cnblog list
    if (!$("#left-middle").html().trim()) {
        $.get("/", null, function (data) {
            var $data = $(data);

            $("#left-middle").replaceWith($data.find("#left-middle"));
            $("#right-middle").replaceWith($data.find("#right-middle"));
        }, "html");
    }
    init();
});

$("#aside").on({
    "mouseenter": function () {
        !PhoneView && $(this).removeClass("aside-close").addClass("aside-open");
        $("#aside .profile").scrollTop(0);
    },
    "mouseleave": function () {
        !PhoneView && $(this).removeClass("aside-open").addClass("aside-close");
    },
    "click": function(e){
        var $this = $(this);

        if(PhoneView) {
            if (e.target.className == "close") {//click close button
                $this.removeClass("aside-open").addClass("aside-close");
            }else if(!$this.hasClass("aside-open")){
                $this.removeClass("aside-close").addClass("aside-open");
                $("#aside .profile").scrollTop(0);
            }
        }
    }
});

$("#switch").on("click",function(){
    if(PhoneView){
        $body.toggleClass("right-middle");
        $("html,body").scrollTop(0);
    }else{
        $(this).one("mouseleave", function () {
            $body.toggleClass("right-middle");
        });
    }
});

$(window).resize(function () {
    PhoneView = $("body").width() < 900;
    doChanged();
});

$(".content").scroll(function(){
    if(!PhoneView) return;

    if($(this).scrollTop() >= 10){
        $("#aside").addClass("slideUp");
    }else{
        $("#aside").removeClass("slideUp");
    }
    fixWidthOfAside();
});

$(".contents,.profile").on("click", "a", function (e) {
    //for normal a link
    var action = $(this).attr("action"),
        title = Title;
    if (!action || !supportHistory) {
        return;
    }

    if (PhoneView && this.id == "readmore"){
        $("#aside").removeClass("aside-open").addClass("aside-close");
        e.stopPropagation();
    }

    e.preventDefault();
    var href = this.href;

    maskLoding.show();
    switch (Type = $(this).attr("action")) {
        case "article":
            $("#left-bottom").load(href + " #left-bottom>*", function () {
                $body.removeClass("left-top left-middle").addClass("left-bottom");

                if(PhoneView){
                    $("html,body").scrollTop(0);
                    playMedia();
                }else{
                    $(this).scrollTop(0);
                }

                doChanged();
                setTitle(title = $("h1.post-title").text());
                window.history.pushState({type: action, url: href}, title, href);
                maskLoding.hide();
                initDuoshuo();
            });
            break;
        case "tag":
            $("#left-top").load(href + " #left-top>*", function () {
                $body.removeClass("left-bottom left-middle").addClass("left-top");
                PhoneView && $("html,body").scrollTop(0);
                doChanged();
                setTitle(title = $("h1.page-title").text());
                window.history.pushState({type: action, url: href}, title, href);
                maskLoding.hide();
            });
            break;
        case "page":
            $("#left-middle").load(href + " #left-middle>*", function () {
                $body.removeClass("left-top left-bottom");
                PhoneView ? $("html,body").scrollTop(0) : $(this).scrollTop(0);
                doChanged();
                setTitle(title);
                window.history.pushState({type: action, url: href}, document.title, href);
                maskLoding.hide();
            });
            break;
        default :
            Type = "list";
            PhoneView && $("html,body").scrollTop(0);
    }
});

//zoom for picture
(function(){
    var $tag = $("原图"),
        img = document.createElement("img"),
        $img = $(img),
        $oriBox = $("

×

"),
        $close = $oriBox.children("#masker-close"),
        //store original image data for zoom smaller to recovery the location
        originalData = {
            ratio: 1,
            width: 0,
            height: 0,
            top: 0,
            left: 0,
            //for limit mousemove event
            isLock: true
        },
        url;

    //$oriBox.append($close);

    $(".contents")
        .on("mouseenter",".post-content img",function(){
            var $this = $(this);

            url = this.src.replace(/-resize$/,"");
            $this.parent().css("position","relative");
            originalData.ratio = $this.width() / $this.height();

            $tag.css({
                "top": $this.position().top,
                "right": $this.parent().width() - $this.width() - $this.position().left
            });

            $this.after($tag);
        }).on("mouseleave",".post-content img",function(e){
            if(e.relatedTarget == $tag[0]){
                return;
            }
            $tag.remove();
        });

    $tag[0].onclick = function(){
        var $body = $("body"),
            width,
            height;

        //do it before get width because the scroll bar
        if(PhoneView){
            $body.css("overflow","hidden");
        }

        width = $body.width();
        height = $body.height();
        maskLoding.show();
        $oriBox.prepend($img);
        img.src = url;

        if(originalData.ratio >  width / height){
            originalData.width = width;
            originalData.height = width / originalData.ratio;
            originalData.top = (height - originalData.height)/2;
            originalData.left = 0;
        }else{
            originalData.width =  height * originalData.ratio;
            originalData.height = height;
            originalData.top = 0;
            originalData.left = (width - originalData.width)/2;
        }

        $img.css({
            height: originalData.height,
            width: originalData.width,
            top: originalData.top,
            left: originalData.left
        });

        //for sync showing image and masker
        //so we will get a better transition
        setTimeout(function(){
            $body.append($oriBox);
        },300);
    };

    //see "jquery remove() and Event" with bug tag in evernote
    img.onload = function(){
        $("#loading").fadeOut();
    };

    $close[0].onclick = function(){
        if(PhoneView){
            $("body").css("overflow","");
        }

        $oriBox.remove();
        maskLoding.hide();
    };

    img.onmousewheel = img.dommousescroll = debounce(mousewheel,20);
    img.addEventListener("DOMMouseScroll", img.onmousewheel);

    function mousewheel(e) {
        var temp;
        if (!$img[0].complete) return;
        if (e.detail ? e.detail < 0 : e.wheelDelta > 0) {
            $img.css({
                "width": function (index, value) {
                    return parseInt(value) * 1.1;
                }, "height": function (index, value) {
                    return parseInt(value) * 1.1;
                }, "left": function (index, value) {
                    return parseInt(value) - (e.offsetX || e.layerX) * 0.1;
                }, "top": function (index, value) {
                    return parseInt(value) - (e.offsetY || e.layerY) * 0.1;
                }
            });
        } else {
            $img.css({
                "width": function (index, value) {
                    value = parseInt(value);
                    temp = value / 1.1;
                    return value > originalData.width && temp > originalData.width ? temp : (temp = false, originalData.width);
                }, "height": function (index, value) {
                    value = parseInt(value);
                    temp = value / 1.1;
                    return value > originalData.height && temp > originalData.height ? temp : (temp = false, originalData.height);
                }, "left": function (index, value) {
                    return temp === false ? ($oriBox.width() - originalData.width) / 2 : parseInt(value) + (e.offsetX || e.layerX) / 11;
                }, "top": function (index, value) {
                    return temp === false ? ($oriBox.height() - originalData.height) / 2 : parseInt(value) + (e.offsetY || e.layerY) / 11;
                }
            })
        }
    }

    //open the limit of draging
    img.ondragstart = function (e) {
        e.returnValue = false;
        return false;
    };
    img.onmousedown = function (e) {
        if (!img.complete) return;
        originalData.isLock = false;
        originalData.left = e.clientX;
        originalData.top = e.clientY;
    };
    img.onmousemove = debounce(function (e) {
        e.preventDefault();
        if (!img.complete || originalData.isLock) return;
        $img.css({
            left: parseInt($img.css("left")) + e.clientX - originalData.left,
            top: parseInt($img.css("top")) + e.clientY - originalData.top
        });
        originalData.left = e.clientX;
        originalData.top = e.clientY;
    }, 20);
    img.onmouseup = function () {
        originalData.isLock = true;
    };
    img.onmouseout = function (e) {
        originalData.isLock = true;
    }
})();

$("#home-btn").click(function () {
    $body.removeClass("left-bottom left-top right-middle").addClass("left-middle");
    setTitle(Title)
    window.history.pushState({type: Type = "list", url: "/"}, Title, "/");
    doChanged();
    stopMedia();
});

window.addEventListener("popstate", function (e) {
    switch (Type = e.state.type) {
        case "article":
            $body.removeClass("left-top left-middle").addClass("left-bottom");
            break;
        case "tag":
            $body.removeClass("left-bottom left-middle").addClass("left-top");
            break;
        case "list":
            if (window.location.pathname.search(/^\/$||\/page\//) != 0) {
                $body.removeClass("left-bottom left-top").addClass("left-middle");
                break;
            }
        case "page":
            maskLoding.show();
            $("#left-middle").load(e.state.url + " #left-middle>*", function () {
                $body.removeClass("left-top left-bottom");
                doChanged();
                window.history.pushState({
                    type: "page",
                    url: window.location.href
                }, document.title, window.location.href);
                maskLoding.hide();
            });
    }
    doChanged();
    stopMedia();
});

function setTitle(t){
    $("title").text(t)
}

var masker = (function (noTransition) {
    var $mask = $("#mask-layer");

    return {
        show: function () {
            if(noTransition){
                $mask.show();
            }else{
                $mask.fadeIn();
            }
        },
        hide: function () {
            if(noTransition){
                $mask.hide();
            }else{
                $mask.fadeOut();
            }
        }
    }
})();

var maskLoding = (function (noTransition) {
    var $loading = $("#loading");

    return {
        show: function () {
            $loading.fadeIn();
            masker.show(noTransition);
        },
        hide: function () {
            $loading.fadeOut();
            masker.hide(noTransition);
        }
    }
})();

function init() {
    PhoneView = $("body").width() < 900;

    var path = window.location.pathname;

    if (path == "/") {
        Type = "list";
    } else if (path.indexOf("/tag/") == 0) {
        Type = "tag";
    } else if (path.indexOf("/page/") == 0) {
        Type = "page";
    } else {
        Type = "article";
        playMedia();
        initDuoshuo();
    }
    window.history.replaceState({type: Type, url: window.location.href}, document.title, window.location.href);
}

function doChanged() {
    fixWidthOfAside();
}

function stopMedia() {
    $("#left-bottom").find("audio,video").each(function () {
        this.pause();
    })
}

function playMedia(){
    $("#left-bottom").find("audio[autoplay=autoplay]").each(function(){
        setTimeout(function(){
            this.play();
        },1000)
    })
}

var fixWidthOfAside = (function() {
    /**
     * 修正浏览器bug,test.html中测试
     * 如果子节点为img，其宽度auto，高度根据父节点高度百分比变化
     * 父节点宽度为auto，在resize之后，父节点不会发生宽度变化，在所有浏览器中表现都不一样
     * 只能用js去纠正
     */
    var isPhoneViewBefore = $("body").width() < 900,
        $aside = $("#aside"),
        $title = $aside.find(".title"),
        $container = $("#container"),
        width;

    return function() {
        //do the change when convert layout
        if(isPhoneViewBefore && !PhoneView){
            //phone to pc
            $body.css("padding-top", "");
            isPhoneViewBefore = PhoneView;
        }else if(!isPhoneViewBefore && PhoneView){
            //pc to phone
            $body.css("padding-left", "");
            $title.width("auto");
            isPhoneViewBefore = PhoneView;
        }

        if (PhoneView) {
            if(Type == "article") {return $body.css("padding-top",0)};
            $body.css("padding-top", $aside.hasClass("slideUp") ? 0 : $title.height());
        }else{
            if ($body.hasClass("left-bottom")) {
                $body.css("padding-left",0);
            } else {
                width = $body.height() * 0.3;
                $title.width(width);
                $body.css("padding-left",width);
            }
        }
    }
})();

function debounce(func,delay){
    var lasttime = new Date();

    return function(){
        var now = new Date();
        if(now - lasttime > delay){
            lasttime = now;
            func.apply(this,arguments);
        }

    }
}

//duoshuo
function initDuoshuo() {
    var ds = document.getElementById("ds-thread");
    DUOSHUO.EmbedThread(ds);
}<commit_msg>add transition for multiple click<commit_after>var $body = $("#inner-body"),
    Type,
    PhoneView = false,
    Title = "纸异兽",
    supportHistory = !!(window.history.pushState && window.history.replaceState);

//alert(!!navigator.userAgent.match(/mobile/i));

$(function () {
    doChanged();
    //load article list and cnblog list
    if (!$("#left-middle").html().trim()) {
        $.get("/", null, function (data) {
            var $data = $(data);

            $("#left-middle").replaceWith($data.find("#left-middle"));
            $("#right-middle").replaceWith($data.find("#right-middle"));
        }, "html");
    }
    init();
});

$("#aside").on({
    "mouseenter": function () {
        !PhoneView && $(this).removeClass("aside-close").addClass("aside-open");
        $("#aside .profile").scrollTop(0);
    },
    "mouseleave": function () {
        !PhoneView && $(this).removeClass("aside-open").addClass("aside-close");
    },
    "click": function(e){
        var $this = $(this);

        if(PhoneView) {
            if (e.target.className == "close") {//click close button
                $this.removeClass("aside-open").addClass("aside-close");
            }else if(!$this.hasClass("aside-open")){
                $this.removeClass("aside-close").addClass("aside-open");
                $("#aside .profile").scrollTop(0);
            }
        }
    }
});

$("#switch").on({
    "mouseenter": function(){
        !PhoneView && $(this).addClass("hover");
    },
    "mouseleave": function(){
        !PhoneView && $(this).removeClass("hover");
    },
    "click": function(){
        var $this = $(this);
        if(PhoneView){
            $body.toggleClass("right-middle");
            $("html,body").scrollTop(0);
        }else{
            //toggle hover class, if hover exists, so that this is first click after mouseenter
            //if hover not exist, so prove that this isn't.
            $this.toggleClass("hover");

            //if isn't first click, add animation to this event
            if($this.hasClass("hover")){
                setTimeout(function(){
                    $body.toggleClass("right-middle");
                    $this.removeClass("hover");
                },500);
            }else{
                $body.toggleClass("right-middle");
            }
        }
    }
});
//$("#switch").on("click",function(){
//    if(PhoneView){
//        $body.toggleClass("right-middle");
//        $("html,body").scrollTop(0);
//    }else{
//        //$(this).one("mouseleave", function () {
//            $body.toggleClass("right-middle");
//            //$(this).removeAttr("id");
//        //});
//    }
//});

$(window).resize(function () {
    PhoneView = $("body").width() < 900;
    doChanged();
});

$(".content").scroll(function(){
    if(!PhoneView) return;

    if($(this).scrollTop() >= 10){
        $("#aside").addClass("slideUp");
    }else{
        $("#aside").removeClass("slideUp");
    }
    fixWidthOfAside();
});

$(".contents,.profile").on("click", "a", function (e) {
    //for normal a link
    var action = $(this).attr("action"),
        title = Title;
    if (!action || !supportHistory) {
        return;
    }

    if (PhoneView && this.id == "readmore"){
        $("#aside").removeClass("aside-open").addClass("aside-close");
        e.stopPropagation();
    }

    e.preventDefault();
    var href = this.href;

    maskLoding.show();
    switch (Type = $(this).attr("action")) {
        case "article":
            $("#left-bottom").load(href + " #left-bottom>*", function () {
                $body.removeClass("left-top left-middle").addClass("left-bottom");

                if(PhoneView){
                    $("html,body").scrollTop(0);
                    playMedia();
                }else{
                    $(this).scrollTop(0);
                }

                doChanged();
                setTitle(title = $("h1.post-title").text());
                window.history.pushState({type: action, url: href}, title, href);
                maskLoding.hide();
                initDuoshuo();
            });
            break;
        case "tag":
            $("#left-top").load(href + " #left-top>*", function () {
                $body.removeClass("left-bottom left-middle").addClass("left-top");
                PhoneView && $("html,body").scrollTop(0);
                doChanged();
                setTitle(title = $("h1.page-title").text());
                window.history.pushState({type: action, url: href}, title, href);
                maskLoding.hide();
            });
            break;
        case "page":
            $("#left-middle").load(href + " #left-middle>*", function () {
                $body.removeClass("left-top left-bottom");
                PhoneView ? $("html,body").scrollTop(0) : $(this).scrollTop(0);
                doChanged();
                setTitle(title);
                window.history.pushState({type: action, url: href}, document.title, href);
                maskLoding.hide();
            });
            break;
        default :
            Type = "list";
            PhoneView && $("html,body").scrollTop(0);
    }
});

//zoom for picture
(function(){
    var $tag = $("原图"),
        img = document.createElement("img"),
        $img = $(img),
        $oriBox = $("

×

"),
        $close = $oriBox.children("#masker-close"),
        //store original image data for zoom smaller to recovery the location
        originalData = {
            ratio: 1,
            width: 0,
            height: 0,
            top: 0,
            left: 0,
            //for limit mousemove event
            isLock: true
        },
        url;

    //$oriBox.append($close);

    $(".contents")
        .on("mouseenter",".post-content img",function(){
            var $this = $(this);

            url = this.src.replace(/-resize$/,"");
            $this.parent().css("position","relative");
            originalData.ratio = $this.width() / $this.height();

            $tag.css({
                "top": $this.position().top,
                "right": $this.parent().width() - $this.width() - $this.position().left
            });

            $this.after($tag);
        }).on("mouseleave",".post-content img",function(e){
            if(e.relatedTarget == $tag[0]){
                return;
            }
            $tag.remove();
        });

    $tag[0].onclick = function(){
        var $body = $("body"),
            width,
            height;

        //do it before get width because the scroll bar
        if(PhoneView){
            $body.css("overflow","hidden");
        }

        width = $body.width();
        height = $body.height();
        maskLoding.show();
        $oriBox.prepend($img);
        img.src = url;

        if(originalData.ratio >  width / height){
            originalData.width = width;
            originalData.height = width / originalData.ratio;
            originalData.top = (height - originalData.height)/2;
            originalData.left = 0;
        }else{
            originalData.width =  height * originalData.ratio;
            originalData.height = height;
            originalData.top = 0;
            originalData.left = (width - originalData.width)/2;
        }

        $img.css({
            height: originalData.height,
            width: originalData.width,
            top: originalData.top,
            left: originalData.left
        });

        //for sync showing image and masker
        //so we will get a better transition
        setTimeout(function(){
            $body.append($oriBox);
        },300);
    };

    //see "jquery remove() and Event" with bug tag in evernote
    img.onload = function(){
        $("#loading").fadeOut();
    };

    $close[0].onclick = function(){
        if(PhoneView){
            $("body").css("overflow","");
        }

        $oriBox.remove();
        maskLoding.hide();
    };

    img.onmousewheel = img.dommousescroll = debounce(mousewheel,20);
    img.addEventListener("DOMMouseScroll", img.onmousewheel);

    function mousewheel(e) {
        var temp;
        if (!$img[0].complete) return;
        if (e.detail ? e.detail < 0 : e.wheelDelta > 0) {
            $img.css({
                "width": function (index, value) {
                    return parseInt(value) * 1.1;
                }, "height": function (index, value) {
                    return parseInt(value) * 1.1;
                }, "left": function (index, value) {
                    return parseInt(value) - (e.offsetX || e.layerX) * 0.1;
                }, "top": function (index, value) {
                    return parseInt(value) - (e.offsetY || e.layerY) * 0.1;
                }
            });
        } else {
            $img.css({
                "width": function (index, value) {
                    value = parseInt(value);
                    temp = value / 1.1;
                    return value > originalData.width && temp > originalData.width ? temp : (temp = false, originalData.width);
                }, "height": function (index, value) {
                    value = parseInt(value);
                    temp = value / 1.1;
                    return value > originalData.height && temp > originalData.height ? temp : (temp = false, originalData.height);
                }, "left": function (index, value) {
                    return temp === false ? ($oriBox.width() - originalData.width) / 2 : parseInt(value) + (e.offsetX || e.layerX) / 11;
                }, "top": function (index, value) {
                    return temp === false ? ($oriBox.height() - originalData.height) / 2 : parseInt(value) + (e.offsetY || e.layerY) / 11;
                }
            })
        }
    }

    //open the limit of draging
    img.ondragstart = function (e) {
        e.returnValue = false;
        return false;
    };
    img.onmousedown = function (e) {
        if (!img.complete) return;
        originalData.isLock = false;
        originalData.left = e.clientX;
        originalData.top = e.clientY;
    };
    img.onmousemove = debounce(function (e) {
        e.preventDefault();
        if (!img.complete || originalData.isLock) return;
        $img.css({
            left: parseInt($img.css("left")) + e.clientX - originalData.left,
            top: parseInt($img.css("top")) + e.clientY - originalData.top
        });
        originalData.left = e.clientX;
        originalData.top = e.clientY;
    }, 20);
    img.onmouseup = function () {
        originalData.isLock = true;
    };
    img.onmouseout = function (e) {
        originalData.isLock = true;
    }
})();

$("#home-btn").click(function () {
    $body.removeClass("left-bottom left-top right-middle").addClass("left-middle");
    setTitle(Title)
    window.history.pushState({type: Type = "list", url: "/"}, Title, "/");
    doChanged();
    stopMedia();
});

window.addEventListener("popstate", function (e) {
    switch (Type = e.state.type) {
        case "article":
            $body.removeClass("left-top left-middle").addClass("left-bottom");
            break;
        case "tag":
            $body.removeClass("left-bottom left-middle").addClass("left-top");
            break;
        case "list":
            if (window.location.pathname.search(/^\/$||\/page\//) != 0) {
                $body.removeClass("left-bottom left-top").addClass("left-middle");
                break;
            }
        case "page":
            maskLoding.show();
            $("#left-middle").load(e.state.url + " #left-middle>*", function () {
                $body.removeClass("left-top left-bottom");
                doChanged();
                window.history.pushState({
                    type: "page",
                    url: window.location.href
                }, document.title, window.location.href);
                maskLoding.hide();
            });
    }
    doChanged();
    stopMedia();
});

function setTitle(t){
    $("title").text(t)
}

var masker = (function (noTransition) {
    var $mask = $("#mask-layer");

    return {
        show: function () {
            if(noTransition){
                $mask.show();
            }else{
                $mask.fadeIn();
            }
        },
        hide: function () {
            if(noTransition){
                $mask.hide();
            }else{
                $mask.fadeOut();
            }
        }
    }
})();

var maskLoding = (function (noTransition) {
    var $loading = $("#loading");

    return {
        show: function () {
            $loading.fadeIn();
            masker.show(noTransition);
        },
        hide: function () {
            $loading.fadeOut();
            masker.hide(noTransition);
        }
    }
})();

function init() {
    PhoneView = $("body").width() < 900;

    var path = window.location.pathname;

    if (path == "/") {
        Type = "list";
    } else if (path.indexOf("/tag/") == 0) {
        Type = "tag";
    } else if (path.indexOf("/page/") == 0) {
        Type = "page";
    } else {
        Type = "article";
        playMedia();
        initDuoshuo();
    }
    window.history.replaceState({type: Type, url: window.location.href}, document.title, window.location.href);
}

function doChanged() {
    fixWidthOfAside();
}

function stopMedia() {
    $("#left-bottom").find("audio,video").each(function () {
        this.pause();
    })
}

function playMedia(){
    $("#left-bottom").find("audio[autoplay=autoplay]").each(function(){
        setTimeout(function(){
            this.play();
        },1000)
    })
}

var fixWidthOfAside = (function() {
    /**
     * 修正浏览器bug,test.html中测试
     * 如果子节点为img，其宽度auto，高度根据父节点高度百分比变化
     * 父节点宽度为auto，在resize之后，父节点不会发生宽度变化，在所有浏览器中表现都不一样
     * 只能用js去纠正
     */
    var isPhoneViewBefore = $("body").width() < 900,
        $aside = $("#aside"),
        $title = $aside.find(".title"),
        $container = $("#container"),
        width;

    return function() {
        //do the change when convert layout
        if(isPhoneViewBefore && !PhoneView){
            //phone to pc
            $body.css("padding-top", "");
            isPhoneViewBefore = PhoneView;
        }else if(!isPhoneViewBefore && PhoneView){
            //pc to phone
            $body.css("padding-left", "");
            $title.width("auto");
            isPhoneViewBefore = PhoneView;
        }

        if (PhoneView) {
            if(Type == "article") {return $body.css("padding-top",0)};
            $body.css("padding-top", $aside.hasClass("slideUp") ? 0 : $title.height());
        }else{
            if ($body.hasClass("left-bottom")) {
                $body.css("padding-left",0);
            } else {
                width = $body.height() * 0.3;
                $title.width(width);
                $body.css("padding-left",width);
            }
        }
    }
})();

function debounce(func,delay){
    var lasttime = new Date();

    return function(){
        var now = new Date();
        if(now - lasttime > delay){
            lasttime = now;
            func.apply(this,arguments);
        }

    }
}

//duoshuo
function initDuoshuo() {
    var ds = document.getElementById("ds-thread");
    DUOSHUO.EmbedThread(ds);
}<|endoftext|>


<commit_before>var dataStructure = require('./dataStructure');
var service = require('./service');
var contract = require('./contract');
var dataHelp = {
    parse : function(sheet){
      var name = sheet.name;
      if(name == "Overview"){
        return ;
      }
      var reg = /(\d+)(.+)/;
      var res = reg.exec(name);
      var serverno, servername;
      if(res){
        serverno = res[1];
        servername = res[2];
      }
      var rows = sheet.data,
          startIndex = 1,
          requestCount = 2,
          endIndex = rows.length;
      //没有request，格式不对，直接退出
      if(!rows[startIndex][0]){
        return;
      }
      //找到response 开始的行数
      for(; requestCount<endIndex; requestCount++){
        if(rows[requestCount][0]){
          break;
        }
      }

      var request = dataStructure(sheet.data, startIndex, requestCount);
      var response = dataStructure(sheet.data, requestCount+1, endIndex);

      return {
        serverno : serverno,
        servername: servername,
        req : request.root,
        res : response.root
      }
    },

    save : function(data, callback){
      var msg;
      if(!data){
        callback && callback(msg);
        return;
      }
      service.create({name:data.servername, NO: data.serverno, url: data.serverno},
        function(err, res){
          if(err){
              //console.log(err);
              msg = { text: "创建service:"+data.serverno+"失败", ack:1 };
              callback && callback(msg);
              return;
            }
            msg = { text: "创建service:"+data.serverno+"成功", ack:0};
            contract.create({
              srv_id : res,
              NO: data.serverno,
              res: data.res
            },function(err){
              if(err){
                  //console.log(err);
                  msg ={ text:"创建contract:"+data.serverno+"失败", ack:1};
                  callback && callback(msg);
                  return;
                }
                msg = {text: "创建contract:"+data.serverno+"成功", ack:0};
                callback && callback(msg);
            });
        });
      }
}

function iterate(datas,msg, callback){
    var data = datas.shift();
    dataHelp.save(data, function(result){
        msg = msg || [];
        msg.push(result);
        if(datas.length){
          iterate(datas, msg,callback);
        }else{
          callback && callback(msg);
        }
    });
}

// 导入契约
module.exports = function (xlsObject, callback){
    var datas = [];
    // 遍历 Sheet
    xlsObject.forEach(function(sheet, index){
        var data = dataHelp.parse(sheet);
        if(data){
            datas.push(data);
        }
    });
    iterate(datas, [], callback);
}
<commit_msg>update server rest url<commit_after>var dataStructure = require('./dataStructure');
var service = require('./service');
var contract = require('./contract');
var dataHelp = {
    parseURL: function(sheet){
      var name = sheet.name,
          rows = sheet.data;
      var resturl = /Restful\s?URL/i,
          serverno = /Service\s?Code/i,
          urlindex = 0 ,
          servernoindex = 0,
          findurl = false,
          findserverno = false;
      var result = [];
      if(name == "Overview" && rows && rows.length){
        var title = rows[0];
        for(var i=0, len=title.length; i<len; i++){
          var t = title[i];
          if(resturl.test(t) && !findurl){
            urlindex = i;
            findurl = true;
          }
          if(serverno.test(t) && !findserverno){
            servernoindex = i;
            findserverno = true;
          }

          if(findserverno && findurl){
            break;
          }
        }

        for(j=1, l= rows.length; j<l; j++){
          var row = rows[j];
          result.push({
            serverno : row[servernoindex],
            resturl  : row[urlindex]
          });
        }
        return result;
      }
      return null;
    },

    parse : function(sheet, serverurlmap){
      var name = sheet.name;
      if(name == "Overview"){
        return ;
      }
      var reg = /(\d+)(.+)/;
      var res = reg.exec(name);
      var serverno, servername, serverresturl;
      if(res){
        serverno = res[1];
        servername = res[2];
      }
      var rows = sheet.data,
          startIndex = 1,
          requestCount = 2,
          endIndex = rows.length;
      //没有request，格式不对，直接退出
      if(!rows[startIndex][0]){
        return;
      }
      //找到response 开始的行数
      for(; requestCount<endIndex; requestCount++){
        if(rows[requestCount][0]){
          break;
        }
      }

      var request = dataStructure(sheet.data, startIndex, requestCount);
      var response = dataStructure(sheet.data, requestCount+1, endIndex);

      //获取服务对象的rest url
      if(serverurlmap && serverurlmap.length){
        serverurlmap.forEach(function(s){
          if(s.serverno == serverno){
            serverresturl = s.resturl;
            return false;
          }
        });
      }

      return {
        serverno : serverno,
        servername: servername,
        serverresturl : serverresturl,
        req : request.root,
        res : response.root
      }
    },

    save : function(data, callback){
      var msg;
      if(!data){
        callback && callback(msg);
        return;
      }
      service.create({name:data.servername, NO: data.serverno, url: data.serverresturl},
        function(err, res){
          if(err){
              //console.log(err);
              msg = { text: "创建service:"+data.serverno+"失败", ack:1 };
              callback && callback(msg);
              return;
            }
            msg = { text: "创建service:"+data.serverno+"成功", ack:0};
            contract.create({
              srv_id : res,
              NO: data.serverno,
              res: data.res
            },function(err){
              if(err){
                  //console.log(err);
                  msg ={ text:"创建contract:"+data.serverno+"失败", ack:1};
                  callback && callback(msg);
                  return;
                }
                msg = {text: "创建contract:"+data.serverno+"成功", ack:0};
                callback && callback(msg);
            });
        });
      }
}

function iterate(datas,msg, callback){
    var data = datas.shift();
    dataHelp.save(data, function(result){
        msg = msg || [];
        msg.push(result);
        if(datas.length){
          iterate(datas, msg,callback);
        }else{
          callback && callback(msg);
        }
    });
}

// 导入契约
module.exports = function (xlsObject, callback){
    var datas = [];
    var serverurlmap = [];
    // 遍历 Sheet
    xlsObject.forEach(function(sheet, index){
        //解析overview， 提取resturl
        if(index == 0){
          serverurlmap = dataHelp.parseURL(sheet);
        }else{
          //解析具体契约，提取每个契约对象
          var data = dataHelp.parse(sheet, serverurlmap);
          if(data){
              datas.push(data);
          }
        }
    });
    iterate(datas, [], callback);
}
<|endoftext|>


<commit_before>//This code is heavily based on code from
//http://mbostock.github.io/d3/talk/20111018/tree.html

d3.selection.prototype.moveToFront = function() {
  return this.each(function(){
    this.parentNode.appendChild(this);
  });
};

var scaleSize = d3.scale.linear()
    .domain([1,100])
    .range([80,4000]);

var markers = [
   { id: 0, name: 'circle', path: 'M 0, 0  m -5, 0  a 5,5 0 1,0 10,0  a 5,5 0 1,0 -10,0', viewbox: '-6 -6 12 12' },
   { id: 1, name: 'square', path: 'M 0,0 m -5,-5 L 5,-5 L 5,5 L -5,5 Z', viewbox: '-5 -5 10 10' },
   { id: 2, name: 'arrow', path: 'M 0,0 m -5,-5 L 5,0 L -5,5 Z', viewbox: '-5 -5 10 10' },
   { id: 2, name: 'stub', path: 'M 0,0 m -1,-5 L 1,-5 L 1,5 L -1,5 Z', viewbox: '-1 -5 2 10' }
];

d3.bst = function (d3, canvasID, w, h) {

//    d3.select("#reset").on("click", reset);

    //defaults
    var bst = {},
        mw = 0, mh = 0,
        w = w || 1280,
        h = h || 800,
        i = 0,
        tree,
        depthStep = 75,
        canvasID = canvasID, //canvasID must have hash like "#vis" or "#canvas"
        root;
    var svgGroup, defs;

    var drag = d3.behavior.drag()
        //.origin(function(d) {  });
        .on("dragstart", dragstarted)
        .on("drag", dragged)
        .on("dragend", dragended);

    // error when zooming directly after pan on OSX
    // https://github.com/mbostock/d3/issues/2205
    var zoom = d3.behavior.zoom()
        .scaleExtent([0.1,5])
        //.on("dblclick.zoom",null)
        .on("zoom", zoomHandler);
        //.on("mousedown.zoom",null);
        zoom.scale(1);
    zoom.translate([(w/2), 0]);
    allZoom.push(zoom);

    bst.init = function (_w, _h, _mw, _mh, ds) {
        mw = _mw;
        mh = _mh;
        w = _w;
        h = _h;
        depthStep = ds;
        return bst;
    };

    //boilerplate stuff
    bst.make = function (data) {
        tree = d3.layout.tree()
            .nodeSize([50, 50]);
        diagonal = d3.svg.diagonal();
            //.projection(function(d, i) { if(i >= 0) return [d.x + 50, d.y]; else return [d.x, d.y] });

        vis = d3.select(canvasID).append("svg:svg")
            .attr("width", w )
            .attr("height", h )
            .attr("id", "svg" + canvasID.substr(4))
            .classed("svg", true)
            //.attr("height", h * 2)
            .call(zoom)
            .call(drag);

        svgGroup = vis.append("svg:g")
            .attr("transform", "translate(" + (mh + (w/2)) + "," + mw + ")");
        allSVG.push(svgGroup);

        defs = vis.append('svg:defs');

       var marker = defs.selectAll('marker')
         .data(markers)
         .enter()
         .append('svg:marker')
           .attr('id', function(d){ return 'marker_' + d.name; })
           .attr("markerUnits", "userSpaceOnUse")
           .attr('markerHeight', 5)
           .attr('markerWidth', 5)
           //.attr('markerUnits', 'strokeWidth')
           .attr('orient', 'auto')
           .attr('refX', 0)
           .attr('refY', 0)
           .attr('viewBox', function(d){ return d.viewbox; })
           .append('svg:path')
             .attr('d', function(d){ return d.path; })
             .attr('fill', function(d,i) { return "#ccc"; });

        root = data;
        root.x0 = 0;
        root.y0 = (w) / 2;

        update(root);
    };

    return bst;

    function toggle (d) {

        if (d.children) {
            d._children = d.children;
            d.children = null;
        } else {
            d.children = d._children;
            d._children = null;
        }
    }

    function update(source) {
        var duration = 600;

        // Compute the new tree layout.
        var nodes = tree.nodes(root).reverse();

        // Normalize for fixed-depth.
        nodes.forEach(function(d) { d.y = 15 + d.depth * depthStep; });
        nodes.forEach(function(d) { d.x = -1 * d.x; }); // -1 here flips. Fix for new representation

        // Update the nodes…
        var node = svgGroup.selectAll("g.node")
            .data(nodes, function(d) { return d.id || (d.id = ++i); })
            .on("mouseover", mouseover)
            .on("mouseout", mouseout);

        // Enter any new nodes at the parent's previous position.
        var nodeEnter = node.enter().append("svg:g")
            .attr("class", "node")
            // .attr("d", d3.svg.symbol()
            //     .type(function(d) { return d.shape || "rect"; })
            //     .size( 1 )
            // )
            .attr("transform", function(d) {
                return "translate(" + source.x0 + "," + source.y0 + ")";
            })
            .on("click", function(d) { toggle(d); update(d); })
            .on("mouseover", mouseover)
            .on("mouseout", mouseout);

        nodeEnter.append('path')
            .attr("d", d3.svg.symbol()
                .type(function(d) { return d.shape || "rect"; })
                .size(function(d) { return scaleSize(d.size) || 1; })
            )
            .style("fill", function(d) {
                return d.color || "#fff";
            })
            .style("opacity", function(d) {
                return d.role ? 0 : ( d.opacity || 1 );
            });

        nodeEnter.append("svg:text")
            .attr("dy", ".35em")
            .attr("x", "35px")
            .attr("y",  "-7px")
            .attr("text-anchor", "start")
            .style("display", "none")
            .text( function( d ) { return d.name; } );

       if(nodes[0].key !== null) {
           nodeEnter.append("svg:text")
            .attr("dy", ".35em")
            .attr("x", "-8px")
            .attr("y",  "-15px")
            .attr("text-anchor", "start")
            // .style("display", "none")
            .text(function(d) { return d.key || ""; } );
       }

        // Transition nodes to their new position.
        var nodeUpdate = node.transition()
            .duration(duration)
            .attr("transform", function(d) {
                // var dx = d.x-15;
                var dx = d.x;
                return "translate(" + dx + "," + d.y + ")";
            });

        // Transition exiting nodes to the parent's new position.
        var nodeExit = node.exit().transition()
            .duration(duration)
            .attr("transform", function(d) {
                return "translate(" + (source.x) + "," + source.y + ")";
            })
            .remove();

        // Update the links…
        var link = svgGroup.selectAll("path.link")
            .data(tree.links(nodes), function(d) {
                return d.target.id;
            });

        // Enter any new links at the parent's previous position.
        link.enter().insert("svg:path", "g")
            .attr("class", "link")
            //.style("stroke", function(d,i) { return i < 250 ? "red" : "#ccc"})
            .style("stroke", function(d,i) {
                 return "#ccc";
            })
            .style("opacity", function(d,i) {
                return d.target.role ? 0 : 1;
            })
            .attr("d", function(d) {
              var o = {x: source.x0, y: source.y0};
              return diagonal({source: o, target: o});
            })
            .attr('marker-start', function(d,i){ return 'url(#marker_circle)'; })
            .attr('marker-end', function(d,i){ return 'url(#marker_arrow)'; })
            .transition()
            .duration(duration)
            .attr("d", diagonal);

        // Transition links to their new position.
        link.transition()
            .duration(duration)
            .attr("d", diagonal);
        // Transition exiting nodes to the parent's new position.
        link.exit().transition()
            .duration(duration)
            .attr("d", function(d) {
              var o = {x: source.x, y: source.y};
              return diagonal({source: o, target: o});
            })
            .remove();
        // Stash the old positions for transition.
        nodes.forEach(function(d) {
            d.x0 = d.x;
            d.y0 = d.y;
        });

        // Add line breaks to node labels
        svgGroup.selectAll('text').each(insertLineBreaks);
    }

// Function to add line breaks to node labels/names
function insertLineBreaks (d){

	var el = d3.select(this);
    var words = d3.select(this).text().split('\n');

    if(words.length > 1) {
        el.text('');

        for (var i = 0; i < words.length; i++) {
            var tspan = el.append('tspan').text(words[i]);
            if (i > 0)
            tspan.attr('x',"35").attr('dy','15');
            //tspan.attr('x',"0").attr('dy','15');
        }
    }
}

//    // zoom function
function zoomHandler() {
    //console.log("zoom");
    svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}

function dragstarted() {
    //console.log("dragstart");
    //d3.event.sourceEvent.stopPropagation();
    d3.select(this).classed("dragging", true);
}

function dragged() {
     //console.log("dragging");
    //svgGroup.attr("transform", "translate(" + d3.event.translate + ")");
}
function dragended() {
//    console.log("dragend");
    d3.select(this).classed("dragging", false);
}

function mouseover() {
    d3.select(this).select("text").transition()
        .duration(750)
        .style("display","block");

    var el = d3.select(this);
    el.moveToFront();
}

function mouseout() {
    d3.select(this).select("text").transition()
        .duration(750)
        .style("display","none");
}

};
<commit_msg>Revert "Set link opacity to 0 for null child nodes in order to visualize left/right children in tree"<commit_after>//This code is heavily based on code from
//http://mbostock.github.io/d3/talk/20111018/tree.html

d3.selection.prototype.moveToFront = function() {
  return this.each(function(){
    this.parentNode.appendChild(this);
  });
};

var scaleSize = d3.scale.linear()
    .domain([1,100])
    .range([80,4000]);

var markers = [
   { id: 0, name: 'circle', path: 'M 0, 0  m -5, 0  a 5,5 0 1,0 10,0  a 5,5 0 1,0 -10,0', viewbox: '-6 -6 12 12' },
   { id: 1, name: 'square', path: 'M 0,0 m -5,-5 L 5,-5 L 5,5 L -5,5 Z', viewbox: '-5 -5 10 10' },
   { id: 2, name: 'arrow', path: 'M 0,0 m -5,-5 L 5,0 L -5,5 Z', viewbox: '-5 -5 10 10' },
   { id: 2, name: 'stub', path: 'M 0,0 m -1,-5 L 1,-5 L 1,5 L -1,5 Z', viewbox: '-1 -5 2 10' }
];

d3.bst = function (d3, canvasID, w, h) {

//    d3.select("#reset").on("click", reset);

    //defaults
    var bst = {},
        mw = 0, mh = 0,
        w = w || 1280,
        h = h || 800,
        i = 0,
        tree,
        depthStep = 75,
        canvasID = canvasID, //canvasID must have hash like "#vis" or "#canvas"
        root;
    var svgGroup, defs;

    var drag = d3.behavior.drag()
        //.origin(function(d) {  });
        .on("dragstart", dragstarted)
        .on("drag", dragged)
        .on("dragend", dragended);

    // error when zooming directly after pan on OSX
    // https://github.com/mbostock/d3/issues/2205
    var zoom = d3.behavior.zoom()
        .scaleExtent([0.1,5])
        //.on("dblclick.zoom",null)
        .on("zoom", zoomHandler);
        //.on("mousedown.zoom",null);
        zoom.scale(1);
    zoom.translate([(w/2), 0]);
    allZoom.push(zoom);

    bst.init = function (_w, _h, _mw, _mh, ds) {
        mw = _mw;
        mh = _mh;
        w = _w;
        h = _h;
        depthStep = ds;
        return bst;
    };

    //boilerplate stuff
    bst.make = function (data) {
        tree = d3.layout.tree()
            .nodeSize([50, 50]);
        diagonal = d3.svg.diagonal();
            //.projection(function(d, i) { if(i >= 0) return [d.x + 50, d.y]; else return [d.x, d.y] });

        vis = d3.select(canvasID).append("svg:svg")
            .attr("width", w )
            .attr("height", h )
            .attr("id", "svg" + canvasID.substr(4))
            .classed("svg", true)
            //.attr("height", h * 2)
            .call(zoom)
            .call(drag);

        svgGroup = vis.append("svg:g")
            .attr("transform", "translate(" + (mh + (w/2)) + "," + mw + ")");
        allSVG.push(svgGroup);

        defs = vis.append('svg:defs');

       var marker = defs.selectAll('marker')
         .data(markers)
         .enter()
         .append('svg:marker')
           .attr('id', function(d){ return 'marker_' + d.name; })
           .attr("markerUnits", "userSpaceOnUse")
           .attr('markerHeight', 5)
           .attr('markerWidth', 5)
           //.attr('markerUnits', 'strokeWidth')
           .attr('orient', 'auto')
           .attr('refX', 0)
           .attr('refY', 0)
           .attr('viewBox', function(d){ return d.viewbox; })
           .append('svg:path')
             .attr('d', function(d){ return d.path; })
             .attr('fill', function(d,i) { return "#ccc"; });

        root = data;
        root.x0 = 0;
        root.y0 = (w) / 2;

        update(root);
    };

    return bst;

    function toggle (d) {

        if (d.children) {
            d._children = d.children;
            d.children = null;
        } else {
            d.children = d._children;
            d._children = null;
        }
    }

    function update(source) {
        var duration = 600;

        // Compute the new tree layout.
        var nodes = tree.nodes(root).reverse();

        // Normalize for fixed-depth.
        nodes.forEach(function(d) { d.y = 15 + d.depth * depthStep; });
        nodes.forEach(function(d) { d.x = -1 * d.x; }); // -1 here flips. Fix for new representation

        // Update the nodes…
        var node = svgGroup.selectAll("g.node")
            .data(nodes, function(d) { return d.id || (d.id = ++i); })
            .on("mouseover", mouseover)
            .on("mouseout", mouseout);

        // Enter any new nodes at the parent's previous position.
        var nodeEnter = node.enter().append("svg:g")
            .attr("class", "node")
            // .attr("d", d3.svg.symbol()
            //     .type(function(d) { return d.shape || "rect"; })
            //     .size( 1 )
            // )
            .attr("transform", function(d) {
                return "translate(" + source.x0 + "," + source.y0 + ")";
            })
            .on("click", function(d) { toggle(d); update(d); })
            .on("mouseover", mouseover)
            .on("mouseout", mouseout);

        nodeEnter.append('path')
            .attr("d", d3.svg.symbol()
                .type(function(d) { return d.shape || "rect"; })
                .size(function(d) { return scaleSize(d.size) || 1; })
            )
            .style("fill", function(d) {
                return d.color || "#fff";
            })
            .style("opacity", function(d) {
                return d.role ? 0 : ( d.opacity || 1 );
            });

        nodeEnter.append("svg:text")
            .attr("dy", ".35em")
            .attr("x", "35px")
            .attr("y",  "-7px")
            .attr("text-anchor", "start")
            .style("display", "none")
            .text( function( d ) { return d.name; } );

       if(nodes[0].key !== null) {
           nodeEnter.append("svg:text")
            .attr("dy", ".35em")
            .attr("x", "-8px")
            .attr("y",  "-15px")
            .attr("text-anchor", "start")
            // .style("display", "none")
            .text(function(d) { return d.key || ""; } );
       }

        // Transition nodes to their new position.
        var nodeUpdate = node.transition()
            .duration(duration)
            .attr("transform", function(d) {
                // var dx = d.x-15;
                var dx = d.x;
                return "translate(" + dx + "," + d.y + ")";
            });

        // Transition exiting nodes to the parent's new position.
        var nodeExit = node.exit().transition()
            .duration(duration)
            .attr("transform", function(d) {
                return "translate(" + (source.x) + "," + source.y + ")";
            })
            .remove();

        // Update the links…
        var link = svgGroup.selectAll("path.link")
            .data(tree.links(nodes), function(d) {
                return d.target.id;
            });

        // Enter any new links at the parent's previous position.
        link.enter().insert("svg:path", "g")
            .attr("class", "link")
            //.style("stroke", function(d,i) { return i < 250 ? "red" : "#ccc"})
            .style("stroke", function(d,i) {
                 return "#ccc";
            })
            .style("opacity", function(d,i) {
                return d.opacity || 1;
            })
            .attr("d", function(d) {
              var o = {x: source.x0, y: source.y0};
              return diagonal({source: o, target: o});
            })
            .attr('marker-start', function(d,i){ return 'url(#marker_circle)'; })
            .attr('marker-end', function(d,i){ return 'url(#marker_arrow)'; })
            .transition()
            .duration(duration)
            .attr("d", diagonal);

        // Transition links to their new position.
        link.transition()
            .duration(duration)
            .attr("d", diagonal);
        // Transition exiting nodes to the parent's new position.
        link.exit().transition()
            .duration(duration)
            .attr("d", function(d) {
              var o = {x: source.x, y: source.y};
              return diagonal({source: o, target: o});
            })
            .remove();
        // Stash the old positions for transition.
        nodes.forEach(function(d) {
            d.x0 = d.x;
            d.y0 = d.y;
        });

        // Add line breaks to node labels
        svgGroup.selectAll('text').each(insertLineBreaks);
    }

// Function to add line breaks to node labels/names
function insertLineBreaks (d){

	var el = d3.select(this);
    var words = d3.select(this).text().split('\n');

    if(words.length > 1) {
        el.text('');

        for (var i = 0; i < words.length; i++) {
            var tspan = el.append('tspan').text(words[i]);
            if (i > 0)
            tspan.attr('x',"35").attr('dy','15');
            //tspan.attr('x',"0").attr('dy','15');
        }
    }
}

//    // zoom function
function zoomHandler() {
    //console.log("zoom");
    svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}

function dragstarted() {
    //console.log("dragstart");
    //d3.event.sourceEvent.stopPropagation();
    d3.select(this).classed("dragging", true);
}

function dragged() {
     //console.log("dragging");
    //svgGroup.attr("transform", "translate(" + d3.event.translate + ")");
}
function dragended() {
//    console.log("dragend");
    d3.select(this).classed("dragging", false);
}

function mouseover() {
    d3.select(this).select("text").transition()
        .duration(750)
        .style("display","block");

    var el = d3.select(this);
    el.moveToFront();
}

function mouseout() {
    d3.select(this).select("text").transition()
        .duration(750)
        .style("display","none");
}

};
<|endoftext|>


<commit_before>Homes = new Mongo.Collection('homes');

var HomesSchema = new SimpleSchema({
  name:{
    type:String,
    label: 'Home Name',
  },
  groupId: {
    type: String,
    label: 'Group',
    autoform: {
      options: function() {
        return _.map(Groups.find().fetch(), function(group) {
          return {
            label: group.name,
            value: group._id
          };
        });
      }
    }
  }
});

Homes.attachSchema(HomesSchema);

Homes.helpers({
  groupName: function () {
    // Get the Group ID;
    var groupId = this.groupId;

    // Get Group from Groups collection, by ID(s)
    var group = Groups.findOne(groupId);

    // Return the Group name
    return group.name;
  }
});
<commit_msg>All Homes update<commit_after>Homes = new Mongo.Collection('homes');

var HomesSchema = new SimpleSchema({
  name:{
    type:String,
    label: 'Home Name',
  },
  groupId: {
    type: String,
    label: 'Group',
    autoform: {
      options: function() {
        return _.map(Groups.find().fetch(), function(group) {
          return {
            label: group.name,
            value: group._id
          };
        });
      }
    }
  }
});

Homes.attachSchema(HomesSchema);

Homes.helpers({
  groupName: function () {
    // Get the Group ID;
    var groupId = this.groupId;

    // Get Group from Groups collection, by ID(s)
    var group = Groups.findOne(groupId);

    // Return the Group name
    return group.name;
  }
});

Homes.allow({
  update: function () {
    return true;
  }
});
<|endoftext|>