<commit_before>/**
 * Copyright 2013-2014 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @providesModule ReactPropTypes
 */

"use strict";

var ReactDescriptor = require('ReactDescriptor');
var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');

var emptyFunction = require('emptyFunction');

/**
 * Collection of methods that allow declaration and validation of props that are
 * supplied to React components. Example usage:
 *
 *   var Props = require('ReactPropTypes');
 *   var MyArticle = React.createClass({
 *     propTypes: {
 *       // An optional string prop named "description".
 *       description: Props.string,
 *
 *       // A required enum prop named "category".
 *       category: Props.oneOf(['News','Photos']).isRequired,
 *
 *       // A prop named "dialog" that requires an instance of Dialog.
 *       dialog: Props.instanceOf(Dialog).isRequired
 *     },
 *     render: function() { ... }
 *   });
 *
 * A more formal specification of how these methods are used:
 *
 *   type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...)
 *   decl := ReactPropTypes.{type}(.isRequired)?
 *
 * Each and every declaration produces a function with the same signature. This
 * allows the creation of custom validation functions. For example:
 *
 *  var MyLink = React.createClass({
 *    propTypes: {
 *      // An optional string or URI prop named "href".
 *      href: function(props, propName, componentName) {
 *        var propValue = props[propName];
 *        if (typeof propValue === 'string' || propValue instanceof URI) {
 *          return new Error(
 *            'Expected a string or an URI for ' + propName + ' in ' +
 *            componentName
 *          );
 *        }
 *      }
 *    },
 *    render: function() {...}
 *  });
 *
 * @internal
 */

var ANONYMOUS = '<<anonymous>>';

var ReactPropTypes = {
  array: createPrimitiveTypeChecker('array'),
  bool: createPrimitiveTypeChecker('boolean'),
  func: createPrimitiveTypeChecker('function'),
  number: createPrimitiveTypeChecker('number'),
  object: createPrimitiveTypeChecker('object'),
  string: createPrimitiveTypeChecker('string'),

  any: createAnyTypeChecker(),
  arrayOf: createArrayOfTypeChecker,
  component: createComponentTypeChecker(),
  instanceOf: createInstanceTypeChecker,
  objectOf: createObjectOfTypeChecker,
  oneOf: createEnumTypeChecker,
  oneOfType: createUnionTypeChecker,
  renderable: createRenderableTypeChecker(),
  shape: createShapeTypeChecker
};

function createChainableTypeChecker(validate) {
  function checkType(isRequired, props, propName, componentName, location) {
    componentName = componentName || ANONYMOUS;
    if (props[propName] == null) {
      var locationName = ReactPropTypeLocationNames[location];
      if (isRequired) {
        return new Error(
          `Required ${locationName} \`${propName}\` was not specified in `+
          `\`${componentName}\`.`
        );
      }
    } else {
      return validate(props, propName, componentName, location);
    }
  }

  var chainedCheckType = checkType.bind(null, false);
  chainedCheckType.isRequired = checkType.bind(null, true);

  return chainedCheckType;
}

function createPrimitiveTypeChecker(expectedType) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    var propType = getPropType(propValue);
    if (propType !== expectedType) {
      var locationName = ReactPropTypeLocationNames[location];
      // `propValue` being instance of, say, date/regexp, pass the 'object'
      // check, but we can offer a more precise error message here rather than
      // 'of type `object`'.
      var preciseType = getPreciseType(propValue);

      return new Error(
        `Invalid ${locationName} \`${propName}\` of type \`${preciseType}\` ` +
        `supplied to \`${componentName}\`, expected \`${expectedType}\`.`
      );
    }
  }
  return createChainableTypeChecker(validate);
}

function createAnyTypeChecker() {
  return createChainableTypeChecker(emptyFunction.thatReturns());
}

function createArrayOfTypeChecker(typeChecker) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    if (!Array.isArray(propValue)) {
      var locationName = ReactPropTypeLocationNames[location];
      var propType = getPropType(propValue);
      return new Error(
        `Invalid ${locationName} \`${propName}\` of type ` +
        `\`${propType}\` supplied to \`${componentName}\`, expected an array.`
      );
    }
    for (var i = 0; i < propValue.length; i++) {
      var error = typeChecker(propValue, i, componentName, location);
      if (error instanceof Error) {
        return error;
      }
    }
  }
  return createChainableTypeChecker(validate);
}

function createComponentTypeChecker() {
  function validate(props, propName, componentName, location) {
    if (!ReactDescriptor.isValidDescriptor(props[propName])) {
      var locationName = ReactPropTypeLocationNames[location];
      return new Error(
        `Invalid ${locationName} \`${propName}\` supplied to ` +
        `\`${componentName}\`, expected a React component.`
      );
    }
  }
  return createChainableTypeChecker(validate);
}

function createInstanceTypeChecker(expectedClass) {
  function validate(props, propName, componentName, location) {
    if (!(props[propName] instanceof expectedClass)) {
      var locationName = ReactPropTypeLocationNames[location];
      var expectedClassName = expectedClass.name || ANONYMOUS;
      return new Error(
        `Invalid ${locationName} \`${propName}\` supplied to ` +
        `\`${componentName}\`, expected instance of \`${expectedClassName}\`.`
      );
    }
  }
  return createChainableTypeChecker(validate);
}

function createEnumTypeChecker(expectedValues) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    for (var i = 0; i < expectedValues.length; i++) {
      if (propValue === expectedValues[i]) {
        return;
      }
    }

    var locationName = ReactPropTypeLocationNames[location];
    var valuesString = JSON.stringify(expectedValues);
    return new Error(
      `Invalid ${locationName} \`${propName}\` of value \`${propValue}\` ` +
      `supplied to \`${componentName}\`, expected one of ${valuesString}.`
    );
  }
  return createChainableTypeChecker(validate);
}

function createObjectOfTypeChecker(typeChecker) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    var propType = getPropType(propValue);
    if (propType !== 'object') {
      var locationName = ReactPropTypeLocationNames[location];
      return new Error(
        `Invalid ${locationName} \`${propName}\` of type ` +
        `\`${propType}\` supplied to \`${componentName}\`, expected an object.`
      );
    }
    for (var key in propValue) {
      if (propValue.hasOwnProperty(key)) {
        var error = typeChecker(propValue, key, componentName, location);
        if (error instanceof Error) {
          return error;
        }
      }
    }
  }
  return createChainableTypeChecker(validate);
}

function createUnionTypeChecker(arrayOfTypeCheckers) {
  function validate(props, propName, componentName, location) {
    for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
      var checker = arrayOfTypeCheckers[i];
      if (checker(props, propName, componentName, location) == null) {
        return;
      }
    }

    var locationName = ReactPropTypeLocationNames[location];
    return new Error(
      `Invalid ${locationName} \`${propName}\` supplied to ` +
      `\`${componentName}\`.`
    );
  }
  return createChainableTypeChecker(validate);
}

function createRenderableTypeChecker() {
  function validate(props, propName, componentName, location) {
    if (!isRenderable(props[propName])) {
      var locationName = ReactPropTypeLocationNames[location];
      return new Error(
        `Invalid ${locationName} \`${propName}\` supplied to ` +
        `\`${componentName}\`, expected a renderable prop.`
      );
    }
  }
  return createChainableTypeChecker(validate);
}

function createShapeTypeChecker(shapeTypes) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    var propType = getPropType(propValue);
    if (propType !== 'object') {
      var locationName = ReactPropTypeLocationNames[location];
      return new Error(
        `Invalid ${locationName} \`${propName}\` of type \`${propType}\` ` +
        `supplied to \`${componentName}\`, expected \`object\`.`
      );
    }
    for (var key in shapeTypes) {
      var checker = shapeTypes[key];
      if (!checker) {
        continue;
      }
      var error = checker(propValue, key, componentName, location);
      if (error) {
        return error;
      }
    }
  }
  return createChainableTypeChecker(validate, 'expected `object`');
}

function isRenderable(propValue) {
  switch(typeof propValue) {
    // TODO: this was probably written with the assumption that we're not
    // returning `this.props.component` directly from `render`. This is
    // currently not supported but we should, to make it consistent.
    case 'number':
    case 'string':
      return true;
    case 'boolean':
      return !propValue;
    case 'object':
      if (Array.isArray(propValue)) {
        return propValue.every(isRenderable);
      }
      if (ReactDescriptor.isValidDescriptor(propValue)) {
        return true;
      }
      for (var k in propValue) {
        if (!isRenderable(propValue[k])) {
          return false;
        }
      }
      return true;
    default:
      return false;
  }
}

// Equivalent of `typeof` but with special handling for array and regexp.
function getPropType(propValue) {
  var propType = typeof propValue;
  if (Array.isArray(propValue)) {
    return 'array';
  }
  if (propValue instanceof RegExp) {
    // Old webkits (at least until Android 4.0) return 'function' rather than
    // 'object' for typeof a RegExp. We'll normalize this here so that /bla/
    // passes PropTypes.object.
    return 'object';
  }
  return propType;
}

// This handles more types than `getPropType`. Only used for error messages.
// See `createPrimitiveTypeChecker`.
function getPreciseType(propValue) {
  var propType = getPropType(propValue);
  if (propType === 'object') {
    if (propValue instanceof Date) {
      return 'date';
    } else if (propValue instanceof RegExp) {
      return 'regexp';
    }
  }
  return propType;
}

module.exports = ReactPropTypes;
<commit_msg>Fix to sample code for href in ReactPropTypes<commit_after>/**
 * Copyright 2013-2014 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @providesModule ReactPropTypes
 */

"use strict";

var ReactDescriptor = require('ReactDescriptor');
var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');

var emptyFunction = require('emptyFunction');

/**
 * Collection of methods that allow declaration and validation of props that are
 * supplied to React components. Example usage:
 *
 *   var Props = require('ReactPropTypes');
 *   var MyArticle = React.createClass({
 *     propTypes: {
 *       // An optional string prop named "description".
 *       description: Props.string,
 *
 *       // A required enum prop named "category".
 *       category: Props.oneOf(['News','Photos']).isRequired,
 *
 *       // A prop named "dialog" that requires an instance of Dialog.
 *       dialog: Props.instanceOf(Dialog).isRequired
 *     },
 *     render: function() { ... }
 *   });
 *
 * A more formal specification of how these methods are used:
 *
 *   type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...)
 *   decl := ReactPropTypes.{type}(.isRequired)?
 *
 * Each and every declaration produces a function with the same signature. This
 * allows the creation of custom validation functions. For example:
 *
 *  var MyLink = React.createClass({
 *    propTypes: {
 *      // An optional string or URI prop named "href".
 *      href: function(props, propName, componentName) {
 *        var propValue = props[propName];
 *        if (propValue != null && typeof propValue !== 'string' && !(propValue instanceof URI)) {
 *          return new Error(
 *            'Expected a string or an URI for ' + propName + ' in ' +
 *            componentName
 *          );
 *        }
 *      }
 *    },
 *    render: function() {...}
 *  });
 *
 * @internal
 */

var ANONYMOUS = '<<anonymous>>';

var ReactPropTypes = {
  array: createPrimitiveTypeChecker('array'),
  bool: createPrimitiveTypeChecker('boolean'),
  func: createPrimitiveTypeChecker('function'),
  number: createPrimitiveTypeChecker('number'),
  object: createPrimitiveTypeChecker('object'),
  string: createPrimitiveTypeChecker('string'),

  any: createAnyTypeChecker(),
  arrayOf: createArrayOfTypeChecker,
  component: createComponentTypeChecker(),
  instanceOf: createInstanceTypeChecker,
  objectOf: createObjectOfTypeChecker,
  oneOf: createEnumTypeChecker,
  oneOfType: createUnionTypeChecker,
  renderable: createRenderableTypeChecker(),
  shape: createShapeTypeChecker
};

function createChainableTypeChecker(validate) {
  function checkType(isRequired, props, propName, componentName, location) {
    componentName = componentName || ANONYMOUS;
    if (props[propName] == null) {
      var locationName = ReactPropTypeLocationNames[location];
      if (isRequired) {
        return new Error(
          `Required ${locationName} \`${propName}\` was not specified in `+
          `\`${componentName}\`.`
        );
      }
    } else {
      return validate(props, propName, componentName, location);
    }
  }

  var chainedCheckType = checkType.bind(null, false);
  chainedCheckType.isRequired = checkType.bind(null, true);

  return chainedCheckType;
}

function createPrimitiveTypeChecker(expectedType) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    var propType = getPropType(propValue);
    if (propType !== expectedType) {
      var locationName = ReactPropTypeLocationNames[location];
      // `propValue` being instance of, say, date/regexp, pass the 'object'
      // check, but we can offer a more precise error message here rather than
      // 'of type `object`'.
      var preciseType = getPreciseType(propValue);

      return new Error(
        `Invalid ${locationName} \`${propName}\` of type \`${preciseType}\` ` +
        `supplied to \`${componentName}\`, expected \`${expectedType}\`.`
      );
    }
  }
  return createChainableTypeChecker(validate);
}

function createAnyTypeChecker() {
  return createChainableTypeChecker(emptyFunction.thatReturns());
}

function createArrayOfTypeChecker(typeChecker) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    if (!Array.isArray(propValue)) {
      var locationName = ReactPropTypeLocationNames[location];
      var propType = getPropType(propValue);
      return new Error(
        `Invalid ${locationName} \`${propName}\` of type ` +
        `\`${propType}\` supplied to \`${componentName}\`, expected an array.`
      );
    }
    for (var i = 0; i < propValue.length; i++) {
      var error = typeChecker(propValue, i, componentName, location);
      if (error instanceof Error) {
        return error;
      }
    }
  }
  return createChainableTypeChecker(validate);
}

function createComponentTypeChecker() {
  function validate(props, propName, componentName, location) {
    if (!ReactDescriptor.isValidDescriptor(props[propName])) {
      var locationName = ReactPropTypeLocationNames[location];
      return new Error(
        `Invalid ${locationName} \`${propName}\` supplied to ` +
        `\`${componentName}\`, expected a React component.`
      );
    }
  }
  return createChainableTypeChecker(validate);
}

function createInstanceTypeChecker(expectedClass) {
  function validate(props, propName, componentName, location) {
    if (!(props[propName] instanceof expectedClass)) {
      var locationName = ReactPropTypeLocationNames[location];
      var expectedClassName = expectedClass.name || ANONYMOUS;
      return new Error(
        `Invalid ${locationName} \`${propName}\` supplied to ` +
        `\`${componentName}\`, expected instance of \`${expectedClassName}\`.`
      );
    }
  }
  return createChainableTypeChecker(validate);
}

function createEnumTypeChecker(expectedValues) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    for (var i = 0; i < expectedValues.length; i++) {
      if (propValue === expectedValues[i]) {
        return;
      }
    }

    var locationName = ReactPropTypeLocationNames[location];
    var valuesString = JSON.stringify(expectedValues);
    return new Error(
      `Invalid ${locationName} \`${propName}\` of value \`${propValue}\` ` +
      `supplied to \`${componentName}\`, expected one of ${valuesString}.`
    );
  }
  return createChainableTypeChecker(validate);
}

function createObjectOfTypeChecker(typeChecker) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    var propType = getPropType(propValue);
    if (propType !== 'object') {
      var locationName = ReactPropTypeLocationNames[location];
      return new Error(
        `Invalid ${locationName} \`${propName}\` of type ` +
        `\`${propType}\` supplied to \`${componentName}\`, expected an object.`
      );
    }
    for (var key in propValue) {
      if (propValue.hasOwnProperty(key)) {
        var error = typeChecker(propValue, key, componentName, location);
        if (error instanceof Error) {
          return error;
        }
      }
    }
  }
  return createChainableTypeChecker(validate);
}

function createUnionTypeChecker(arrayOfTypeCheckers) {
  function validate(props, propName, componentName, location) {
    for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
      var checker = arrayOfTypeCheckers[i];
      if (checker(props, propName, componentName, location) == null) {
        return;
      }
    }

    var locationName = ReactPropTypeLocationNames[location];
    return new Error(
      `Invalid ${locationName} \`${propName}\` supplied to ` +
      `\`${componentName}\`.`
    );
  }
  return createChainableTypeChecker(validate);
}

function createRenderableTypeChecker() {
  function validate(props, propName, componentName, location) {
    if (!isRenderable(props[propName])) {
      var locationName = ReactPropTypeLocationNames[location];
      return new Error(
        `Invalid ${locationName} \`${propName}\` supplied to ` +
        `\`${componentName}\`, expected a renderable prop.`
      );
    }
  }
  return createChainableTypeChecker(validate);
}

function createShapeTypeChecker(shapeTypes) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    var propType = getPropType(propValue);
    if (propType !== 'object') {
      var locationName = ReactPropTypeLocationNames[location];
      return new Error(
        `Invalid ${locationName} \`${propName}\` of type \`${propType}\` ` +
        `supplied to \`${componentName}\`, expected \`object\`.`
      );
    }
    for (var key in shapeTypes) {
      var checker = shapeTypes[key];
      if (!checker) {
        continue;
      }
      var error = checker(propValue, key, componentName, location);
      if (error) {
        return error;
      }
    }
  }
  return createChainableTypeChecker(validate, 'expected `object`');
}

function isRenderable(propValue) {
  switch(typeof propValue) {
    // TODO: this was probably written with the assumption that we're not
    // returning `this.props.component` directly from `render`. This is
    // currently not supported but we should, to make it consistent.
    case 'number':
    case 'string':
      return true;
    case 'boolean':
      return !propValue;
    case 'object':
      if (Array.isArray(propValue)) {
        return propValue.every(isRenderable);
      }
      if (ReactDescriptor.isValidDescriptor(propValue)) {
        return true;
      }
      for (var k in propValue) {
        if (!isRenderable(propValue[k])) {
          return false;
        }
      }
      return true;
    default:
      return false;
  }
}

// Equivalent of `typeof` but with special handling for array and regexp.
function getPropType(propValue) {
  var propType = typeof propValue;
  if (Array.isArray(propValue)) {
    return 'array';
  }
  if (propValue instanceof RegExp) {
    // Old webkits (at least until Android 4.0) return 'function' rather than
    // 'object' for typeof a RegExp. We'll normalize this here so that /bla/
    // passes PropTypes.object.
    return 'object';
  }
  return propType;
}

// This handles more types than `getPropType`. Only used for error messages.
// See `createPrimitiveTypeChecker`.
function getPreciseType(propValue) {
  var propType = getPropType(propValue);
  if (propType === 'object') {
    if (propValue instanceof Date) {
      return 'date';
    } else if (propValue instanceof RegExp) {
      return 'regexp';
    }
  }
  return propType;
}

module.exports = ReactPropTypes;
<|endoftext|>


<commit_before>DV.DocumentViewer = function(options) {
  this.options    = options;
  this.$          = this.jQuery;
  this.schema     = new DV.Schema();
  this.api        = new DV.Api(this);
  this.history    = new DV.History(this);

  // Build the data models
  this.models     = this.schema.models;
  this.events     = _.extend({}, DV.Schema.events);
  this.helpers    = _.extend({}, DV.Schema.helpers);
  this.states     = _.extend({}, DV.Schema.states);

  // state values
  this.isFocus            = true;
  this.activeElement      = null;
  this.observers          = [];
  this.windowDimensions   = {};
  this.scrollPosition     = null;
  this.checkTimer         = {};
  this.busy               = false;
  this.annotationToLoadId = null;
  this.dragReporter       = null;
  this.compiled           = {};
  this.tracker            = {};

  this.onStateChangeCallbacks = [];

  this.events     = _.extend(this.events, {
    viewer      : this,
    states      : this.states,
    elements    : this.elements,
    helpers     : this.helpers,
    models      : this.models,
    // this allows us to bind events to call the method corresponding to the current state
    compile     : function(){
      var a           = this.viewer;
      var methodName  = arguments[0];
      return function(){
        if(!a.events[a.state][methodName]){
          a.events[methodName].apply(a.events,arguments);
        }else{
          a.events[a.state][methodName].apply(a.events,arguments);
        }
      };
    }
  });

  this.helpers  = _.extend(this.helpers, {
    viewer      : this,
    states      : this.states,
    elements    : this.elements,
    events      : this.events,
    models      : this.models
  });

  this.states   = _.extend(this.states, {
    viewer      : this,
    helpers     : this.helpers,
    elements    : this.elements,
    events      : this.events,
    models      : this.models
  });
};

DV.DocumentViewer.prototype.loadModels = function() {
  this.models.chapters     = new DV.model.Chapters(this);
  this.models.document     = new DV.model.Document(this);
  this.models.pages        = new DV.model.Pages(this);
  this.models.annotations  = new DV.model.Annotations(this);
  this.models.removedPages = {};
};

// Transition to a given state ... unless we're already in it.
DV.DocumentViewer.prototype.open = function(state) {
  if (this.state == state) return;
  this.state = state;
  this.states[state].apply(this, arguments);
  this.notifyChangedState();
};

DV.DocumentViewer.prototype.notifyChangedState = function() {
  _.each(this.onStateChangeCallbacks, function(c) { c(); });
};

// jQuery object, scoped to this viewer's container.
DV.DocumentViewer.prototype.jQuery = function(selector, context) {
  context = context || this.options.container;
  return DV.jQuery.call(DV.jQuery, selector, context);
};

// The origin function, kicking off the entire documentViewer render.
DV.load = function(documentRep, options) {
  options = options || {};
  var id  = documentRep.id || documentRep.match(/([^\/]+)(\.js|\.json)$/)[1];
  if ('showSidebar' in options) options.sidebar = options.showSidebar;
  var defaults = {
    container : document.body,
    zoom      : 'auto',
    sidebar   : true
  };
  options            = _.extend({}, defaults, options);
  options.fixedSize  = !!(options.width || options.height);
  var viewer         = new DV.DocumentViewer(options);
  DV.viewers[id]     = viewer;
  // Once we have the JSON representation in-hand, finish loading the viewer.
  var continueLoad = DV.loadJSON = function(json) {
    var viewer = DV.viewers[json.id];
    viewer.schema.importCanonicalDocument(json);
    viewer.loadModels();
    DV.jQuery(function() {
      viewer.open('InitialLoad');
      if (options.afterLoad) options.afterLoad(viewer);
      if (DV.afterLoad) DV.afterLoad(viewer);
    });
  };

  // If we've been passed the JSON directly, we can go ahead,
  // otherwise make a JSONP request to fetch it.
  var jsonLoad = function() {
    if (_.isString(documentRep)) {
      if (documentRep.match(/\.js$/)) {
        DV.jQuery.getScript(documentRep);
      } else {
        var crossDomain = viewer.helpers.isCrossDomain(documentRep);
        if (crossDomain) documentRep = documentRep + '?callback=?';
        DV.jQuery.getJSON(documentRep, continueLoad);
      }
    } else {
      continueLoad(documentRep);
    }
  };

  // If we're being asked the fetch the templates, load them remotely before
  // continuing.
  if (options.templates) {
    DV.jQuery.getScript(options.templates, jsonLoad);
  } else {
    jsonLoad();
  }

  return viewer;
};

// If the document viewer has been loaded dynamically, allow the external
// script to specify the onLoad behavior.
if (DV.onload) _.defer(DV.onload);

<commit_msg>have the viewer instance keep a reference to its window.<commit_after>DV.DocumentViewer = function(options) {
  this.options    = options;
  this.window     = window;
  this.$          = this.jQuery;
  this.schema     = new DV.Schema();
  this.api        = new DV.Api(this);
  this.history    = new DV.History(this);

  // Build the data models
  this.models     = this.schema.models;
  this.events     = _.extend({}, DV.Schema.events);
  this.helpers    = _.extend({}, DV.Schema.helpers);
  this.states     = _.extend({}, DV.Schema.states);

  // state values
  this.isFocus            = true;
  this.activeElement      = null;
  this.observers          = [];
  this.windowDimensions   = {};
  this.scrollPosition     = null;
  this.checkTimer         = {};
  this.busy               = false;
  this.annotationToLoadId = null;
  this.dragReporter       = null;
  this.compiled           = {};
  this.tracker            = {};

  this.onStateChangeCallbacks = [];

  this.events     = _.extend(this.events, {
    viewer      : this,
    states      : this.states,
    elements    : this.elements,
    helpers     : this.helpers,
    models      : this.models,
    // this allows us to bind events to call the method corresponding to the current state
    compile     : function(){
      var a           = this.viewer;
      var methodName  = arguments[0];
      return function(){
        if(!a.events[a.state][methodName]){
          a.events[methodName].apply(a.events,arguments);
        }else{
          a.events[a.state][methodName].apply(a.events,arguments);
        }
      };
    }
  });

  this.helpers  = _.extend(this.helpers, {
    viewer      : this,
    states      : this.states,
    elements    : this.elements,
    events      : this.events,
    models      : this.models
  });

  this.states   = _.extend(this.states, {
    viewer      : this,
    helpers     : this.helpers,
    elements    : this.elements,
    events      : this.events,
    models      : this.models
  });
};

DV.DocumentViewer.prototype.loadModels = function() {
  this.models.chapters     = new DV.model.Chapters(this);
  this.models.document     = new DV.model.Document(this);
  this.models.pages        = new DV.model.Pages(this);
  this.models.annotations  = new DV.model.Annotations(this);
  this.models.removedPages = {};
};

// Transition to a given state ... unless we're already in it.
DV.DocumentViewer.prototype.open = function(state) {
  if (this.state == state) return;
  this.state = state;
  this.states[state].apply(this, arguments);
  this.notifyChangedState();
};

DV.DocumentViewer.prototype.notifyChangedState = function() {
  _.each(this.onStateChangeCallbacks, function(c) { c(); });
};

// jQuery object, scoped to this viewer's container.
DV.DocumentViewer.prototype.jQuery = function(selector, context) {
  context = context || this.options.container;
  return DV.jQuery.call(DV.jQuery, selector, context);
};

// The origin function, kicking off the entire documentViewer render.
DV.load = function(documentRep, options) {
  options = options || {};
  var id  = documentRep.id || documentRep.match(/([^\/]+)(\.js|\.json)$/)[1];
  if ('showSidebar' in options) options.sidebar = options.showSidebar;
  var defaults = {
    container : document.body,
    zoom      : 'auto',
    sidebar   : true
  };
  options            = _.extend({}, defaults, options);
  options.fixedSize  = !!(options.width || options.height);
  var viewer         = new DV.DocumentViewer(options);
  DV.viewers[id]     = viewer;
  // Once we have the JSON representation in-hand, finish loading the viewer.
  var continueLoad = DV.loadJSON = function(json) {
    var viewer = DV.viewers[json.id];
    viewer.schema.importCanonicalDocument(json);
    viewer.loadModels();
    DV.jQuery(function() {
      viewer.open('InitialLoad');
      if (options.afterLoad) options.afterLoad(viewer);
      if (DV.afterLoad) DV.afterLoad(viewer);
    });
  };

  // If we've been passed the JSON directly, we can go ahead,
  // otherwise make a JSONP request to fetch it.
  var jsonLoad = function() {
    if (_.isString(documentRep)) {
      if (documentRep.match(/\.js$/)) {
        DV.jQuery.getScript(documentRep);
      } else {
        var crossDomain = viewer.helpers.isCrossDomain(documentRep);
        if (crossDomain) documentRep = documentRep + '?callback=?';
        DV.jQuery.getJSON(documentRep, continueLoad);
      }
    } else {
      continueLoad(documentRep);
    }
  };

  // If we're being asked the fetch the templates, load them remotely before
  // continuing.
  if (options.templates) {
    DV.jQuery.getScript(options.templates, jsonLoad);
  } else {
    jsonLoad();
  }

  return viewer;
};

// If the document viewer has been loaded dynamically, allow the external
// script to specify the onLoad behavior.
if (DV.onload) _.defer(DV.onload);

<|endoftext|>


<commit_before>/**
 * A Tag module.
 *
 * @param {*} params Properties of tag.
 * @returns {Tag}
 * @constructor
 */
function Tag (params) {
    let self = this;

    // UI element of Tag.
    let tagElement = null;

    // Properties of this Tag.
    let properties = {
        tagId: undefined,
        labelType: undefined,
        tag: undefined
    };

    // Status of the tag.
    let status = {
        applied: false
    };

    /**
     * Initialize Tag.
     *
     * @param {*} param Tag properties.
     */
    function _init (param) {
        Object.keys(param).forEach( attrName => properties[attrName] = param[attrName]);

        tagElement = document.createElement('button');
        tagElement.className = "gallery-tag";
        tagElement.id = properties.tag;
        tagElement.innerText = properties.tag;
        tagElement.disabled = true;

        tagElement.onclick = handleTagClickCallback;
    }

    /**
     * Handles what happens when Tag is clicked.
     */
    function handleTagClickCallback() {
        if (status.applied) {
            sg.tracker.push("TagUnapply", null, {
                Tag: properties.tag,
                Label_Type: properties.labelType
            });
            unapply();
        } else {
            sg.tracker.push("TagApply", null, {
                Tag: properties.tag,
                Label_Type: properties.labelType
            });
            apply();
        }

        sg.cardContainer.updateCardsByTag();
    }

    /**
     * Applies Tag.
     */
    function apply() {
        setStatus("applied", true);
        console.log("clicked and toggled on");
        tagElement.setAttribute("style", "background-color: #78c8aa");
    }

    /**
     * Unapplies Tag.
     */
    function unapply() {
        setStatus("applied", false);
        console.log("clicked and toggled off");
        tagElement.setAttribute("style", "background-color: none");
    }

    /**
     * Returns Tag name.
     */
    function getTag() {
        return properties.tag;
    }

    /**
     * Returns the tagId of this Tag.
     */
    function getTagId() {
        return properties.tagId;
    }

    /**
     * Returns label type of Tag.
     */
    function getLabelType() {
        return properties.labelType;
    }

    /**
     * Return the deep copy of the properties object, so the caller can only modify properties from setProperty().
     *
     * JavaScript Deepcopy:
     * http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-a-javascript-object
     */
    function getProperties() { return $.extend(true, {}, properties); }

    /**
     * Gets property of Tag.
     *
     * @param propName Property name.
     * @returns {*} Property value if property name is valid. Otherwise false.
     */
    function getProperty(propName) { return (propName in properties) ? properties[propName] : false; }

    /**
     * Get status of tag.
     */
    function getStatus() {
        return status;
    }

    /**
     * Sets a property of Tag.
     *
     * @param key Property name.
     * @param value Property value.
     * @returns {setProperty}
     */
    function setProperty (key, value) {
        properties[key] = value;
        return this;
    }

    /**
     * Set status attribute of tag.
     *
     * @param {*} key Status name.
     * @param {*} value Status value.
     */
    function setStatus(key, value) {
        if (key in status) {
            status[key] = value;
        } else {
            throw self.className + ": Illegal status name.";
        }
    }

    /**
     * Renders the Tag.
     *
     * @param filterContainer UI element to render Tag in.
     * @returns {self}
     */
    function render(filterContainer) {
        filterContainer.append(tagElement);
    }

    self.apply = apply;
    self.unapply = unapply;
    self.getTag = getTag;
    self.getTagId = getTagId;
    self.getLabelType = getLabelType;
    self.getProperties = getProperties;
    self.getProperty = getProperty;
    self.getStatus = getStatus;
    self.setProperty = setProperty;
    self.setStatus = setStatus;
    self.render = render;

    _init(params);
    return this;
}
<commit_msg>Made names in Tag.js back to snake case<commit_after>/**
 * A Tag module.
 *
 * @param {*} params Properties of tag.
 * @returns {Tag}
 * @constructor
 */
function Tag (params) {
    let self = this;

    // UI element of Tag.
    let tagElement = null;

    // Properties of this Tag.
    let properties = {
        tag_id: undefined,
        label_type: undefined,
        tag: undefined
    };

    // Status of the tag.
    let status = {
        applied: false
    };

    /**
     * Initialize Tag.
     *
     * @param {*} param Tag properties.
     */
    function _init (param) {
        Object.keys(param).forEach( attrName => properties[attrName] = param[attrName]);

        tagElement = document.createElement('button');
        tagElement.className = "gallery-tag";
        tagElement.id = properties.tag;
        tagElement.innerText = properties.tag;
        tagElement.disabled = true;

        tagElement.onclick = handleTagClickCallback;
    }

    /**
     * Handles what happens when Tag is clicked.
     */
    function handleTagClickCallback() {
        if (status.applied) {
            sg.tracker.push("TagUnapply", null, {
                Tag: properties.tag,
                Label_Type: properties.label_type
            });
            unapply();
        } else {
            sg.tracker.push("TagApply", null, {
                Tag: properties.tag,
                Label_Type: properties.label_type
            });
            apply();
        }

        sg.cardContainer.updateCardsByTag();
    }

    /**
     * Applies Tag.
     */
    function apply() {
        setStatus("applied", true);
        console.log("clicked and toggled on");
        tagElement.setAttribute("style", "background-color: #78c8aa");
    }

    /**
     * Unapplies Tag.
     */
    function unapply() {
        setStatus("applied", false);
        console.log("clicked and toggled off");
        tagElement.setAttribute("style", "background-color: none");
    }

    /**
     * Returns Tag name.
     */
    function getTag() {
        return properties.tag;
    }

    /**
     * Returns the tagId of this Tag.
     */
    function getTagId() {
        return properties.tag_id;
    }

    /**
     * Returns label type of Tag.
     */
    function getLabelType() {
        return properties.label_type;
    }

    /**
     * Return the deep copy of the properties object, so the caller can only modify properties from setProperty().
     *
     * JavaScript Deepcopy:
     * http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-a-javascript-object
     */
    function getProperties() { return $.extend(true, {}, properties); }

    /**
     * Gets property of Tag.
     *
     * @param propName Property name.
     * @returns {*} Property value if property name is valid. Otherwise false.
     */
    function getProperty(propName) { return (propName in properties) ? properties[propName] : false; }

    /**
     * Get status of tag.
     */
    function getStatus() {
        return status;
    }

    /**
     * Sets a property of Tag.
     *
     * @param key Property name.
     * @param value Property value.
     * @returns {setProperty}
     */
    function setProperty (key, value) {
        properties[key] = value;
        return this;
    }

    /**
     * Set status attribute of tag.
     *
     * @param {*} key Status name.
     * @param {*} value Status value.
     */
    function setStatus(key, value) {
        if (key in status) {
            status[key] = value;
        } else {
            throw self.className + ": Illegal status name.";
        }
    }

    /**
     * Renders the Tag.
     *
     * @param filterContainer UI element to render Tag in.
     * @returns {self}
     */
    function render(filterContainer) {
        filterContainer.append(tagElement);
    }

    self.apply = apply;
    self.unapply = unapply;
    self.getTag = getTag;
    self.getTagId = getTagId;
    self.getLabelType = getLabelType;
    self.getProperties = getProperties;
    self.getProperty = getProperty;
    self.getStatus = getStatus;
    self.setProperty = setProperty;
    self.setStatus = setStatus;
    self.render = render;

    _init(params);
    return this;
}
<|endoftext|>


<commit_before>define([
	'matreshka_dir/polyfills/classlist',
	'matreshka_dir/polyfills/addeventlistener'
], function() {
	"use strict";
	// we need to refactor all this stuff
	if(typeof window == 'undefined') {
		return;
	}

	var s_classList = 'classList',
		nsReg = /\.(.+)/,
		allEvents = {},
		nodeIndex = 0,
		$b;

	// this is cutted version of balalaika
	// nsRegAndEvents is regesp for eventname.namespace and the list of all events
	// fn is empty array and balalaika prototype
	$b = (function(window, document, fn, s_MatchesSelector, i, j, k, l, $) {
		$ = function(s, context) {
			return new $.i(s, context);
		};

		$.i = function(s, context) {
			fn.push.apply(this, !s ? fn : s.nodeType || s == window ? [s] : "" + s === s ? /</.test(s) ? ((i = document.createElement(context || 'div')).innerHTML = s, i.children) : (context && $(context)[0] || document).querySelectorAll(s) : /f/.test(typeof s) ? /c/.test(document.readyState) ? s() : $(document).on('DOMContentLoaded', s) : 'length' in s ? s : [s]);
		};

		$.i[l = 'prototype'] = ($.extend = function(obj) {
			k = arguments;
			for (i = 1; i < k.length; i++) {
				if (l = k[i]) {
					for (j in l) {
						obj[j] = l[j];
					}
				}
			}

			return obj;
		})($.fn = $[l] = fn, { // $.fn = $.prototype = fn
			is: function(s) {
				i = this[0];
				j = !!i && (i.matches || i['webkit' + s_MatchesSelector] || i['moz' + s_MatchesSelector]
						|| i['ms' + s_MatchesSelector] || i['o' + s_MatchesSelector]);
				return !!j && j.call(i, s);
			}
		});
		return $;
	})(window, document, [], 'MatchesSelector');

	$b.extend($b.fn, {
		on: function(names, selector, handler) {
			var _this = this,
				delegate,
				name,
				namespace,
				node,
				nodeID,
				events,
				event,
				exist,
				i, j, k;

			if(typeof selector == 'function') {
				handler = selector;
				selector = null;
			}

			if(selector) {
				delegate = function(evt) {
					var randomID = 'x' + String(Math.random()).split('.')[1],
						node = this,
						is;

					node.setAttribute(randomID, randomID);

					is = '[' + randomID + '="' + randomID + '"] ' + selector;

					if ($b(evt.target).is(is + ',' + is + ' *')) {
						handler.call(node, evt);
					}

					node.removeAttribute(randomID);
				};

				//delegate._callback = handler;
				//handler = delegate;
			}

			names = names.split(/\s/);

			for(i = 0; i < names.length; i++) {
				name = names[i].split(nsReg);
				namespace = name[1];
				name = name[0];

				for(j = 0; j < _this.length; j++) {
					node = _this[j];

					nodeID = node.b$ = node.b$ || ++nodeIndex,
					events = allEvents[name + nodeID] = allEvents[name + nodeID] || [],
					exist = false;

					for(k = 0; k < events.length; k++) {
						event = events[k];

						if(handler == event.handler && (!selector || selector == event.selector)) {
							exist = true;
							break;
						}
					}

					if(!exist) {
						events.push({
							delegate: delegate,
							handler: handler,
							namespace: namespace,
							selector: selector
						});

						node.addEventListener(name, delegate || handler, false);
					}
				}
			}

			return _this;
		},
		off: function(names, selector, handler) {
			var _this = this,
				name,
				namespace,
				node,
				events,
				event,
				i, j, k;

			if(typeof selector == 'function') {
				handler = selector;
				selector = null;
			}

			names = names.split(/\s/);

			for(i = 0; i < names.length; i++) {
				name = names[i].split(nsReg);
				namespace = name[1];
				name = name[0];

				for(j = 0; j < _this.length; j++) {
					node = _this[j];

					events = allEvents[name + node.b$];

					if (events) {
						for(k = 0; k < events.length; k++) {
							var event = events[k];
							if((!handler || handler == event.handler || handler == event.delegate)
									&& (!namespace || namespace == event.namespace)
									&& (!selector || selector == event.selector)) {
								node.removeEventListener(name, event.delegate || event.handler);
								events.splice(k--, 1);
							}
						}
					} else {
						if(!namespace && !selector) {
							node.removeEventListener(name, handler);
						}
					}
				}
			}

			return _this;
		},
		hasClass: function(className) {
			return !!this[0] && this[0][s_classList].contains(className);
		},
		addClass: function(className) {
			this.forEach(function(item) {
				var classList = item[s_classList];
				classList.add.apply(classList, className.split(/\s/));
			});
			return this;
		},
		removeClass: function(className) {
			this.forEach(function(item) {
				var classList = item[s_classList];
				classList.remove.apply(classList, className.split(/\s/));
			});
			return this;
		},
		toggleClass: function(className, b) {
			this.forEach(function(item) {
				var classList = item[s_classList];
				if (typeof b !== 'boolean') {
					b = !classList.contains(className);
				}
				classList[b ? 'add' : 'remove'].apply(classList, className.split(/\s/));
			});
			return this;
		},
		add: function(s) {
			var result = $b(this),
				map = {},
				nodeID,
				node,
				i;

			s = $b(s);

			for(i = 0; i < result.length; i++) {
				node = result[i];
				nodeID = node.b$ = node.b$ || ++nodeIndex;
				map[nodeID] = 1;
			}

			for(i = 0; i < s.length; i++) {
				node = s[i];
				nodeID = node.b$ = node.b$ || ++nodeIndex;
				if(!map[nodeID]) {
					map[nodeID] = 1;
					result.push(node);
				}
			}

			return result;
		},
		not: function(s) {
			var result = $b(this),
				index,
				i;

			s = $b(s);

			for (i = 0; i < s.length; i++) {
				if (~(index = result.indexOf(s[i]))) {
					result.splice(index, 1);
				}
			}

			return result;
		},
		find: function(s) {
			var result = $b();
			this.forEach(function(item) {
				result = result.add($b(s, item));
			});
			return result;
		}
	});

	// simple html parser
	$b.parseHTML = function(html) {
		var node = document.createElement('div'),
			// wrapMap is taken from jQuery
			wrapMap = {
				option: [1, "<select multiple='multiple'>", "</select>"],
				legend: [1, "<fieldset>", "</fieldset>"],
				thead: [1, "
", "
"],
				tr: [2, "

", "

"],
				td: [3, "

", "

"],
				col: [2, "

<colgroup>", "</colgroup>
"],
				area: [1, "<map>", "</map>"],
				_: [0, "", ""]
			},
			wrapper,
			i,
			ex;

		html = html.replace(/^\s+|\s+$/g, '');

		wrapMap.optgroup = wrapMap.option;
		wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
		wrapMap.th = wrapMap.td;

		ex = /<([\w:]+)/.exec(html);

		wrapper = ex && wrapMap[ex[1]] || wrapMap._;

		node.innerHTML = wrapper[1] + html + wrapper[2];

		i = wrapper[0];

		while (i--) {
			node = node.children[0];
		}

		return $b(node.childNodes);
	};

	$b.create = function create(tagName, props) {
		var el, i, j, prop;

		if (typeof tagName == 'object') {
			props = tagName;
			tagName = props.tagName;
		}

		el = document.createElement(tagName)

		if (props)
			for (i in props) {
				prop = props[i];
				if (i == 'attributes' && typeof prop == 'object') {
					for (j in prop)
						if (prop.hasOwnProperty(j)) {
							el.setAttribute(j, prop[j]);
						}
				} else if (i == 'tagName') {
					continue;
				} else if (i == 'children' && prop) {
					for (j = 0; j < prop.length; j++) {
						el.appendChild(create(prop[j]));
					}
				} else if (typeof el[i] == 'object' && el[i] !== null && typeof props == 'object') {
					for (j in prop)
						if (prop.hasOwnProperty(j)) {
							el[i][j] = prop[j];
						}
				} else {
					el[i] = prop;
				}
			}
		return el;
	};

	// @IE8 Balalaika fix. This browser doesn't support HTMLCollection and NodeList as second argument for .apply
	(function(document, $, i, j, k, fn) {
		var bugs,
			children = document.createElement('div').children;
		try {
			[].push.apply([], children);
		} catch (e) {
			bugs = true;
		}
		bugs = bugs || typeof children == 'function' || document.documentMode < 9;

		if (bugs) {
			fn = $.i[j = 'prototype'];

			$.i = function(s, context) {
				k = !s ? fn : s && s.nodeType || s == window ? [s] : typeof s == 'string' ? /</.test(s) ? ((i = document.createElement('div')).innerHTML = s, i.children) : (context && $(context)[0] || document).querySelectorAll(s) : /f/.test(typeof s) && (!s[0] && !s[0].nodeType) ? /c/.test(document.readyState) ? s() : ! function r(f) {
					/in/ (document.readyState) ? setTimeout(r, 9, f): f()
				}(s) : s;

				j = [];
				for (i = k ? k.length : 0; i--; j[i] = k[i]) {}

				fn.push.apply(this, j);
			};

			$.i[j] = fn;

			fn.is = function(selector) {
				var elem = this[0],
					elems = elem.parentNode.querySelectorAll(selector),
					i;

				for (i = 0; i < elems.length; i++) {
					if (elems[i] === elem) return true;
				}
				return false;
			};
		}
		return $;
	})(document, $b);

	return $b;
});
<commit_msg>fixed jshint issues<commit_after>define([
	'matreshka_dir/polyfills/classlist',
	'matreshka_dir/polyfills/addeventlistener'
], function() {
	"use strict";
	// we need to refactor all this stuff
	if(typeof window == 'undefined') {
		return;
	}

	var s_classList = 'classList',
		nsReg = /\.(.+)/,
		allEvents = {},
		nodeIndex = 0,
		$b;

	// this is cutted version of balalaika
	// nsRegAndEvents is regesp for eventname.namespace and the list of all events
	// fn is empty array and balalaika prototype
	$b = (function(window, document, fn, s_MatchesSelector, i, j, k, l, $) {
		$ = function(s, context) {
			return new $.i(s, context);
		};

		$.i = function(s, context) {
			fn.push.apply(this, !s ? fn : s.nodeType || s == window ? [s] : "" + s === s ? /</.test(s) ? ((i = document.createElement(context || 'div')).innerHTML = s, i.children) : (context && $(context)[0] || document).querySelectorAll(s) : /f/.test(typeof s) ? /c/.test(document.readyState) ? s() : $(document).on('DOMContentLoaded', s) : 'length' in s ? s : [s]);
		};

		$.extend = function(obj) {
			k = arguments;
			for (i = 1; i < k.length; i++) {
				if (l = k[i]) {
					for (j in l) {
						obj[j] = l[j];
					}
				}
			}

			return obj;
		};

		$.fn = $.i.fn = $.i.prototype = fn;

		fn.is = function(s) {
			i = this[0];
			j = !!i && (i.matches || i['webkit' + s_MatchesSelector] || i['moz' + s_MatchesSelector]
					|| i['ms' + s_MatchesSelector] || i['o' + s_MatchesSelector]);
			return !!j && j.call(i, s);
		};

		return $;
	})(window, document, [], 'MatchesSelector');

	$b.extend($b.fn, {
		on: function(names, selector, handler) {
			var _this = this,
				delegate,
				name,
				namespace,
				node,
				nodeID,
				events,
				event,
				exist,
				i, j, k;

			if(typeof selector == 'function') {
				handler = selector;
				selector = null;
			}

			if(selector) {
				delegate = function(evt) {
					var randomID = 'x' + String(Math.random()).split('.')[1],
						node = this,
						is;

					node.setAttribute(randomID, randomID);

					is = '[' + randomID + '="' + randomID + '"] ' + selector;

					if ($b(evt.target).is(is + ',' + is + ' *')) {
						handler.call(node, evt);
					}

					node.removeAttribute(randomID);
				};

				//delegate._callback = handler;
				//handler = delegate;
			}

			names = names.split(/\s/);

			for(i = 0; i < names.length; i++) {
				name = names[i].split(nsReg);
				namespace = name[1];
				name = name[0];

				for(j = 0; j < _this.length; j++) {
					node = _this[j];

					nodeID = node.b$ = node.b$ || ++nodeIndex,
					events = allEvents[name + nodeID] = allEvents[name + nodeID] || [],
					exist = false;

					for(k = 0; k < events.length; k++) {
						event = events[k];

						if(handler == event.handler && (!selector || selector == event.selector)) {
							exist = true;
							break;
						}
					}

					if(!exist) {
						events.push({
							delegate: delegate,
							handler: handler,
							namespace: namespace,
							selector: selector
						});

						node.addEventListener(name, delegate || handler, false);
					}
				}
			}

			return _this;
		},
		off: function(names, selector, handler) {
			var _this = this,
				name,
				namespace,
				node,
				events,
				event,
				i, j, k;

			if(typeof selector == 'function') {
				handler = selector;
				selector = null;
			}

			names = names.split(/\s/);

			for(i = 0; i < names.length; i++) {
				name = names[i].split(nsReg);
				namespace = name[1];
				name = name[0];

				for(j = 0; j < _this.length; j++) {
					node = _this[j];

					events = allEvents[name + node.b$];

					if (events) {
						for(k = 0; k < events.length; k++) {
							event = events[k];
							if((!handler || handler == event.handler || handler == event.delegate)
									&& (!namespace || namespace == event.namespace)
									&& (!selector || selector == event.selector)) {
								node.removeEventListener(name, event.delegate || event.handler);
								events.splice(k--, 1);
							}
						}
					} else {
						if(!namespace && !selector) {
							node.removeEventListener(name, handler);
						}
					}
				}
			}

			return _this;
		},
		hasClass: function(className) {
			return !!this[0] && this[0][s_classList].contains(className);
		},
		addClass: function(className) {
			this.forEach(function(item) {
				var classList = item[s_classList];
				classList.add.apply(classList, className.split(/\s/));
			});
			return this;
		},
		removeClass: function(className) {
			this.forEach(function(item) {
				var classList = item[s_classList];
				classList.remove.apply(classList, className.split(/\s/));
			});
			return this;
		},
		toggleClass: function(className, b) {
			this.forEach(function(item) {
				var classList = item[s_classList];
				if (typeof b !== 'boolean') {
					b = !classList.contains(className);
				}
				classList[b ? 'add' : 'remove'].apply(classList, className.split(/\s/));
			});
			return this;
		},
		add: function(s) {
			var result = $b(this),
				map = {},
				nodeID,
				node,
				i;

			s = $b(s);

			for(i = 0; i < result.length; i++) {
				node = result[i];
				nodeID = node.b$ = node.b$ || ++nodeIndex;
				map[nodeID] = 1;
			}

			for(i = 0; i < s.length; i++) {
				node = s[i];
				nodeID = node.b$ = node.b$ || ++nodeIndex;
				if(!map[nodeID]) {
					map[nodeID] = 1;
					result.push(node);
				}
			}

			return result;
		},
		not: function(s) {
			var result = $b(this),
				index,
				i;

			s = $b(s);

			for (i = 0; i < s.length; i++) {
				if (~(index = result.indexOf(s[i]))) {
					result.splice(index, 1);
				}
			}

			return result;
		},
		find: function(s) {
			var result = $b();
			this.forEach(function(item) {
				result = result.add($b(s, item));
			});
			return result;
		}
	});

	// simple html parser
	$b.parseHTML = function(html) {
		var node = document.createElement('div'),
			// wrapMap is taken from jQuery
			wrapMap = {
				option: [1, "<select multiple='multiple'>", "</select>"],
				legend: [1, "<fieldset>", "</fieldset>"],
				thead: [1, "
", "
"],
				tr: [2, "

", "

"],
				td: [3, "

", "

"],
				col: [2, "

<colgroup>", "</colgroup>
"],
				area: [1, "<map>", "</map>"],
				_: [0, "", ""]
			},
			wrapper,
			i,
			ex;

		html = html.replace(/^\s+|\s+$/g, '');

		wrapMap.optgroup = wrapMap.option;
		wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
		wrapMap.th = wrapMap.td;

		ex = /<([\w:]+)/.exec(html);

		wrapper = ex && wrapMap[ex[1]] || wrapMap._;

		node.innerHTML = wrapper[1] + html + wrapper[2];

		i = wrapper[0];

		while (i--) {
			node = node.children[0];
		}

		return $b(node.childNodes);
	};

	$b.create = function create(tagName, props) {
		var el, i, j, prop;

		if (typeof tagName == 'object') {
			props = tagName;
			tagName = props.tagName;
		}

		el = document.createElement(tagName);

		if (props)
			for (i in props) {
				prop = props[i];
				if (i == 'attributes' && typeof prop == 'object') {
					for (j in prop)
						if (prop.hasOwnProperty(j)) {
							el.setAttribute(j, prop[j]);
						}
				} else if (i == 'tagName') {
					continue;
				} else if (i == 'children' && prop) {
					for (j = 0; j < prop.length; j++) {
						el.appendChild(create(prop[j]));
					}
				} else if (typeof el[i] == 'object' && el[i] !== null && typeof props == 'object') {
					for (j in prop)
						if (prop.hasOwnProperty(j)) {
							el[i][j] = prop[j];
						}
				} else {
					el[i] = prop;
				}
			}
		return el;
	};

	// @IE8 Balalaika fix. This browser doesn't support HTMLCollection and NodeList as second argument for .apply
	(function(document, $, i, j, k, fn) {
		var bugs,
			children = document.createElement('div').children;
		try {
			[].push.apply([], children);
		} catch (e) {
			bugs = true;
		}
		bugs = bugs || typeof children == 'function' || document.documentMode < 9;

		if (bugs) {
			fn = $.i[j = 'prototype'];

			$.i = function(s, context) {
				k = !s ? fn : s && s.nodeType || s == window ? [s] : typeof s == 'string' ? /</.test(s) ? ((i = document.createElement('div')).innerHTML = s, i.children) : (context && $(context)[0] || document).querySelectorAll(s) : /f/.test(typeof s) && (!s[0] && !s[0].nodeType) ? /c/.test(document.readyState) ? s() : !function r(f) {
					if(/in/.test(document.readyState)) {
						 setTimeout(r, 9, f);
					} else {
						f();
					}
				}(s) : s;

				j = [];
				for (i = k ? k.length : 0; i--; j[i] = k[i]) {}

				fn.push.apply(this, j);
			};

			$.i[j] = fn;

			fn.is = function(selector) {
				var elem = this[0],
					elems = elem.parentNode.querySelectorAll(selector),
					i;

				for (i = 0; i < elems.length; i++) {
					if (elems[i] === elem) return true;
				}
				return false;
			};
		}
		return $;
	})(document, $b);

	return $b;
});
<|endoftext|>


<commit_before>/**
 * @fileoverview
 * Constants and functions about basic metrics.
 * @author Partridge Jiang
 */

/*
 * requires /lan/classes.js
 * requires /core/kekule.root.js
 * requires /localization
 */

(function(){

"use strict";

/**
 * Root name space for units.
 * @namespace
 */
Kekule.Unit = {
	/** @private */
	ALL: {},
	/** @private */
	_KEY_MAP: {},
	/**
	 * Register a unit.
	 * After register, a Kekule.Unit[category][name.capitalized] will be set with value symbol (e.g., Kekule.Unit.Frequency.HERTZ = 'Hz').
	 * @param {String} symbol The symbol of unit, e.g. 'Hz'.
	 *   This value will be regarded as key of unit. If this value is empty, name will be regarded as key instead.
	 * @param {String} name Name of unit, e.g., 'Hertz'.
	 * @param {String} category Category of unit, e.g. 'Frequency'.
	 *   Note the first letter of category is recommended to be capitalized.
	 * @param {Number} rateToStandard The conversion rate to SI standard unit in this category.
	 *   For example, this value should be 1e-3 to millimeter.
	 *   If this value is 1, this unit will be treated as the standard one in this category.
	 * @param {Hash} extraParams Additional information of unit.
	 * @returns {Object} Unit object created.
	 */
	register: function(symbol, name, category, rateToStandard, extraParams)
	{
		var categoryObj = KU[category];
		if (!categoryObj)
		{
			categoryObj = KU._createCategoryObj(category);
			KU[category] = categoryObj;
		}
		var id = name.toUpperCase();
		categoryObj[id] = KU._createUnitObj(symbol, name, categoryObj, rateToStandard, extraParams);
		if (rateToStandard === 1)
			categoryObj.setStandardUnit(categoryObj[id]);
		KU.ALL[id] = categoryObj[id];  // also set ALL value
		KU._KEY_MAP[categoryObj[id].getKey()] = categoryObj[id];  // register a key map item
		return categoryObj[id];
	},
	/**
	 * Unregister a unit object from category.
	 * @param {Object} symbolOrId
	 */
	unregister: function(symbolOrId)
	{
		var unitObj = KU.getUnit(symbolOrId);
		if (unitObj)
		{
			var id = unitObj.getKey().toUpperCase();
			delete KU.ALL[id];
			delete KU._KEY_MAP[id];
			var category = unitObj.category;
			delete category[id];
		}
	},
	/**
	 * Returns an unit object.
	 * @param {String} key
	 * @returns {Object}
	 */
	getUnit: function(key)
	{
		if (typeof(key) === 'object')  // already an object?
			return key.getKey? key: null;
		else
			return KU._KEY_MAP[key];
	},

	/** @private */
	_createCategoryObj: function(category)
	{
		var result = Object.create(KU._categoryObjProto);
		result.name = category;
		return result;
	},
	/** @private */
	_createUnitObj: function(symbol, name, categoryObj, rateToStandard, params)
	{
		var result = Object.create(Kekule.Unit._unitObjProto);
		Object.extend(result, {
			'symbol': symbol,
			'name': name,
			'category': categoryObj,
			'rateToStandard': rateToStandard
		});
		if (params)
			Object.extend(result, params);
		return result;
	}
};
var KU = Kekule.Unit;

/**
 * Prototype of unit category objects.
 * @object
 * @private
 */
Kekule.Unit._categoryObjProto = {
	getName: function()
	{
		return this.name;
	},
	getStandardUnit: function()
	{
		return this._standardUnit;
	},
	setStandardUnit: function(unitObj)
	{
		this._standardUnit = unitObj;
	}
};

/**
 * Prototype of all unit objects.
 * @object
 * @private
 */
Kekule.Unit._unitObjProto = {
	getKey: function()
	{
		return this.symbol || this.name;
	},
	/**
	 * Check whether this object is the standard one in category.
	 * @returns {Bool}
	 */
	isStandard: function()
	{
		return this.rateToStandard === 1;
	},
	/**
	 * Returns the value with this unit can be converted to another unit.
	 * @param {Pbject} toUnitObj
	 * @param {Hash} extraParams
	 * @returns {Bool}
	 */
	canConvertValueTo: function(toUnitObj, extraParams)
	{
		return (toUnitObj.category === this.category);
	},
	/**
	 * Convert a value with this unit to another one.
	 * @param {Number} value
	 * @param {Variant} toUnit Unit object or name.
	 * @param {Hash} extraParams
	 * @returns {Number}
	 */
	convertValueTo: function(value, toUnit, extraParams)
	{
		var toUnitObj = (typeof(toUnit) === 'string')? KU.getUnit(toUnit): toUnit;
		if (toUnitObj)
		{
			return this.doConvertValueTo(value, toUnitObj, extraParams);
		}
		else
		{
			Kekule.error(Kekule.$L('ErrorMsg.UNIT_NOT_FOUND').format(toUnit.symbol || toUnit.name || toUnit));
		}
	},
	/** @private */
	doConvertValueTo: function(value, toUnitObj, extraParams)
	{
		// check if category is same
		if (/*toUnitObj.category !== this.category*/ !this.canConvertValueTo(toUnitObj, extraParams))  // defaultly we can not convert this
			Kekule.error(Kekule.$L('ErrorMsg.UNABLE_TO_CONVERT_BETWEEN_UNITS').format(this.getKey(), toUnitObj.getKey()));
		else
		{
			var r1 = toUnitObj.rateToStandard;
			var r0 = this.rateToStandard;
			if (!r1 || !r0)
				Kekule.error(Kekule.$L('ErrorMsg.UNABLE_TO_CONVERT_BETWEEN_UNITS').format(this.getKey(), toUnitObj.getKey()));
			else
			{
				return value * r0 / r1;
			}
		}
	}
};

/**
 * Util methods about metrics units.
 * @class
 */
Kekule.UnitUtils = {
	/**
	 * Convert to a value based with another unit.
	 * @param {Number} fromValue
	 * @param {Variant} fromUnit String or unit object.
	 * @param {Variant} toUnit String or unit object.
	 * @param {Hash} extraParams
	 * @returns {Number}
	 */
	convertValue: function(fromValue, fromUnit, toUnit, extraParams)
	{
		var fuObj = KU.getUnit(fromUnit);
		return fuObj.convertValueTo(fromValue, toUnit, extraParams);
	}
};

var register = KU.register;

// register common used units
register('', 'arbitrary', 'General', null);

register('', 'one', 'Ratio', 1);
register('%', 'percent', 'Ratio', 1e-2);
register('‰', 'thousandth', 'Ratio', 1e-3);
register('ppm', 'millionth', 'Ratio', 1e-6);

register('hr', 'hour', 'Time', 3600);
register('min', 'minute', 'Time', 60);
register('sec', 'second', 'Time', 1);
register('ms', 'millisecond', 'Time', 1e-3);
register('μs', 'microsecond', 'Time', 1e-6);
register('ns', 'nanosecond', 'Time', 1e-9);

register('m', 'meter', 'Length', 1);
register('cm', 'centimeter', 'Length', 1e-2);
register('mm', 'millimeter', 'Length', 1e-3);
register('μm', 'micrometer', 'Length', 1e-6);
register('mm', 'nanometer', 'Length', 1e-9);
register('Å', 'angstrom', 'Length', 1e-10);

register('mol', 'mole', 'AmountOfSubstance', 1);

register('g', 'gram', 'Weight', 1);
register('kg', 'kilogram', 'Weight', 1e3);

register('K', 'kelvin', 'Temperature', 1);

register('A', 'ampere', 'ElectricCurrent', 1);
register('μA', 'microampere', 'ElectricCurrent', 1e-6);
register('nA', 'nanoampere', 'ElectricCurrent', 1e-9);
register('pA', 'picoampere', 'ElectricCurrent', 1e-12);

register('V', 'volts', 'ElectricVoltage', 1);

register('Hz', 'hertz', 'Frequency', 1);
register('kHz', 'kilohertz', 'Frequency', 1e3);
register('MHz', 'megahertz', 'Frequency', 1e6);

})();<commit_msg>Fix a typo<commit_after>/**
 * @fileoverview
 * Constants and functions about basic metrics.
 * @author Partridge Jiang
 */

/*
 * requires /lan/classes.js
 * requires /core/kekule.root.js
 * requires /localization
 */

(function(){

"use strict";

/**
 * Root name space for units.
 * @namespace
 */
Kekule.Unit = {
	/** @private */
	ALL: {},
	/** @private */
	_KEY_MAP: {},
	/**
	 * Register a unit.
	 * After register, a Kekule.Unit[category][name.capitalized] will be set with value symbol (e.g., Kekule.Unit.Frequency.HERTZ = 'Hz').
	 * @param {String} symbol The symbol of unit, e.g. 'Hz'.
	 *   This value will be regarded as key of unit. If this value is empty, name will be regarded as key instead.
	 * @param {String} name Name of unit, e.g., 'Hertz'.
	 * @param {String} category Category of unit, e.g. 'Frequency'.
	 *   Note the first letter of category is recommended to be capitalized.
	 * @param {Number} rateToStandard The conversion rate to SI standard unit in this category.
	 *   For example, this value should be 1e-3 to millimeter.
	 *   If this value is 1, this unit will be treated as the standard one in this category.
	 * @param {Hash} extraParams Additional information of unit.
	 * @returns {Object} Unit object created.
	 */
	register: function(symbol, name, category, rateToStandard, extraParams)
	{
		var categoryObj = KU[category];
		if (!categoryObj)
		{
			categoryObj = KU._createCategoryObj(category);
			KU[category] = categoryObj;
		}
		var id = name.toUpperCase();
		categoryObj[id] = KU._createUnitObj(symbol, name, categoryObj, rateToStandard, extraParams);
		if (rateToStandard === 1)
			categoryObj.setStandardUnit(categoryObj[id]);
		KU.ALL[id] = categoryObj[id];  // also set ALL value
		KU._KEY_MAP[categoryObj[id].getKey()] = categoryObj[id];  // register a key map item
		return categoryObj[id];
	},
	/**
	 * Unregister a unit object from category.
	 * @param {Object} symbolOrId
	 */
	unregister: function(symbolOrId)
	{
		var unitObj = KU.getUnit(symbolOrId);
		if (unitObj)
		{
			var id = unitObj.getKey().toUpperCase();
			delete KU.ALL[id];
			delete KU._KEY_MAP[id];
			var category = unitObj.category;
			delete category[id];
		}
	},
	/**
	 * Returns an unit object.
	 * @param {String} key
	 * @returns {Object}
	 */
	getUnit: function(key)
	{
		if (typeof(key) === 'object')  // already an object?
			return key.getKey? key: null;
		else
			return KU._KEY_MAP[key];
	},

	/** @private */
	_createCategoryObj: function(category)
	{
		var result = Object.create(KU._categoryObjProto);
		result.name = category;
		return result;
	},
	/** @private */
	_createUnitObj: function(symbol, name, categoryObj, rateToStandard, params)
	{
		var result = Object.create(Kekule.Unit._unitObjProto);
		Object.extend(result, {
			'symbol': symbol,
			'name': name,
			'category': categoryObj,
			'rateToStandard': rateToStandard
		});
		if (params)
			Object.extend(result, params);
		return result;
	}
};
var KU = Kekule.Unit;

/**
 * Prototype of unit category objects.
 * @object
 * @private
 */
Kekule.Unit._categoryObjProto = {
	getName: function()
	{
		return this.name;
	},
	getStandardUnit: function()
	{
		return this._standardUnit;
	},
	setStandardUnit: function(unitObj)
	{
		this._standardUnit = unitObj;
	}
};

/**
 * Prototype of all unit objects.
 * @object
 * @private
 */
Kekule.Unit._unitObjProto = {
	getKey: function()
	{
		return this.symbol || this.name;
	},
	/**
	 * Check whether this object is the standard one in category.
	 * @returns {Bool}
	 */
	isStandard: function()
	{
		return this.rateToStandard === 1;
	},
	/**
	 * Returns the value with this unit can be converted to another unit.
	 * @param {Object} toUnitObj
	 * @param {Hash} extraParams
	 * @returns {Bool}
	 */
	canConvertValueTo: function(toUnitObj, extraParams)
	{
		return (toUnitObj.category === this.category);
	},
	/**
	 * Convert a value with this unit to another one.
	 * @param {Number} value
	 * @param {Variant} toUnit Unit object or name.
	 * @param {Hash} extraParams
	 * @returns {Number}
	 */
	convertValueTo: function(value, toUnit, extraParams)
	{
		var toUnitObj = (typeof(toUnit) === 'string')? KU.getUnit(toUnit): toUnit;
		if (toUnitObj)
		{
			return this.doConvertValueTo(value, toUnitObj, extraParams);
		}
		else
		{
			Kekule.error(Kekule.$L('ErrorMsg.UNIT_NOT_FOUND').format(toUnit.symbol || toUnit.name || toUnit));
		}
	},
	/** @private */
	doConvertValueTo: function(value, toUnitObj, extraParams)
	{
		// check if category is same
		if (/*toUnitObj.category !== this.category*/ !this.canConvertValueTo(toUnitObj, extraParams))  // defaultly we can not convert this
			Kekule.error(Kekule.$L('ErrorMsg.UNABLE_TO_CONVERT_BETWEEN_UNITS').format(this.getKey(), toUnitObj.getKey()));
		else
		{
			var r1 = toUnitObj.rateToStandard;
			var r0 = this.rateToStandard;
			if (!r1 || !r0)
				Kekule.error(Kekule.$L('ErrorMsg.UNABLE_TO_CONVERT_BETWEEN_UNITS').format(this.getKey(), toUnitObj.getKey()));
			else
			{
				return value * r0 / r1;
			}
		}
	}
};

/**
 * Util methods about metrics units.
 * @class
 */
Kekule.UnitUtils = {
	/**
	 * Convert to a value based with another unit.
	 * @param {Number} fromValue
	 * @param {Variant} fromUnit String or unit object.
	 * @param {Variant} toUnit String or unit object.
	 * @param {Hash} extraParams
	 * @returns {Number}
	 */
	convertValue: function(fromValue, fromUnit, toUnit, extraParams)
	{
		var fuObj = KU.getUnit(fromUnit);
		return fuObj.convertValueTo(fromValue, toUnit, extraParams);
	}
};

var register = KU.register;

// register common used units
register('', 'arbitrary', 'General', null);

register('', 'one', 'Ratio', 1);
register('%', 'percent', 'Ratio', 1e-2);
register('‰', 'thousandth', 'Ratio', 1e-3);
register('ppm', 'millionth', 'Ratio', 1e-6);

register('hr', 'hour', 'Time', 3600);
register('min', 'minute', 'Time', 60);
register('sec', 'second', 'Time', 1);
register('ms', 'millisecond', 'Time', 1e-3);
register('μs', 'microsecond', 'Time', 1e-6);
register('ns', 'nanosecond', 'Time', 1e-9);

register('m', 'meter', 'Length', 1);
register('cm', 'centimeter', 'Length', 1e-2);
register('mm', 'millimeter', 'Length', 1e-3);
register('μm', 'micrometer', 'Length', 1e-6);
register('mm', 'nanometer', 'Length', 1e-9);
register('Å', 'angstrom', 'Length', 1e-10);

register('mol', 'mole', 'AmountOfSubstance', 1);

register('g', 'gram', 'Weight', 1);
register('kg', 'kilogram', 'Weight', 1e3);

register('K', 'kelvin', 'Temperature', 1);

register('A', 'ampere', 'ElectricCurrent', 1);
register('μA', 'microampere', 'ElectricCurrent', 1e-6);
register('nA', 'nanoampere', 'ElectricCurrent', 1e-9);
register('pA', 'picoampere', 'ElectricCurrent', 1e-12);

register('V', 'volts', 'ElectricVoltage', 1);

register('Hz', 'hertz', 'Frequency', 1);
register('kHz', 'kilohertz', 'Frequency', 1e3);
register('MHz', 'megahertz', 'Frequency', 1e6);

})();<|endoftext|>