<commit_before>import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { styled, useThemeProps } from '@mui/material/styles';
import { capitalize } from '@mui/material/utils';
import { unstable_composeClasses as composeClasses } from '@mui/base';
import { getTimelineDotUtilityClass } from './timelineDotClasses';

const useUtilityClasses = (ownerState) => {
  const { color, variant, classes } = ownerState;

  const slots = {
    root: ['root', variant, color !== 'inherit' && `${variant}${capitalize(color)}`],
  };

  return composeClasses(slots, getTimelineDotUtilityClass, classes);
};

const TimelineDotRoot = styled('span', {
  name: 'MuiTimelineDot',
  slot: 'Root',
  overridesResolver: (props, styles) => {
    const { ownerState } = props;

    return [
      styles.root,
      styles[
        ownerState.color !== 'inherit' && `${ownerState.variant}${capitalize(ownerState.color)}`
      ],
      styles[ownerState.variant],
    ];
  },
})(({ ownerState, theme }) => ({
  display: 'flex',
  alignSelf: 'baseline',
  borderStyle: 'solid',
  borderWidth: 2,
  padding: 4,
  borderRadius: '50%',
  boxShadow: theme.shadows[1],
  margin: '11.5px 0',
  ...(ownerState.variant === 'filled' && {
    borderColor: 'transparent',
    ...(ownerState.color !== 'inherit' && {
      ...(ownerState.color === 'grey'
        ? {
            color: theme.palette.grey[50],
            backgroundColor: theme.palette.grey[400],
          }
        : {
            color: theme.palette[ownerState.color].contrastText,
            backgroundColor: theme.palette[ownerState.color].main,
          }),
    }),
  }),
  ...(ownerState.variant === 'outlined' && {
    boxShadow: 'none',
    backgroundColor: 'transparent',
    ...(ownerState.color !== 'inherit' && {
      ...(ownerState.color === 'grey'
        ? {
            borderColor: theme.palette.grey[400],
          }
        : {
            borderColor: theme.palette[ownerState.color].main,
          }),
    }),
  }),
}));

const TimelineDot = React.forwardRef(function TimelineDot(inProps, ref) {
  const props = useThemeProps({ props: inProps, name: 'MuiTimelineDot' });
  const { className, color = 'grey', variant = 'filled', ...other } = props;

  const ownerState = {
    ...props,
    color,
    variant,
  };

  const classes = useUtilityClasses(ownerState);

  return (
    <TimelineDotRoot
      className={clsx(classes.root, className)}
      ownerState={ownerState}
      ref={ref}
      {...other}
    />
  );
});

TimelineDot.propTypes /* remove-proptypes */ = {
  // ----------------------------- Warning --------------------------------
  // | These PropTypes are generated from the TypeScript type definitions |
  // |     To update them edit the d.ts file and run "yarn proptypes"     |
  // ----------------------------------------------------------------------
  /**
   * The content of the component.
   */
  children: PropTypes.node,
  /**
   * Override or extend the styles applied to the component.
   */
  classes: PropTypes.object,
  /**
   * @ignore
   */
  className: PropTypes.string,
  /**
   * The dot can have a different colors.
   * @default 'grey'
   */
  color: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([
    PropTypes.oneOf([
      'error',
      'grey',
      'info',
      'inherit',
      'primary',
      'secondary',
      'success',
      'warning',
    ]),
    PropTypes.string,
  ]),
  /**
   * The system prop that allows defining system overrides as well as additional CSS styles.
   */
  sx: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])),
    PropTypes.func,
    PropTypes.object,
  ]),
  /**
   * The dot can appear filled or outlined.
   * @default 'filled'
   */
  variant: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([
    PropTypes.oneOf(['filled', 'outlined']),
    PropTypes.string,
  ]),
};

export default TimelineDot;
<commit_msg>[TimelineDot] Add support for CSS variables (#34003)<commit_after>import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { styled, useThemeProps } from '@mui/material/styles';
import { capitalize } from '@mui/material/utils';
import { unstable_composeClasses as composeClasses } from '@mui/base';
import { getTimelineDotUtilityClass } from './timelineDotClasses';

const useUtilityClasses = (ownerState) => {
  const { color, variant, classes } = ownerState;

  const slots = {
    root: ['root', variant, color !== 'inherit' && `${variant}${capitalize(color)}`],
  };

  return composeClasses(slots, getTimelineDotUtilityClass, classes);
};

const TimelineDotRoot = styled('span', {
  name: 'MuiTimelineDot',
  slot: 'Root',
  overridesResolver: (props, styles) => {
    const { ownerState } = props;

    return [
      styles.root,
      styles[
        ownerState.color !== 'inherit' && `${ownerState.variant}${capitalize(ownerState.color)}`
      ],
      styles[ownerState.variant],
    ];
  },
})(({ ownerState, theme }) => ({
  display: 'flex',
  alignSelf: 'baseline',
  borderStyle: 'solid',
  borderWidth: 2,
  padding: 4,
  borderRadius: '50%',
  boxShadow: (theme.vars || theme).shadows[1],
  margin: '11.5px 0',
  ...(ownerState.variant === 'filled' && {
    borderColor: 'transparent',
    ...(ownerState.color !== 'inherit' && {
      ...(ownerState.color === 'grey'
        ? {
            color: (theme.vars || theme).palette.grey[50],
            backgroundColor: (theme.vars || theme).palette.grey[400],
          }
        : {
            color: (theme.vars || theme).palette[ownerState.color].contrastText,
            backgroundColor: (theme.vars || theme).palette[ownerState.color].main,
          }),
    }),
  }),
  ...(ownerState.variant === 'outlined' && {
    boxShadow: 'none',
    backgroundColor: 'transparent',
    ...(ownerState.color !== 'inherit' && {
      ...(ownerState.color === 'grey'
        ? {
            borderColor: (theme.vars || theme).palette.grey[400],
          }
        : {
            borderColor: (theme.vars || theme).palette[ownerState.color].main,
          }),
    }),
  }),
}));

const TimelineDot = React.forwardRef(function TimelineDot(inProps, ref) {
  const props = useThemeProps({ props: inProps, name: 'MuiTimelineDot' });
  const { className, color = 'grey', variant = 'filled', ...other } = props;

  const ownerState = {
    ...props,
    color,
    variant,
  };

  const classes = useUtilityClasses(ownerState);

  return (
    <TimelineDotRoot
      className={clsx(classes.root, className)}
      ownerState={ownerState}
      ref={ref}
      {...other}
    />
  );
});

TimelineDot.propTypes /* remove-proptypes */ = {
  // ----------------------------- Warning --------------------------------
  // | These PropTypes are generated from the TypeScript type definitions |
  // |     To update them edit the d.ts file and run "yarn proptypes"     |
  // ----------------------------------------------------------------------
  /**
   * The content of the component.
   */
  children: PropTypes.node,
  /**
   * Override or extend the styles applied to the component.
   */
  classes: PropTypes.object,
  /**
   * @ignore
   */
  className: PropTypes.string,
  /**
   * The dot can have a different colors.
   * @default 'grey'
   */
  color: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([
    PropTypes.oneOf([
      'error',
      'grey',
      'info',
      'inherit',
      'primary',
      'secondary',
      'success',
      'warning',
    ]),
    PropTypes.string,
  ]),
  /**
   * The system prop that allows defining system overrides as well as additional CSS styles.
   */
  sx: PropTypes.oneOfType([
    PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])),
    PropTypes.func,
    PropTypes.object,
  ]),
  /**
   * The dot can appear filled or outlined.
   * @default 'filled'
   */
  variant: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([
    PropTypes.oneOf(['filled', 'outlined']),
    PropTypes.string,
  ]),
};

export default TimelineDot;
<|endoftext|>


<commit_before>import { jsExtend as extend } from 'pouchdb-utils';

import PouchDB from './constructor';
import inherits from 'inherits';
import { Map } from 'pouchdb-collections';
import { EventEmitter as EE } from 'events';

PouchDB.adapters = {};
PouchDB.preferredAdapters = [];

PouchDB.prefix = '_pouch_';

var eventEmitter = new EE();

function setUpEventEmitter(Pouch) {
  Object.keys(EE.prototype).forEach(function (key) {
    if (typeof EE.prototype[key] === 'function') {
      Pouch[key] = eventEmitter[key].bind(eventEmitter);
    }
  });

  // these are created in constructor.js, and allow us to notify each DB with
  // the same name that it was destroyed, via the constructor object
  var destructListeners = Pouch._destructionListeners = new Map();
  Pouch.on('destroyed', function onConstructorDestroyed(name) {
    destructListeners.get(name).forEach(function (callback) {
      callback();
    });
    destructListeners.delete(name);
  });
}

setUpEventEmitter(PouchDB);

PouchDB.adapter = function (id, obj, addToPreferredAdapters) {
  /* istanbul ignore else */
  if (obj.valid()) {
    PouchDB.adapters[id] = obj;
    if (addToPreferredAdapters) {
      PouchDB.preferredAdapters.push(id);
    }
  }
};

PouchDB.plugin = function (obj) {
  if (typeof obj === 'function') { // function style for plugins
    obj(PouchDB);
  } else if (typeof obj !== 'object' || Object.keys(obj).length === 0){
    throw new Error('Invalid plugin: object passed in is empty or not an object');
  } else {
    Object.keys(obj).forEach(function (id) { // object style for plugins
      PouchDB.prototype[id] = obj[id];
    });
  }
  return PouchDB;
};

PouchDB.defaults = function (defaultOpts) {
  function PouchAlt(name, opts) {
    if (!(this instanceof PouchAlt)) {
      return new PouchAlt(name, opts);
    }

    opts = opts || {};

    if (name && typeof name === 'object') {
      opts = name;
      name = opts.name;
      delete opts.name;
    }

    opts = extend({}, PouchAlt.__defaults, opts);
    PouchDB.call(this, name, opts);
  }

  inherits(PouchAlt, PouchDB);

  PouchAlt.preferredAdapters = PouchDB.preferredAdapters.slice();
  Object.keys(PouchDB).forEach(function (key) {
    if (!(key in PouchAlt)) {
      PouchAlt[key] = PouchDB[key];
    }
  });

  // make default options transitive
  // https://github.com/pouchdb/pouchdb/issues/5922
  PouchAlt.__defaults = extend({}, this.__defaults, defaultOpts);

  return PouchAlt;
};

export default PouchDB;
<commit_msg>(#5904) - more helpful error message for invalid plugin<commit_after>import { jsExtend as extend } from 'pouchdb-utils';

import PouchDB from './constructor';
import inherits from 'inherits';
import { Map } from 'pouchdb-collections';
import { EventEmitter as EE } from 'events';

PouchDB.adapters = {};
PouchDB.preferredAdapters = [];

PouchDB.prefix = '_pouch_';

var eventEmitter = new EE();

function setUpEventEmitter(Pouch) {
  Object.keys(EE.prototype).forEach(function (key) {
    if (typeof EE.prototype[key] === 'function') {
      Pouch[key] = eventEmitter[key].bind(eventEmitter);
    }
  });

  // these are created in constructor.js, and allow us to notify each DB with
  // the same name that it was destroyed, via the constructor object
  var destructListeners = Pouch._destructionListeners = new Map();
  Pouch.on('destroyed', function onConstructorDestroyed(name) {
    destructListeners.get(name).forEach(function (callback) {
      callback();
    });
    destructListeners.delete(name);
  });
}

setUpEventEmitter(PouchDB);

PouchDB.adapter = function (id, obj, addToPreferredAdapters) {
  /* istanbul ignore else */
  if (obj.valid()) {
    PouchDB.adapters[id] = obj;
    if (addToPreferredAdapters) {
      PouchDB.preferredAdapters.push(id);
    }
  }
};

PouchDB.plugin = function (obj) {
  if (typeof obj === 'function') { // function style for plugins
    obj(PouchDB);
  } else if (typeof obj !== 'object' || Object.keys(obj).length === 0){
    throw new Error('Invalid plugin: got \"' + obj + '\", expected an object or a function');
  } else {
    Object.keys(obj).forEach(function (id) { // object style for plugins
      PouchDB.prototype[id] = obj[id];
    });
  }
  return PouchDB;
};

PouchDB.defaults = function (defaultOpts) {
  function PouchAlt(name, opts) {
    if (!(this instanceof PouchAlt)) {
      return new PouchAlt(name, opts);
    }

    opts = opts || {};

    if (name && typeof name === 'object') {
      opts = name;
      name = opts.name;
      delete opts.name;
    }

    opts = extend({}, PouchAlt.__defaults, opts);
    PouchDB.call(this, name, opts);
  }

  inherits(PouchAlt, PouchDB);

  PouchAlt.preferredAdapters = PouchDB.preferredAdapters.slice();
  Object.keys(PouchDB).forEach(function (key) {
    if (!(key in PouchAlt)) {
      PouchAlt[key] = PouchDB[key];
    }
  });

  // make default options transitive
  // https://github.com/pouchdb/pouchdb/issues/5922
  PouchAlt.__defaults = extend({}, this.__defaults, defaultOpts);

  return PouchAlt;
};

export default PouchDB;
<|endoftext|>


<commit_before>/* Copyright (c) 2012-2014 The TagSpaces Authors. All rights reserved.
 * Use of this source code is governed by a AGPL3 license that
 * can be found in the LICENSE file. */
/* global define, Handlebars  */

define(function(require, exports, module) {
    "use strict";

    console.log("Loading perspectiveOCRO templates");

    exports.mainToolBar = Handlebars.compile(
        '
' +
            '
'+
                '<button class="btn btn-link" data-i18n="[title]ns.perspectiveOCRO:toggleSelectAll" title="" id="{{id}}ToogleSelectAll"></button>'+
                '<button class="btn btn-link" data-i18n="[title]ns.perspectiveOCRO:downloadTooltip" id="{{id}}DownloadButton"></button>'+
                '<button class="btn btn-link" data-i18n="[title]ns.perspectiveOCRO:reloadDirectoryTooltip" id="{{id}}ReloadFolderButton"></button>'+
                '<button class="btn btn-link" data-i18n="[title]ns.perspectiveOCRO:showSubfolderContentTooltip" id="{{id}}IncludeSubDirsButton"></button>'+
                //'<button class="btn btn-link" data-i18n="[title]ns.perspectiveList:toggleThumbnailsTooltip" data-toggle="button" id="{{id}}ShowTmbButton"></button>'+
                //'<button class="btn btn-link" data-i18n="[title]ns.perspectiveList:increasThumbnailsTooltip" id="{{id}}IncreaseThumbsButton"></button>'+
            '
'+
            '
'+
                '<input type="search" name="Search" class="form-control" id="{{id}}searchBoxOC" placeholder="Search" data-i18n="[placeholder]ns.common:searchPlaceholder">'+
                //'<button class="btn btn-default" type="submit"></button>'+
            '
'+
        '
'
    );

    exports.dialogOCSetting = Handlebars.compile(
        '
'+
            '
'+
                '
'+
                    '
'+
                        '<button type="button" class="close" data-dismiss="modal" aria-hidden="true"></button>'+
                        '
Settings
'+
                    '
'+
                    '
'+
                        ''+
                    '
'+
                    '
'+
                        '<button class="btn btn-primary" data-dismiss="modal" title="Close Dialog" aria-hidden="true"></button>'+
                    '
'+
                '
'+
            '
'+
        '
'
    );

    exports.fileTiles = Handlebars.compile(
        '
'+
        '{{#each files}}'+
        '
'+
            ''+
            '
{{title}}
' +
            ''+
                '{{#each tags}}'+
                '<button class="btn btn-sm tagButton fileTagsTile" style="{{style}}">{{tag}} </button>'+
                '{{/each}}'+
            '' +
            '{{fileext}}'+
            '<button class="btn btn-link fileTileSelector" data-filepath="{{filepath}}"></button>' +
        '
'+
        '{{/each}}'+
        '
'
    );

});<commit_msg>code style improvement<commit_after>/* Copyright (c) 2012-2014 The TagSpaces Authors. All rights reserved.
 * Use of this source code is governed by a AGPL3 license that
 * can be found in the LICENSE file. */
/* global define, Handlebars  */

define(function(require, exports, module) {
    "use strict";

    console.log("Loading perspectiveOCRO templates");

    exports.mainToolBar = Handlebars.compile(
        '
' +
            '
'+
                '<button class="btn btn-link" data-i18n="[title]ns.perspectiveOCRO:toggleSelectAll" title="" id="{{id}}ToogleSelectAll"></button>'+
                '<button class="btn btn-link" data-i18n="[title]ns.perspectiveOCRO:downloadTooltip" id="{{id}}DownloadButton"></button>'+
                '<button class="btn btn-link" data-i18n="[title]ns.perspectiveOCRO:reloadDirectoryTooltip" id="{{id}}ReloadFolderButton"></button>'+
                '<button class="btn btn-link" data-i18n="[title]ns.perspectiveOCRO:showSubfolderContentTooltip" id="{{id}}IncludeSubDirsButton"></button>'+
                //'<button class="btn btn-link" data-i18n="[title]ns.perspectiveList:toggleThumbnailsTooltip" data-toggle="button" id="{{id}}ShowTmbButton"></button>'+
                //'<button class="btn btn-link" data-i18n="[title]ns.perspectiveList:increasThumbnailsTooltip" id="{{id}}IncreaseThumbsButton"></button>'+
            '
'+
            '
'+
                '<input type="search" name="Search" class="form-control" id="{{id}}searchBoxOC" placeholder="Search" data-i18n="[placeholder]ns.common:searchPlaceholder">'+
                //'<button class="btn btn-default" type="submit"></button>'+
            '
'+
        '
'
    );

    exports.dialogOCSetting = Handlebars.compile(
        '
'+
            '
'+
                '
'+
                    '
'+
                        '<button type="button" class="close" data-dismiss="modal" aria-hidden="true"></button>'+
                        '
Settings
'+
                    '
'+
                    '
'+
                        ''+
                    '
'+
                    '
'+
                        '<button class="btn btn-primary" data-dismiss="modal" title="Close Dialog" aria-hidden="true"></button>'+
                    '
'+
                '
'+
            '
'+
        '
'
    );

    exports.fileTiles = Handlebars.compile(
        '
'+
        '{{#each files}}'+
        '
'+
            ''+
            '
{{title}}
' +
            ''+
                '{{#each tags}}'+
                '<button class="btn btn-sm tagButton fileTagsTile" style="{{style}}">{{tag}} </button>'+
                '{{/each}}'+
            '' +
            '{{fileext}}'+
            '<button class="btn btn-link fileTileSelector" data-filepath="{{filepath}}"></button>' +
        '
'+
        '{{/each}}'+
        '
'
    );

});<|endoftext|>


<commit_before>/**
 * Backbone Firebase Adapter.
 */

(function() {

var _ = this._;
var Backbone = this.Backbone;

Backbone.Firebase = function(ref) {
  this._fbref = ref;
  this._children = [];
  if (typeof ref == "string") {
    this._fbref = new Firebase(ref);
  }

  _.bindAll(this);
  this._fbref.on("child_added", this._childAdded);
  this._fbref.on("child_moved", this._childMoved);
  this._fbref.on("child_changed", this._childChanged);
  this._fbref.on("child_removed", this._childRemoved);
};

_.extend(Backbone.Firebase.prototype, {

  _childAdded: function(childSnap, prevChild) {
    var model = childSnap.val();
    model.id = childSnap.name();
    if (prevChild) {
      var item = _.find(this._children, function(child) {
        return child.id == prevChild
      });
      this._children.splice(this._children.indexOf(item) + 1, 0, model);
    } else {
      this._children.unshift(model);
    }
  },
  _childMoved: function(childSnap, prevChild) {
    var model = childSnap.val();
    this._children = _.reject(this._children, function(child) {
      return child.id == model.id;
    });
    this._childAdded(childSnap, prevChild);
  },
  _childChanged: function(childSnap, prevChild) {
    var model = childSnap.val();
    model.id = childSnap.name();
    var item = _.find(this._children, function(child) {
      return child.id == model.id
    });
    this._children[this._children.indexOf(item)] = model;
  },
  _childRemoved: function(oldChildSnap) {
    var model = oldChildSnap.val();
    this._children = _.reject(this._children, function(child) {
      return child.id == model.id
    });
  },

  create: function(model, cb) {
    if (!model.id) {
      model.id = this._fbref.push().name();
    }
    var val = model.toJSON();
    this._fbref.child(model.id).set(val, _.bind(function(success) {
      if (success) {
        cb(null, val);
      } else {
        cb("Could not create model " + model.id);
      }
    }, this));
  },

  read: function(model, cb) {
    if (!model.id) {
      _.defer(cb, "Invalid model ID provided to read");
      return;
    }
    var index = _.find(this._children, function(child) {
      return child.id == model.id
    });
    _.defer(cb, null, this._children[index]);
  },

  readAll: function(model, cb) {
    _.defer(cb, null, this._children);
  },

  update: function(model, cb) {
    var val = model.toJSON();
    this._fbref.child(model.id).update(val, function(success) {
      if (success) {
        cb(null, val);
      } else {
        cb("Could not update model " + model.id, null);
      }
    });
  },

  delete: function(model, cb) {
    this._fbref.child(model.id).remove(function(success) {
      if (success) {
        cb(null, model);
      } else {
        cb("Could not delete model " + model.id);
      }
    });
  }
});

Backbone.Firebase.sync = function(method, model, options, error) {
  var store = model.firebase || model.collection.firebase;

  // Backwards compatibility with Backbone <= 0.3.3
  if (typeof options == 'function') {
    options = {
      success: options,
      error: error
    };
  }

  if (method == "read" && model.id == undefined) {
    method = "readAll";
  }

  store[method].apply(this, [model, function(err, val) {
    if (err) {
      options.error(model, err, options);
    } else {
      options.success(model, val, options);
    }
  }]);
};

Backbone.oldSync = Backbone.sync;

// Override 'Backbone.sync' to default to Firebase sync.
// the original 'Backbone.sync' is still available in 'Backbone.oldSync'
Backbone.sync = function(method, model, options, error) {
  var syncMethod = Backbone.oldSync;
  if (model.firebase || (model.collection && model.collection.firebase)) {
    syncMethod = Backbone.Firebase.sync;
  }
	return syncMethod.apply(this, [method, model, options, error]);
};

// Custom Firebase Collection.
Backbone.Firebase.Collection = Backbone.Collection.extend({
  sync: function() {
    throw new Error("Sync called on a Firebase collection");
  },
  fetch: function() {
    throw new Error("Fetch called on a Firebase collection");
  },
  create: function() {
    throw new Error("Please use Backbone.Collection.add instead");
  },

  constructor: function(models, options) {
    if (options && options.firebase) {
      this.firebase = options.firebase;
    }
    switch (typeof this.firebase) {
      case "object": break;
      case "string": this.firebase = new Firebase(this.firebase); break;
      default: throw new Error("Invalid firebase reference created");
    }

    // Add handlers for remote events.
    this.firebase.on("child_added", this._childAdded.bind(this));
    this.firebase.on("child_moved", this._childMoved.bind(this));
    this.firebase.on("child_changed", this._childChanged.bind(this));
    this.firebase.on("child_removed", this._childRemoved.bind(this));

    // Apply parent constructor (this will also call initialize).
    Backbone.Collection.apply(this, arguments);

    // Add handlers for all models in this collection, and any future ones
    // that may be added.
    function _updateModel(model, options) {
      this.firebase.child(model.id).update(model.toJSON());
    }
    function _unUpdateModel(model) {
      model.off("change", _updateModel, this);
    }

    for (var i = 0; i < this.models.length; i++) {
      this.models[i].on("change", _updateModel, this);
      this.models[i].once("remove", _unUpdateModel, this);
    }
    this.on("add", function(model) {
      model.on("change", _updateModel, this);
      model.once("remove", _unUpdateModel, this);
    }, this);
  },

  comparator: function(model) {
    return model.id;
  },

  add: function(models, options) {
    if (options) {
      throw new Error("Backbone.Firebase.Collection.add called with options")
    }
    var parsed = this._parseModels(models);
    for (var i = 0; i < parsed.length; i++) {
      var model = parsed[i];
      this.firebase.child(model.id).set(model);
    }
  },

  remove: function(models, options) {
    if (options) {
      throw new Error("Backbone.Firebase.Collection.remove called with options");
    }
    var parsed = this._parseModels(models);
    for (var i = 0; i < parsed.length; i++) {
      var model = parsed[i];
      this.firebase.child(model.id).set(null);
    }
  },

  // XXX: Options will be ignored for add & remove!
  _parseModels: function(models) {
    var ret = [];
    models = _.isArray(models) ? models.slice() : [models];
    for (var i = 0; i < models.length; i++) {
      var model = models[i];
      if (!model.id) {
        model.id = this.firebase.push().name();
      }
      if (model.toJSON && typeof model.toJSON == "function") {
        model = model.toJSON();
      }
      ret.push(model);
    }
    return ret;
  },

  _childAdded: function(snap) {
    Backbone.Collection.prototype.add.apply(this, [snap.val()]);
  },

  _childMoved: function(snap) {
    // XXX: Can this occur without the ID changing?
  },

  _childChanged: function(snap) {
    var model = snap.val();
    var item = _.find(this.models, function(child) {
      return child.id == model.id
    });
    if (!item) {
      // ???
      throw new Error("Could not find model with ID " + model.id);
    }
    item.set(model);
  },

  _childRemoved: function(snap) {
    Backbone.Collection.prototype.remove.apply(this, [snap.val()]);
  }
});

})();

<commit_msg>Allow options in remove call<commit_after>/**
 * Backbone Firebase Adapter.
 */

(function() {

var _ = this._;
var Backbone = this.Backbone;

Backbone.Firebase = function(ref) {
  this._fbref = ref;
  this._children = [];
  if (typeof ref == "string") {
    this._fbref = new Firebase(ref);
  }

  _.bindAll(this);
  this._fbref.on("child_added", this._childAdded);
  this._fbref.on("child_moved", this._childMoved);
  this._fbref.on("child_changed", this._childChanged);
  this._fbref.on("child_removed", this._childRemoved);
};

_.extend(Backbone.Firebase.prototype, {

  _childAdded: function(childSnap, prevChild) {
    var model = childSnap.val();
    model.id = childSnap.name();
    if (prevChild) {
      var item = _.find(this._children, function(child) {
        return child.id == prevChild
      });
      this._children.splice(this._children.indexOf(item) + 1, 0, model);
    } else {
      this._children.unshift(model);
    }
  },
  _childMoved: function(childSnap, prevChild) {
    var model = childSnap.val();
    this._children = _.reject(this._children, function(child) {
      return child.id == model.id;
    });
    this._childAdded(childSnap, prevChild);
  },
  _childChanged: function(childSnap, prevChild) {
    var model = childSnap.val();
    model.id = childSnap.name();
    var item = _.find(this._children, function(child) {
      return child.id == model.id
    });
    this._children[this._children.indexOf(item)] = model;
  },
  _childRemoved: function(oldChildSnap) {
    var model = oldChildSnap.val();
    this._children = _.reject(this._children, function(child) {
      return child.id == model.id
    });
  },

  create: function(model, cb) {
    if (!model.id) {
      model.id = this._fbref.push().name();
    }
    var val = model.toJSON();
    this._fbref.child(model.id).set(val, _.bind(function(success) {
      if (success) {
        cb(null, val);
      } else {
        cb("Could not create model " + model.id);
      }
    }, this));
  },

  read: function(model, cb) {
    if (!model.id) {
      _.defer(cb, "Invalid model ID provided to read");
      return;
    }
    var index = _.find(this._children, function(child) {
      return child.id == model.id
    });
    _.defer(cb, null, this._children[index]);
  },

  readAll: function(model, cb) {
    _.defer(cb, null, this._children);
  },

  update: function(model, cb) {
    var val = model.toJSON();
    this._fbref.child(model.id).update(val, function(success) {
      if (success) {
        cb(null, val);
      } else {
        cb("Could not update model " + model.id, null);
      }
    });
  },

  delete: function(model, cb) {
    this._fbref.child(model.id).remove(function(success) {
      if (success) {
        cb(null, model);
      } else {
        cb("Could not delete model " + model.id);
      }
    });
  }
});

Backbone.Firebase.sync = function(method, model, options, error) {
  var store = model.firebase || model.collection.firebase;

  // Backwards compatibility with Backbone <= 0.3.3
  if (typeof options == 'function') {
    options = {
      success: options,
      error: error
    };
  }

  if (method == "read" && model.id == undefined) {
    method = "readAll";
  }

  store[method].apply(this, [model, function(err, val) {
    if (err) {
      options.error(model, err, options);
    } else {
      options.success(model, val, options);
    }
  }]);
};

Backbone.oldSync = Backbone.sync;

// Override 'Backbone.sync' to default to Firebase sync.
// the original 'Backbone.sync' is still available in 'Backbone.oldSync'
Backbone.sync = function(method, model, options, error) {
  var syncMethod = Backbone.oldSync;
  if (model.firebase || (model.collection && model.collection.firebase)) {
    syncMethod = Backbone.Firebase.sync;
  }
	return syncMethod.apply(this, [method, model, options, error]);
};

// Custom Firebase Collection.
Backbone.Firebase.Collection = Backbone.Collection.extend({
  sync: function() {
    throw new Error("Sync called on a Firebase collection");
  },
  fetch: function() {
    throw new Error("Fetch called on a Firebase collection");
  },
  create: function() {
    throw new Error("Please use Backbone.Collection.add instead");
  },

  constructor: function(models, options) {
    if (options && options.firebase) {
      this.firebase = options.firebase;
    }
    switch (typeof this.firebase) {
      case "object": break;
      case "string": this.firebase = new Firebase(this.firebase); break;
      default: throw new Error("Invalid firebase reference created");
    }

    // Add handlers for remote events.
    this.firebase.on("child_added", this._childAdded.bind(this));
    this.firebase.on("child_moved", this._childMoved.bind(this));
    this.firebase.on("child_changed", this._childChanged.bind(this));
    this.firebase.on("child_removed", this._childRemoved.bind(this));

    // Apply parent constructor (this will also call initialize).
    Backbone.Collection.apply(this, arguments);

    // Add handlers for all models in this collection, and any future ones
    // that may be added.
    function _updateModel(model, options) {
      this.firebase.child(model.id).update(model.toJSON());
    }
    function _unUpdateModel(model) {
      model.off("change", _updateModel, this);
    }

    for (var i = 0; i < this.models.length; i++) {
      this.models[i].on("change", _updateModel, this);
      this.models[i].once("remove", _unUpdateModel, this);
    }
    this.on("add", function(model) {
      model.on("change", _updateModel, this);
      model.once("remove", _unUpdateModel, this);
    }, this);
  },

  comparator: function(model) {
    return model.id;
  },

  add: function(models, options) {
    if (options) {
      throw new Error("Backbone.Firebase.Collection.add called with options")
    }
    var parsed = this._parseModels(models);
    for (var i = 0; i < parsed.length; i++) {
      var model = parsed[i];
      this.firebase.child(model.id).set(model);
    }
  },

  remove: function(models, options) {
    var parsed = this._parseModels(models);
    for (var i = 0; i < parsed.length; i++) {
      var model = parsed[i];
      this.firebase.child(model.id).set(null, function() {
        if (options && options.success) {
          options.success(models, options);
        }
      });
    }
  },

  // XXX: Options will be ignored for add & remove!
  _parseModels: function(models) {
    var ret = [];
    models = _.isArray(models) ? models.slice() : [models];
    for (var i = 0; i < models.length; i++) {
      var model = models[i];
      if (!model.id) {
        model.id = this.firebase.push().name();
      }
      if (model.toJSON && typeof model.toJSON == "function") {
        model = model.toJSON();
      }
      ret.push(model);
    }
    return ret;
  },

  _childAdded: function(snap) {
    Backbone.Collection.prototype.add.apply(this, [snap.val()]);
  },

  _childMoved: function(snap) {
    // XXX: Can this occur without the ID changing?
  },

  _childChanged: function(snap) {
    var model = snap.val();
    var item = _.find(this.models, function(child) {
      return child.id == model.id
    });
    if (!item) {
      // ???
      throw new Error("Could not find model with ID " + model.id);
    }
    item.set(model);
  },

  _childRemoved: function(snap) {
    Backbone.Collection.prototype.remove.apply(this, [snap.val()]);
  }
});

})();

<|endoftext|>


<commit_before>import Route from 'route-parser';
import formatRoutes from './formatRoutes';

import type { $RouteConfig } from './Router';

type $MatchedRoute = {|
	params: Object,
	component: ReactClass<*>,
	route?: Object,
	isMiss?: boolean,
|};

const matchRoute = (routeConfig: $RouteConfig, pathname: string): $MatchedRoute => {
	const formattedRoutes = formatRoutes(routeConfig.routes);

	const foundRoute = formattedRoutes.find(({ route }) => {
		return route.match(pathname);
	});

	return foundRoute
		? Object.assign({}, foundRoute, { params: foundRoute.route.match(pathname) })
		: { component: routeConfig.miss, params: {}, isMiss: true };
};

export default matchRoute;

export const matchSingleRoute = (route: string, pathname: string): boolean | Object => {
	const routeMatcher = new Route(route);
	const matched = routeMatcher.match(pathname);

	return matched ? { params: matched } : false;
};
<commit_msg>More flowtypes<commit_after>import Route from 'route-parser';
import formatRoutes from './formatRoutes';

import type { $RouteConfig } from './Router';

type $MatchedRoute = {|
	params: Object,
	component: ReactClass<*>,
	route?: Object,
	isMiss?: boolean,
|};

const matchRoute = (routeConfig: $RouteConfig, pathname: string): $MatchedRoute => {
	const formattedRoutes = formatRoutes(routeConfig.routes);

	const foundRoute = formattedRoutes.find(({ route }) => {
		return route.match(pathname);
	});

	return foundRoute
		? Object.assign({}, foundRoute, { params: foundRoute.route.match(pathname) })
		: { component: routeConfig.miss, params: {}, isMiss: true };
};

export default matchRoute;

export const matchSingleRoute = (route: string, pathname: string): boolean | {| params: Object |} => {
	const routeMatcher = new Route(route);
	const matched: Object = routeMatcher.match(pathname);

	return matched ? { params: matched } : false;
};
<|endoftext|>


<commit_before>import Avatar from 'meteor-avatar-core';
// import Email from 'meteor/nova:email';

// create new "campaign" view for all posts from the past X days that haven't been scheduled yet
Posts.views.add("campaign", function (terms) {
  return {
    find: {
      scheduledAt: {$exists: false},
      postedAt: {
        $gte: terms.after
      }
    },
    options: {
      sort: {baseScore: -1},
      limit: terms.limit
    }
  };
});

const Campaign = {};

/**
 * @summary Return an array containing the latest n posts that can be sent in a newsletter
 * @param {Number} postsCount
 */
Campaign.getPosts = function (postsCount) {

  // look for last scheduled campaign in the database
  var lastCampaign = SyncedCron._collection.findOne({name: 'scheduleNewsletter'}, {sort: {finishedAt: -1}, limit: 1});

  // if there is a last campaign and it was sent less than 7 days ago use its date, else default to posts from the last 7 days
  var lastWeek = moment().subtract(7, 'days');
  var after = (lastCampaign && moment(lastCampaign.finishedAt).isAfter(lastWeek)) ? lastCampaign.finishedAt : lastWeek.toDate();

  // get parameters using "campaign" view
  var params = Posts.parameters.get({
    view: 'campaign',
    after: after,
    limit: postsCount
  });
  return Posts.find(params.selector, params.options).fetch();
};

/**
 * @summary Build a newsletter campaign from an array of posts
 * (Called from Campaign.scheduleNextWithMailChimp)
 * @param {Array} postsArray
 */
Campaign.build = function (postsArray) {
  var postsHTML = '', subject = '';

  // 1. Iterate through posts and pass each of them through a handlebars template
  postsArray.forEach(function (post, index) {

    // add post title to email subject (don't add a coma for the first post)
    if(index > 0) subject += ', ';
    subject += post.title;

    // get author of the current post
    var postUser = Meteor.users.findOne(post.userId);

    // the naked post object as stored in the database is missing a few properties, so let's add them
    var properties = _.extend(post, {
      authorName: post.getAuthorName(),
      postLink: Posts.getLink(post, true),
      profileUrl: Users.getProfileUrl(postUser, true),
      postPageLink: Posts.getPageUrl(post, true),
      date: moment(post.postedAt).format("MMMM D YYYY"),
      authorAvatarUrl: Avatar.getUrl(postUser)
    });

    // if post author's avatar returns an error, remove it from properties object
    try {
      HTTP.get(post.authorAvatarUrl);
    } catch (error) {
      post.authorAvatarUrl = false;
    }

    // trim the body and remove any HTML tags
    if (post.body) {
      properties.body = Telescope.utils.trimHTML(post.htmlBody, 20);
    }

    // if post has comments
    if (post.commentCount > 0) {

      // get the two highest-scoring comments
      properties.popularComments = Comments.find({postId: post._id}, {sort: {score: -1}, limit: 2, transform: function (comment) {

        // get comment author
        var user = Meteor.users.findOne(comment.userId);

        // add properties to comment
        comment.body = Telescope.utils.trimHTML(comment.htmlBody, 20);
        comment.authorProfileUrl = Users.getProfileUrl(user, true);
        comment.authorAvatarUrl = Avatar.getUrl(user);

        try {
          HTTP.get(comment.authorAvatarUrl);
        } catch (error) {
          comment.authorAvatarUrl = false;
        }

        return comment;

      }}).fetch();

    }

    // if post has an URL, at the link domain as a property
    if(post.url) {
      properties.domain = Telescope.utils.getDomain(post.url);
    }

    // if post has a thumbnail, add the thumbnail URL as a property
    if (properties.thumbnailUrl) {
      properties.thumbnailUrl = Telescope.utils.addHttp(properties.thumbnailUrl);
    }

    // generate post item HTML and add it to the postsHTML string
    postsHTML += Telescope.email.getTemplate('postItem')(properties);
  });

  // 2. Wrap posts HTML in newsletter template
  var newsletterHTML = Telescope.email.getTemplate('newsletter')({
    siteName: Telescope.settings.get('title'),
    date: moment().format("dddd, MMMM Do YYYY"),
    content: postsHTML
  });

  // 3. wrap newsletter HTML in email wrapper template
  var emailHTML = Telescope.email.buildTemplate(newsletterHTML);

  // 4. build campaign object and return it
  var campaign = {
    postIds: _.pluck(postsArray, '_id'),
    subject: Telescope.utils.trimWords(subject, 15),
    html: emailHTML
  };
  return campaign;
};

export default Campaign;
module.exports = Campaign;<commit_msg>complete dcf0561<commit_after>//import Avatar from 'meteor-avatar-core';
// import Email from 'meteor/nova:email';

// create new "campaign" view for all posts from the past X days that haven't been scheduled yet
Posts.views.add("campaign", function (terms) {
  return {
    find: {
      scheduledAt: {$exists: false},
      postedAt: {
        $gte: terms.after
      }
    },
    options: {
      sort: {baseScore: -1},
      limit: terms.limit
    }
  };
});

const Campaign = {};

/**
 * @summary Return an array containing the latest n posts that can be sent in a newsletter
 * @param {Number} postsCount
 */
Campaign.getPosts = function (postsCount) {

  // look for last scheduled campaign in the database
  var lastCampaign = SyncedCron._collection.findOne({name: 'scheduleNewsletter'}, {sort: {finishedAt: -1}, limit: 1});

  // if there is a last campaign and it was sent less than 7 days ago use its date, else default to posts from the last 7 days
  var lastWeek = moment().subtract(7, 'days');
  var after = (lastCampaign && moment(lastCampaign.finishedAt).isAfter(lastWeek)) ? lastCampaign.finishedAt : lastWeek.toDate();

  // get parameters using "campaign" view
  var params = Posts.parameters.get({
    view: 'campaign',
    after: after,
    limit: postsCount
  });
  return Posts.find(params.selector, params.options).fetch();
};

/**
 * @summary Build a newsletter campaign from an array of posts
 * (Called from Campaign.scheduleNextWithMailChimp)
 * @param {Array} postsArray
 */
Campaign.build = function (postsArray) {
  var postsHTML = '', subject = '';

  // 1. Iterate through posts and pass each of them through a handlebars template
  postsArray.forEach(function (post, index) {

    // add post title to email subject (don't add a coma for the first post)
    if(index > 0) subject += ', ';
    subject += post.title;

    // get author of the current post
    var postUser = Meteor.users.findOne(post.userId);

    // the naked post object as stored in the database is missing a few properties, so let's add them
    var properties = _.extend(post, {
      authorName: post.getAuthorName(),
      postLink: Posts.getLink(post, true),
      profileUrl: Users.getProfileUrl(postUser, true),
      postPageLink: Posts.getPageUrl(post, true),
      date: moment(post.postedAt).format("MMMM D YYYY"),
      authorAvatarUrl: Avatar.getUrl(postUser)
    });

    // if post author's avatar returns an error, remove it from properties object
    try {
      HTTP.get(post.authorAvatarUrl);
    } catch (error) {
      post.authorAvatarUrl = false;
    }

    // trim the body and remove any HTML tags
    if (post.body) {
      properties.body = Telescope.utils.trimHTML(post.htmlBody, 20);
    }

    // if post has comments
    if (post.commentCount > 0) {

      // get the two highest-scoring comments
      properties.popularComments = Comments.find({postId: post._id}, {sort: {score: -1}, limit: 2, transform: function (comment) {

        // get comment author
        var user = Meteor.users.findOne(comment.userId);

        // add properties to comment
        comment.body = Telescope.utils.trimHTML(comment.htmlBody, 20);
        comment.authorProfileUrl = Users.getProfileUrl(user, true);
        comment.authorAvatarUrl = Avatar.getUrl(user);

        try {
          HTTP.get(comment.authorAvatarUrl);
        } catch (error) {
          comment.authorAvatarUrl = false;
        }

        return comment;

      }}).fetch();

    }

    // if post has an URL, at the link domain as a property
    if(post.url) {
      properties.domain = Telescope.utils.getDomain(post.url);
    }

    // if post has a thumbnail, add the thumbnail URL as a property
    if (properties.thumbnailUrl) {
      properties.thumbnailUrl = Telescope.utils.addHttp(properties.thumbnailUrl);
    }

    // generate post item HTML and add it to the postsHTML string
    postsHTML += Telescope.email.getTemplate('postItem')(properties);
  });

  // 2. Wrap posts HTML in newsletter template
  var newsletterHTML = Telescope.email.getTemplate('newsletter')({
    siteName: Telescope.settings.get('title'),
    date: moment().format("dddd, MMMM Do YYYY"),
    content: postsHTML
  });

  // 3. wrap newsletter HTML in email wrapper template
  var emailHTML = Telescope.email.buildTemplate(newsletterHTML);

  // 4. build campaign object and return it
  var campaign = {
    postIds: _.pluck(postsArray, '_id'),
    subject: Telescope.utils.trimWords(subject, 15),
    html: emailHTML
  };
  return campaign;
};

export default Campaign;
module.exports = Campaign;
<|endoftext|>


<commit_before>// backbone-subroute.js v0.3.2lx
//
// Copyright (C) 2012 Dave Cadwallader, Model N, Inc.
// Distributed under the MIT License
//
// Documentation and full license available at:
// https://github.com/ModelN/backbone.subroute

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // Register as an AMD module if available...
        define(['underscore', 'backbone'], factory);
    } else {
        // Browser globals for the unenlightened...
        factory(_, Backbone);
    }
}(function(_, Backbone){

    Backbone.SubRoute = Backbone.Router.extend( {
        constructor:function ( prefix, options ) {

            // Prefix is optional, set to empty string if not passed
            this.prefix = prefix = prefix || "";

            // SubRoute instances may be instantiated using a prefix with or without a trailing slash.
            // If the prefix does *not* have a trailing slash, we need to insert a slash as a separator
            // between the prefix and the sub-route path for each route that we register with Backbone.
            this.separator =
                    ( prefix.slice( -1 ) === "/" )
                            ? ""
                            : "/";

            // if you want to match "books" and "books/" without creating separate routes, set this
            // option to "true" and the sub-router will automatically create those routes for you.
            this.createTrailingSlashRoutes = options && options.createTrailingSlashRoutes;

            // Required to have Backbone set up routes
            Backbone.Router.prototype.constructor.call( this, options );

            // grab the full URL
            var hash;
            if (Backbone.history.fragment) {
                hash = Backbone.history.getFragment();
            } else {
                hash = Backbone.history.getHash();
            }

            // Trigger the subroute immediately.  this supports the case where
            // a user directly navigates to a URL with a subroute on the first page load.
            if (hash.indexOf(prefix) === 0) {
                Backbone.history.loadUrl( hash );
            }

            if (this.postInitialize) {
                this.postInitialize(options);
            }
        },
        navigate:function ( route, options ) {
            if ( route.substr( 0, 1 ) != '/' && route.indexOf( this.prefix.substr( 0,
                    this.prefix.length - 1 ) ) != 0 ) {

                route = this.prefix +
                        ( route ? this.separator : "") +
                        route;
            }
            Backbone.Router.prototype.navigate.call( this, route, options );
        },
        route : function (route, name, callback) {
          // strip off any leading slashes in the sub-route path,
          // since we already handle inserting them when needed.
          if (route.substr(0) === "/") {
            route = route.substr(1, route.length);
          }

          var _route = this.prefix
          if (route && route.length > 0)
            _route += (this.separator + route);

          if (this.createTrailingSlashRoutes) {
            this.routes[_route + '/'] = name
            Backbone.Router.prototype.route.call(this, _route + '/', name, callback);
          }

          // Adding this mainly to support the specs, and for debug-ability.  We're altering the way the router
          // handles routing, but not updating the actual routes hash.  Might seem weird to anyone trying to
          // debug a routing issue.
          this.routes[_route] = name;

          return Backbone.Router.prototype.route.call(this, _route, name, callback);
        }
    } );
    return Backbone.SubRoute;
}));
<commit_msg>Fixed bug where prefix would not match due to parameters in it<commit_after>// backbone-subroute.js v0.3.2lx
//
// Copyright (C) 2012 Dave Cadwallader, Model N, Inc.
// Distributed under the MIT License
//
// Documentation and full license available at:
// https://github.com/ModelN/backbone.subroute

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // Register as an AMD module if available...
        define(['underscore', 'backbone'], factory);
    } else {
        // Browser globals for the unenlightened...
        factory(_, Backbone);
    }
}(function(_, Backbone){

    Backbone.SubRoute = Backbone.Router.extend( {
        constructor:function ( prefix, options ) {

            // Prefix is optional, set to empty string if not passed
            this.prefix = prefix = prefix || "";

            // SubRoute instances may be instantiated using a prefix with or without a trailing slash.
            // If the prefix does *not* have a trailing slash, we need to insert a slash as a separator
            // between the prefix and the sub-route path for each route that we register with Backbone.
            this.separator =
                    ( prefix.slice( -1 ) === "/" )
                            ? ""
                            : "/";

            // if you want to match "books" and "books/" without creating separate routes, set this
            // option to "true" and the sub-router will automatically create those routes for you.
            this.createTrailingSlashRoutes = options && options.createTrailingSlashRoutes;

            // Required to have Backbone set up routes
            Backbone.Router.prototype.constructor.call( this, options );

            // grab the full URL
            var hash;
            if (Backbone.history.fragment) {
                hash = Backbone.history.getFragment();
            } else {
                hash = Backbone.history.getHash();
            }

            // Trigger the subroute immediately.  this supports the case where
            // a user directly navigates to a URL with a subroute on the first page load.
            // Check every element, if one matches, break. Prevent multiple matches
            _.every(this.routes, function(key, route){
                // Use the Backbone parser to turn route into regex for matching
    			if(hash.match(Backbone.Router.prototype._routeToRegExp(route))) {
					Backbone.history.loadUrl(hash);
					return false;
				}
				return true;
			}, this);

            if (this.postInitialize) {
                this.postInitialize(options);
            }
        },
        navigate:function ( route, options ) {
            if ( route.substr( 0, 1 ) != '/' && route.indexOf( this.prefix.substr( 0,
                    this.prefix.length - 1 ) ) != 0 ) {

                route = this.prefix +
                        ( route ? this.separator : "") +
                        route;
            }
            Backbone.Router.prototype.navigate.call( this, route, options );
        },
        route : function (route, name, callback) {
          // strip off any leading slashes in the sub-route path,
          // since we already handle inserting them when needed.
          if (route.substr(0) === "/") {
            route = route.substr(1, route.length);
          }

          var _route = this.prefix
          if (route && route.length > 0)
            _route += (this.separator + route);

          if (this.createTrailingSlashRoutes) {
            this.routes[_route + '/'] = name
            Backbone.Router.prototype.route.call(this, _route + '/', name, callback);
          }

          // Adding this mainly to support the specs, and for debug-ability.  We're altering the way the router
          // handles routing, but not updating the actual routes hash.  Might seem weird to anyone trying to
          // debug a routing issue.
          this.routes[_route] = name;

          return Backbone.Router.prototype.route.call(this, _route, name, callback);
        }
    } );
    return Backbone.SubRoute;
}));
<|endoftext|>


<commit_before>const { assert } = require('chai');
const clone = require('clone');
const { validate, isValid, isValidatable } = require('../../lib/validate');
const fixtures = require('../fixtures');

describe('Gavel proxies to functions with callbacks', () => {
  // Examples from README.md
  baseHttpMessage = {
    statusCode: '200',
    headers: {
      'content-type': 'application/json',
      date: 'Wed, 03 Jul 2013 13:30:53 GMT',
      server: 'gunicorn/0.17.4',
      'content-length': '30',
      connection: 'keep-alive'
    },
    body: '{\n  "origin": "94.113.241.2"\n}'
  };

  cloneHttpMessage = clone(baseHttpMessage, false);

  differentHttpMessage = {
    statusCode: '404',
    headers: {
      'content-type': 'application/vnd.gavel.vX+json', // different from baseHttpMessage
      date: 'Wed, 03 Jul 2014 13:30:53 GMT',
      server: 'Apache/2.42', // different from baseHttpMessage
      connection: 'close' // different from baseHttpMessage
      // missing key "content-length"
    },
    body: '{"r2":"d2"}'
  };

  similarHttpMessage = {
    statusCode: '200',
    headers: {
      'CONTENT-TYPE': 'application/json',
      DATE: 'Mon, 01 Jan 2011 01:01:01 GMT', // shall ignore DATE header differences
      SERVER: 'gunicorn/0.17.4',
      'CONTENT-LENGTH': '30',
      CONNECTION: 'keep-alive'
    },
    body: '{"origin":"1.2.3.4"}'
  };

  describe('isValidatable', () => {
    describe('when I provide data from README (good objects)', () => {
      ['response', 'request'].forEach((variant) => {
        describe('for two cloned #{variant}s', () => {
          results = null;
          error = null;

          before((done) => {
            isValidatable(
              cloneHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should be ok as a result of isValidatable', () =>
            assert.isTrue(results));
        });

        describe('for similar #{variant}s', () => {
          results = null;
          error = null;

          before((done) => {
            isValidatable(
              similarHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should be ok as a result of isValidatable', () =>
            assert.isTrue(results));
        });

        describe('for different #{variant}s', () => {
          results = null;
          error = null;

          before((done) => {
            isValidatable(
              differentHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should be ok as a result of isValidatable', () =>
            assert.isTrue(results));
        });
      });
    });
  });

  describe('isValid', () => {
    describe('when I provide data', () => {
      ['response', 'request'].forEach((variant) => {
        describe('for two cloned #{variant}s', () => {
          results = null;
          error = null;

          before((done) => {
            isValid(
              cloneHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should be true as a result of isValid', () =>
            assert.isTrue(results));
        });

        describe('for similar #{variant}s', () => {
          results = null;
          error = null;

          before((done) => {
            isValid(
              similarHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should be ok as a result of isValid', () =>
            assert.isTrue(results));
        });

        describe('for different #{variant}s', () => {
          results = null;
          error = null;

          before((done) => {
            isValid(
              differentHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should be false as a result of isValid', () =>
            assert.isFalse(results));
        });
      });
    });
  });

  describe('validate', () => {
    describe('when I provide data', () => {
      ['response', 'request'].forEach((variant) => {
        describe('for two cloned #{variant}s', () => {
          results = null;
          error = null;

          before((done) => {
            validate(
              cloneHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should results be an object', () => assert.isObject(results));
        });

        describe('for similar #{variant}s', () => {
          results = null;
          error = null;

          before((done) => {
            validate(
              similarHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should results be an object', () => assert.isObject(results));
        });

        describe('for different #{variant}s', () => {
          results = null;
          error = null;

          before((done) => {
            validate(
              differentHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should results be an object', () => assert.isObject(results));
          it('should results contain 2 different headers messages (missing content-length, different content-type)', () => {
            assert.isObject(results);
            assert.property(results, 'headers');
            assert.isObject(results.headers);
            assert.isArray(results.headers.results);
            assert.lengthOf(results.headers.results, 2);
          });
        });
      });
    });
  });
});
<commit_msg>test: adds proper variables declarations<commit_after>const { assert } = require('chai');
const clone = require('clone');
const { validate, isValid, isValidatable } = require('../../lib/validate');
const fixtures = require('../fixtures');

describe('Gavel proxies to functions with callbacks', () => {
  // Examples from README.md
  const baseHttpMessage = {
    statusCode: '200',
    headers: {
      'content-type': 'application/json',
      date: 'Wed, 03 Jul 2013 13:30:53 GMT',
      server: 'gunicorn/0.17.4',
      'content-length': '30',
      connection: 'keep-alive'
    },
    body: '{\n  "origin": "94.113.241.2"\n}'
  };

  const cloneHttpMessage = clone(baseHttpMessage, false);

  const differentHttpMessage = {
    statusCode: '404',
    headers: {
      'content-type': 'application/vnd.gavel.vX+json', // different from baseHttpMessage
      date: 'Wed, 03 Jul 2014 13:30:53 GMT',
      server: 'Apache/2.42', // different from baseHttpMessage
      connection: 'close' // different from baseHttpMessage
      // missing key "content-length"
    },
    body: '{"r2":"d2"}'
  };

  const similarHttpMessage = {
    statusCode: '200',
    headers: {
      'CONTENT-TYPE': 'application/json',
      DATE: 'Mon, 01 Jan 2011 01:01:01 GMT', // shall ignore DATE header differences
      SERVER: 'gunicorn/0.17.4',
      'CONTENT-LENGTH': '30',
      CONNECTION: 'keep-alive'
    },
    body: '{"origin":"1.2.3.4"}'
  };

  describe('isValidatable', () => {
    describe('when I provide data from README (good objects)', () => {
      ['response', 'request'].forEach((variant) => {
        describe('for two cloned #{variant}s', () => {
          let results = null;
          let error = null;

          before((done) => {
            isValidatable(
              cloneHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should be ok as a result of isValidatable', () =>
            assert.isTrue(results));
        });

        describe('for similar #{variant}s', () => {
          let results = null;
          let error = null;

          before((done) => {
            isValidatable(
              similarHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should be ok as a result of isValidatable', () =>
            assert.isTrue(results));
        });

        describe('for different #{variant}s', () => {
          let results = null;
          let error = null;

          before((done) => {
            isValidatable(
              differentHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should be ok as a result of isValidatable', () =>
            assert.isTrue(results));
        });
      });
    });
  });

  describe('isValid', () => {
    describe('when I provide data', () => {
      ['response', 'request'].forEach((variant) => {
        describe('for two cloned #{variant}s', () => {
          let results = null;
          let error = null;

          before((done) => {
            isValid(
              cloneHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should be true as a result of isValid', () =>
            assert.isTrue(results));
        });

        describe('for similar #{variant}s', () => {
          let results = null;
          let error = null;

          before((done) => {
            isValid(
              similarHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should be ok as a result of isValid', () =>
            assert.isTrue(results));
        });

        describe('for different #{variant}s', () => {
          let results = null;
          let error = null;

          before((done) => {
            isValid(
              differentHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should be false as a result of isValid', () =>
            assert.isFalse(results));
        });
      });
    });
  });

  describe('validate', () => {
    describe('when I provide data', () => {
      ['response', 'request'].forEach((variant) => {
        describe('for two cloned #{variant}s', () => {
          let results = null;
          let error = null;

          before((done) => {
            validate(
              cloneHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should results be an object', () => assert.isObject(results));
        });

        describe('for similar #{variant}s', () => {
          let results = null;
          let error = null;

          before((done) => {
            validate(
              similarHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should results be an object', () => assert.isObject(results));
        });

        describe('for different #{variant}s', () => {
          let results = null;
          let error = null;

          before((done) => {
            validate(
              differentHttpMessage,
              baseHttpMessage,
              variant,
              (err, result) => {
                error = err;
                results = result;
                done();
              }
            );
          });

          it('should call the callback without any errors', () =>
            assert.isNull(error));
          it('should results be an object', () => assert.isObject(results));
          it('should results contain 2 different headers messages (missing content-length, different content-type)', () => {
            assert.isObject(results);
            assert.property(results, 'headers');
            assert.isObject(results.headers);
            assert.isArray(results.headers.results);
            assert.lengthOf(results.headers.results, 2);
          });
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

'use strict';

// This alternative WebpackDevServer combines the functionality of:
// https://github.com/webpack/webpack-dev-server/blob/webpack-1/client/index.js
// https://github.com/webpack/webpack/blob/webpack-1/hot/dev-server.js

// It only supports their simplest configuration (hot updates on same server).
// It makes some opinionated choices on top, like adding a syntax error overlay
// that looks similar to our console output. The error overlay is inspired by:
// https://github.com/glenjamin/webpack-hot-middleware

var SockJS = require('sockjs-client');
var stripAnsi = require('strip-ansi');
var url = require('url');
var formatWebpackMessages = require('./formatWebpackMessages');
var Entities = require('html-entities').AllHtmlEntities;
var ansiHTML = require('./ansiHTML');
var entities = new Entities();

function createOverlayIframe(onIframeLoad) {
  var iframe = document.createElement('iframe');
  iframe.id = 'react-dev-utils-webpack-hot-dev-client-overlay';
  iframe.src = 'about:blank';
  iframe.style.position = 'fixed';
  iframe.style.left = 0;
  iframe.style.top = 0;
  iframe.style.right = 0;
  iframe.style.bottom = 0;
  iframe.style.width = '100vw';
  iframe.style.height = '100vh';
  iframe.style.border = 'none';
  iframe.style.zIndex = 2147483647;
  iframe.onload = onIframeLoad;
  return iframe;
}

function addOverlayDivTo(iframe) {
  // TODO: unify these styles with react-error-overlay
  iframe.contentDocument.body.style.margin = 0;
  iframe.contentDocument.body.style.maxWidth = '100vw';

  var outerDiv = iframe.contentDocument.createElement('div');
  outerDiv.id = 'react-dev-utils-webpack-hot-dev-client-overlay-div';
  outerDiv.style.width = '100%';
  outerDiv.style.height = '100%';
  outerDiv.style.boxSizing = 'border-box';
  outerDiv.style.textAlign = 'center';
  outerDiv.style.backgroundColor = 'rgb(255, 255, 255)';

  var div = iframe.contentDocument.createElement('div');
  div.style.position = 'relative';
  div.style.display = 'inline-flex';
  div.style.flexDirection = 'column';
  div.style.height = '100%';
  div.style.width = '1024px';
  div.style.maxWidth = '100%';
  div.style.overflowX = 'hidden';
  div.style.overflowY = 'auto';
  div.style.padding = '0.5rem';
  div.style.boxSizing = 'border-box';
  div.style.textAlign = 'left';
  div.style.fontFamily = 'Consolas, Menlo, monospace';
  div.style.fontSize = '11px';
  div.style.whiteSpace = 'pre-wrap';
  div.style.wordBreak = 'break-word';
  div.style.lineHeight = '1.5';
  div.style.color = 'rgb(41, 50, 56)';

  outerDiv.appendChild(div);
  iframe.contentDocument.body.appendChild(outerDiv);
  return div;
}

function overlayHeaderStyle() {
  return 'font-size: 2em;' +
    'font-family: sans-serif;' +
    'color: rgb(206, 17, 38);' +
    'white-space: pre-wrap;' +
    'margin: 0 2rem 0.75rem 0px;' +
    'flex: 0 0 auto;' +
    'max-height: 35%;' +
    'overflow: auto;';
}

var overlayIframe = null;
var overlayDiv = null;
var lastOnOverlayDivReady = null;

function ensureOverlayDivExists(onOverlayDivReady) {
  if (overlayDiv) {
    // Everything is ready, call the callback right away.
    onOverlayDivReady(overlayDiv);
    return;
  }

  // Creating an iframe may be asynchronous so we'll schedule the callback.
  // In case of multiple calls, last callback wins.
  lastOnOverlayDivReady = onOverlayDivReady;

  if (overlayIframe) {
    // We're already creating it.
    return;
  }

  // Create iframe and, when it is ready, a div inside it.
  overlayIframe = createOverlayIframe(function onIframeLoad() {
    overlayDiv = addOverlayDivTo(overlayIframe);
    // Now we can talk!
    lastOnOverlayDivReady(overlayDiv);
  });

  // Zalgo alert: onIframeLoad() will be called either synchronously
  // or asynchronously depending on the browser.
  // We delay adding it so `overlayIframe` is set when `onIframeLoad` fires.
  document.body.appendChild(overlayIframe);
}

function showErrorOverlay(message) {
  ensureOverlayDivExists(function onOverlayDivReady(overlayDiv) {
    // TODO: unify this with our runtime overlay
    overlayDiv.innerHTML = '
Failed to compile
' +
      '
' +
      '' +
      ansiHTML(entities.encode(message)) +
      '
' +
      '
' +
      'This error occurred during the build time and cannot be dismissed.
';
  });
}

function destroyErrorOverlay() {
  if (!overlayDiv) {
    // It is not there in the first place.
    return;
  }

  // Clean up and reset internal state.
  document.body.removeChild(overlayIframe);
  overlayDiv = null;
  overlayIframe = null;
  lastOnOverlayDivReady = null;
}

// Connect to WebpackDevServer via a socket.
var connection = new SockJS(
  url.format({
    protocol: window.location.protocol,
    hostname: window.location.hostname,
    port: window.location.port,
    // Hardcoded in WebpackDevServer
    pathname: '/sockjs-node',
  })
);

// Unlike WebpackDevServer client, we won't try to reconnect
// to avoid spamming the console. Disconnect usually happens
// when developer stops the server.
connection.onclose = function() {
  if (typeof console !== 'undefined' && typeof console.info === 'function') {
    console.info(
      'The development server has disconnected.\nRefresh the page if necessary.'
    );
  }
};

// Remember some state related to hot module replacement.
var isFirstCompilation = true;
var mostRecentCompilationHash = null;
var hasCompileErrors = false;

function clearOutdatedErrors() {
  // Clean up outdated compile errors, if any.
  if (typeof console !== 'undefined' && typeof console.clear === 'function') {
    if (hasCompileErrors) {
      console.clear();
    }
  }
}

// Successful compilation.
function handleSuccess() {
  clearOutdatedErrors();

  var isHotUpdate = !isFirstCompilation;
  isFirstCompilation = false;
  hasCompileErrors = false;

  // Attempt to apply hot updates or reload.
  if (isHotUpdate) {
    tryApplyUpdates(function onHotUpdateSuccess() {
      // Only destroy it when we're sure it's a hot update.
      // Otherwise it would flicker right before the reload.
      destroyErrorOverlay();
    });
  }
}

// Compilation with warnings (e.g. ESLint).
function handleWarnings(warnings) {
  clearOutdatedErrors();

  var isHotUpdate = !isFirstCompilation;
  isFirstCompilation = false;
  hasCompileErrors = false;

  function printWarnings() {
    // Print warnings to the console.
    var formatted = formatWebpackMessages({
      warnings: warnings,
      errors: [],
    });

    if (typeof console !== 'undefined' && typeof console.warn === 'function') {
      for (var i = 0; i < formatted.warnings.length; i++) {
        console.warn(stripAnsi(formatted.warnings[i]));
      }
    }
  }

  // Attempt to apply hot updates or reload.
  if (isHotUpdate) {
    tryApplyUpdates(function onSuccessfulHotUpdate() {
      // Only print warnings if we aren't refreshing the page.
      // Otherwise they'll disappear right away anyway.
      printWarnings();
      // Only destroy it when we're sure it's a hot update.
      // Otherwise it would flicker right before the reload.
      destroyErrorOverlay();
    });
  } else {
    // Print initial warnings immediately.
    printWarnings();
  }
}

// Compilation with errors (e.g. syntax error or missing modules).
function handleErrors(errors) {
  clearOutdatedErrors();

  isFirstCompilation = false;
  hasCompileErrors = true;

  // "Massage" webpack messages.
  var formatted = formatWebpackMessages({
    errors: errors,
    warnings: [],
  });

  // Only show the first error.
  showErrorOverlay(formatted.errors[0]);

  // Also log them to the console.
  if (typeof console !== 'undefined' && typeof console.error === 'function') {
    for (var i = 0; i < formatted.errors.length; i++) {
      console.error(stripAnsi(formatted.errors[i]));
    }
  }

  // Do not attempt to reload now.
  // We will reload on next success instead.
}

// There is a newer version of the code available.
function handleAvailableHash(hash) {
  // Update last known compilation hash.
  mostRecentCompilationHash = hash;
}

// Handle messages from the server.
connection.onmessage = function(e) {
  var message = JSON.parse(e.data);
  switch (message.type) {
    case 'hash':
      handleAvailableHash(message.data);
      break;
    case 'still-ok':
    case 'ok':
      handleSuccess();
      break;
    case 'content-changed':
      // Triggered when a file from `contentBase` changed.
      window.location.reload();
      break;
    case 'warnings':
      handleWarnings(message.data);
      break;
    case 'errors':
      handleErrors(message.data);
      break;
    default:
    // Do nothing.
  }
};

// Is there a newer version of this code available?
function isUpdateAvailable() {
  /* globals __webpack_hash__ */
  // __webpack_hash__ is the hash of the current compilation.
  // It's a global variable injected by Webpack.
  return mostRecentCompilationHash !== __webpack_hash__;
}

// Webpack disallows updates in other states.
function canApplyUpdates() {
  return module.hot.status() === 'idle';
}

// Attempt to update code on the fly, fall back to a hard reload.
function tryApplyUpdates(onHotUpdateSuccess) {
  if (!module.hot) {
    // HotModuleReplacementPlugin is not in Webpack configuration.
    window.location.reload();
    return;
  }

  if (!isUpdateAvailable() || !canApplyUpdates()) {
    return;
  }

  function handleApplyUpdates(err, updatedModules) {
    if (err || !updatedModules) {
      window.location.reload();
      return;
    }

    if (typeof onHotUpdateSuccess === 'function') {
      // Maybe we want to do something.
      onHotUpdateSuccess();
    }

    if (isUpdateAvailable()) {
      // While we were updating, there was a new update! Do it again.
      tryApplyUpdates();
    }
  }

  // https://webpack.github.io/docs/hot-module-replacement.html#check
  var result = module.hot.check(/* autoApply */ true, handleApplyUpdates);

  // // Webpack 2 returns a Promise instead of invoking a callback
  if (result && result.then) {
    result.then(
      function(updatedModules) {
        handleApplyUpdates(null, updatedModules);
      },
      function(err) {
        handleApplyUpdates(err, null);
      }
    );
  }
}
<commit_msg>Limit console warnings to 5 files at most (#2327)<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

'use strict';

// This alternative WebpackDevServer combines the functionality of:
// https://github.com/webpack/webpack-dev-server/blob/webpack-1/client/index.js
// https://github.com/webpack/webpack/blob/webpack-1/hot/dev-server.js

// It only supports their simplest configuration (hot updates on same server).
// It makes some opinionated choices on top, like adding a syntax error overlay
// that looks similar to our console output. The error overlay is inspired by:
// https://github.com/glenjamin/webpack-hot-middleware

var SockJS = require('sockjs-client');
var stripAnsi = require('strip-ansi');
var url = require('url');
var formatWebpackMessages = require('./formatWebpackMessages');
var Entities = require('html-entities').AllHtmlEntities;
var ansiHTML = require('./ansiHTML');
var entities = new Entities();

function createOverlayIframe(onIframeLoad) {
  var iframe = document.createElement('iframe');
  iframe.id = 'react-dev-utils-webpack-hot-dev-client-overlay';
  iframe.src = 'about:blank';
  iframe.style.position = 'fixed';
  iframe.style.left = 0;
  iframe.style.top = 0;
  iframe.style.right = 0;
  iframe.style.bottom = 0;
  iframe.style.width = '100vw';
  iframe.style.height = '100vh';
  iframe.style.border = 'none';
  iframe.style.zIndex = 2147483647;
  iframe.onload = onIframeLoad;
  return iframe;
}

function addOverlayDivTo(iframe) {
  // TODO: unify these styles with react-error-overlay
  iframe.contentDocument.body.style.margin = 0;
  iframe.contentDocument.body.style.maxWidth = '100vw';

  var outerDiv = iframe.contentDocument.createElement('div');
  outerDiv.id = 'react-dev-utils-webpack-hot-dev-client-overlay-div';
  outerDiv.style.width = '100%';
  outerDiv.style.height = '100%';
  outerDiv.style.boxSizing = 'border-box';
  outerDiv.style.textAlign = 'center';
  outerDiv.style.backgroundColor = 'rgb(255, 255, 255)';

  var div = iframe.contentDocument.createElement('div');
  div.style.position = 'relative';
  div.style.display = 'inline-flex';
  div.style.flexDirection = 'column';
  div.style.height = '100%';
  div.style.width = '1024px';
  div.style.maxWidth = '100%';
  div.style.overflowX = 'hidden';
  div.style.overflowY = 'auto';
  div.style.padding = '0.5rem';
  div.style.boxSizing = 'border-box';
  div.style.textAlign = 'left';
  div.style.fontFamily = 'Consolas, Menlo, monospace';
  div.style.fontSize = '11px';
  div.style.whiteSpace = 'pre-wrap';
  div.style.wordBreak = 'break-word';
  div.style.lineHeight = '1.5';
  div.style.color = 'rgb(41, 50, 56)';

  outerDiv.appendChild(div);
  iframe.contentDocument.body.appendChild(outerDiv);
  return div;
}

function overlayHeaderStyle() {
  return 'font-size: 2em;' +
    'font-family: sans-serif;' +
    'color: rgb(206, 17, 38);' +
    'white-space: pre-wrap;' +
    'margin: 0 2rem 0.75rem 0px;' +
    'flex: 0 0 auto;' +
    'max-height: 35%;' +
    'overflow: auto;';
}

var overlayIframe = null;
var overlayDiv = null;
var lastOnOverlayDivReady = null;

function ensureOverlayDivExists(onOverlayDivReady) {
  if (overlayDiv) {
    // Everything is ready, call the callback right away.
    onOverlayDivReady(overlayDiv);
    return;
  }

  // Creating an iframe may be asynchronous so we'll schedule the callback.
  // In case of multiple calls, last callback wins.
  lastOnOverlayDivReady = onOverlayDivReady;

  if (overlayIframe) {
    // We're already creating it.
    return;
  }

  // Create iframe and, when it is ready, a div inside it.
  overlayIframe = createOverlayIframe(function onIframeLoad() {
    overlayDiv = addOverlayDivTo(overlayIframe);
    // Now we can talk!
    lastOnOverlayDivReady(overlayDiv);
  });

  // Zalgo alert: onIframeLoad() will be called either synchronously
  // or asynchronously depending on the browser.
  // We delay adding it so `overlayIframe` is set when `onIframeLoad` fires.
  document.body.appendChild(overlayIframe);
}

function showErrorOverlay(message) {
  ensureOverlayDivExists(function onOverlayDivReady(overlayDiv) {
    // TODO: unify this with our runtime overlay
    overlayDiv.innerHTML = '
Failed to compile
' +
      '
' +
      '' +
      ansiHTML(entities.encode(message)) +
      '
' +
      '
' +
      'This error occurred during the build time and cannot be dismissed.
';
  });
}

function destroyErrorOverlay() {
  if (!overlayDiv) {
    // It is not there in the first place.
    return;
  }

  // Clean up and reset internal state.
  document.body.removeChild(overlayIframe);
  overlayDiv = null;
  overlayIframe = null;
  lastOnOverlayDivReady = null;
}

// Connect to WebpackDevServer via a socket.
var connection = new SockJS(
  url.format({
    protocol: window.location.protocol,
    hostname: window.location.hostname,
    port: window.location.port,
    // Hardcoded in WebpackDevServer
    pathname: '/sockjs-node',
  })
);

// Unlike WebpackDevServer client, we won't try to reconnect
// to avoid spamming the console. Disconnect usually happens
// when developer stops the server.
connection.onclose = function() {
  if (typeof console !== 'undefined' && typeof console.info === 'function') {
    console.info(
      'The development server has disconnected.\nRefresh the page if necessary.'
    );
  }
};

// Remember some state related to hot module replacement.
var isFirstCompilation = true;
var mostRecentCompilationHash = null;
var hasCompileErrors = false;

function clearOutdatedErrors() {
  // Clean up outdated compile errors, if any.
  if (typeof console !== 'undefined' && typeof console.clear === 'function') {
    if (hasCompileErrors) {
      console.clear();
    }
  }
}

// Successful compilation.
function handleSuccess() {
  clearOutdatedErrors();

  var isHotUpdate = !isFirstCompilation;
  isFirstCompilation = false;
  hasCompileErrors = false;

  // Attempt to apply hot updates or reload.
  if (isHotUpdate) {
    tryApplyUpdates(function onHotUpdateSuccess() {
      // Only destroy it when we're sure it's a hot update.
      // Otherwise it would flicker right before the reload.
      destroyErrorOverlay();
    });
  }
}

// Compilation with warnings (e.g. ESLint).
function handleWarnings(warnings) {
  clearOutdatedErrors();

  var isHotUpdate = !isFirstCompilation;
  isFirstCompilation = false;
  hasCompileErrors = false;

  function printWarnings() {
    // Print warnings to the console.
    var formatted = formatWebpackMessages({
      warnings: warnings,
      errors: [],
    });

    if (typeof console !== 'undefined' && typeof console.warn === 'function') {
      for (var i = 0; i < formatted.warnings.length; i++) {
        if (i === 5) {
          console.warn(
            'There were more warnings in other files.\n' +
              'You can find a complete log in the terminal.'
          );
          break;
        }
        console.warn(stripAnsi(formatted.warnings[i]));
      }
    }
  }

  // Attempt to apply hot updates or reload.
  if (isHotUpdate) {
    tryApplyUpdates(function onSuccessfulHotUpdate() {
      // Only print warnings if we aren't refreshing the page.
      // Otherwise they'll disappear right away anyway.
      printWarnings();
      // Only destroy it when we're sure it's a hot update.
      // Otherwise it would flicker right before the reload.
      destroyErrorOverlay();
    });
  } else {
    // Print initial warnings immediately.
    printWarnings();
  }
}

// Compilation with errors (e.g. syntax error or missing modules).
function handleErrors(errors) {
  clearOutdatedErrors();

  isFirstCompilation = false;
  hasCompileErrors = true;

  // "Massage" webpack messages.
  var formatted = formatWebpackMessages({
    errors: errors,
    warnings: [],
  });

  // Only show the first error.
  showErrorOverlay(formatted.errors[0]);

  // Also log them to the console.
  if (typeof console !== 'undefined' && typeof console.error === 'function') {
    for (var i = 0; i < formatted.errors.length; i++) {
      console.error(stripAnsi(formatted.errors[i]));
    }
  }

  // Do not attempt to reload now.
  // We will reload on next success instead.
}

// There is a newer version of the code available.
function handleAvailableHash(hash) {
  // Update last known compilation hash.
  mostRecentCompilationHash = hash;
}

// Handle messages from the server.
connection.onmessage = function(e) {
  var message = JSON.parse(e.data);
  switch (message.type) {
    case 'hash':
      handleAvailableHash(message.data);
      break;
    case 'still-ok':
    case 'ok':
      handleSuccess();
      break;
    case 'content-changed':
      // Triggered when a file from `contentBase` changed.
      window.location.reload();
      break;
    case 'warnings':
      handleWarnings(message.data);
      break;
    case 'errors':
      handleErrors(message.data);
      break;
    default:
    // Do nothing.
  }
};

// Is there a newer version of this code available?
function isUpdateAvailable() {
  /* globals __webpack_hash__ */
  // __webpack_hash__ is the hash of the current compilation.
  // It's a global variable injected by Webpack.
  return mostRecentCompilationHash !== __webpack_hash__;
}

// Webpack disallows updates in other states.
function canApplyUpdates() {
  return module.hot.status() === 'idle';
}

// Attempt to update code on the fly, fall back to a hard reload.
function tryApplyUpdates(onHotUpdateSuccess) {
  if (!module.hot) {
    // HotModuleReplacementPlugin is not in Webpack configuration.
    window.location.reload();
    return;
  }

  if (!isUpdateAvailable() || !canApplyUpdates()) {
    return;
  }

  function handleApplyUpdates(err, updatedModules) {
    if (err || !updatedModules) {
      window.location.reload();
      return;
    }

    if (typeof onHotUpdateSuccess === 'function') {
      // Maybe we want to do something.
      onHotUpdateSuccess();
    }

    if (isUpdateAvailable()) {
      // While we were updating, there was a new update! Do it again.
      tryApplyUpdates();
    }
  }

  // https://webpack.github.io/docs/hot-module-replacement.html#check
  var result = module.hot.check(/* autoApply */ true, handleApplyUpdates);

  // // Webpack 2 returns a Promise instead of invoking a callback
  if (result && result.then) {
    result.then(
      function(updatedModules) {
        handleApplyUpdates(null, updatedModules);
      },
      function(err) {
        handleApplyUpdates(err, null);
      }
    );
  }
}
<|endoftext|>