<commit_before>var d3 = require('d3'),
    dl = require('datalib'),
    df = require('vega-dataflow'),
    sg = require('vega-scenegraph').render,
    log = require('vega-logging'),
    Deps = df.Dependencies,
    parseStreams = require('../parse/streams'),
    Encoder = require('../scene/Encoder'),
    Transition = require('../scene/Transition');

function View(el, width, height) {
  this._el    = null;
  this._model = null;
  this._width   = this.__width = width || 500;
  this._height  = this.__height = height || 300;
  this._bgcolor = null;
  this._autopad = 1;
  this._padding = {top:0, left:0, bottom:0, right:0};
  this._viewport = null;
  this._renderer = null;
  this._handler  = null;
  this._streamer = null; // Targeted update for streaming changes
  this._changeset = null;
  this._repaint = true; // Full re-render on every re-init
  this._renderers = sg;
  this._io  = null;
  this._api = {}; // Stash streaming data API sandboxes.
}

var prototype = View.prototype;

prototype.model = function(model) {
  if (!arguments.length) return this._model;
  if (this._model !== model) {
    this._model = model;
    this._streamer = new df.Node(model);
    this._streamer._rank = -1;  // HACK: To reduce re-ranking churn.
    this._changeset = df.ChangeSet.create();
    if (this._handler) this._handler.model(model);
  }
  return this;
};

// Sandboxed streaming data API
function streaming(src) {
  var view = this,
      ds = this._model.data(src),
      name = ds.name(),
      listener = ds.pipeline()[0],
      streamer = this._streamer,
      api = {};

  // If we have it stashed, don't create a new closure.
  if (this._api[src]) return this._api[src];

  api.insert = function(vals) {
    ds.insert(dl.duplicate(vals));  // Don't pollute the environment
    streamer.addListener(listener);
    view._changeset.data[name] = 1;
    return api;
  };

  api.update = function() {
    streamer.addListener(listener);
    view._changeset.data[name] = 1;
    return (ds.update.apply(ds, arguments), api);
  };

  api.remove = function() {
    streamer.addListener(listener);
    view._changeset.data[name] = 1;
    return (ds.remove.apply(ds, arguments), api);
  };

  api.values = function() { return ds.values(); };

  return (this._api[src] = api);
}

prototype.data = function(data) {
  var v = this;
  if (!arguments.length) return v._model.values();
  else if (dl.isString(data)) return streaming.call(v, data);
  else if (dl.isObject(data)) {
    dl.keys(data).forEach(function(k) {
      var api = streaming.call(v, k);
      data[k](api);
    });
  }
  return this;
};

prototype.signal = function(name, value, propagate) {
  var m  = this._model,
      cs = this._changeset,
      streamer = this._streamer,
      batch;

  // Getter. Returns the value for the specified signal, or
  // returns all signal values.
  if (!arguments.length) {
    return m.values(Deps.SIGNALS);
  } else if (arguments.length === 1 && dl.isString(name)) {
    return m.values(Deps.SIGNALS, name);
  }

  // Setter. Can be done in batch or individually. In either case,
  // the final argument determines if set values should propagate.
  if (dl.isObject(name)) {
    batch = name;
    propagate = value;
  } else {
    batch = {};
    batch[name] = value;
  }

  dl.keys(batch).forEach(function(k) {
    streamer.addListener(m.signal(k).value(batch[k]));
    if (propagate !== false) cs.signals[k] = 1;
    cs.reflow = true;
  });

  return this;
};

prototype.width = function(width) {
  if (!arguments.length) return this.__width;
  if (this.__width !== width) {
    this._width = this.__width = width;
    this.model().width(width);
    this.initialize();
    if (this._strict) this._autopad = 1;
    this.signal('width', width);
  }
  return this;
};

prototype.height = function(height) {
  if (!arguments.length) return this.__height;
  if (this.__height !== height) {
    this._height = this.__height = height;
    this.model().height(height);
    this.initialize();
    if (this._strict) this._autopad = 1;
    this.signal('height', height);
  }
  return this;
};

prototype.background = function(bgcolor) {
  if (!arguments.length) return this._bgcolor;
  if (this._bgcolor !== bgcolor) {
    this._bgcolor = bgcolor;
    this.initialize();
  }
  return this;
};

prototype.padding = function(pad) {
  if (!arguments.length) return this._padding;
  if (this._padding !== pad) {
    if (dl.isString(pad)) {
      this._autopad = 1;
      this._padding = {top:0, left:0, bottom:0, right:0};
      this._strict = (pad === 'strict');
    } else {
      this._autopad = 0;
      this._padding = pad;
      this._strict = false;
    }
    if (this._renderer) this._renderer.resize(this._width, this._height, this._padding);
    if (this._handler)  this._handler.padding(this._padding);
    this.signal('padding', this._padding);
  }
  return (this._repaint = true, this);
};

prototype.autopad = function(opt) {
  if (this._autopad < 1) return this;
  else this._autopad = 0;

  var b = this.model().scene().bounds,
      pad = this._padding,
      config = this.model().config(),
      inset = config.autopadInset,
      l = b.x1 < 0 ? Math.ceil(-b.x1) + inset : 0,
      t = b.y1 < 0 ? Math.ceil(-b.y1) + inset : 0,
      r = b.x2 > this._width  ? Math.ceil(+b.x2 - this._width) + inset : 0;
  b = b.y2 > this._height ? Math.ceil(+b.y2 - this._height) + inset : 0;
  pad = {left:l, top:t, right:r, bottom:b};

  if (this._strict) {
    this._autopad = 0;
    this._padding = pad;
    this._width = Math.max(0, this.__width - (l+r));
    this._height = Math.max(0, this.__height - (t+b));

    this._model.width(this._width).height(this._height).reset();
    this.signal('width', this._width);
    this.signal('height', this._height);
    this.signal('padding', pad);

    this.initialize().update({props:'enter'}).update({props:'update'});
  } else {
    this.padding(pad).update(opt);
  }
  return this;
};

prototype.viewport = function(size) {
  if (!arguments.length) return this._viewport;
  if (this._viewport !== size) {
    this._viewport = size;
    this.initialize();
  }
  return this;
};

prototype.renderer = function(type) {
  if (!arguments.length) return this._renderer;
  if (this._renderers[type]) type = this._renderers[type];
  else if (dl.isString(type)) throw new Error('Unknown renderer: ' + type);
  else if (!type) throw new Error('No renderer specified');

  if (this._io !== type) {
    this._io = type;
    this._renderer = null;
    this.initialize();
    if (this._build) this.render();
  }
  return this;
};

prototype.initialize = function(el) {
  var v = this, prevHandler,
      w = v._width, h = v._height, pad = v._padding, bg = v._bgcolor,
      config = this.model().config();

  if (!arguments.length || el === null) {
    el = this._el ? this._el.parentNode : null;
    if (!el) return this;  // This View cannot init w/o an
  }

  // clear pre-existing container
  d3.select(el).select('div.vega').remove();

  // add div container
  this._el = el = d3.select(el)
    .append('div')
    .attr('class', 'vega')
    .style('position', 'relative')
    .node();
  if (v._viewport) {
    d3.select(el)
      .style('width',  (v._viewport[0] || w)+'px')
      .style('height', (v._viewport[1] || h)+'px')
      .style('overflow', 'auto');
  }

  // renderer
  sg.canvas.Renderer.RETINA = config.render.retina;
  v._renderer = (v._renderer || new this._io.Renderer(config.load))
    .initialize(el, w, h, pad)
    .background(bg);

  // input handler
  prevHandler = v._handler;
  v._handler = new this._io.Handler()
    .initialize(el, pad, v);

  if (prevHandler) {
    prevHandler.handlers().forEach(function(h) {
      v._handler.on(h.type, h.handler);
    });
  } else {
    // Register event listeners for signal stream definitions.
    v._detach = parseStreams(this);
  }

  return (this._repaint = true, this);
};

prototype.destroy = function() {
  if (this._detach) this._detach();
};

function build() {
  var v = this;
  v._renderNode = new df.Node(v._model)
    .router(true);

  v._renderNode.evaluate = function(input) {
    log.debug(input, ['rendering']);

    var s = v._model.scene(),
        h = v._handler;

    if (h && h.scene) h.scene(s);

    if (input.trans) {
      input.trans.start(function(items) { v._renderer.render(s, items); });
    } else if (v._repaint) {
      v._renderer.render(s);
      v._repaint = false;
    } else if (input.dirty.length) {
      v._renderer.render(s, input.dirty);
    }

    if (input.dirty.length) {
      input.dirty.forEach(function(i) { i._dirty = false; });
      s.items[0]._dirty = false;
    }

    // For all updated datasources, clear their previous values.
    for (var d in input.data) { v._model.data(d).synchronize(); }
    return input;
  };

  return (v._model.scene(v._renderNode), true);
}

prototype.update = function(opt) {
  opt = opt || {};
  var v = this,
      trans = opt.duration ? new Transition(opt.duration, opt.ease) : null;

  var cs = v._changeset;
  if (trans) cs.trans = trans;
  if (opt.props !== undefined) {
    if (dl.keys(cs.data).length > 0) {
      throw Error(
        'New data values are not reflected in the visualization.' +
        ' Please call view.update() before updating a specified property set.'
      );
    }

    cs.reflow  = true;
    cs.request = opt.props;
  }

  var built = v._build;
  v._build = v._build || build.call(this);

  // If specific items are specified, short-circuit dataflow graph.
  // Else-If there are streaming updates, perform a targeted propagation.
  // Otherwise, re-evaluate the entire model (datasources + scene).
  if (opt.items && built) {
    Encoder.update(this._model, opt.trans, opt.props, opt.items, cs.dirty);
    v._renderNode.evaluate(cs);
  } else if (v._streamer.listeners().length && built) {
    if (this._repaint) {
      // Include re-evaluation entire model when repaint flag is set
      v._streamer.addListener(v._model.node());
    }
    v._model.propagate(cs, v._streamer);
    v._streamer.disconnect();
  } else {
    v._model.fire(cs);
  }

  v._changeset = df.ChangeSet.create();

  return v.autopad(opt);
};

prototype.toImageURL = function(type) {
  var v = this, Renderer;

  // lookup appropriate renderer
  switch (type || 'png') {
    case 'canvas':
    case 'png':
      Renderer = sg.canvas.Renderer; break;
    case 'svg':
      Renderer = sg.svg.string.Renderer; break;
    default: throw Error('Unrecognized renderer type: ' + type);
  }

  var retina = sg.canvas.Renderer.RETINA;
  sg.canvas.Renderer.RETINA = false; // ignore retina screen

  // render the scenegraph
  var ren = new Renderer(v._model.config.load)
    .initialize(null, v._width, v._height, v._padding)
    .render(v._model.scene());

  sg.canvas.Renderer.RETINA = retina; // restore retina settings

  // return data url
  if (type === 'svg') {
    var blob = new Blob([ren.svg()], {type: 'image/svg+xml'});
    return window.URL.createObjectURL(blob);
  } else {
    return ren.canvas().toDataURL('image/png');
  }
};

prototype.render = function(items) {
  this._renderer.render(this._model.scene(), items);
  return this;
};

prototype.on = function() {
  this._handler.on.apply(this._handler, arguments);
  return this;
};

prototype.onSignal = function(name, handler) {
  this._model.signal(name).on(handler);
  return this;
};

prototype.off = function() {
  this._handler.off.apply(this._handler, arguments);
  return this;
};

prototype.offSignal = function(name, handler) {
  this._model.signal(name).off(handler);
  return this;
};

View.factory = function(model) {
  var HeadlessView = require('./HeadlessView');
  return function(opt) {
    opt = opt || {};
    var defs = model.defs();
    var v = (opt.el ? new View() : new HeadlessView())
      .model(model)
      .renderer(opt.renderer || 'canvas')
      .width(defs.width)
      .height(defs.height)
      .background(defs.background)
      .padding(defs.padding)
      .viewport(defs.viewport)
      .initialize(opt.el);

    if (opt.data) v.data(opt.data);

    if (opt.hover !== false && opt.el) {
      v.on('mouseover', function(evt, item) {
        if (item && item.hasPropertySet('hover')) {
          this.update({props:'hover', items:item});
        }
      })
      .on('mouseout', function(evt, item) {
        if (item && item.hasPropertySet('hover')) {
          this.update({props:'update', items:item});
        }
      });
    }

    return v;
  };
};

module.exports = View;
<commit_msg>Handle width/height/padding updates through signal API.<commit_after>var d3 = require('d3'),
    dl = require('datalib'),
    df = require('vega-dataflow'),
    sg = require('vega-scenegraph').render,
    log = require('vega-logging'),
    Deps = df.Dependencies,
    parseStreams = require('../parse/streams'),
    Encoder = require('../scene/Encoder'),
    Transition = require('../scene/Transition');

function View(el, width, height) {
  this._el    = null;
  this._model = null;
  this._width   = this.__width = width || 500;
  this._height  = this.__height = height || 300;
  this._bgcolor = null;
  this._autopad = 1;
  this._padding = {top:0, left:0, bottom:0, right:0};
  this._viewport = null;
  this._renderer = null;
  this._handler  = null;
  this._streamer = null; // Targeted update for streaming changes
  this._changeset = null;
  this._repaint = true; // Full re-render on every re-init
  this._renderers = sg;
  this._io  = null;
  this._api = {}; // Stash streaming data API sandboxes.
}

var prototype = View.prototype;

prototype.model = function(model) {
  if (!arguments.length) return this._model;
  if (this._model !== model) {
    this._model = model;
    this._streamer = new df.Node(model);
    this._streamer._rank = -1;  // HACK: To reduce re-ranking churn.
    this._changeset = df.ChangeSet.create();
    if (this._handler) this._handler.model(model);
  }
  return this;
};

// Sandboxed streaming data API
function streaming(src) {
  var view = this,
      ds = this._model.data(src),
      name = ds.name(),
      listener = ds.pipeline()[0],
      streamer = this._streamer,
      api = {};

  // If we have it stashed, don't create a new closure.
  if (this._api[src]) return this._api[src];

  api.insert = function(vals) {
    ds.insert(dl.duplicate(vals));  // Don't pollute the environment
    streamer.addListener(listener);
    view._changeset.data[name] = 1;
    return api;
  };

  api.update = function() {
    streamer.addListener(listener);
    view._changeset.data[name] = 1;
    return (ds.update.apply(ds, arguments), api);
  };

  api.remove = function() {
    streamer.addListener(listener);
    view._changeset.data[name] = 1;
    return (ds.remove.apply(ds, arguments), api);
  };

  api.values = function() { return ds.values(); };

  return (this._api[src] = api);
}

prototype.data = function(data) {
  var v = this;
  if (!arguments.length) return v._model.values();
  else if (dl.isString(data)) return streaming.call(v, data);
  else if (dl.isObject(data)) {
    dl.keys(data).forEach(function(k) {
      var api = streaming.call(v, k);
      data[k](api);
    });
  }
  return this;
};

var VIEW_SIGNALS = dl.toMap(['width', 'height', 'padding']);

prototype.signal = function(name, value, propagate) {
  var m = this._model,
      key, values;

  // Getter. Returns the value for the specified signal, or
  // returns all signal values.
  if (!arguments.length) {
    return m.values(Deps.SIGNALS);
  } else if (arguments.length === 1 && dl.isString(name)) {
    return m.values(Deps.SIGNALS, name);
  }

  // Setter. Can be done in batch or individually. In either case,
  // the final argument determines if set values should propagate.
  if (dl.isObject(name)) {
    values = name;
    propagate = value;
  } else {
    values = {};
    values[name] = value;
  }
  for (key in values) {
    if (VIEW_SIGNALS[key]) {
      this[key](values[key]);
    } else {
      this._setSignal(key, values[key], propagate);
    }
  }
  return this;
};

prototype._setSignal = function(name, value, propagate) {
  var cs = this._changeset;
  this._streamer.addListener(this._model.signal(name).value(value));
  if (propagate !== false) cs.signals[name] = 1;
  cs.reflow = true;
};

prototype.width = function(width) {
  if (!arguments.length) return this.__width;
  if (this.__width !== width) {
    this._width = this.__width = width;
    this.model().width(width);
    this.initialize();
    if (this._strict) this._autopad = 1;
    this._setSignal('width', width);
  }
  return this;
};

prototype.height = function(height) {
  if (!arguments.length) return this.__height;
  if (this.__height !== height) {
    this._height = this.__height = height;
    this.model().height(height);
    this.initialize();
    if (this._strict) this._autopad = 1;
    this._setSignal('height', height);
  }
  return this;
};

prototype.background = function(bgcolor) {
  if (!arguments.length) return this._bgcolor;
  if (this._bgcolor !== bgcolor) {
    this._bgcolor = bgcolor;
    this.initialize();
  }
  return this;
};

prototype.padding = function(pad) {
  if (!arguments.length) return this._padding;
  if (this._padding !== pad) {
    if (dl.isString(pad)) {
      this._autopad = 1;
      this._padding = {top:0, left:0, bottom:0, right:0};
      this._strict = (pad === 'strict');
    } else {
      this._autopad = 0;
      this._padding = pad;
      this._strict = false;
    }
    if (this._renderer) this._renderer.resize(this._width, this._height, this._padding);
    if (this._handler)  this._handler.padding(this._padding);
    this._setSignal('padding', this._padding);
  }
  return (this._repaint = true, this);
};

prototype.autopad = function(opt) {
  if (this._autopad < 1) return this;
  else this._autopad = 0;

  var b = this.model().scene().bounds,
      pad = this._padding,
      config = this.model().config(),
      inset = config.autopadInset,
      l = b.x1 < 0 ? Math.ceil(-b.x1) + inset : 0,
      t = b.y1 < 0 ? Math.ceil(-b.y1) + inset : 0,
      r = b.x2 > this._width  ? Math.ceil(+b.x2 - this._width) + inset : 0;
  b = b.y2 > this._height ? Math.ceil(+b.y2 - this._height) + inset : 0;
  pad = {left:l, top:t, right:r, bottom:b};

  if (this._strict) {
    this._autopad = 0;
    this._padding = pad;
    this._width = Math.max(0, this.__width - (l+r));
    this._height = Math.max(0, this.__height - (t+b));

    this._model.width(this._width).height(this._height).reset();
    this._setSignal('width', this._width);
    this._setSignal('height', this._height);
    this._setSignal('padding', pad);

    this.initialize().update({props:'enter'}).update({props:'update'});
  } else {
    this.padding(pad).update(opt);
  }
  return this;
};

prototype.viewport = function(size) {
  if (!arguments.length) return this._viewport;
  if (this._viewport !== size) {
    this._viewport = size;
    this.initialize();
  }
  return this;
};

prototype.renderer = function(type) {
  if (!arguments.length) return this._renderer;
  if (this._renderers[type]) type = this._renderers[type];
  else if (dl.isString(type)) throw new Error('Unknown renderer: ' + type);
  else if (!type) throw new Error('No renderer specified');

  if (this._io !== type) {
    this._io = type;
    this._renderer = null;
    this.initialize();
    if (this._build) this.render();
  }
  return this;
};

prototype.initialize = function(el) {
  var v = this, prevHandler,
      w = v._width, h = v._height, pad = v._padding, bg = v._bgcolor,
      config = this.model().config();

  if (!arguments.length || el === null) {
    el = this._el ? this._el.parentNode : null;
    if (!el) return this;  // This View cannot init w/o an
  }

  // clear pre-existing container
  d3.select(el).select('div.vega').remove();

  // add div container
  this._el = el = d3.select(el)
    .append('div')
    .attr('class', 'vega')
    .style('position', 'relative')
    .node();
  if (v._viewport) {
    d3.select(el)
      .style('width',  (v._viewport[0] || w)+'px')
      .style('height', (v._viewport[1] || h)+'px')
      .style('overflow', 'auto');
  }

  // renderer
  sg.canvas.Renderer.RETINA = config.render.retina;
  v._renderer = (v._renderer || new this._io.Renderer(config.load))
    .initialize(el, w, h, pad)
    .background(bg);

  // input handler
  prevHandler = v._handler;
  v._handler = new this._io.Handler()
    .initialize(el, pad, v);

  if (prevHandler) {
    prevHandler.handlers().forEach(function(h) {
      v._handler.on(h.type, h.handler);
    });
  } else {
    // Register event listeners for signal stream definitions.
    v._detach = parseStreams(this);
  }

  return (this._repaint = true, this);
};

prototype.destroy = function() {
  if (this._detach) this._detach();
};

function build() {
  var v = this;
  v._renderNode = new df.Node(v._model)
    .router(true);

  v._renderNode.evaluate = function(input) {
    log.debug(input, ['rendering']);

    var s = v._model.scene(),
        h = v._handler;

    if (h && h.scene) h.scene(s);

    if (input.trans) {
      input.trans.start(function(items) { v._renderer.render(s, items); });
    } else if (v._repaint) {
      v._renderer.render(s);
      v._repaint = false;
    } else if (input.dirty.length) {
      v._renderer.render(s, input.dirty);
    }

    if (input.dirty.length) {
      input.dirty.forEach(function(i) { i._dirty = false; });
      s.items[0]._dirty = false;
    }

    // For all updated datasources, clear their previous values.
    for (var d in input.data) { v._model.data(d).synchronize(); }
    return input;
  };

  return (v._model.scene(v._renderNode), true);
}

prototype.update = function(opt) {
  opt = opt || {};
  var v = this,
      trans = opt.duration ? new Transition(opt.duration, opt.ease) : null;

  var cs = v._changeset;
  if (trans) cs.trans = trans;
  if (opt.props !== undefined) {
    if (dl.keys(cs.data).length > 0) {
      throw Error(
        'New data values are not reflected in the visualization.' +
        ' Please call view.update() before updating a specified property set.'
      );
    }

    cs.reflow  = true;
    cs.request = opt.props;
  }

  var built = v._build;
  v._build = v._build || build.call(this);

  // If specific items are specified, short-circuit dataflow graph.
  // Else-If there are streaming updates, perform a targeted propagation.
  // Otherwise, re-evaluate the entire model (datasources + scene).
  if (opt.items && built) {
    Encoder.update(this._model, opt.trans, opt.props, opt.items, cs.dirty);
    v._renderNode.evaluate(cs);
  } else if (v._streamer.listeners().length && built) {
    if (this._repaint) {
      // Include re-evaluation entire model when repaint flag is set
      v._streamer.addListener(v._model.node());
    }
    v._model.propagate(cs, v._streamer);
    v._streamer.disconnect();
  } else {
    v._model.fire(cs);
  }

  v._changeset = df.ChangeSet.create();

  return v.autopad(opt);
};

prototype.toImageURL = function(type) {
  var v = this, Renderer;

  // lookup appropriate renderer
  switch (type || 'png') {
    case 'canvas':
    case 'png':
      Renderer = sg.canvas.Renderer; break;
    case 'svg':
      Renderer = sg.svg.string.Renderer; break;
    default: throw Error('Unrecognized renderer type: ' + type);
  }

  var retina = sg.canvas.Renderer.RETINA;
  sg.canvas.Renderer.RETINA = false; // ignore retina screen

  // render the scenegraph
  var ren = new Renderer(v._model.config.load)
    .initialize(null, v._width, v._height, v._padding)
    .render(v._model.scene());

  sg.canvas.Renderer.RETINA = retina; // restore retina settings

  // return data url
  if (type === 'svg') {
    var blob = new Blob([ren.svg()], {type: 'image/svg+xml'});
    return window.URL.createObjectURL(blob);
  } else {
    return ren.canvas().toDataURL('image/png');
  }
};

prototype.render = function(items) {
  this._renderer.render(this._model.scene(), items);
  return this;
};

prototype.on = function() {
  this._handler.on.apply(this._handler, arguments);
  return this;
};

prototype.onSignal = function(name, handler) {
  this._model.signal(name).on(handler);
  return this;
};

prototype.off = function() {
  this._handler.off.apply(this._handler, arguments);
  return this;
};

prototype.offSignal = function(name, handler) {
  this._model.signal(name).off(handler);
  return this;
};

View.factory = function(model) {
  var HeadlessView = require('./HeadlessView');
  return function(opt) {
    opt = opt || {};
    var defs = model.defs();
    var v = (opt.el ? new View() : new HeadlessView())
      .model(model)
      .renderer(opt.renderer || 'canvas')
      .width(defs.width)
      .height(defs.height)
      .background(defs.background)
      .padding(defs.padding)
      .viewport(defs.viewport)
      .initialize(opt.el);

    if (opt.data) v.data(opt.data);

    if (opt.hover !== false && opt.el) {
      v.on('mouseover', function(evt, item) {
        if (item && item.hasPropertySet('hover')) {
          this.update({props:'hover', items:item});
        }
      })
      .on('mouseout', function(evt, item) {
        if (item && item.hasPropertySet('hover')) {
          this.update({props:'update', items:item});
        }
      });
    }

    return v;
  };
};

module.exports = View;
<|endoftext|>


<commit_before>    //////////////////////////////////////////////////////
   //* The Boot state preloads assets that the preloader
  //* state needs.
 //*
//*
(function() {

    Lilja = {
        gameWidth: 800,
        gameHeight: 600
    };

    Lilja.Booter = function () {

    };

    Lilja.Booter.prototype = {

          ///////{ create loading screen and setup sates }/////////////////////////
         //
        //
        create: function () {
            this.state.add('Preload', Lilja.Preloader);
            this.state.add('Main', Lilja.Main);
        },

          ///////{ Update loading screen }/////////////////////////////////////////
         //
        //
        loadUpdate: function () {
            return;
        },

          ///////{ define loaded resources }////////////////////////////////////////
         //
        //
        preload: function () {
            WebFont.load({
                google: {
                  families: ['VT323']
                }
            });
        },

          ///////{ Start the actual game }//////////////////////////////////////////
         //
        //
        update: function () {
            this.state.start('Preload');
        }
    };

    var game = new Phaser.Game(Lilja.gameWidth, Lilja.gameHeight, Phaser.AUTO, 'lilja-game');
    game.state.add('Boot', Lilja.Booter, true);

})();<commit_msg>Small fix to Boot.<commit_after>    //////////////////////////////////////////////////////
   //* The Boot state preloads assets that the preloader
  //* state needs.
 //*
//*
(function() {

    Lilja = {
        gameWidth: 800,
        gameHeight: 600
    };

    Lilja.Booter = function () {

    };

    Lilja.Booter.prototype = {

          ///////{ create loading screen and setup sates }/////////////////////////
         //
        //
        create: function () {
            this.state.add('Preload', Lilja.Preloader);
            this.state.add('Main', Lilja.Main);
        },

          ///////{ define loaded resources }////////////////////////////////////////
         //
        //
        preload: function () {
            WebFont.load({
                google: {
                  families: ['VT323']
                }
            });
        },

          ///////{ Start the actual game }//////////////////////////////////////////
         //
        //
        update: function () {
            this.state.start('Preload');
        }
    };

    var game = new Phaser.Game(Lilja.gameWidth, Lilja.gameHeight, Phaser.AUTO, 'lilja-game');
    game.state.add('Boot', Lilja.Booter, true);

})();<|endoftext|>


<commit_before>var Game;

(function() {

/*
 * Game
 * ====
 *
 * The main Game constructor
 */

Game = function(options, plugins, categories) {
    if(!options) {
        var options = {};
        console.warn(warnings.noOptionsConstructor);
    }
    if(!plugins) {
        var plugins = [];
        console.warn(warnings.noPluginsConstructor);
    }
    if(!categories) {
        var categories = [];
        console.warn(warnings.noCategoriesConstructor);
    }

    EventEmitter(this);

    this.options    = options;

    this.Assets     = null;
    this.Camera     = null;
    this.Colliders  = null;
    this.Draw       = null;
    this.Sound      = null;
    this.World      = null;
    this.Plugins    = new Plugins(this, plugins);
    this.Categories = new Categories(this, categories);

    this.initTime   = null;
    this.loadTime   = null;
    this.startTime  = null;
    this.pauseTime  = null;
    this.stopTime   = null;

    this.playing    = false;
    this.timer      = null;
    this.frames     = 0;

    return this;
}

/* Setup Engine */
Game.prototype.init = function() {
    this.emit("beforeinit", [this]);
    // Throw an Error if a plugin is missing.
    // If Game[plugin] is null, that plugin is missing
    if(!this.Assets || !this.Camera || !this.Colliders || !this.Draw || !this.Sound || !this.World) {
        console.warn(warnings.missingPluginInit);
    }

    this.initTime = this.Utils.time();
    this.Plugins.Init(this);

    // Attach Draw.domElement to Game
    if(this.Draw && this.Draw.domElement) {
        this.domElement = this.Draw.domElement;
    }
    else {
        console.warn(warnings.noDomElement);
    }

    this.emit("init", [this]);
    return this;
}

/* Setup world */
Game.prototype.load = function() {
    if(!this.initTime) {
        this.init();
    }

    this.emit("beforeload", [this]);

    this.loadTime = this.Utils.time();
    this.Plugins.Load(this);

    this.emit("load", [this]);
    return this;
}

/* Start game loop */
Game.prototype.start = function() {
    if(!this.playing) {
        this.startTime = this.Utils.time();
        if(!this.loadTime) {
            this.load();
        }

        this.emit("beforestart", [this]);

        this.timer = this.requestAnimationFrame(this.Loop);
        this.Loop();

        this.emit("start", [this]);
    }

    return this;
}

Game.prototype.pause = function() {
    if(this.playing) {
        this.emit("beforepause", [this]);
        this.pauseTime = this.Utils.time();
        this.cancelAnimationFrame(this.timer);
        this.emit("pause", [this]);
    }
}

Game.prototype.stop = function() {
    if(this.playing) {
        this.emit("beforestop", [this]);
        this.stopTime = this.Utils.time();
        this.cancelAnimationFrame(this.timer);
        this.emit("beforestopreset");
        this.reset();
        this.emit("stop", [this]);
    }

    return this;
}

Game.prototype.Loop = function() {
    this.emit("beforeframe", [this]);
    this.frames++;

    this.emit("beforeupdate", [this]);
    this.World.Update(this);
    this.Camera.Update(this);

    this.emit("beforedraw", [this]);
    this.World.Draw(this);

    this.emit("frame", [this]);
    return this;
}

Game.prototype.Utils = {
    capitalize: function(str) {
        return str.substr(0,1).toUpperCase() + str.substr(1).toLowerCase();
    },
    merge: function(first, second, blacklist) {
        if(!blacklist) var blacklist = [];

        for(key in second) {
            if(blacklist.indexOf(key) === -1) {
                first[key] = second[key];
            }
        }

        return first;
    },
    toRadians: function(deg) {
        return (deg * Math.PI) / 180;
    },
    toDegrees: function(rad) {
        return (rad * 180) / Math.PI;
    },
    time: (function() {
        if(performance && performance.now) {
            return function() { return performance.now(); }
        } else if(performance && performance.webkitNow) {
            return function() { return performance.webkitNow(); }
        } else {
            return function() { return Date.now(); }
        }
    })()
}

Game.prototype.plugin = function(plugin) {
    this.Plugins.add(plugin);

    this.emit("plugin", [this, plugin]);
    return this;
}

Game.prototype.category = function(category) {
    this.Categories.add(category);

    this.emit("category", [this, category]);
    return this;
}

// Add Polyfill HERE!
Game.prototype.requestAnimationFrame = function(callback) {
    return requestAnimationFrame(callback);
}

//Add Polyfill HERE!
Game.prototype.cancelAnimationFrame = function(af) {
    cancelAnimationFrame(af);
}

/*
 * Plugins
 * =======
 *
 * The Plugins constructor
 * Provides the plugin system for Game
 */

var Plugins = function(game, plugins) {
    //Save Game for later
    this.game = game;

    this.plugins = {};

    //Add already provided plugins
    if(plugins instanceof Array) {
        for(var i = 0, len = Game.plugins.length; i < len; i++) {
            var plugin = new Game.plugins[i]();
            var index = plugins.indexOf(plugin.name);
            if(index !== -1) {
                this.add(plugin);
            }
        }
    }

    return this;
}

Plugins.prototype.add = function(plugin, override) {
    var type   = plugin.type = this.game.Utils.capitalize(plugin.type);
    var name   = plugin.name;
    var Plugin = this.get(name);

    if(!/^(add|remove|get|use|loop)$/.test(name)) {
        //This type is not yet registered
        if(!this.plugins[type]) {
            this.plugins[type] = [];
        }

        //A plugin with this name already exists, but may be overridden
        if(Plugin && override) {
            this.remove(name);
            this.add(plugin);
        }
        else if(!Plugin) {
            //Push to plugin pool
            this.plugins[type].push(plugin);
            //Use the new plugin. If one already exists, it will not be overridden.
            this.use(name);
        }
    }
    else {
        console.warn(warnings.invalidName, name);
    }

    return this;
}

Plugins.prototype.remove = function(name) {
    var Plugin = this.get(name);

    if(Plugin) {
        var type = Plugin.type;

        //Remove from plugin pool
        this.loop(function(plugin, index, array) {
            if(plugin.name === name) {
                array.splice(index, 1);
            }
        });
        //Remove from Game
        if(Plugin === this.game[type]) {
            this.game[type] = null;

            //Replace by last added plugin of the same type (if any)
            var plugins = this.plugins[type];
            if(plugins && plugins.length) {
                this.game[type] = plugins[ plugins.length-1 ];
            }
        }
    }

    return this;
}

Plugins.prototype.get = function(name, warn) {
    var Plugin = null;

    //Loop through all the plugins and get the right one out
    this.loop(function(plugin, index, array) {
        if(plugin.name === name) {
            Plugin = plugin;
            return true;
        }
    });

    //No plugin with this name exists
    if(!Plugin && warn) {
        console.warn(warnings.pluginDoesNotExist, name);
        console.trace();
    }

    return Plugin;
}

Plugins.prototype.use = function(name, override) {
    var plugin = this.get(name);

    //Plugin exists
    if(plugin) {
        var type = plugin.type;

        //Only proceed when no plugin of this type is in use, or the plugin in use may be overridden
        if(!this.game[type] || override) {
            this.game[type] = plugin;
            if(this.game.initTime && plugin.Init) {
                plugin.Init(this.game);
            }
        }
        else if(this.game[type]) {
            console.warn(warnings.useAlreadySet, name);
        }
    }
    else {
        console.warn(warnings.useNonExistentPlugin, name);
    }

    return this;
}

Plugins.prototype.loop = function(cb) {
    //Loop through types
    outer:
    for(type in this.plugins) {
        var plugins = this.plugins[type];

        //Loop through plugins (per type)
        for(var i = 0; i < plugins.length; i++) {
            var br = cb(plugins[i], i, plugins);
            // Break loop if `cb` returns `true` (or another truthy value)
            if(br) { break outer; }
        }
    }

    return this;
}

Plugins.prototype.Init = function() {
    var game = this.game;
    this.loop(function(plugin) {
        if(plugin.Init) {
            plugin.Init(game);
        }
    });

    return this;
}

Plugins.prototype.Load = function() {
    var game = this.game;
    this.loop(function(plugin) {
        if(plugin.Load) {
            plugin.Load(game);
        }
    });

    return this;
}

/*
 * Categories
 * ==========
 *
 * The main Categories constructor
 * Provides the categories system for Game
 */

var Categories = function(game, categories) {
    //Save Game for later
    this.game = game;

    //Add already provided catgories
    if(categories instanceof Array) {
        for(var i = 0, len = categories.length; i < len; i++) {
            this.add(categories[i]);
        }
    }

    return this;
}

Categories.prototype.add = function(category) {
    var name = category.name = this.game.Utils.capitalize(category.name);

    if(!/^(add|remove|get|loop)$/.test(name)) {
        this[name] = category;
        if(this.game.initTime && category.Init) {
            category.Init(this.game);
        }
    }
    else {
        console.warn(warnings.invalidName, name);
    }
}

Categories.prototype.remove = function(name) {
    var name = this.game.Utils.capitalize(name);

    this[name] = undefined;

    return this;
}

Categories.prototype.get = function(name) {
    var name = this.game.Utils.capitalize(name);

    return this[name] || null;
}

Categories.prototype.loop = function(cb) {
    for(name in this) {
        if(!/^(add|remove|get|loop)$/.test(name)) {
            cb(this[name], name);
        }
    }
}

/*
 * EventEmitter
 *
 * EventEmitter allows for easy event registering and emitting. The API is a copy of the Node.js EventEmitter class.
 */

var EventEmitter = function(obj) {
    if(!obj) obj = this;

    obj.__events = {};
    obj.__allEvents = [];

    obj.addListener = obj.on = function(event, listener) {
        if(!this.__events[event]) this.__events[event] = [];

        if(listener) {
            this.__events[event].push(listener);
        }
        else {
            this.__allEvents.push(event); // event is now the callback
        }

        return this;
    }

    obj.once = function(event, listener) {
        if(!this.__events[event]) this.__events[event] = [];

        if(listener) {
            var func = function() {
                listener.call(null, arguments);
                obj.removeListener(event, func);
            }
            this.__events[event].push(func);
        }
        else {
            var func = function() {
                event.call(null, arguments);
                obj.removeListener(func);
            }
            this.__allEvents.push(func);
        }

        return this;
    }

    obj.emit = function(event, args) {
        if(!args) args = [];
        if(this.__events[event]) {
            var listeners = this.__events[event];
            for(var i = 0, len = listeners.length; i < len; i++) {
                listeners[i].apply(null, args);
            }
        }
        var args = [event].concat(args);
        for(var i = 0, len = this.__allEvents.length; i < len; i++) {
            this.__allEvents[i].apply(null, args);
        }

        return this;
    }

    obj.removeListener = function(event, listener) {
        if(!listener) {
            var listener = event;
            for(event in this.__events) {
                this.removeListener(event, listener);
            }
        }
        else {
            var listeners = this.__events[event];
            if(listeners.indexOf(listener) !== -1) {
                listeners.splice(listeners.indexOf(listener), 1);
            }
            if(this.__allEvents.indexOf(listener) !== -1) {
                this.__allEvents.splice(this.__allEvents.indexOf(listener), 1);
            }
        }

        return this;
    }

    obj.removeAllListeners = function(event) {
        this.__events[event] = [];

        return this;
    }

    obj.listeners = function(event) {
        return this.__events[event] || [];
    }

    return obj;
}

Game.prototype.EventEmitter = EventEmitter;

Game.plugins = [];

/*
 * VARS
 * ====
 *
 * Some variables used  by Game.
 */

    var warnings = {
        "noOptionsConstructor": "WARN: No options passed to the Game constructor. Default options will be used.",
        "noPluginsConstructor": "WARN: No plugins passed to the Game constructor. Make sure to add plugins with 'Game.plugin(plugin);'.",
        "noCategoriesConstructor": "WARN: No categories passed to the Game constructor. Make sure to add categories with 'Game.category(category);'.",
        "pluginDoesNotExist": "WARN: A plugin with the name '%s' does not exist.",
        "useNonExistentPlugin": "WARN: You are trying to use() a non-existent plugin, named '%s'.",
        "useAlreadySet": "WARN: You are trying to use() a plugin, named '%s', but a plugin of this type is already in use. Please use Plugins.use(name, true) to override any plugins already in use.",
        "invalidName": "WARN: The name '%s' is invalid.",
        "noPluginPassed": "WARN: No plugin passed to Plugin.add().",
        "noCategoryPassed": "WARN: No category passed to Categories.add().",
        "missingPluginInit": "A vital plugin is missing after Game.init().",
        "noDomElement": "Game.Draw.domElement is empty."
    }

    var container = Game.prototype.container = document.createElement("div");
    container.setAttribute("id", "2D-loaders");
    container.setAttribute("style", "width:0;height:0;visibility:hidden;overflow:hidden");
    document.addEventListener("load", function() {
        document.body.appendChild(container);
    });

})();<commit_msg>Commented out some code to prevent crashes<commit_after>var Game;

(function() {

/*
 * Game
 * ====
 *
 * The main Game constructor
 */

Game = function(options, plugins, categories) {
    if(!options) {
        var options = {};
        console.warn(warnings.noOptionsConstructor);
    }
    if(!plugins) {
        var plugins = [];
        console.warn(warnings.noPluginsConstructor);
    }
    if(!categories) {
        var categories = [];
        console.warn(warnings.noCategoriesConstructor);
    }

    EventEmitter(this);

    this.options    = options;

    this.Assets     = null;
    this.Camera     = null;
    this.Colliders  = null;
    this.Draw       = null;
    this.Sound      = null;
    this.World      = null;
    this.Plugins    = new Plugins(this, plugins);
    this.Categories = new Categories(this, categories);

    this.initTime   = null;
    this.loadTime   = null;
    this.startTime  = null;
    this.pauseTime  = null;
    this.stopTime   = null;

    this.playing    = false;
    this.timer      = null;
    this.frames     = 0;

    return this;
}

/* Setup Engine */
Game.prototype.init = function() {
    this.emit("beforeinit", [this]);
    // Throw an Error if a plugin is missing.
    // If Game[plugin] is null, that plugin is missing
    if(!this.Assets || !this.Camera || !this.Colliders || !this.Draw || !this.Sound || !this.World) {
        console.warn(warnings.missingPluginInit);
    }

    this.initTime = this.Utils.time();
    this.Plugins.Init(this);

    // Attach Draw.domElement to Game
    if(this.Draw && this.Draw.domElement) {
        this.domElement = this.Draw.domElement;
    }
    else {
        console.warn(warnings.noDomElement);
    }

    this.emit("init", [this]);
    return this;
}

/* Setup world */
Game.prototype.load = function() {
    if(!this.initTime) {
        this.init();
    }

    this.emit("beforeload", [this]);

    this.loadTime = this.Utils.time();
    this.Plugins.Load(this);

    this.emit("load", [this]);
    return this;
}

/* Start game loop */
Game.prototype.start = function() {
    if(!this.playing) {
        this.startTime = this.Utils.time();
        if(!this.loadTime) {
            this.load();
        }

        this.emit("beforestart", [this]);

        this.timer = this.requestAnimationFrame(this.Loop);
        this.Loop();

        this.emit("start", [this]);
    }

    return this;
}

Game.prototype.pause = function() {
    if(this.playing) {
        this.emit("beforepause", [this]);
        this.pauseTime = this.Utils.time();
        this.cancelAnimationFrame(this.timer);
        this.emit("pause", [this]);
    }
}

Game.prototype.stop = function() {
    if(this.playing) {
        this.emit("beforestop", [this]);
        this.stopTime = this.Utils.time();
        this.cancelAnimationFrame(this.timer);
        this.emit("beforestopreset");
        this.reset();
        this.emit("stop", [this]);
    }

    return this;
}

Game.prototype.Loop = function() {
    this.emit("beforeframe", [this]);
    this.frames++;

    this.emit("beforeupdate", [this]);
    // this.World.Update(this);
    // this.Camera.Update(this);

    this.emit("beforedraw", [this]);
    // this.World.Draw(this);

    this.emit("frame", [this]);
    return this;
}

Game.prototype.Utils = {
    capitalize: function(str) {
        return str.substr(0,1).toUpperCase() + str.substr(1).toLowerCase();
    },
    merge: function(first, second, blacklist) {
        if(!blacklist) var blacklist = [];

        for(key in second) {
            if(blacklist.indexOf(key) === -1) {
                first[key] = second[key];
            }
        }

        return first;
    },
    toRadians: function(deg) {
        return (deg * Math.PI) / 180;
    },
    toDegrees: function(rad) {
        return (rad * 180) / Math.PI;
    },
    time: (function() {
        if(performance && performance.now) {
            return function() { return performance.now(); }
        } else if(performance && performance.webkitNow) {
            return function() { return performance.webkitNow(); }
        } else {
            return function() { return Date.now(); }
        }
    })()
}

Game.prototype.plugin = function(plugin) {
    this.Plugins.add(plugin);

    this.emit("plugin", [this, plugin]);
    return this;
}

Game.prototype.category = function(category) {
    this.Categories.add(category);

    this.emit("category", [this, category]);
    return this;
}

// Add Polyfill HERE!
Game.prototype.requestAnimationFrame = function(callback) {
    return requestAnimationFrame(callback);
}

//Add Polyfill HERE!
Game.prototype.cancelAnimationFrame = function(af) {
    cancelAnimationFrame(af);
}

/*
 * Plugins
 * =======
 *
 * The Plugins constructor
 * Provides the plugin system for Game
 */

var Plugins = function(game, plugins) {
    //Save Game for later
    this.game = game;

    this.plugins = {};

    //Add already provided plugins
    if(plugins instanceof Array) {
        for(var i = 0, len = Game.plugins.length; i < len; i++) {
            var plugin = new Game.plugins[i]();
            var index = plugins.indexOf(plugin.name);
            if(index !== -1) {
                this.add(plugin);
            }
        }
    }

    return this;
}

Plugins.prototype.add = function(plugin, override) {
    var type   = plugin.type = this.game.Utils.capitalize(plugin.type);
    var name   = plugin.name;
    var Plugin = this.get(name);

    if(!/^(add|remove|get|use|loop)$/.test(name)) {
        //This type is not yet registered
        if(!this.plugins[type]) {
            this.plugins[type] = [];
        }

        //A plugin with this name already exists, but may be overridden
        if(Plugin && override) {
            this.remove(name);
            this.add(plugin);
        }
        else if(!Plugin) {
            //Push to plugin pool
            this.plugins[type].push(plugin);
            //Use the new plugin. If one already exists, it will not be overridden.
            this.use(name);
        }
    }
    else {
        console.warn(warnings.invalidName, name);
    }

    return this;
}

Plugins.prototype.remove = function(name) {
    var Plugin = this.get(name);

    if(Plugin) {
        var type = Plugin.type;

        //Remove from plugin pool
        this.loop(function(plugin, index, array) {
            if(plugin.name === name) {
                array.splice(index, 1);
            }
        });
        //Remove from Game
        if(Plugin === this.game[type]) {
            this.game[type] = null;

            //Replace by last added plugin of the same type (if any)
            var plugins = this.plugins[type];
            if(plugins && plugins.length) {
                this.game[type] = plugins[ plugins.length-1 ];
            }
        }
    }

    return this;
}

Plugins.prototype.get = function(name, warn) {
    var Plugin = null;

    //Loop through all the plugins and get the right one out
    this.loop(function(plugin, index, array) {
        if(plugin.name === name) {
            Plugin = plugin;
            return true;
        }
    });

    //No plugin with this name exists
    if(!Plugin && warn) {
        console.warn(warnings.pluginDoesNotExist, name);
        console.trace();
    }

    return Plugin;
}

Plugins.prototype.use = function(name, override) {
    var plugin = this.get(name);

    //Plugin exists
    if(plugin) {
        var type = plugin.type;

        //Only proceed when no plugin of this type is in use, or the plugin in use may be overridden
        if(!this.game[type] || override) {
            this.game[type] = plugin;
            if(this.game.initTime && plugin.Init) {
                plugin.Init(this.game);
            }
        }
        else if(this.game[type]) {
            console.warn(warnings.useAlreadySet, name);
        }
    }
    else {
        console.warn(warnings.useNonExistentPlugin, name);
    }

    return this;
}

Plugins.prototype.loop = function(cb) {
    //Loop through types
    outer:
    for(type in this.plugins) {
        var plugins = this.plugins[type];

        //Loop through plugins (per type)
        for(var i = 0; i < plugins.length; i++) {
            var br = cb(plugins[i], i, plugins);
            // Break loop if `cb` returns `true` (or another truthy value)
            if(br) { break outer; }
        }
    }

    return this;
}

Plugins.prototype.Init = function() {
    var game = this.game;
    this.loop(function(plugin) {
        if(plugin.Init) {
            plugin.Init(game);
        }
    });

    return this;
}

Plugins.prototype.Load = function() {
    var game = this.game;
    this.loop(function(plugin) {
        if(plugin.Load) {
            plugin.Load(game);
        }
    });

    return this;
}

/*
 * Categories
 * ==========
 *
 * The main Categories constructor
 * Provides the categories system for Game
 */

var Categories = function(game, categories) {
    //Save Game for later
    this.game = game;

    //Add already provided catgories
    if(categories instanceof Array) {
        for(var i = 0, len = categories.length; i < len; i++) {
            this.add(categories[i]);
        }
    }

    return this;
}

Categories.prototype.add = function(category) {
    var name = category.name = this.game.Utils.capitalize(category.name);

    if(!/^(add|remove|get|loop)$/.test(name)) {
        this[name] = category;
        if(this.game.initTime && category.Init) {
            category.Init(this.game);
        }
    }
    else {
        console.warn(warnings.invalidName, name);
    }
}

Categories.prototype.remove = function(name) {
    var name = this.game.Utils.capitalize(name);

    this[name] = undefined;

    return this;
}

Categories.prototype.get = function(name) {
    var name = this.game.Utils.capitalize(name);

    return this[name] || null;
}

Categories.prototype.loop = function(cb) {
    for(name in this) {
        if(!/^(add|remove|get|loop)$/.test(name)) {
            cb(this[name], name);
        }
    }
}

/*
 * EventEmitter
 *
 * EventEmitter allows for easy event registering and emitting. The API is a copy of the Node.js EventEmitter class.
 */

var EventEmitter = function(obj) {
    if(!obj) obj = this;

    obj.__events = {};
    obj.__allEvents = [];

    obj.addListener = obj.on = function(event, listener) {
        if(!this.__events[event]) this.__events[event] = [];

        if(listener) {
            this.__events[event].push(listener);
        }
        else {
            this.__allEvents.push(event); // event is now the callback
        }

        return this;
    }

    obj.once = function(event, listener) {
        if(!this.__events[event]) this.__events[event] = [];

        if(listener) {
            var func = function() {
                listener.call(null, arguments);
                obj.removeListener(event, func);
            }
            this.__events[event].push(func);
        }
        else {
            var func = function() {
                event.call(null, arguments);
                obj.removeListener(func);
            }
            this.__allEvents.push(func);
        }

        return this;
    }

    obj.emit = function(event, args) {
        if(!args) args = [];
        if(this.__events[event]) {
            var listeners = this.__events[event];
            for(var i = 0, len = listeners.length; i < len; i++) {
                listeners[i].apply(null, args);
            }
        }
        var args = [event].concat(args);
        for(var i = 0, len = this.__allEvents.length; i < len; i++) {
            this.__allEvents[i].apply(null, args);
        }

        return this;
    }

    obj.removeListener = function(event, listener) {
        if(!listener) {
            var listener = event;
            for(event in this.__events) {
                this.removeListener(event, listener);
            }
        }
        else {
            var listeners = this.__events[event];
            if(listeners.indexOf(listener) !== -1) {
                listeners.splice(listeners.indexOf(listener), 1);
            }
            if(this.__allEvents.indexOf(listener) !== -1) {
                this.__allEvents.splice(this.__allEvents.indexOf(listener), 1);
            }
        }

        return this;
    }

    obj.removeAllListeners = function(event) {
        this.__events[event] = [];

        return this;
    }

    obj.listeners = function(event) {
        return this.__events[event] || [];
    }

    return obj;
}

Game.prototype.EventEmitter = EventEmitter;

Game.plugins = [];

/*
 * VARS
 * ====
 *
 * Some variables used  by Game.
 */

    var warnings = {
        "noOptionsConstructor": "WARN: No options passed to the Game constructor. Default options will be used.",
        "noPluginsConstructor": "WARN: No plugins passed to the Game constructor. Make sure to add plugins with 'Game.plugin(plugin);'.",
        "noCategoriesConstructor": "WARN: No categories passed to the Game constructor. Make sure to add categories with 'Game.category(category);'.",
        "pluginDoesNotExist": "WARN: A plugin with the name '%s' does not exist.",
        "useNonExistentPlugin": "WARN: You are trying to use() a non-existent plugin, named '%s'.",
        "useAlreadySet": "WARN: You are trying to use() a plugin, named '%s', but a plugin of this type is already in use. Please use Plugins.use(name, true) to override any plugins already in use.",
        "invalidName": "WARN: The name '%s' is invalid.",
        "noPluginPassed": "WARN: No plugin passed to Plugin.add().",
        "noCategoryPassed": "WARN: No category passed to Categories.add().",
        "missingPluginInit": "A vital plugin is missing after Game.init().",
        "noDomElement": "Game.Draw.domElement is empty."
    }

    var container = Game.prototype.container = document.createElement("div");
    container.setAttribute("id", "2D-loaders");
    container.setAttribute("style", "width:0;height:0;visibility:hidden;overflow:hidden");
    document.addEventListener("load", function() {
        document.body.appendChild(container);
    });

})();<|endoftext|>


<commit_before>/**
* The constructor of Core
*
* @class Core
* @constructor
*/
var Core = function() {
  this.modules = {};
};

/**
* Registers a new module
*
* @method register
* @param {string} module the name of the new module
* @param {function} constructor the constructor of the new module
*/
Core.prototype.register = function(module, constructor) {
  if(this.modules[module]) {
    this.helpers.err('!!module', module);
    return false;
  }
  this.modules[module] = {
    constructor: constructor,
    instance: null
  };
};

/**
* Check if the module is already initialized or not
*
* @method moduleCheck
* @param {string} module the name of the module that will be checked
* @param {boolean} destroy check if the module exists, but is already destroyed
* @return {boolean} if the module exists or already have an instance
*/
Core.prototype.moduleCheck = function(module, destroy) {
  if(destroy) return !module || !module.instance;

  return !module || module.instance;
};

/**
* Gets an element by ID to attach to the module instance
*
* @method getElement
* @param {string} id the id of the main element in the module
*/
Core.prototype.getElement = function(id) {
  return document.getElementById(id);
};

/**
* Starts a registered module
*
* @method start
* @param {string} module the name of the module
*/
Core.prototype.start = function(module) {
  var cModule = this.modules[module],
    el = this.getElement(module);

  if(this.moduleCheck(cModule)) {
    this.helpers.err('!start', module);
    return false;
  }

  cModule.instance = new cModule.constructor(new this.Sandbox(module));

  // attachs the element to the instance of the module
  cModule.instance.el = el;

  if(cModule.instance.init) return cModule.instance.init();
};

/**
* Stops a registered module
*
* @method start
* @param {string} module the name of the module
*/
Core.prototype.stop = function(module) {
  var cModule = this.modules[module], stopReturn;

  if(this.moduleCheck(cModule, true)) {
    this.helpers.err('!stop', module);
    return false;
  }

  if(cModule.instance.destroy) stopReturn = cModule.instance.destroy();

  cModule.instance = null;

  this.Sandbox.clearNotifications(module);

  return stopReturn;
};

/**
* Stop all started modules
*
* @method stopAll
*/
Core.prototype.stopAll = function() {
  this.xAll('stop');
};

/**
* Stop all started modules
*
* @method stopAll
*/
Core.prototype.startAll = function() {
  this.xAll('start');
};

/**
* Helper for startAll and stopAll
*
* @method xAll
* @param {string} method the method that will be triggered
*/
Core.prototype.xAll = function(method) {
  for(var module in this.modules) {
    if(this.modules.hasOwnProperty(module)) this[method](module);
  }
};

Core = new Core();
<commit_msg>check if module is passed, and calls startAll<commit_after>/**
* The constructor of Core
*
* @class Core
* @constructor
*/
var Core = function() {
  this.modules = {};
};

/**
* Registers a new module
*
* @method register
* @param {string} module the name of the new module
* @param {function} constructor the constructor of the new module
*/
Core.prototype.register = function(module, constructor) {
  if(this.modules[module]) {
    this.helpers.err('!!module', module);
    return false;
  }
  this.modules[module] = {
    constructor: constructor,
    instance: null
  };
};

/**
* Check if the module is already initialized or not
*
* @method moduleCheck
* @param {string} module the name of the module that will be checked
* @param {boolean} destroy check if the module exists, but is already destroyed
* @return {boolean} if the module exists or already have an instance
*/
Core.prototype.moduleCheck = function(module, destroy) {
  if(destroy) return !module || !module.instance;

  return !module || module.instance;
};

/**
* Gets an element by ID to attach to the module instance
*
* @method getElement
* @param {string} id the id of the main element in the module
*/
Core.prototype.getElement = function(id) {
  return document.getElementById(id);
};

/**
* Starts a registered module
*
* @method start
* @param {string} module the name of the module
*/
Core.prototype.start = function(module) {
  if(!module) {
    this.startAll();
    return;
  }

  var cModule = this.modules[module],
    el = this.getElement(module);

  if(this.moduleCheck(cModule)) {
    this.helpers.err('!start', module);
    return false;
  }

  cModule.instance = new cModule.constructor(new this.Sandbox(module));

  // attachs the element to the instance of the module
  cModule.instance.el = el;

  if(cModule.instance.init) return cModule.instance.init();
};

/**
* Stops a registered module
*
* @method start
* @param {string} module the name of the module
*/
Core.prototype.stop = function(module) {
  var cModule = this.modules[module], stopReturn;

  if(this.moduleCheck(cModule, true)) {
    this.helpers.err('!stop', module);
    return false;
  }

  if(cModule.instance.destroy) stopReturn = cModule.instance.destroy();

  cModule.instance = null;

  this.Sandbox.clearNotifications(module);

  return stopReturn;
};

/**
* Stop all started modules
*
* @method stopAll
*/
Core.prototype.stopAll = function() {
  this.xAll('stop');
};

/**
* Stop all started modules
*
* @method stopAll
*/
Core.prototype.startAll = function() {
  this.xAll('start');
};

/**
* Helper for startAll and stopAll
*
* @method xAll
* @param {string} method the method that will be triggered
*/
Core.prototype.xAll = function(method) {
  for(var module in this.modules) {
    if(this.modules.hasOwnProperty(module)) this[method](module);
  }
};

Core = new Core();
<|endoftext|>


<commit_before>/**
* The constructor of Core
*
* @class Core
* @constructor
*/
var Core = function() {
  this.modules = {};
};

/**
* Registers a new module
*
* @method register
* @param {string} module the name of the new module
* @param {function} constructor the constructor of the new module
*/
Core.prototype.register = function(module, constructor) {
  if(this.modules[module]) {
    this.helpers.err('!!module', module);
    return false;
  }
  this.modules[module] = {
    constructor: constructor,
    instance: null
  };
};

/**
* Check if the module is already initialized or not
*
* @method moduleCheck
* @param {string} module the name of the module that will be checked
* @param {boolean} destroy check if the module exists, but is already destroyed
* @return {boolean} if the module exists or already have an instance
*/
Core.prototype.moduleCheck = function(module, destroy) {
  if(destroy) return !module || !module.instance;

  return !module || module.instance;
};

/**
* Gets an element by ID to attach to the module instance
*
* @method getElement
* @param {string} id the id of the main element in the module
*/
Core.prototype.getElement = function(id) {
  return document.getElementById(id);
};

/**
* Starts a registered module, if no module is passed, it starts all modules
*
* @method start
* @param {string} module the name of the module
*/
Core.prototype.start = function(module) {
  if(!module) return this.startAll();

  var cModule = this.modules[module],
    el = this.getElement(module);

  if(this.moduleCheck(cModule)) {
    this.helpers.err('!start', module);
    return false;
  }

  cModule.instance = new cModule.constructor(new this.Sandbox(module));

  // attachs the element to the instance of the module
  cModule.instance.el = el;

  if(cModule.instance.init) return cModule.instance.init();
};

/**
* Stops a registered module
*
* @method start
* @param {string} module the name of the module
*/
Core.prototype.stop = function(module) {
  if(!module) return this.stopAll();

  var cModule = this.modules[module], stopReturn;

  if(this.moduleCheck(cModule, true)) {
    this.helpers.err('!stop', module);
    return false;
  }

  if(cModule.instance.destroy) stopReturn = cModule.instance.destroy();

  cModule.instance = null;

  this.Sandbox.clearNotifications(module);

  return stopReturn;
};

/**
* Stop all started modules
*
* @method stopAll
*/
Core.prototype.stopAll = function() {
  this.xAll('stop');
};

/**
* Stop all started modules
*
* @method stopAll
*/
Core.prototype.startAll = function() {
  this.xAll('start');
};

/**
* Helper for startAll and stopAll
*
* @method xAll
* @param {string} method the method that will be triggered
*/
Core.prototype.xAll = function(method) {
  for(var module in this.modules) {
    if(this.modules.hasOwnProperty(module)) this[method](module);
  }
};

Core = new Core();
<commit_msg>fix minor bug in blackberry with IDs, #18<commit_after>/**
* The constructor of Core
*
* @class Core
* @constructor
*/
var Core = function() {
  this.modules = {};
};

/**
* Registers a new module
*
* @method register
* @param {string} module the name of the new module
* @param {function} constructor the constructor of the new module
*/
Core.prototype.register = function(module, constructor) {
  if(this.modules[module]) {
    this.helpers.err('!!module', module);
    return false;
  }
  this.modules[module] = {
    constructor: constructor,
    instance: null
  };
};

/**
* Check if the module is already initialized or not
*
* @method moduleCheck
* @param {string} module the name of the module that will be checked
* @param {boolean} destroy check if the module exists, but is already destroyed
* @return {boolean} if the module exists or already have an instance
*/
Core.prototype.moduleCheck = function(module, destroy) {
  if(destroy) return !module || !module.instance;

  return !module || module.instance;
};

/**
* Gets an element by ID to attach to the module instance
*
* @method getElement
* @param {string} id the id of the main element in the module
*/
Core.prototype.getElement = function(id) {
  var el = document.getElementById(id);

  return (el && el.id === id) ? el : null;
};

/**
* Starts a registered module, if no module is passed, it starts all modules
*
* @method start
* @param {string} module the name of the module
*/
Core.prototype.start = function(module) {
  if(!module) return this.startAll();

  var cModule = this.modules[module],
    el = this.getElement(module);

  if(this.moduleCheck(cModule)) {
    this.helpers.err('!start', module);
    return false;
  }

  cModule.instance = new cModule.constructor(new this.Sandbox(module));

  // attachs the element to the instance of the module
  cModule.instance.el = el;

  if(cModule.instance.init) return cModule.instance.init();
};

/**
* Stops a registered module
*
* @method start
* @param {string} module the name of the module
*/
Core.prototype.stop = function(module) {
  if(!module) return this.stopAll();

  var cModule = this.modules[module], stopReturn;

  if(this.moduleCheck(cModule, true)) {
    this.helpers.err('!stop', module);
    return false;
  }

  if(cModule.instance.destroy) stopReturn = cModule.instance.destroy();

  cModule.instance = null;

  this.Sandbox.clearNotifications(module);

  return stopReturn;
};

/**
* Stop all started modules
*
* @method stopAll
*/
Core.prototype.stopAll = function() {
  this.xAll('stop');
};

/**
* Stop all started modules
*
* @method stopAll
*/
Core.prototype.startAll = function() {
  this.xAll('start');
};

/**
* Helper for startAll and stopAll
*
* @method xAll
* @param {string} method the method that will be triggered
*/
Core.prototype.xAll = function(method) {
  for(var module in this.modules) {
    if(this.modules.hasOwnProperty(module)) this[method](module);
  }
};

Core = new Core();
<|endoftext|>


<commit_before>/*
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * 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.
 */

// Polyfill

if ( ! Array.from ) {
  /** Turn array-like objects into real arrays. **/
  Array.from = function(a) {
    var b = new Array(a.length);
    for ( var i = 0 ; i < a.length ; i++ ) b[i] = a[i];
    return b;
  }
}

// TODO: Polyfill this? Enum is using array.find, IE and old node have no support.
if ( ! Array.prototype.find ) {
  Array.prototype.find = function(predicate) {
    if ( this === null ) {
      throw new TypeError('Array.prototype.find called on null or undefined');
    }
    if ( typeof predicate !== 'function' ) {
      throw new TypeError('predicate must be a function');
    }
    var list    = Object(this);
    var length  = list.length >>> 0;
    var thisArg = arguments[1];
    var value;

    for ( var i = 0 ; i < length ; i++ ) {
      value = list[i];
      if ( predicate.call(thisArg, value, i, list) ) return value;
    }
    return undefined;
  };
}

if ( ! String.prototype.endsWith ) {
  // Official polyfill
  String.prototype.endsWith = function(searchString, position) {
      var subjectString = this.toString();
      if ( typeof position !== 'number' ||
          ! isFinite(position) ||
          Math.floor(position) !== position ||
          position > subjectString.length ) {
        position = subjectString.length;
      }
      position -= searchString.length;
      var lastIndex = subjectString.indexOf(searchString, position);
      return lastIndex !== -1 && lastIndex === position;
  };
}
<commit_msg>Removed polyfill TODO.<commit_after>/*
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * 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.
 */

// Polyfill

if ( ! Array.from ) {
  /** Turn array-like objects into real arrays. **/
  Array.from = function(a) {
    var b = new Array(a.length);
    for ( var i = 0 ; i < a.length ; i++ ) b[i] = a[i];
    return b;
  }
}

if ( ! Array.prototype.find ) {
  Array.prototype.find = function(predicate) {
    if ( this === null ) {
      throw new TypeError('Array.prototype.find called on null or undefined');
    }
    if ( typeof predicate !== 'function' ) {
      throw new TypeError('predicate must be a function');
    }
    var list    = Object(this);
    var length  = list.length >>> 0;
    var thisArg = arguments[1];
    var value;

    for ( var i = 0 ; i < length ; i++ ) {
      value = list[i];
      if ( predicate.call(thisArg, value, i, list) ) return value;
    }
    return undefined;
  };
}

if ( ! String.prototype.endsWith ) {
  // Official polyfill
  String.prototype.endsWith = function(searchString, position) {
      var subjectString = this.toString();
      if ( typeof position !== 'number' ||
          ! isFinite(position) ||
          Math.floor(position) !== position ||
          position > subjectString.length ) {
        position = subjectString.length;
      }
      position -= searchString.length;
      var lastIndex = subjectString.indexOf(searchString, position);
      return lastIndex !== -1 && lastIndex === position;
  };
}
<|endoftext|>


<commit_before>/*
 * TimeSpan(milliseconds);
 * TimeSpan(days, hours, minutes, seconds);
 * TimeSpan(days, hours, minutes, seconds, milliseconds);
 */
var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
	var attrs = "days hours minutes seconds milliseconds".split(/\s+/);

	var gFn = function (attr) {
		return function () {
			return this[attr];
		};
	};

	var sFn = function (attr) {
		return function (val) {
			this[attr] = val;
			return this;
		};
	};

	for (var i = 0; i < attrs.length ; i++) {
		var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
		TimeSpan.prototype[$a] = 0;
		TimeSpan.prototype["get" + $b] = gFn($a);
		TimeSpan.prototype["set" + $b] = sFn($a);
	}

	if (arguments.length === 4) {
		this.setDays(days);
		this.setHours(hours);
		this.setMinutes(minutes);
		this.setSeconds(seconds);
	} else if (arguments.length === 5) {
		this.setDays(days);
		this.setHours(hours);
		this.setMinutes(minutes);
		this.setSeconds(seconds);
		this.setMilliseconds(milliseconds);
	} else if (arguments.length === 1 && typeof days === "number") {
		var orient = (days < 0) ? -1 : +1;
		this.setMilliseconds(Math.abs(days));

		this.setDays(Math.floor(this.getMilliseconds() / 86400000) * orient);
		this.setMilliseconds(this.getMilliseconds() % 86400000);

		this.setHours(Math.floor(this.getMilliseconds() / 3600000) * orient);
		this.setMilliseconds(this.getMilliseconds() % 3600000);

		this.setMinutes(Math.floor(this.getMilliseconds() / 60000) * orient);
		this.setMilliseconds(this.getMilliseconds() % 60000);

		this.setSeconds(Math.floor(this.getMilliseconds() / 1000) * orient);
		this.setMilliseconds(this.getMilliseconds() % 1000);

		this.setMilliseconds(this.getMilliseconds() * orient);
	}

	this.getTotalMilliseconds = function () {
		return	(this.getDays() * 86400000) +
				(this.getHours() * 3600000) +
				(this.getMinutes() * 60000) +
				(this.getSeconds() * 1000);
	};

	this.compareTo = function (time) {
		var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
		if (time === null) {
			t2 = new Date(1970, 1, 1, 0, 0, 0);
		}
		else {
			t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
		}
		return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
	};

	this.equals = function (time) {
		return (this.compareTo(time) === 0);
	};

	this.add = function (time) {
		return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
	};

	this.subtract = function (time) {
		return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
	};

	this.addDays = function (n) {
		return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
	};

	this.addHours = function (n) {
		return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
	};

	this.addMinutes = function (n) {
		return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
	};

	this.addSeconds = function (n) {
		return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
	};

	this.addMilliseconds = function (n) {
		return new TimeSpan(this.getTotalMilliseconds() + n);
	};

	this.get12HourHour = function () {
		return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
	};

	this.getDesignator = function () {
		return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
	};

	this.toString = function (format) {
		this._toString = function () {
			if (this.getDays() !== null && this.getDays() > 0) {
				return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
			} else {
				return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
			}
		};

		this.p = function (s) {
			return (s.toString().length < 2) ? "0" + s : s;
		};

		var me = this;

		return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
		function (format) {
			switch (format) {
			case "d":
				return me.getDays();
			case "dd":
				return me.p(me.getDays());
			case "H":
				return me.getHours();
			case "HH":
				return me.p(me.getHours());
			case "h":
				return me.get12HourHour();
			case "hh":
				return me.p(me.get12HourHour());
			case "m":
				return me.getMinutes();
			case "mm":
				return me.p(me.getMinutes());
			case "s":
				return me.getSeconds();
			case "ss":
				return me.p(me.getSeconds());
			case "t":
				return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
			case "tt":
				return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
			}
		}
		) : this._toString();
	};
	return this;
};

/**
 * Gets the time of day for this date instances.
 * @return {TimeSpan} TimeSpan
 */
Date.prototype.getTimeOfDay = function () {
	return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
};

/*
 * TimePeriod(startDate, endDate);
 * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
 */
var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
	var attrs = "years months days hours minutes seconds milliseconds".split(/\s+/);

	var gFn = function (attr) {
		return function () {
			return this[attr];
		};
	};

	var sFn = function (attr) {
		return function (val) {
			this[attr] = val;
			return this;
		};
	};

	for (var i = 0; i < attrs.length ; i++) {
		var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
		TimePeriod.prototype[$a] = 0;
		TimePeriod.prototype["get" + $b] = gFn($a);
		TimePeriod.prototype["set" + $b] = sFn($a);
	}

	if (arguments.length === 7) {
		this.years = years;
		this.months = months;
		this.setDays(days);
		this.setHours(hours);
		this.setMinutes(minutes);
		this.setSeconds(seconds);
		this.setMilliseconds(milliseconds);
	} else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
		// startDate and endDate as arguments

		var d1 = years.clone();
		var d2 = months.clone();

		var temp = d1.clone();
		var orient = (d1 > d2) ? -1 : +1;

		this.years = d2.getFullYear() - d1.getFullYear();
		temp.addYears(this.years);

		if (orient === +1) {
			if (temp > d2) {
				if (this.years !== 0) {
					this.years--;
				}
			}
		} else {
			if (temp < d2) {
				if (this.years !== 0) {
					this.years++;
				}
			}
		}

		d1.addYears(this.years);

		if (orient === +1) {
			while (d1 < d2 && d1.clone().addMonths(1) <= d2) {
				d1.addMonths(1);
				this.months++;
			}
		}
		else {
			while (d1 > d2 && d1.clone().addDays(-d1.getDaysInMonth()) > d2) {
				d1.addMonths(-1);
				this.months--;
			}
		}

		var diff = d2 - d1;

		if (diff !== 0) {
			var ts = new TimeSpan(diff);
			this.setDays(ts.getDays());
			this.setHours(ts.getHours());
			this.setMinutes(ts.getMinutes());
			this.setSeconds(ts.getSeconds());
			this.setMilliseconds(ts.getMilliseconds());
		}
	}
	return this;
};<commit_msg>refactor the if-statements<commit_after>/*
 * TimeSpan(milliseconds);
 * TimeSpan(days, hours, minutes, seconds);
 * TimeSpan(days, hours, minutes, seconds, milliseconds);
 */
var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
	var attrs = "days hours minutes seconds milliseconds".split(/\s+/);

	var gFn = function (attr) {
		return function () {
			return this[attr];
		};
	};

	var sFn = function (attr) {
		return function (val) {
			this[attr] = val;
			return this;
		};
	};

	for (var i = 0; i < attrs.length ; i++) {
		var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
		TimeSpan.prototype[$a] = 0;
		TimeSpan.prototype["get" + $b] = gFn($a);
		TimeSpan.prototype["set" + $b] = sFn($a);
	}
	TimeSpan.prototype.set = function (days, hours, minutes, seconds, milliseconds){
		this.setDays(days || this.getDays());
		this.setHours(hours || this.getHours());
		this.setMinutes(minutes || this.getMinutes());
		this.setSeconds(seconds || this.getSeconds());
		this.setMilliseconds(milliseconds || this.getMilliseconds());
	};

	if (arguments.length === 1 && typeof days === "number") {
		var orient = (days < 0) ? -1 : +1;
		this.setMilliseconds(Math.abs(days));

		this.setDays(Math.floor(this.getMilliseconds() / 86400000) * orient);
		this.setMilliseconds(this.getMilliseconds() % 86400000);

		this.setHours(Math.floor(this.getMilliseconds() / 3600000) * orient);
		this.setMilliseconds(this.getMilliseconds() % 3600000);

		this.setMinutes(Math.floor(this.getMilliseconds() / 60000) * orient);
		this.setMilliseconds(this.getMilliseconds() % 60000);

		this.setSeconds(Math.floor(this.getMilliseconds() / 1000) * orient);
		this.setMilliseconds(this.getMilliseconds() % 1000);

		this.setMilliseconds(this.getMilliseconds() * orient);
	} else {
		this.set(days, hours, minutes, seconds, milliseconds);
	}

	this.getTotalMilliseconds = function () {
		return	(this.getDays() * 86400000) +
				(this.getHours() * 3600000) +
				(this.getMinutes() * 60000) +
				(this.getSeconds() * 1000);
	};

	this.compareTo = function (time) {
		var t1 = new Date(1970, 1, 1, this.getHours(), this.getMinutes(), this.getSeconds()), t2;
		if (time === null) {
			t2 = new Date(1970, 1, 1, 0, 0, 0);
		}
		else {
			t2 = new Date(1970, 1, 1, time.getHours(), time.getMinutes(), time.getSeconds());
		}
		return (t1 < t2) ? -1 : (t1 > t2) ? 1 : 0;
	};

	this.equals = function (time) {
		return (this.compareTo(time) === 0);
	};

	this.add = function (time) {
		return (time === null) ? this : this.addSeconds(time.getTotalMilliseconds() / 1000);
	};

	this.subtract = function (time) {
		return (time === null) ? this : this.addSeconds(-time.getTotalMilliseconds() / 1000);
	};

	this.addDays = function (n) {
		return new TimeSpan(this.getTotalMilliseconds() + (n * 86400000));
	};

	this.addHours = function (n) {
		return new TimeSpan(this.getTotalMilliseconds() + (n * 3600000));
	};

	this.addMinutes = function (n) {
		return new TimeSpan(this.getTotalMilliseconds() + (n * 60000));
	};

	this.addSeconds = function (n) {
		return new TimeSpan(this.getTotalMilliseconds() + (n * 1000));
	};

	this.addMilliseconds = function (n) {
		return new TimeSpan(this.getTotalMilliseconds() + n);
	};

	this.get12HourHour = function () {
		return (this.getHours() > 12) ? this.getHours() - 12 : (this.getHours() === 0) ? 12 : this.getHours();
	};

	this.getDesignator = function () {
		return (this.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
	};

	this.toString = function (format) {
		this._toString = function () {
			if (this.getDays() !== null && this.getDays() > 0) {
				return this.getDays() + "." + this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
			} else {
				return this.getHours() + ":" + this.p(this.getMinutes()) + ":" + this.p(this.getSeconds());
			}
		};

		this.p = function (s) {
			return (s.toString().length < 2) ? "0" + s : s;
		};

		var me = this;

		return format ? format.replace(/dd?|HH?|hh?|mm?|ss?|tt?/g,
		function (format) {
			switch (format) {
			case "d":
				return me.getDays();
			case "dd":
				return me.p(me.getDays());
			case "H":
				return me.getHours();
			case "HH":
				return me.p(me.getHours());
			case "h":
				return me.get12HourHour();
			case "hh":
				return me.p(me.get12HourHour());
			case "m":
				return me.getMinutes();
			case "mm":
				return me.p(me.getMinutes());
			case "s":
				return me.getSeconds();
			case "ss":
				return me.p(me.getSeconds());
			case "t":
				return ((me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator).substring(0, 1);
			case "tt":
				return (me.getHours() < 12) ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
			}
		}
		) : this._toString();
	};
	return this;
};

/**
 * Gets the time of day for this date instances.
 * @return {TimeSpan} TimeSpan
 */
Date.prototype.getTimeOfDay = function () {
	return new TimeSpan(0, this.getHours(), this.getMinutes(), this.getSeconds(), this.getMilliseconds());
};

/*
 * TimePeriod(startDate, endDate);
 * TimePeriod(years, months, days, hours, minutes, seconds, milliseconds);
 */
var TimePeriod = function (years, months, days, hours, minutes, seconds, milliseconds) {
	var attrs = "years months days hours minutes seconds milliseconds".split(/\s+/);

	var gFn = function (attr) {
		return function () {
			return this[attr];
		};
	};

	var sFn = function (attr) {
		return function (val) {
			this[attr] = val;
			return this;
		};
	};

	for (var i = 0; i < attrs.length ; i++) {
		var $a = attrs[i], $b = $a.slice(0, 1).toUpperCase() + $a.slice(1);
		TimePeriod.prototype[$a] = 0;
		TimePeriod.prototype["get" + $b] = gFn($a);
		TimePeriod.prototype["set" + $b] = sFn($a);
	}

	if (arguments.length === 7) {
		this.years = years;
		this.months = months;
		this.setDays(days);
		this.setHours(hours);
		this.setMinutes(minutes);
		this.setSeconds(seconds);
		this.setMilliseconds(milliseconds);
	} else if (arguments.length === 2 && arguments[0] instanceof Date && arguments[1] instanceof Date) {
		// startDate and endDate as arguments

		var d1 = years.clone();
		var d2 = months.clone();

		var temp = d1.clone();
		var orient = (d1 > d2) ? -1 : +1;

		this.years = d2.getFullYear() - d1.getFullYear();
		temp.addYears(this.years);

		if (orient === +1) {
			if (temp > d2) {
				if (this.years !== 0) {
					this.years--;
				}
			}
		} else {
			if (temp < d2) {
				if (this.years !== 0) {
					this.years++;
				}
			}
		}

		d1.addYears(this.years);

		if (orient === +1) {
			while (d1 < d2 && d1.clone().addMonths(1) <= d2) {
				d1.addMonths(1);
				this.months++;
			}
		}
		else {
			while (d1 > d2 && d1.clone().addDays(-d1.getDaysInMonth()) > d2) {
				d1.addMonths(-1);
				this.months--;
			}
		}

		var diff = d2 - d1;

		if (diff !== 0) {
			var ts = new TimeSpan(diff);
			this.setDays(ts.getDays());
			this.setHours(ts.getHours());
			this.setMinutes(ts.getMinutes());
			this.setSeconds(ts.getSeconds());
			this.setMilliseconds(ts.getMilliseconds());
		}
	}
	return this;
};<|endoftext|>