<commit_before>import React from 'react';
import classnames from 'classnames';
import _ from 'underscore';

import m from '../services/materialService.js';
import sign from '../services/sign.js';
import h from '../helpers.js';

import Table from './Table.js';
import Column from './Column.js';
import Cell from './Cell.js';
import AddMaterialForm from './Form.AddMaterial.js';
import SelectCell from './Cell.Select.js';

class Materials extends React.Component {
  constructor() {
    super();

    this.state = {
      isFormOpen: false,
      materials: [],
      removeMode: false, // If true, display removal column in table
      types: []
    };
  }

  componentDidMount() {
    this._updateMaterials();

    m.getTypes()
      .then(types => {
        this.setState({ types });
      }).catch(() => {
        sign.setError('Failed to retrieve material types. Try refreshing.');
      });
  }

  _handleAddClick(event) {
    if (event) {
      event.preventDefault();
    }

    this.setState({ isFormOpen: !this.state.isFormOpen });
  }

  _handleFormSubmit(item, description) {
    m.addMaterial({
      item,
      description
    }).then(() => {
      this._updateMaterials();
    }).catch(() => {
      sign.setError('Failed to add material. Try refreshing.');
    });
  }

  _handleRemove() {
    this.setState({ removeMode: !this.state.removeMode });
  }

  _modifyField(materialId, field, value) {
    let state = this.state;
    let materials = state.materials;

    for (let i = 0; i < materials.length; i++) {
      if (materials[i].id === materialId) {
        if (field === 'type') {
          materials[i].typeId = h.findTypeId(state.types, value);
        } else {
          materials[i][field] = value;
        }

        this.setState({ materials });
        break;
      }
    }

    m.modifyMaterial(materialId, field, value)
      .catch(() => {
        sign.setError('Failed to modify material.');
        this.setState({ materials: [] });
      });
  }

  _removeMaterial(material) {
    let confirmed = confirm(`Are you sure you want to remove ${material.description}?`);

    if (confirmed) {
      m.removeMaterial(material.id).then(() => {
        this._updateMaterials();
      }).catch(() => {
        sign.setError('Failed to remove material.');
      });
    }
  }

  _updateMaterials() {
    m.getAllMaterials()
      .then(materials => this.setState({ materials }))
      .catch(error => {
        console.log('[Component] Error retrieving materials: ', error);
        sign.setError('Failed to retrieve materials. Try refreshing.');
        this.setState({ materials: [] });
      });
  }

  render() {
    let state = this.state;

    let removeClasses = {
      'remove-button': true,
      active: state.removeMode
    };

    return (

            All
            Other
            Low Stock
            Out of Stock

            <button className="add-button" onClick={this._handleAddClick.bind(this)}>+</button>
            <button className={classnames(removeClasses)} onClick={this._handleRemove.bind(this)}>--</button>

            <Column header="Item #" cell={material => (
                <Cell modifyField={this._modifyField.bind(this, material.id, 'item')}>{material.item}</Cell>
              )}
            />
            <Column classes="extra-wide" header="Description" cell={material => (
                <Cell modifyField={this._modifyField.bind(this, material.id, 'description')}>{material.description}</Cell>
              )}
            />
            <Column header="Type" cell={material => (
                <SelectCell modifyField={this._modifyField.bind(this, material.id, 'type')}
                  options={state.types.map(type => type.name)}
                  defaultValue={h.findTypeName(state.types, material.typeId)}
                />
              )}
            />
            <Column header="Cost / Unit" cell={material => {
              let type = _.findWhere(state.types, { id: material.typeId });

              if (!type) {
                return null;
              }

              return (
                <Cell modifyField={this._modifyField.bind(this, material.id, 'costPerUnit')} pricePerUnit>
                  {h.displayPricePerUnit(material.costPerUnit, type.unit)}
                </Cell>
              );
            }}
            />
            <Column header="Qty on Order" cell={material => (
                <Cell modifyField={this._modifyField.bind(this, material.id, 'qtyOnOrder')} integer>{material.qtyOnOrder}</Cell>
              )}
            />
            <Column header="Qty in Stock" cell={material => (
                <Cell modifyField={this._modifyField.bind(this, material.id, 'qtyInStock')} integer>{material.qtyInStock}</Cell>
              )}
            />
            {this._renderRemoveColumn()}

        {this._renderForm()}

    );
  }

  _renderForm() {
    if (this.state.isFormOpen) {
      return (
        <AddMaterialForm
          cancel={this._handleAddClick.bind(this)}
          submit={this._handleFormSubmit.bind(this)}
        />
      );
    }
  }

  _renderRemoveColumn() {
    if (this.state.removeMode) {
      return (
        <Column header="Remove" cell={material => (
            <Cell className="remove">
X
</Cell>
          )}
        />
      );
    }
  }
}

export default Materials;
<commit_msg>Add vendor column<commit_after>import React from 'react';
import classnames from 'classnames';
import _ from 'underscore';

import m from '../services/materialService.js';
import v from '../services/vendorService.js';
import sign from '../services/sign.js';
import h from '../helpers.js';

import Table from './Table.js';
import Column from './Column.js';
import Cell from './Cell.js';
import AddMaterialForm from './Form.AddMaterial.js';
import SelectCell from './Cell.Select.js';

class Materials extends React.Component {
  constructor() {
    super();

    this.state = {
      isFormOpen: false,
      materials: [],
      removeMode: false, // If true, display removal column in table
      types: [],
      vendors: []
    };
  }

  componentDidMount() {
    this._updateMaterials();

    m.getTypes().then(types => {
      this.setState({ types });
    }).catch(() => {
      sign.setError('Failed to retrieve material types. Try refreshing.');
    });

    v.getVendors().then(vendors => {
      this.setState({ vendors });
    }).catch(() => {
      sign.setError('Failed to retrieve vendors. Try refreshing.');
    });
  }

  _handleAddClick(event) {
    if (event) {
      event.preventDefault();
    }

    this.setState({ isFormOpen: !this.state.isFormOpen });
  }

  _handleFormSubmit(item, description) {
    m.addMaterial({
      item,
      description
    }).then(() => {
      this._updateMaterials();
    }).catch(() => {
      sign.setError('Failed to add material. Try refreshing.');
    });
  }

  _handleRemove() {
    this.setState({ removeMode: !this.state.removeMode });
  }

  _modifyField(materialId, field, value) {
    let state = this.state;
    let materials = state.materials;

    for (let i = 0; i < materials.length; i++) {
      if (materials[i].id === materialId) {
        if (field === 'type') {
          materials[i].typeId = h.findTypeId(state.types, value);
        } else if (field === 'vendor') {
          materials[i].vendorId = h.findVendorId(state.vendors, value);
        } else {
          materials[i][field] = value;
        }

        this.setState({ materials });
        break;
      }
    }

    m.modifyMaterial(materialId, field, value)
      .catch(() => {
        sign.setError('Failed to modify material.');
        this.setState({ materials: [] });
      });
  }

  _removeMaterial(material) {
    let confirmed = confirm(`Are you sure you want to remove ${material.description}?`);

    if (confirmed) {
      m.removeMaterial(material.id).then(() => {
        this._updateMaterials();
      }).catch(() => {
        sign.setError('Failed to remove material.');
      });
    }
  }

  _updateMaterials() {
    m.getAllMaterials()
      .then(materials => this.setState({ materials }))
      .catch(error => {
        console.log('[Component] Error retrieving materials: ', error);
        sign.setError('Failed to retrieve materials. Try refreshing.');
        this.setState({ materials: [] });
      });
  }

  render() {
    let state = this.state;

    let removeClasses = {
      'remove-button': true,
      active: state.removeMode
    };

    return (

            All
            Other
            Low Stock
            Out of Stock

            <button className="add-button" onClick={this._handleAddClick.bind(this)}>+</button>
            <button className={classnames(removeClasses)} onClick={this._handleRemove.bind(this)}>--</button>

            <Column header="Item #" cell={material => (
                <Cell modifyField={this._modifyField.bind(this, material.id, 'item')}>{material.item}</Cell>
              )}
            />
            <Column classes="extra-wide" header="Description" cell={material => (
                <Cell modifyField={this._modifyField.bind(this, material.id, 'description')}>{material.description}</Cell>
              )}
            />
            <Column header="Type" cell={material => (
                <SelectCell modifyField={this._modifyField.bind(this, material.id, 'type')}
                  options={state.types.map(type => type.name)}
                  defaultValue={h.findTypeName(state.types, material.typeId)}
                />
              )}
            />
            <Column header="Vendor" cell={material => (
                <SelectCell modifyField={this._modifyField.bind(this, material.id, 'vendor')}
                  options={state.vendors.map(vendor => vendor.company)}
                  defaultValue={h.findVendorCompany(state.vendors, material.vendorId)}
                />
              )}
            />
            <Column header="Cost / Unit" cell={material => {
              let type = _.findWhere(state.types, { id: material.typeId });

              if (!type) {
                return <Cell />;
              }

              return (
                <Cell modifyField={this._modifyField.bind(this, material.id, 'costPerUnit')} pricePerUnit>
                  {h.displayPricePerUnit(material.costPerUnit, type.unit)}
                </Cell>
              );
            }}
            />
            <Column header="Qty on Order" cell={material => (
                <Cell modifyField={this._modifyField.bind(this, material.id, 'qtyOnOrder')} integer>{material.qtyOnOrder}</Cell>
              )}
            />
            <Column header="Qty in Stock" cell={material => (
                <Cell modifyField={this._modifyField.bind(this, material.id, 'qtyInStock')} integer>{material.qtyInStock}</Cell>
              )}
            />
            {this._renderRemoveColumn()}

        {this._renderForm()}

    );
  }

  _renderForm() {
    if (this.state.isFormOpen) {
      return (
        <AddMaterialForm
          cancel={this._handleAddClick.bind(this)}
          submit={this._handleFormSubmit.bind(this)}
        />
      );
    }
  }

  _renderRemoveColumn() {
    if (this.state.removeMode) {
      return (
        <Column header="Remove" cell={material => (
            <Cell className="remove">
X
</Cell>
          )}
        />
      );
    }
  }
}

export default Materials;
<|endoftext|>


<commit_before>/*
 * Module.js
 * Fabian Irsara
 * Copyright 2015, Licensed GPL & MIT
 */
/** @namespace modules **/
define([
  '../sys',
  'EaselJS',
  './Component',
  '../data/Loader'
], function(
  sys,
  createjs,
  Component,
  Loader
) {
  var Parent = createjs.EventDispatcher;

  // Event constants

  var PRELOADED = 'preloaded';
  var INIT = 'init';
  var SHOW = 'show';
  var SHOWED = 'showed';
  var HIDE = 'hide';
  var HIDDEN = 'hidden';

  return sys.Class({
    __extends: Parent
  },
  /**
   * A module is a set of components

   * with a separate controller and view instance
   *
   * automatically calls init and dispose in child class

   * .hide and .show gets called automatically by TemplateEngine
   *
   * acts as a controller. automatically sets controller property in component view
   *
   * public functions that need to be overridden by child classes:
   *
   * * _this.init: binds events and initializes module construction
   * * _this.dispose: unbinds and destroys module
   * * _this.progress: called when a single file got preloaded (optional)
   * * _this.hide: hides module by animating elements out (optional)
   * * _this.show: shows module by animating elements in (optional)
   *
   * @class Module
   * @extends createjs.EventDispatcher
   * @memberof dom
   * @param {Class} ContainerClass class reference of a container or component that the module uses
   * @param {object} options to override in component
   **/
  function Module(ContainerClass, options){
    var _this = this;

    /**
     * container holder. keeps needed component class.

     * gets set automatically by using passed ContainerClass from constructor
     * @memberof dom.Module
     * @instance
     * @var {object} container
     */
    _this.container = _this.container || null;

    /**
     * preload element manifest. Has to be an array of objects containing id and src [{id: 'mydata', src: 'http:/file.png'}]
     * @see data.Loader
     * @memberof dom.Module
     * @instance
     * @var {object} preload
     */
    _this.preload = [];

    /**
     * data.Loader instance
     * @see data.Loader
     * @memberof dom.Module
     * @instance
     * @var {object} data
     */
    _this.data = null;

    // empty function that get used if child class has no functions
    var _noop = function(){};

    // set default show and hide behaviour to simply dispatch appropriate events
    // and call callbacks for use in template class
    // NOTE: if overriding hide or show module MUST call _this.hidden() and _this.show() at some point
    // otherwise template rendering functionality will be broken
    var _childFunctions = {};
    _childFunctions.init = _this.init || _noop;
    _childFunctions.dispose = _this.dispose || _noop;
    _childFunctions.progress = _this.progress || _noop;
    _childFunctions.hide = _this.hide;
    _childFunctions.show = _this.show;

    var Init = function(){
      Parent.call(_this);

      if (ContainerClass) {
        if (typeof ContainerClass === 'string') {
          _this.container = new Component(ContainerClass, null, options);
        } else {
          _this.container = new ContainerClass(options);
        }
      } else {
        _this.container = new Component('

', null, options);
      }

      _this.container.controller = _this;
      _this.container.addEventListener('addedToStage', _init);
    };

    /**
     * initializes module.
     * gets called from Module.js automatically.
     * override in child class to initialize module
     *
     * @method init
     * @memberof dom.Module
     * @instance
     * @public
     **/
    _this.init = function(){
      _childFunctions.init();
      _this.dispatchEvent(INIT);
      _this.show();
    };

    /**
     * dispatches hidden event that gets used in TemplateEngine
     * if ovverriding hide() in child class: needs to call hidden() at some point
     *
     * @method hidden
     * @memberof dom.Module
     * @instance
     * @public
     **/
    _this.hidden = function(){
      _this.destroy();
      _this.dispatchEvent(HIDDEN);
    };

    /**
     * dispatches showed event that gets used in TemplateEngine
     * if ovverriding show() in child class: needs to call showed() at some point
     *
     * @method showed
     * @memberof dom.Module
     * @instance
     * @public
     **/
    _this.showed = function(){
      _this.dispatchEvent(SHOWED);
    };

    /**
     * dispatches hidden by default.
     * if overridden needs to do some sort of animation
     * and then call hidden manually
     *
     * @method hide
     * @memberof dom.Module
     * @instance
     * @public
     **/
    _this.hide = function(){
      // disallow multiple hide calls by setting hide to noop when first called
      _this.hide = _noop;
      _childFunctions.hide();
      _this.dispatchEvent(HIDE);
    };

    /**
     * dispatches showed by default.
     * if overridden needs to do some sort of animation
     * and then call showed manually
     *
     * @method show
     * @memberof dom.Module
     * @instance
     * @public
     **/
    _this.show = function(){
      // disallow multiple show calls by setting show to noop when first called
      _this.show = _noop;

      // hides component for a short duration before really showing element
      _this.container.el.style.visibility = 'hidden';

      // add a little timeout so components can resize and align properly
      setTimeout(_doShow, 50);
    };

    /**
     * cleans up some data
     *
     * @method destroy
     * @memberof dom.Module
     * @instance
     * @protected
     **/
    _this.destroy = function(){
      if (_this.data) {
        try {
          _this.data.reset();
        } catch(e){}

        _this.data.removeAll();
        _this.data.destroy();

        _this.data = null;
      }
    };

    /**
     * calls show on child class
     * or simply dispatches showed event by default
     * if show is not overriden in child class
     *
     * @method _doShow
     * @memberof dom.Module
     * @instance
     * @private
     **/
    var _doShow = function(){
      // re-shows component
      _this.container.el.style.visibility = '';
      _childFunctions.show();
      _this.dispatchEvent(SHOW);
    };

    /**
     * dispatches preloaded event and initializes module
     *
     * @method _complete
     * @memberof dom.Module
     * @instance
     * @private
     **/
    var _complete = function(){
      if (_this.data) {
        _this.data.removeEventListener('cached', _progress);
        _this.data.removeEventListener('progress', _progress);
        _this.data.removeEventListener('fileload', _fileLoad);
        _this.data.removeEventListener('complete', _complete);
      }

      _this.dispatchEvent(PRELOADED);
      _this.init();
    };

    /**
     * dispatches progress event used in preload components
     *
     * @method _progress
     * @memberof dom.Module
     * @instance
     * @private
     **/
    var _progress = function(event){
      var tmp = new createjs.Event(event.type);
      tmp.progress = event.progress;
      _this.dispatchEvent(tmp);
    };

    /**
     * dispatches filelload event used in preload components
     * also calls .progress event on child module class to display element immediately if needed
     *
     * @method _fileLoad
     * @memberof dom.Module
     * @instance
     * @private
     **/
    var _fileLoad = function(event){
      _this.dispatchEvent(event);
      _childFunctions.progress(event.result);
    };

    /**
     * preloads data, shows and initializes module
     *
     * @method _init
     * @memberof dom.Module
     * @instance
     * @private
     **/
    var _init = function(){
      _this.container.removeEventListener('addedToStage', _init);
      _this.container.addEventListener('removedFromStage', _dispose);

      if (_this.preload.length > 0) {
        _this.data = new Loader();
        _this.data.addEventListener('cached', _progress);
        _this.data.addEventListener('progress', _progress);
        _this.data.addEventListener('fileload', _fileLoad);
        _this.data.addEventListener('complete', _complete);
        _this.data.load(_this.preload);
      } else {
        _complete();
      }
    };

    /**
     * calls dispose to unbind events on child class module
     *
     * @method _dispose
     * @memberof dom.Module
     * @instance
     * @private
     **/
    var _dispose = function(){
      _this.container.removeEventListener('removedFromStage', _dispose);
      if (_this.dispose) _this.dispose();
    };

    if (! _childFunctions.hide) _childFunctions.hide = _this.hidden;
    if (! _childFunctions.show) _childFunctions.show = _this.showed;

    Init();
  });
});
<commit_msg>cleanup<commit_after>/*
 * Module.js
 * Fabian Irsara
 * Copyright 2015, Licensed GPL & MIT
 */
/** @namespace modules **/
define([
  '../sys',
  'EaselJS',
  './Component',
  '../data/Loader'
], function(
  sys,
  createjs,
  Component,
  Loader
) {
  var Parent = createjs.EventDispatcher;

  // Event constants

  var PRELOADED = 'preloaded';
  var INIT = 'init';
  var SHOW = 'show';
  var SHOWED = 'showed';
  var HIDE = 'hide';
  var HIDDEN = 'hidden';

  return sys.Class({
    __extends: Parent
  },
  /**
   * A module is a set of components

   * with a separate controller and view instance
   *
   * automatically calls init and dispose in child class

   * .hide and .show gets called automatically by TemplateEngine
   *
   * acts as a controller. automatically sets controller property in component view
   *
   * public functions that need to be overridden by child classes:
   *
   * * _this.init: binds events and initializes module construction
   * * _this.dispose: unbinds and destroys module
   * * _this.progress: called when a single file got preloaded (optional)
   * * _this.hide: hides module by animating elements out (optional)
   * * _this.show: shows module by animating elements in (optional)
   *
   * @class Module
   * @extends createjs.EventDispatcher
   * @memberof dom
   * @param {Class} ContainerClass class reference of a container or component that the module uses
   * @param {object} options to override in component
   **/
  function Module(ContainerClass, options){
    var _this = this;

    /**
     * container holder. keeps needed component class.

     * gets set automatically by using passed ContainerClass from constructor
     * @memberof dom.Module
     * @instance
     * @var {object} container
     */
    _this.container = _this.container || null;

    /**
     * preload element manifest. Has to be an array of objects containing id and src [{id: 'mydata', src: 'http:/file.png'}]
     * @see data.Loader
     * @memberof dom.Module
     * @instance
     * @var {object} preload
     */
    _this.preload = [];

    /**
     * data.Loader instance
     * @see data.Loader
     * @memberof dom.Module
     * @instance
     * @var {object} data
     */
    _this.data = null;

    // empty function that get used if child class has no functions
    var _noop = function(){};

    // set default show and hide behaviour to simply dispatch appropriate events
    // and call callbacks for use in template class
    // NOTE: if overriding hide or show module MUST call _this.hidden() and _this.show() at some point
    // otherwise template rendering functionality will be broken
    var _childFunctions = {};
    _childFunctions.init = _this.init || _noop;
    _childFunctions.dispose = _this.dispose || _noop;
    _childFunctions.progress = _this.progress || _noop;
    _childFunctions.hide = _this.hide;
    _childFunctions.show = _this.show;

    var Init = function(){
      Parent.call(_this);

      if (ContainerClass) {
        if (typeof ContainerClass === 'string') {
          _this.container = new Component(ContainerClass, null, options);
        } else {
          _this.container = new ContainerClass(options);
        }
      } else {
        _this.container = new Component('

', null, options);
      }

      _this.container.controller = _this;
      _this.container.addEventListener('addedToStage', _init);
    };

    /**
     * initializes module.
     * gets called from Module.js automatically.
     * override in child class to initialize module
     *
     * @method init
     * @memberof dom.Module
     * @instance
     * @public
     **/
    _this.init = function(){
      _childFunctions.init();
      _this.dispatchEvent(INIT);
      _this.show();
    };

    /**
     * dispatches hidden event that gets used in TemplateEngine
     * if ovverriding hide() in child class: needs to call hidden() at some point
     *
     * @method hidden
     * @memberof dom.Module
     * @instance
     * @public
     **/
    _this.hidden = function(){
      _this.destroy();
      _this.dispatchEvent(HIDDEN);
    };

    /**
     * dispatches showed event that gets used in TemplateEngine
     * if ovverriding show() in child class: needs to call showed() at some point
     *
     * @method showed
     * @memberof dom.Module
     * @instance
     * @public
     **/
    _this.showed = function(){
      _this.dispatchEvent(SHOWED);
    };

    /**
     * dispatches hidden by default.
     * if overridden needs to do some sort of animation
     * and then call hidden manually
     *
     * @method hide
     * @memberof dom.Module
     * @instance
     * @public
     **/
    _this.hide = function(){
      // disallow multiple hide calls by setting hide to noop when first called
      _this.hide = _noop;
      _childFunctions.hide();
      _this.dispatchEvent(HIDE);
    };

    /**
     * dispatches showed by default.
     * if overridden needs to do some sort of animation
     * and then call showed manually
     *
     * @method show
     * @memberof dom.Module
     * @instance
     * @public
     **/
    _this.show = function(){
      // disallow multiple show calls by setting show to noop when first called
      _this.show = _noop;

      // hides component for a short duration before really showing element
      _this.container.el.style.visibility = 'hidden';

      // add a little timeout so components can resize and align properly
      _this.__doShowTimeout = setTimeout(_doShow, 50);
    };

    /**
     * cleans up some data
     *
     * @method destroy
     * @memberof dom.Module
     * @instance
     * @protected
     **/
    _this.destroy = function(){
      if (_this.data) {
        try {
          _this.data.reset();
        } catch(e){}

        _this.data.removeAll();
        _this.data.destroy();

        _this.data = null;

        if (_this.__doShowTimeout) clearTimeout(_this.__doShowTimeout);
      }
    };

    /**
     * calls show on child class
     * or simply dispatches showed event by default
     * if show is not overriden in child class
     *
     * @method _doShow
     * @memberof dom.Module
     * @instance
     * @private
     **/
    var _doShow = function(){
      // re-shows component
      _this.__doShowTimeout = null;
      _this.container.el.style.visibility = '';
      _childFunctions.show();
      _this.dispatchEvent(SHOW);
    };

    /**
     * dispatches preloaded event and initializes module
     *
     * @method _complete
     * @memberof dom.Module
     * @instance
     * @private
     **/
    var _complete = function(){
      if (_this.data) {
        _this.data.removeEventListener('cached', _progress);
        _this.data.removeEventListener('progress', _progress);
        _this.data.removeEventListener('fileload', _fileLoad);
        _this.data.removeEventListener('complete', _complete);
      }

      _this.dispatchEvent(PRELOADED);
      _this.init();
    };

    /**
     * dispatches progress event used in preload components
     *
     * @method _progress
     * @memberof dom.Module
     * @instance
     * @private
     **/
    var _progress = function(event){
      var tmp = new createjs.Event(event.type);
      tmp.progress = event.progress;
      _this.dispatchEvent(tmp);
    };

    /**
     * dispatches filelload event used in preload components
     * also calls .progress event on child module class to display element immediately if needed
     *
     * @method _fileLoad
     * @memberof dom.Module
     * @instance
     * @private
     **/
    var _fileLoad = function(event){
      _this.dispatchEvent(event);
      _childFunctions.progress(event.result);
    };

    /**
     * preloads data, shows and initializes module
     *
     * @method _init
     * @memberof dom.Module
     * @instance
     * @private
     **/
    var _init = function(){
      _this.container.removeEventListener('addedToStage', _init);
      _this.container.addEventListener('removedFromStage', _dispose);

      if (_this.preload.length > 0) {
        _this.data = new Loader();
        _this.data.addEventListener('cached', _progress);
        _this.data.addEventListener('progress', _progress);
        _this.data.addEventListener('fileload', _fileLoad);
        _this.data.addEventListener('complete', _complete);
        _this.data.load(_this.preload);
      } else {
        _complete();
      }
    };

    /**
     * calls dispose to unbind events on child class module
     *
     * @method _dispose
     * @memberof dom.Module
     * @instance
     * @private
     **/
    var _dispose = function(){
      _this.container.removeEventListener('removedFromStage', _dispose);
      if (_this.dispose) _this.dispose();
    };

    if (! _childFunctions.hide) _childFunctions.hide = _this.hidden;
    if (! _childFunctions.show) _childFunctions.show = _this.showed;

    Init();
  });
});
<|endoftext|>


<commit_before>window.Cow = window.Cow || {};
//Synstore keeps track of records
Cow.syncstore =  function(config){
    var self = this;
    this._dbname = config.dbname;
    this._core = config.core;
    //console.log('new store',this._dbname);
    this.loaded = new Promise(function(resolve, reject){
        //console.log('reading db ',self._dbname);
        if (config.noIDB){
            resolve();
        }
        else {
            /**
                See for indexeddb wrapper:
                    https://github.com/aaronpowell/db.js
            **/
            db.open( {
                server: self._dbname,
                version: 1,
                schema: {
                    main: {
                        key: { keyPath: '_id' , autoIncrement: false },
                        // Optionally add indexes
                        indexes: {
                            updated: { },
                            _id: { unique: true }
                        }
                    }
                }
            } ).done( function ( s ) {
                self._db = s;
                self._db_getRecords().then(function(rows){
                    //console.log('Got records from db ',self._dbname);
                    rows.forEach(function(d){
                         //console.log(d);
                         var record = self._recordproto(d._id);
                         record.inflate(d);
                         var existing = false;
                         //Not likely to exist in the _records at this time but better safe then sorry..
                         for (var i=0;i<self._records.length;i++){
                            if (self._records[i]._id == record._id) {
                                //existing = true; //Already in list
                                //record = -1;
                            }
                         }
                         if (!existing){
                             self._records.push(record); //Adding to the list
                         }
                     });
                     self.trigger('datachange');
                     resolve();
                }).catch(function(e){
                    console.warn(e.message);
                });
            });
        }
    });
};
/**
    See for use of promises:
        1. http://www.html5rocks.com/en/tutorials/es6/promises/
        2. https://github.com/jakearchibald/ES6-Promises
**/

Cow.syncstore.prototype =
{ //db object
    //All these calls will be asynchronous and thus returning a promise instead of data

    //_db_addRecord: function(config){
    _db_write: function(config){
        var data = config.data;
        var source = config.source;
        data._id = data._id.toString();
        var self = this;
        var db = this._db;
        return new Promise(function(resolve, reject){
            db.main.remove(data._id).done(function(){
                db.main.add(data).done(function(d){
                    resolve(d);
                }).fail(function(d,e){
                    console.warn(e);
                    reject(e);
                });
            }).fail(function(e){
                console.warn(e);
                reject(e);
            });
        });
    },
    _db_getRecords: function(){
        var self = this;
        return new Promise(function(resolve, reject){
           self._db.main.query().filter().execute().done(function(doc){
                resolve(doc);
           }).fail(function(e){
                reject(e);
           });
        });
    },  //returns promise
    _db_getRecord: function(id){
        var self = this;
        return new Promise(function(resolve, reject){
            self._db.main.query().filter('_id',id).execute().done(function(doc){
                resolve(doc);
            }).fail(function(doc){
                reject(doc);
            });
        });
    }, //returns promise
    _db_removeRecord: function(id){
        var self = this;
        return new Promise(function(resolve, reject){
             db.main.remove(data._id).done(function(){
                 resolve();
             }).fail(function(){
                 reject();
             });
        });
      }, //returns promise
    _initRecords: function(){ //This will start the process of getting records from db (returns promise)
        var promise = this._db_getRecords();
        var self = this;
        promise.then(function(r){

             r.forEach(function(d){
                 //console.log(d.doc);
                 var record = self._recordproto(d._id);
                 record.inflate(d);
                 var existing = false; //Not likely to exist in the _records at this time but better safe then sorry..
                 for (var i=0;i<self._records.length;i++){
                    if (self._records[i]._id == record._id) {
                        existing = true; //Already in list
                        record = -1;
                    }
                 }
                 if (!existing){
                     self._records.push(record); //Adding to the list
                 }
             });
             self.trigger('datachange');
        });
        return promise;
     },
    //_getRecords([<string>]) - return all records, if ID array is filled, only return that records
    _getRecords: function(idarray){
        var returnArray = [];
        for (var i=0;i<this._records.length;i++){
            var record = this._records[i];
            if (idarray.indexOf(record._id) > -1) {
                returnArray.push(record);
            }
        }
        return returnArray;
    },
    //_getRecord(<string>) - return record or create new one based on id
    _getRecord: function(id){
        for (var i=0;i<this._records.length;i++){
            var record = this._records[i];
            if (record._id == id) {
                return record;
            }
        }
        //var config = {_id: id};
        //return this._addRecord({source: 'UI', data: config}).status('dirty');
        //TODO: rethink this strategy: should we make a new record on non-existing or just return null
        return null;
    },
    /**
    _addRecord - creates a new record and replaces an existing one with the same _id
        when the source is 'WS' it immidiately sends to the _db, if not the record needs a manual record.sync()
    **/
    _addRecord: function(config){
        if (!config.source || !config.data){
            console.warn('Wrong input: ',config);
            return false;
        }
        var promise = null;
        var source = config.source;
        var data = config.data;
        var existing = false;
        var record;
        //Check to see if the record is existing or new
        for (var i=0;i<this._records.length;i++){
            if (this._records[i]._id == data._id) {
                existing = true; //Already in list
                record = this._records[i];
                record.inflate(data);
                if (this._db && source == 'WS'){ //update the db
                    //promise = this._db_updateRecord({source:source, data: record.deflate()});
                    this._db_write({source:source, data: record.deflate()});
                }
            }
        }
        if (!existing){
            //Create a new record and inflate with the data we got
            record = this._recordproto(data._id);
            record.inflate(data);
            if (this._db && source == 'WS'){
                promise = this._db_write({source:source,data:record.deflate()});
            }
            this._records.push(record); //Adding to the list
            //console.log(this._records.length);
        }

        return record;
    },
    /**
        _getRecordsOn(timestamp) -
    **/
    _getRecordsOn: function(timestamp){
        var returnarr = [];
        _.each(this._records, function(d){
            //If request is older than feature itself, disregard
            if (timestamp < d._created){
                //don't add
            }
            //If request is younger than last feature update, return normal data
            else if (timestamp > d._updated){
                returnarr.push(d);
            }
            else if (d.data(timestamp)){
                returnarr.push(d); //TODO: hier gebleven
            }
        });
        return returnarr;
    },
   /**
        Only to be used from client API

        records() - returns array of all records
        records(timestamp) - returns array of records created before timestamp
        records(id) - returns record with id (or null)
        records([id]) - returns array of records from id array
        records({config}) - creates and returns record
    **/

    records: function(config){
        if (config && Array.isArray(config)){
            return this._getRecords(config);
        }
        else if (config && typeof(config) == 'object'){
            return this._addRecord({source: 'UI', data: config}).status('dirty');
        }
        else if (config && typeof(config) == 'string'){
            return this._getRecord(config);
        }
        else if (config && typeof(config) == 'number'){
            //TODO return this._getRecordsOn(config);
        }
        else{
            return this._records;
        }
    },
    //Removing records is only useful if no local dbase is used among peers
    _removeRecord: function(id){
        for (var i=0;i<this._records.length;i++){
            if (this._records[i]._id == id) {
                    this._records.splice(i,1);
                    this.trigger('datachange');
                    return true;
            }
        }
        return false;
    },
    /**
        clear() - remove all records, generally not useful since other peers will resent the data
    **/
    clear: function(){
        var self = this;
        return new Promise(function(resolve, reject){
            self._records = [];
            if (self._db){
                self._db.main.clear().then(function(){
                        resolve(); //empty dbase from items
                });
            }
            else {
                resolve();
            }
        });
    },
    /**
        deleteAll() - sets all records to deleted=true
    **/
    deleteAll: function(){
        for (var i=0;i<this._records.length;i++){
            this._records[i].deleted(true);
        }
        this.syncRecords();
        this.trigger('datachange');
        return this;
    },
    /**
    syncRecord() - sync 1 record, returns record
    **/
    syncRecord: function(record){

        var self = this;
        var message = {};
        message.syncType = this._type;
        record.status('clean');

        if (this._projectid){ //parent store
            message.project = this._projectid;
        }
        if (this._db){
            //var promise = this._db_updateRecord({source:'UI', data: record.deflate()});
            var promise = this._db_write({source:'UI', data: record.deflate()});
            promise.then(function(d){ //wait for db
                message.record = record.deflate();
                self.trigger('datachange');
                self._core.websocket().sendData(message, 'updatedRecord');
            },function(err){
                console.warn(err);
            });
        } else { //No db, proceed immediately
            message.record = record.deflate();
            self.trigger('datachange');
            self._core.websocket().sendData(message, 'updatedRecord');
        }//TODO: remove this double code, but keep promise/non-promise intact
        return record;
    },

    /**
    syncRecords() - looks for dirty records and returns them all at once for syncing them
    **/
    syncRecords: function(){
        var pushlist = [];
        for (var i=0;i<this._records.length;i++){
            var record = this._records[i];
            if (record._status == 'dirty') {
                //this.syncRecord(record);
                record.status('clean');
                pushlist.push(record.deflate());
            }
        }
        var data =  {
            "syncType" : this._type,
            "project" : this._projectid,
            "list" : pushlist
        };
        this._core.websocket().sendData(data, 'requestedRecords');
    },

    /**
    deltaList() - needed to sync the delta's
    **/
    deltaList: function(){

    },

    /**
    **/
    compareDeltas: function(){

    },

    /**
    sync() - sync the whole store, not only dirty records
    **/
    sync: function(){
        var self = this;
        this.loaded.then(function(d){
            var message = {};
            message.syncType = self._type;
            message.project = self._projectid;
            message.list = self.idList();
            self.core.websocket().sendData(message, 'newList');
        });
        self.loaded.catch(function(e){
                console.error(e.message);
        });
    },

    /**
    idList() - needed to start the syncing with other peers
                only makes sense after fully loading the indexeddb
    **/
    idList: function(){
        var fids = [];
        for (var i=0;i<this._records.length;i++){
            var item = this._records[i];
            var iditem = {};
            iditem._id = item._id;
            iditem.timestamp = item.timestamp();
            iditem.deleted = item.deleted();
            fids.push(iditem);
        }
        return fids;
    },
    /**
    requestItems(array) - returns the items that were requested
    **/
    requestRecords: function(fidlist){
		var pushlist = [];
		for (i=0;i<this._records.length;i++){
		    var localrecord =  this._records[i];
		    for (j=0;j<fidlist.length;j++){
                var rem_val = fidlist[j];
                if (rem_val == localrecord._id){
                    pushlist.push(localrecord.deflate());
                }
            }
		}
		return pushlist;
	},
    /**
	compareRecords(config) - compares incoming idlist with idlist from current stack based on timestamp and status
					generates 2 lists: requestlist and pushlist
	**/
    compareRecords: function(config){
        if (this._dbname == 'items_test'){
            console.log('break here');
        }
        var uid = config.uid;   //id of peer that sends syncrequest
        var fidlist = config.list;
		var returndata = {};
		var copyof_rem_list = [];
		returndata.requestlist = [];
		returndata.pushlist = [];
		var i;
		//Prepare copy of remote fids as un-ticklist, but only for non-deleted items
		if (fidlist){
			for (i=0;i<fidlist.length;i++){
				if (fidlist[i].deleted != 'true'){
					copyof_rem_list.push(fidlist[i]._id);
				}
			}
			for (i=0;i<this._records.length;i++){
					var local_item = this._records[i];
					var found = -1;
					for (var j=0;j<fidlist.length;j++){
							//in both lists
							var rem_val = fidlist[j];
							if (rem_val._id == local_item._id){
								found = 1;
								//local is newer
								if (rem_val.timestamp < local_item._updated){
									returndata.pushlist.push(local_item.deflate());
								}
								//remote is newer
								else if (rem_val.timestamp > local_item._updated){
									returndata.requestlist.push(rem_val._id);
								}
								//remove from copyremotelist
								//OBS var tmppos = $.inArray(local_item._id,copyof_rem_list);
								var tmppos = copyof_rem_list.indexOf(local_item._id);
								if (tmppos >= 0){
									copyof_rem_list.splice(tmppos,1);
								}
							}
					}
					//local but not remote and not deleted
					if (found == -1 && local_item.deleted() != 'true'){
						returndata.pushlist.push(local_item.deflate());
					}
			}
		}
		//Add remainder of copyof_rem_list to requestlist
		for (i=0;i<copyof_rem_list.length;i++){
		    var val = copyof_rem_list[i];
			returndata.requestlist.push(val);
		}

  //This part is only for sending the data
  /* Obsolete by new websocket prototcol. Still interesting for partial syncing method though.
		var message = {};
        //First the requestlist
        message.requestlist = returndata.requestlist;
        message.pushlist = []; //empty
        //message.storename = payload.storename;
        message.dbname = this._dbname;
        //this._core.websocket().sendData(message,'syncPeer',uid);
        //Now the pushlist bit by bit
        message.requestlist = []; //empty
        var k = 0;
        for (j=0;j<returndata.pushlist.length;j++){
                var item = returndata.pushlist[j];
                message.pushlist.push(item);
                k++;
                if (k >= 1) { //max 1 feat every time
                    k = 0;
                    //this._core.websocket().sendData(message,'syncPeer',uid);
                    message.pushlist = []; //empty
                }
        }
        //sent the remainder of the list
        if (k > 0){
            //this._core.websocket().sendData(message,'syncPeer',uid);
        }
    */
   //end of sending data
        return returndata;
    }
};
//Adding some Backbone event binding functionality to the store
_.extend(Cow.syncstore.prototype, Events);
<commit_msg>Bugfix on last commit<commit_after>window.Cow = window.Cow || {};
//Synstore keeps track of records
Cow.syncstore =  function(config){
    var self = this;
    this._dbname = config.dbname;
    this._core = config.core;
    //console.log('new store',this._dbname);
    this.loaded = new Promise(function(resolve, reject){
        //console.log('reading db ',self._dbname);
        if (config.noIDB){
            resolve();
        }
        else {
            /**
                See for indexeddb wrapper:
                    https://github.com/aaronpowell/db.js
            **/
            db.open( {
                server: self._dbname,
                version: 1,
                schema: {
                    main: {
                        key: { keyPath: '_id' , autoIncrement: false },
                        // Optionally add indexes
                        indexes: {
                            updated: { },
                            _id: { unique: true }
                        }
                    }
                }
            } ).done( function ( s ) {
                self._db = s;
                self._db_getRecords().then(function(rows){
                    //console.log('Got records from db ',self._dbname);
                    rows.forEach(function(d){
                         //console.log(d);
                         var record = self._recordproto(d._id);
                         record.inflate(d);
                         var existing = false;
                         //Not likely to exist in the _records at this time but better safe then sorry..
                         for (var i=0;i<self._records.length;i++){
                            if (self._records[i]._id == record._id) {
                                //existing = true; //Already in list
                                //record = -1;
                            }
                         }
                         if (!existing){
                             self._records.push(record); //Adding to the list
                         }
                     });
                     self.trigger('datachange');
                     resolve();
                }).catch(function(e){
                    console.warn(e.message);
                });
            });
        }
    });
};
/**
    See for use of promises:
        1. http://www.html5rocks.com/en/tutorials/es6/promises/
        2. https://github.com/jakearchibald/ES6-Promises
**/

Cow.syncstore.prototype =
{ //db object
    //All these calls will be asynchronous and thus returning a promise instead of data

    //_db_addRecord: function(config){
    _db_write: function(config){
        var data = config.data;
        var source = config.source;
        data._id = data._id.toString();
        var self = this;
        var db = this._db;
        return new Promise(function(resolve, reject){
            db.main.remove(data._id).done(function(){
                db.main.add(data).done(function(d){
                    resolve(d);
                }).fail(function(d,e){
                    console.warn(e);
                    reject(e);
                });
            }).fail(function(e){
                console.warn(e);
                reject(e);
            });
        });
    },
    _db_getRecords: function(){
        var self = this;
        return new Promise(function(resolve, reject){
           self._db.main.query().filter().execute().done(function(doc){
                resolve(doc);
           }).fail(function(e){
                reject(e);
           });
        });
    },  //returns promise
    _db_getRecord: function(id){
        var self = this;
        return new Promise(function(resolve, reject){
            self._db.main.query().filter('_id',id).execute().done(function(doc){
                resolve(doc);
            }).fail(function(doc){
                reject(doc);
            });
        });
    }, //returns promise
    _db_removeRecord: function(id){
        var self = this;
        return new Promise(function(resolve, reject){
             db.main.remove(data._id).done(function(){
                 resolve();
             }).fail(function(){
                 reject();
             });
        });
      }, //returns promise
    _initRecords: function(){ //This will start the process of getting records from db (returns promise)
        var promise = this._db_getRecords();
        var self = this;
        promise.then(function(r){

             r.forEach(function(d){
                 //console.log(d.doc);
                 var record = self._recordproto(d._id);
                 record.inflate(d);
                 var existing = false; //Not likely to exist in the _records at this time but better safe then sorry..
                 for (var i=0;i<self._records.length;i++){
                    if (self._records[i]._id == record._id) {
                        existing = true; //Already in list
                        record = -1;
                    }
                 }
                 if (!existing){
                     self._records.push(record); //Adding to the list
                 }
             });
             self.trigger('datachange');
        });
        return promise;
     },
    //_getRecords([<string>]) - return all records, if ID array is filled, only return that records
    _getRecords: function(idarray){
        var returnArray = [];
        for (var i=0;i<this._records.length;i++){
            var record = this._records[i];
            if (idarray.indexOf(record._id) > -1) {
                returnArray.push(record);
            }
        }
        return returnArray;
    },
    //_getRecord(<string>) - return record or create new one based on id
    _getRecord: function(id){
        for (var i=0;i<this._records.length;i++){
            var record = this._records[i];
            if (record._id == id) {
                return record;
            }
        }
        //var config = {_id: id};
        //return this._addRecord({source: 'UI', data: config}).status('dirty');
        //TODO: rethink this strategy: should we make a new record on non-existing or just return null
        return null;
    },
    /**
    _addRecord - creates a new record and replaces an existing one with the same _id
        when the source is 'WS' it immidiately sends to the _db, if not the record needs a manual record.sync()
    **/
    _addRecord: function(config){
        if (!config.source || !config.data){
            console.warn('Wrong input: ',config);
            return false;
        }
        var promise = null;
        var source = config.source;
        var data = config.data;
        var existing = false;
        var record;
        //Check to see if the record is existing or new
        for (var i=0;i<this._records.length;i++){
            if (this._records[i]._id == data._id) {
                existing = true; //Already in list
                record = this._records[i];
                record.inflate(data);
                if (this._db && source == 'WS'){ //update the db
                    //promise = this._db_updateRecord({source:source, data: record.deflate()});
                    this._db_write({source:source, data: record.deflate()});
                }
            }
        }
        if (!existing){
            //Create a new record and inflate with the data we got
            record = this._recordproto(data._id);
            record.inflate(data);
            if (this._db && source == 'WS'){
                promise = this._db_write({source:source,data:record.deflate()});
            }
            this._records.push(record); //Adding to the list
            //console.log(this._records.length);
        }

        return record;
    },
    /**
        _getRecordsOn(timestamp) -
    **/
    _getRecordsOn: function(timestamp){
        var returnarr = [];
        _.each(this._records, function(d){
            //If request is older than feature itself, disregard
            if (timestamp < d._created){
                //don't add
            }
            //If request is younger than last feature update, return normal data
            else if (timestamp > d._updated){
                returnarr.push(d);
            }
            else if (d.data(timestamp)){
                returnarr.push(d); //TODO: hier gebleven
            }
        });
        return returnarr;
    },
   /**
        Only to be used from client API

        records() - returns array of all records
        records(timestamp) - returns array of records created before timestamp
        records(id) - returns record with id (or null)
        records([id]) - returns array of records from id array
        records({config}) - creates and returns record
    **/

    records: function(config){
        if (config && Array.isArray(config)){
            return this._getRecords(config);
        }
        else if (config && typeof(config) == 'object'){
            return this._addRecord({source: 'UI', data: config}).status('dirty');
        }
        else if (config && typeof(config) == 'string'){
            return this._getRecord(config);
        }
        else if (config && typeof(config) == 'number'){
            //TODO return this._getRecordsOn(config);
        }
        else{
            return this._records;
        }
    },
    //Removing records is only useful if no local dbase is used among peers
    _removeRecord: function(id){
        for (var i=0;i<this._records.length;i++){
            if (this._records[i]._id == id) {
                    this._records.splice(i,1);
                    this.trigger('datachange');
                    return true;
            }
        }
        return false;
    },
    /**
        clear() - remove all records, generally not useful since other peers will resent the data
    **/
    clear: function(){
        var self = this;
        return new Promise(function(resolve, reject){
            self._records = [];
            if (self._db){
                self._db.main.clear().then(function(){
                        resolve(); //empty dbase from items
                });
            }
            else {
                resolve();
            }
        });
    },
    /**
        deleteAll() - sets all records to deleted=true
    **/
    deleteAll: function(){
        for (var i=0;i<this._records.length;i++){
            this._records[i].deleted(true);
        }
        this.syncRecords();
        this.trigger('datachange');
        return this;
    },
    /**
    syncRecord() - sync 1 record, returns record
    **/
    syncRecord: function(record){

        var self = this;
        var message = {};
        message.syncType = this._type;
        record.status('clean');

        if (this._projectid){ //parent store
            message.project = this._projectid;
        }
        if (this._db){
            //var promise = this._db_updateRecord({source:'UI', data: record.deflate()});
            var promise = this._db_write({source:'UI', data: record.deflate()});
            promise.then(function(d){ //wait for db
                message.record = record.deflate();
                self.trigger('datachange');
                self._core.websocket().sendData(message, 'updatedRecord');
            },function(err){
                console.warn(err);
            });
        } else { //No db, proceed immediately
            message.record = record.deflate();
            self.trigger('datachange');
            self._core.websocket().sendData(message, 'updatedRecord');
        }//TODO: remove this double code, but keep promise/non-promise intact
        return record;
    },

    /**
    syncRecords() - looks for dirty records and returns them all at once for syncing them
    **/
    syncRecords: function(){
        var pushlist = [];
        for (var i=0;i<this._records.length;i++){
            var record = this._records[i];
            if (record._status == 'dirty') {
                //this.syncRecord(record);
                record.status('clean');
                pushlist.push(record.deflate());
            }
        }
        var data =  {
            "syncType" : this._type,
            "project" : this._projectid,
            "list" : pushlist
        };
        this._core.websocket().sendData(data, 'requestedRecords');
    },

    /**
    deltaList() - needed to sync the delta's
    **/
    deltaList: function(){

    },

    /**
    **/
    compareDeltas: function(){

    },

    /**
    sync() - sync the whole store, not only dirty records
    **/
    sync: function(){
        var self = this;
        this.loaded.then(function(d){
            var message = {};
            message.syncType = self._type;
            message.project = self._projectid;
            message.list = self.idList();
            self._core.websocket().sendData(message, 'newList');
        });
        self.loaded.catch(function(e){
                console.error(e.message);
        });
    },

    /**
    idList() - needed to start the syncing with other peers
                only makes sense after fully loading the indexeddb
    **/
    idList: function(){
        var fids = [];
        for (var i=0;i<this._records.length;i++){
            var item = this._records[i];
            var iditem = {};
            iditem._id = item._id;
            iditem.timestamp = item.timestamp();
            iditem.deleted = item.deleted();
            fids.push(iditem);
        }
        return fids;
    },
    /**
    requestItems(array) - returns the items that were requested
    **/
    requestRecords: function(fidlist){
		var pushlist = [];
		for (i=0;i<this._records.length;i++){
		    var localrecord =  this._records[i];
		    for (j=0;j<fidlist.length;j++){
                var rem_val = fidlist[j];
                if (rem_val == localrecord._id){
                    pushlist.push(localrecord.deflate());
                }
            }
		}
		return pushlist;
	},
    /**
	compareRecords(config) - compares incoming idlist with idlist from current stack based on timestamp and status
					generates 2 lists: requestlist and pushlist
	**/
    compareRecords: function(config){
        if (this._dbname == 'items_test'){
            console.log('break here');
        }
        var uid = config.uid;   //id of peer that sends syncrequest
        var fidlist = config.list;
		var returndata = {};
		var copyof_rem_list = [];
		returndata.requestlist = [];
		returndata.pushlist = [];
		var i;
		//Prepare copy of remote fids as un-ticklist, but only for non-deleted items
		if (fidlist){
			for (i=0;i<fidlist.length;i++){
				if (fidlist[i].deleted != 'true'){
					copyof_rem_list.push(fidlist[i]._id);
				}
			}
			for (i=0;i<this._records.length;i++){
					var local_item = this._records[i];
					var found = -1;
					for (var j=0;j<fidlist.length;j++){
							//in both lists
							var rem_val = fidlist[j];
							if (rem_val._id == local_item._id){
								found = 1;
								//local is newer
								if (rem_val.timestamp < local_item._updated){
									returndata.pushlist.push(local_item.deflate());
								}
								//remote is newer
								else if (rem_val.timestamp > local_item._updated){
									returndata.requestlist.push(rem_val._id);
								}
								//remove from copyremotelist
								//OBS var tmppos = $.inArray(local_item._id,copyof_rem_list);
								var tmppos = copyof_rem_list.indexOf(local_item._id);
								if (tmppos >= 0){
									copyof_rem_list.splice(tmppos,1);
								}
							}
					}
					//local but not remote and not deleted
					if (found == -1 && local_item.deleted() != 'true'){
						returndata.pushlist.push(local_item.deflate());
					}
			}
		}
		//Add remainder of copyof_rem_list to requestlist
		for (i=0;i<copyof_rem_list.length;i++){
		    var val = copyof_rem_list[i];
			returndata.requestlist.push(val);
		}

  //This part is only for sending the data
  /* Obsolete by new websocket prototcol. Still interesting for partial syncing method though.
		var message = {};
        //First the requestlist
        message.requestlist = returndata.requestlist;
        message.pushlist = []; //empty
        //message.storename = payload.storename;
        message.dbname = this._dbname;
        //this._core.websocket().sendData(message,'syncPeer',uid);
        //Now the pushlist bit by bit
        message.requestlist = []; //empty
        var k = 0;
        for (j=0;j<returndata.pushlist.length;j++){
                var item = returndata.pushlist[j];
                message.pushlist.push(item);
                k++;
                if (k >= 1) { //max 1 feat every time
                    k = 0;
                    //this._core.websocket().sendData(message,'syncPeer',uid);
                    message.pushlist = []; //empty
                }
        }
        //sent the remainder of the list
        if (k > 0){
            //this._core.websocket().sendData(message,'syncPeer',uid);
        }
    */
   //end of sending data
        return returndata;
    }
};
//Adding some Backbone event binding functionality to the store
_.extend(Cow.syncstore.prototype, Events);
<|endoftext|>


<commit_before>Handlebars.registerHelper(
	"modes", function(mode) {
		var modes = {
			"~": "owner",
			"&": "admin",
			"@": "op",
			"%": "half-op",
			"+": "voice",
			"" : "normal"
		};
		return modes[mode];
	}
);
<commit_msg>Add ! modechar to admin<commit_after>Handlebars.registerHelper(
	"modes", function(mode) {
		var modes = {
			"~": "owner",
			"&": "admin",
			"!": "admin",
			"@": "op",
			"%": "half-op",
			"+": "voice",
			"" : "normal"
		};
		return modes[mode];
	}
);
<|endoftext|>


<commit_before>/**
 * Kotatsu Compiler Creator
 * =========================
 *
 * Function in charge of creating the webpack compilers for the library.
 */
var webpack = require('webpack'),
    BundleUpdateHookPlugin = require('webpack-bundle-update-hook-plugin'),
    NodePlugin = require('./NodePlugin.js'),
    progress = require('./progress.js'),
    path = require('path'),
    fs = require('fs'),
    _ = require('lodash');

/**
 * Constants.
 */
var NODE_ENVIRONMENT = {
  console: false,
  global: false,
  process: false,
  Buffer: false,
  __filename: false,
  __dirname: false,
  setImmediate: false
};

var BABEL_ES2015 = require.resolve('babel-preset-es2015'),
    BABEL_JSX = require.resolve('babel-plugin-transform-react-jsx');

/**
 * Main function.
 */
module.exports = function createCompiler(opts) {
  var frontEnd = opts.command === 'serve',
      backEnd = !frontEnd,
      monitor = opts.command === 'monitor';

  var entry = opts.entry,
      output = opts.output;

  // Building the entry
  var entries = [];

  if (backEnd)
    entries.push(path.join(__dirname, '..', 'hot', 'client.js'));

  if (frontEnd)
    entries.push('webpack-hot-middleware/client');

  entries.push(entry);

  // Creating the webpack config
  var config = {
    entry: entries,
    output: {
      path: frontEnd ? '/kotatsu' : output,
      filename: 'bundle.js',
      publicPath: '/build/'
    },
    plugins: [
      new webpack.optimize.OccurenceOrderPlugin(),
      new webpack.HotModuleReplacementPlugin(),
      new webpack.NoErrorsPlugin(),
      new BundleUpdateHookPlugin()
    ],
    module: {}
  };

  // Are we creating a config for backend?
  if (backEnd) {

    // Env
    config.context = opts.cwd;
    config.target = 'node';
    config.node = NODE_ENVIRONMENT;

    // Source maps
    config.devtoolModuleFilenameTemplate = '[absolute-resource-path]';

    // Registering node_modules as externals
    config.externals = {};
    fs.readdirSync(path.join(process.cwd(), 'node_modules'))
      .filter(function(p) {
        return p !== '.bin';
      })
      .forEach(function(m) {
        config.externals[m] = 'commonjs ' + m;
      });

    // Applying the node plugin
    config.plugins.unshift(new NodePlugin());
  }

  // Should we display a progress bar?
  if (opts.progress)
    config.plugins.push(progress());

  // Do we want sourcemaps
  if (opts.sourceMaps || opts.devtool) {

    if (backEnd) {
      var sourceMapModulePath = require.resolve('source-map-support'),
          injectString = 'require(\'' + sourceMapModulePath + '\').install();';

      config.plugins.push(new webpack.BannerPlugin(injectString, {
        raw: true,
        entryOnly: false
      }));
    }

    config.devtool = opts.devtool || 'source-map';
  }

  // Merging the user's config
  // NOTE: our config should take precedence over the user's one.
  config = _.merge({}, opts.config || {}, config);

  // Additional loaders
  var loaders = config.module.loaders || [];

  // - JSON
  loaders.push({
    test: /\.json$/,
    loader: require.resolve('json-loader')
  });

  // - Babel & ES2015
  if (opts.babel || opts.es2015 || opts.presets.length) {
    var presets = opts.presets.map(function(p) {
      if (p === 'es2015')
        return BABEL_ES2015;
      return p;
    });

    if (opts.es2015)
      presets.push(BABEL_ES2015);

    // Deduping
    presets = _.uniq(presets);

    var babel = {
      test: /\.jsx?$/,
      exclude: /(node_modules|bower_components)/,
      loader: require.resolve('babel-loader'),
      query: {
        presets: presets
      }
    };

    if (opts.jsx && !~opts.presets.indexOf('react')) {
      var plugins = [[BABEL_JSX]];

      if (opts.pragma)
        plugins[0].push({pragma: opts.pragma});

      babel.query.plugins = plugins;
    }

    loaders.push(babel);
  }

  config.module.loaders = loaders;

  return webpack(config);
};
<commit_msg>Linting<commit_after>/**
 * Kotatsu Compiler Creator
 * =========================
 *
 * Function in charge of creating the webpack compilers for the library.
 */
var webpack = require('webpack'),
    BundleUpdateHookPlugin = require('webpack-bundle-update-hook-plugin'),
    NodePlugin = require('./NodePlugin.js'),
    progress = require('./progress.js'),
    path = require('path'),
    fs = require('fs'),
    _ = require('lodash');

/**
 * Constants.
 */
var NODE_ENVIRONMENT = {
  console: false,
  global: false,
  process: false,
  Buffer: false,
  __filename: false,
  __dirname: false,
  setImmediate: false
};

var BABEL_ES2015 = require.resolve('babel-preset-es2015'),
    BABEL_JSX = require.resolve('babel-plugin-transform-react-jsx');

/**
 * Main function.
 */
module.exports = function createCompiler(opts) {
  var frontEnd = opts.command === 'serve',
      backEnd = !frontEnd,
      monitor = opts.command === 'monitor';

  var entry = opts.entry,
      output = opts.output;

  // Building the entry
  var entries = [];

  if (backEnd)
    entries.push(path.join(__dirname, '..', 'hot', 'client.js'));

  if (frontEnd)
    entries.push('webpack-hot-middleware/client');

  entries.push(entry);

  // Creating the webpack config
  var config = {
    entry: entries,
    output: {
      path: frontEnd ? '/kotatsu' : output,
      filename: 'bundle.js',
      publicPath: '/build/'
    },
    plugins: [
      new webpack.optimize.OccurenceOrderPlugin(),
      new webpack.HotModuleReplacementPlugin(),
      new webpack.NoErrorsPlugin(),
      new BundleUpdateHookPlugin()
    ],
    module: {}
  };

  // Are we creating a config for backend?
  if (backEnd) {

    // Env
    config.context = opts.cwd;
    config.target = 'node';
    config.node = NODE_ENVIRONMENT;

    // Source maps
    config.devtoolModuleFilenameTemplate = '[absolute-resource-path]';

    // Registering node_modules as externals
    config.externals = {};
    fs.readdirSync(path.join(process.cwd(), 'node_modules'))
      .filter(function(p) {
        return p !== '.bin';
      })
      .forEach(function(m) {
        config.externals[m] = 'commonjs ' + m;
      });

    // Applying the node plugin
    config.plugins.unshift(new NodePlugin());
  }

  // Should we display a progress bar?
  if (opts.progress)
    config.plugins.push(progress());

  // Do we want sourcemaps
  if (opts.sourceMaps || opts.devtool) {

    if (backEnd) {
      var sourceMapModulePath = require.resolve('source-map-support'),
          injectString = 'require(\'' + sourceMapModulePath + '\').install();';

      config.plugins.push(new webpack.BannerPlugin(injectString, {
        raw: true,
        entryOnly: false
      }));
    }

    config.devtool = opts.devtool || 'source-map';
  }

  // Merging the user's config
  // NOTE: our config should take precedence over the user's one.
  config = _.merge({}, opts.config || {}, config);

  // Additional loaders
  var loaders = config.module.loaders || [];

  // - JSON
  loaders.push({
    test: /\.json$/,
    loader: require.resolve('json-loader')
  });

  // - Babel & ES2015
  if (opts.babel || opts.es2015 || opts.presets.length) {
    var presets = opts.presets.map(function(p) {
      if (p === 'es2015')
        return BABEL_ES2015;
      return p;
    });

    if (opts.es2015)
      presets.push(BABEL_ES2015);

    // Deduping
    presets = _.uniq(presets);

    var babel = {
      test: /\.jsx?$/,
      exclude: /(node_modules|bower_components)/,
      loader: require.resolve('babel-loader'),
      query: {
        presets: presets
      }
    };

    if (opts.jsx && !~opts.presets.indexOf('react')) {
      var plugins = [[BABEL_JSX]];

      if (opts.pragma)
        plugins[0].push({pragma: opts.pragma});

      babel.query.plugins = plugins;
    }

    loaders.push(babel);
  }

  config.module.loaders = loaders;

  return webpack(config);
};
<|endoftext|>


<commit_before>//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Creates focus elements, if available
//------------------------------------------------------------------------------
d3plus.draw.focus = function(vars) {

  vars.g.edge_focus
    .selectAll("g")
    .remove()

  vars.g.data_focus
    .selectAll("g")
    .remove()

  if (vars.focus.value && d3plus.apps[vars.type.value].zoom && vars.zoom.value) {

    if (vars.dev.value) d3plus.console.time("drawing focus elements")

    var edges = vars.g.edges.selectAll("g")

    if (edges.size() > 0) {

      edges.each(function(l){

          var source = l[vars.edges.source][vars.id.key],
              target = l[vars.edges.target][vars.id.key]

          if (source == vars.focus.value || target == vars.focus.value) {
            var elem = vars.g.edge_focus.node().appendChild(this.cloneNode(true))
            var elem = d3.select(elem).datum(l).attr("opacity",1)
          }

        })

      var marker = vars.edges.arrows.value ? "url(#d3plus_edge_marker_focus)" : "none"

      vars.g.edge_focus.selectAll("line, path")
        .attr("vector-effect","non-scaling-stroke")
        .style("stroke",vars.style.highlight.focus)
        .style("stroke-width",vars.style.data.stroke.width*2)
        .attr("marker-start",function(){
          return vars.edges.arrows.direction.value == "source" ? marker : "none"
        })
        .attr("marker-end",function(){
          return vars.edges.arrows.direction.value == "target" ? marker : "none"
        })

      vars.g.edge_focus.selectAll("text")
        .style("fill",vars.style.highlight.focus)

    }

    var focii = d3plus.utils.uniques(vars.connections(vars.focus.value,true),vars.id.key)
    focii.push(vars.focus.value)

    var x_bounds = [], y_bounds = [], x_buffer = [0], y_buffer = [0]

    var groups = vars.g.data.selectAll("g")
      .each(function(d){
        if (focii.indexOf(d[vars.id.key]) >= 0) {
          var elem = vars.g.data_focus.node().appendChild(this.cloneNode(true))
          var elem = d3.select(elem).datum(d).attr("opacity",1)

          if (vars.shape.value == "coordinates") {
            vars.zoom.viewport = vars.path.bounds(d)
          }
          else if ("d3plus" in d) {
            if ("x" in d.d3plus) {
              x_bounds.push(d.d3plus.x)
            }
            if ("y" in d.d3plus) {
              y_bounds.push(d.d3plus.y)
            }
            if ("r" in d.d3plus) {
              x_buffer.push(d.d3plus.r)
              y_buffer.push(d.d3plus.r)
            }
            else {
              if ("width" in d.d3plus) {
                x_buffer.push(d.d3plus.width/2)
              }
              if ("height" in d.d3plus) {
                y_buffer.push(d.d3plus.height/2)
              }
            }
          }

          for (e in d3plus.evt) {
            var evt = d3.select(this).on(d3plus.evt[e])
            if (evt) {
              elem.on(d3plus.evt[e],evt)
            }
          }

        }
      })

    if (x_bounds.length && y_bounds.length) {

      var xcoords = d3.extent(x_bounds),
          ycoords = d3.extent(y_bounds),
          xmax = d3.max(x_buffer),
          ymax = d3.max(y_buffer)

      vars.zoom.viewport = [
        [xcoords[0]-xmax,ycoords[0]-ymax],
        [xcoords[1]+xmax,ycoords[1]+ymax]
      ]

    }

    vars.g.data_focus.selectAll("path")
      .style("stroke-width",vars.style.data.stroke.width*2)

    if (vars.dev.value) d3plus.console.timeEnd("drawing focus elements")

  }
  else {
    vars.zoom.viewport = null
  }

}
<commit_msg>geo_map zooms to the largest area<commit_after>//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Creates focus elements, if available
//------------------------------------------------------------------------------
d3plus.draw.focus = function(vars) {

  vars.g.edge_focus
    .selectAll("g")
    .remove()

  vars.g.data_focus
    .selectAll("g")
    .remove()

  if (vars.focus.value && d3plus.apps[vars.type.value].zoom && vars.zoom.value) {

    if (vars.dev.value) d3plus.console.time("drawing focus elements")

    var edges = vars.g.edges.selectAll("g")

    if (edges.size() > 0) {

      edges.each(function(l){

          var source = l[vars.edges.source][vars.id.key],
              target = l[vars.edges.target][vars.id.key]

          if (source == vars.focus.value || target == vars.focus.value) {
            var elem = vars.g.edge_focus.node().appendChild(this.cloneNode(true))
            var elem = d3.select(elem).datum(l).attr("opacity",1)
          }

        })

      var marker = vars.edges.arrows.value ? "url(#d3plus_edge_marker_focus)" : "none"

      vars.g.edge_focus.selectAll("line, path")
        .attr("vector-effect","non-scaling-stroke")
        .style("stroke",vars.style.highlight.focus)
        .style("stroke-width",vars.style.data.stroke.width*2)
        .attr("marker-start",function(){
          return vars.edges.arrows.direction.value == "source" ? marker : "none"
        })
        .attr("marker-end",function(){
          return vars.edges.arrows.direction.value == "target" ? marker : "none"
        })

      vars.g.edge_focus.selectAll("text")
        .style("fill",vars.style.highlight.focus)

    }

    var focii = d3plus.utils.uniques(vars.connections(vars.focus.value,true),vars.id.key)
    focii.push(vars.focus.value)

    var x_bounds = [], y_bounds = [], x_buffer = [0], y_buffer = [0]

    var groups = vars.g.data.selectAll("g")
      .each(function(d){
        if (focii.indexOf(d[vars.id.key]) >= 0) {
          var elem = vars.g.data_focus.node().appendChild(this.cloneNode(true))
          var elem = d3.select(elem).datum(d).attr("opacity",1)

          if (vars.shape.value == "coordinates") {

            vars.zoom.viewport = vars.path.bounds(d.reduced)

          }
          else if ("d3plus" in d) {
            if ("x" in d.d3plus) {
              x_bounds.push(d.d3plus.x)
            }
            if ("y" in d.d3plus) {
              y_bounds.push(d.d3plus.y)
            }
            if ("r" in d.d3plus) {
              x_buffer.push(d.d3plus.r)
              y_buffer.push(d.d3plus.r)
            }
            else {
              if ("width" in d.d3plus) {
                x_buffer.push(d.d3plus.width/2)
              }
              if ("height" in d.d3plus) {
                y_buffer.push(d.d3plus.height/2)
              }
            }
          }

          for (e in d3plus.evt) {
            var evt = d3.select(this).on(d3plus.evt[e])
            if (evt) {
              elem.on(d3plus.evt[e],evt)
            }
          }

        }
      })

    if (x_bounds.length && y_bounds.length) {

      var xcoords = d3.extent(x_bounds),
          ycoords = d3.extent(y_bounds),
          xmax = d3.max(x_buffer),
          ymax = d3.max(y_buffer)

      vars.zoom.viewport = [
        [xcoords[0]-xmax,ycoords[0]-ymax],
        [xcoords[1]+xmax,ycoords[1]+ymax]
      ]

    }

    vars.g.data_focus.selectAll("path")
      .style("stroke-width",vars.style.data.stroke.width*2)

    if (vars.dev.value) d3plus.console.timeEnd("drawing focus elements")

  }
  else {
    vars.zoom.viewport = null
  }

}
<|endoftext|>