<commit_before>"use strict";

var Class = require("nodeclass").Class,
    is = require("nodeclass").is,
    _ = require("underscore"),
    DisplayObject = require("./DisplayObject.class.js"),
    ModelCollection = require("../shared/ModelCollection.class.js"),
    View = require("./View.class.js"),
    ALAMID = require("./CONSTANTS.js"),
    domAdapter = require("./domAdapter.js");

var ViewCollection = new Class({

    Extends: DisplayObject,

    /**
     * @type Array
     * @protected
     */
    _views: [],

    /**
     * @type ModelCollection
     * @protected
     */
    _models: null,

    /**
     * @type Class
     * @protected
     */
    _ViewClass: null,

    /**
     *
     * @param {Class} ViewClass
     * @param {Class} collectionTemplate (optional)
     */
    init: function (ViewClass, collectionTemplate) {

        var hasOneDataNode;

        this._ViewClass = ViewClass;

        this.Super(collectionTemplate);

        hasOneDataNode = domAdapter(this.Super.getNode())
            .find("[data-node='" + ALAMID.VIEW_COLLECTION_DATA_NODE_VALUE  + "']")
            .length === 1;

        if (hasOneDataNode === false) {
            throw new Error(
                "(alamid) Cannot construct ViewCollection: " +
                "Given template has no or more than one node with [data-node='" + ALAMID.VIEW_COLLECTION_DATA_NODE_VALUE +
                "']-Attribute defined. Template: " + collectionTemplate
            );
        }
    },

    /**
     * @param {function} viewFactory
     * @return {ViewCollection}
     */
    setViewFactory: function (viewFactory) {

        this._viewFactory = viewFactory;

        return this.Instance;

    },

    /**
     * @param {ModelCollection} modelCollection
     * @return {ViewCollection}
     */
    //@TODO What happens if ModelCollection will be sorted?
    bind: function (modelCollection) {

        var newView,
            self = this;

        if (is(modelCollection).notInstanceOf(ModelCollection)) {
            throw new TypeError(
                "(alamid) Unable to bind. Given argument is not instance of ModelCollection"
            );
        }

        if (this._models) {
            this.disposeElements();
            this._models.removeListener("add", this._onAdd);
            this._models.removeListener("remove", this._onRemove);
        }

        this._models = modelCollection;

        modelCollection.each(function createNewView(model) {
            newView = self._viewFactory();
            newView.bind(model);
            self._views.push(newView);
        });

        modelCollection.on("add", this._onAdd);
        modelCollection.on("remove", this._onRemove);

        this.render();

        return this.Instance;
    },

    /**
     * Renders all Views of ViewCollection. If ViewCollection was already rendered than all Views will be re-rendered.
     *
     * @return {ViewCollection}
     */
    //@TODO Tests
    render: function () {

        this._views = this.destroyElements();

        this._addViews(this._views);

        return this.Instance;
    },

    /**
     * Destroys all Views and returns them as array.
     * Views are still part of the ViewCollection after they have been destroyed().
     * @return {array}
     */
    //@TODO Tests
    destroyElements: function () {
        var destroyedViews = [];

        _(this._views).each(function destroyView(view) {
            destroyedViews.push(view.destroy());
        });

        return destroyedViews;
    },

    /**
     * Disposes all elements of ViewCollection, but not ViewCollection itself.
     *
     * @return {ViewCollection}
     */
    //@TODO Tests
    disposeElements: function () {

        _(this._views).each(function disposeView(view) {
            view.dispose();
        });
        this._views = [];

        return this.Instance;
    },

    /**
     * Removes all collection elements from DOM and prepares them for garbage-collection
     */
    //@TODO Tests
    dispose: function () {

        this.Super.dispose();
        this._ViewClass = null;
        this._views = null;
        this._models = null;

    },

    /**
     * NOTE: This is an event-listener and should be called directly.
     *
     * @param {number} index
     * @param {array} models
     * @param {boolean} isMutated
     * @protected
     */
    _onAdd: function (index, models, isMutated) {
        var newView,
            newViews = [],
            spliceArguments,
            prepend,
            self = this;

        if (isMutated === true) {

            //If passded index is 0 it is basically possible that ModelCollection's .push() or .unshift() was called.
            //But it doesn't matter if new Views will be pushed or unshifted to ViewCollection, because if .push()
            //was called on ModelCollection and the passed index is 0 the ModelCollection must have been empty before.
            //In this case .push() and .unshift() mutates an empty Array in the same way.
            prepend = (index === 0);

            _(models).each(function createNewView(model) {
                newView = self._viewFactory();
                newView.bind(model);

                newViews.push(newView);
            });

            spliceArguments = [index, 0].concat(newViews);
            Array.prototype.splice.apply(this._views, spliceArguments);

            this._addViews(newViews, prepend);

        //A new Model was set on an existing index.
        } else {
            this._views[index].bind(models[0]);
        }
    },

    /**
     * NOTE: This is an event-listener and should be called directly.
     *
     * @param {number} index
     * @param {array} models
     * @protected
     */
    _onRemove: function (index, models) {

        var removedViews;

        removedViews = this._views.splice(index, models.length);

        //Prepare removed Views for Garbage-Collection
        _(removedViews).each(function unbindModel(view) {
            view.dispose();
        });

    },

    /**
     * @param {array} views
     * @param {boolean} prepend (optional)
     * @protected
     */
     //@TODO Throw events before a View will be added to ViewCollection
    _addViews: function (views, prepend) {

        var self = this;

        //._prepend() prepends according to first child of ViewCollection.
        //So views must be reversed to achieve right order before iterating over them.
        if (prepend === true) {
            views.reverse();
        }

        _(views).each(function _addView(view) {

            if (prepend === true) {
                self.Super._prepend(view).at("views");
            } else {

                self.Super._append(view).at("views");
            }

        });

    },

    /**
     * @return {this._ViewClass}
     * @protected
     */
    _viewFactory: function () {
        return new this._ViewClass();
    }

});

module.exports = ViewCollection;<commit_msg>Renamed destroyElements() to destroyViews()<commit_after>"use strict";

var Class = require("nodeclass").Class,
    is = require("nodeclass").is,
    _ = require("underscore"),
    DisplayObject = require("./DisplayObject.class.js"),
    ModelCollection = require("../shared/ModelCollection.class.js"),
    View = require("./View.class.js"),
    ALAMID = require("./CONSTANTS.js"),
    domAdapter = require("./domAdapter.js");

var ViewCollection = new Class({

    Extends: DisplayObject,

    /**
     * @type Array
     * @protected
     */
    _views: [],

    /**
     * @type ModelCollection
     * @protected
     */
    _models: null,

    /**
     * @type Class
     * @protected
     */
    _ViewClass: null,

    /**
     *
     * @param {Class} ViewClass
     * @param {Class} collectionTemplate (optional)
     */
    init: function (ViewClass, collectionTemplate) {

        var hasOneDataNode;

        this._ViewClass = ViewClass;

        this.Super(collectionTemplate);

        hasOneDataNode = domAdapter(this.Super.getNode())
            .find("[data-node='" + ALAMID.VIEW_COLLECTION_DATA_NODE_VALUE  + "']")
            .length === 1;

        if (hasOneDataNode === false) {
            throw new Error(
                "(alamid) Cannot construct ViewCollection: " +
                "Given template has no or more than one node with [data-node='" + ALAMID.VIEW_COLLECTION_DATA_NODE_VALUE +
                "']-Attribute defined. Template: " + collectionTemplate
            );
        }
    },

    /**
     * @param {function} viewFactory
     * @return {ViewCollection}
     */
    setViewFactory: function (viewFactory) {

        this._viewFactory = viewFactory;

        return this.Instance;

    },

    /**
     * @param {ModelCollection} modelCollection
     * @return {ViewCollection}
     */
    //@TODO What happens if ModelCollection will be sorted?
    bind: function (modelCollection) {

        var newView,
            self = this;

        if (is(modelCollection).notInstanceOf(ModelCollection)) {
            throw new TypeError(
                "(alamid) Unable to bind. Given argument is not instance of ModelCollection"
            );
        }

        if (this._models) {
            this.disposeElements();
            this._models.removeListener("add", this._onAdd);
            this._models.removeListener("remove", this._onRemove);
        }

        this._models = modelCollection;

        modelCollection.each(function createNewView(model) {
            newView = self._viewFactory();
            newView.bind(model);
            self._views.push(newView);
        });

        modelCollection.on("add", this._onAdd);
        modelCollection.on("remove", this._onRemove);

        this.render();

        return this.Instance;
    },

    /**
     * Renders all Views of ViewCollection. If ViewCollection was already rendered than all Views will be re-rendered.
     *
     * @return {ViewCollection}
     */
    //@TODO Tests
    render: function () {

        this._views = this.destroyViews();

        this._addViews(this._views);

        return this.Instance;
    },

    /**
     * Destroys all Views and returns them as array.
     * Views are still part of the ViewCollection after they have been destroyed().
     * @return {array}
     */
    //@TODO Tests
    destroyViews: function () {
        var destroyedViews = [];

        _(this._views).each(function destroyView(view) {
            destroyedViews.push(view.destroy());
        });

        return destroyedViews;
    },

    /**
     * Disposes all elements of ViewCollection, but not ViewCollection itself.
     *
     * @return {ViewCollection}
     */
    //@TODO Tests
    disposeElements: function () {

        _(this._views).each(function disposeView(view) {
            view.dispose();
        });
        this._views = [];

        return this.Instance;
    },

    /**
     * Removes all collection elements from DOM and prepares them for garbage-collection
     */
    //@TODO Tests
    dispose: function () {

        this.Super.dispose();
        this._ViewClass = null;
        this._views = null;
        this._models = null;

    },

    /**
     * NOTE: This is an event-listener and should be called directly.
     *
     * @param {number} index
     * @param {array} models
     * @param {boolean} isMutated
     * @protected
     */
    _onAdd: function (index, models, isMutated) {
        var newView,
            newViews = [],
            spliceArguments,
            prepend,
            self = this;

        if (isMutated === true) {

            //If passded index is 0 it is basically possible that ModelCollection's .push() or .unshift() was called.
            //But it doesn't matter if new Views will be pushed or unshifted to ViewCollection, because if .push()
            //was called on ModelCollection and the passed index is 0 the ModelCollection must have been empty before.
            //In this case .push() and .unshift() mutates an empty Array in the same way.
            prepend = (index === 0);

            _(models).each(function createNewView(model) {
                newView = self._viewFactory();
                newView.bind(model);

                newViews.push(newView);
            });

            spliceArguments = [index, 0].concat(newViews);
            Array.prototype.splice.apply(this._views, spliceArguments);

            this._addViews(newViews, prepend);

        //A new Model was set on an existing index.
        } else {
            this._views[index].bind(models[0]);
        }
    },

    /**
     * NOTE: This is an event-listener and should be called directly.
     *
     * @param {number} index
     * @param {array} models
     * @protected
     */
    _onRemove: function (index, models) {

        var removedViews;

        removedViews = this._views.splice(index, models.length);

        //Prepare removed Views for Garbage-Collection
        _(removedViews).each(function unbindModel(view) {
            view.dispose();
        });

    },

    /**
     * @param {array} views
     * @param {boolean} prepend (optional)
     * @protected
     */
     //@TODO Throw events before a View will be added to ViewCollection
    _addViews: function (views, prepend) {

        var self = this;

        //._prepend() prepends according to first child of ViewCollection.
        //So views must be reversed to achieve right order before iterating over them.
        if (prepend === true) {
            views.reverse();
        }

        _(views).each(function _addView(view) {

            if (prepend === true) {
                self.Super._prepend(view).at("views");
            } else {

                self.Super._append(view).at("views");
            }

        });

    },

    /**
     * @return {this._ViewClass}
     * @protected
     */
    _viewFactory: function () {
        return new this._ViewClass();
    }

});

module.exports = ViewCollection;<|endoftext|>


<commit_before>// Attaches properties to |exports|.
exports.defineProperties = function (exports) {
  return Object.defineProperties(exports, {
    // Common modules, please sort with alphabet order.
    clipboard: {
      // Must be enumerable, otherwise it woulde be invisible to remote module.
      enumerable: true,
      get: function () {
        return require('../clipboard')
      }
    },
    crashReporter: {
      enumerable: true,
      get: function () {
        return require('../crash-reporter')
      }
    },
    nativeImage: {
      enumerable: true,
      get: function () {
        return require('../native-image')
      }
    },
    shell: {
      enumerable: true,
      get: function () {
        return require('../shell')
      }
    },

    // The internal modules, invisible unless you know their names.
    CallbacksRegistry: {
      get: function () {
        return require('../callbacks-registry')
      }
    }
  })
}
<commit_msg>Keep exporting deprecate/deprecations<commit_after>// Attaches properties to |exports|.
exports.defineProperties = function (exports) {
  return Object.defineProperties(exports, {
    // Common modules, please sort with alphabet order.
    clipboard: {
      // Must be enumerable, otherwise it woulde be invisible to remote module.
      enumerable: true,
      get: function () {
        return require('../clipboard')
      }
    },
    crashReporter: {
      enumerable: true,
      get: function () {
        return require('../crash-reporter')
      }
    },
    nativeImage: {
      enumerable: true,
      get: function () {
        return require('../native-image')
      }
    },
    shell: {
      enumerable: true,
      get: function () {
        return require('../shell')
      }
    },

    // The internal modules, invisible unless you know their names.
    CallbacksRegistry: {
      get: function () {
        return require('../callbacks-registry')
      }
    },
    deprecate: {
      get: function () {
        return require('../deprecate')
      }
    },
    deprecations: {
      get: function () {
        return require('../deprecations')
      }
    }
  })
}
<|endoftext|>


<commit_before>module.exports = {
  name: 'ProductionServer',
  webpack: {
    entry: './src/Server.es6.js',
    output: {
      generator: 'simple',
      dest: './bin',
    },
    resolve: {
      generator: 'npm-and-modules',
      extensions: ['', '.js', '.jsx', 'es6.js', '.json']
    },
    loaders: [
      'esnextreact',
      'json',
      'css',
      'less',
    ],
    plugins: [
      'extract-css',
      'bundle-common',
      'abort-if-errors',
    ],
    postcss: [
      'autoprefixer',
    ]
  },
};
<commit_msg>Remove bundle common from server<commit_after>module.exports = {
  name: 'ProductionServer',
  webpack: {
    entry: './src/Server.es6.js',
    output: {
      generator: 'simple',
      dest: './bin',
    },
    resolve: {
      generator: 'npm-and-modules',
      extensions: ['', '.js', '.jsx', 'es6.js', '.json']
    },
    loaders: [
      'esnextreact',
      'json',
      'css',
      'less',
    ],
    plugins: [
      'extract-css',
      'abort-if-errors',
    ],
    postcss: [
      'autoprefixer',
    ]
  },
};
<|endoftext|>


<commit_before>import Postmate from 'postmate';
import baseUrl from 'helpers/baseUrl';

const setIframeAttributes = (child) => {
  child.frame.setAttribute('width', '100%');
  child.frame.setAttribute('frameborder', 0);
  child.frame.setAttribute('scrolling', 'no');
  child.frame.setAttribute('horizontalscrolling', 'no');
  child.frame.setAttribute('verticalscrolling', 'no');
};

const fetchHeight = (child) => {
  child.get('height')
    .then(height =>
      (child.frame.style.height = `${height}px`)
    );
};

// Kick off the handshake with the iFrame
const handshake = new Postmate({
  container: document.getElementById('petition-widget'), // Element to inject frame into
  url: `${baseUrl()}/embed/7k3vv` // Page to load, must have postmate.js. This will also be the origin used for communication.
});

// When parent <-> child handshake is complete, data may be requested from the child
handshake.then(child => {
  setIframeAttributes(child);
  fetchHeight(child);

  // Listen to a particular event from the child
  child.on('resize', data => console.log(data)); // Logs "Hello, World!"
});
<commit_msg>Use petition ID from embed script<commit_after>import Postmate from 'postmate';
import baseUrl from 'helpers/baseUrl';

const container = document.getElementById('petition-widget');
const id = container.dataset.petitionId;
const url = `${baseUrl()}/embed/${id}`;

const setIframeAttributes = (child) => {
  child.frame.setAttribute('width', '100%');
  child.frame.setAttribute('frameborder', 0);
  child.frame.setAttribute('scrolling', 'no');
  child.frame.setAttribute('horizontalscrolling', 'no');
  child.frame.setAttribute('verticalscrolling', 'no');
};

const fetchHeight = (child) => {
  child.get('height')
    .then(height =>
      (child.frame.style.height = `${height}px`)
    );
};

// Kick off the handshake with the iFrame
const handshake = new Postmate({
  container, // Element to inject frame into
  url // Page to load, must have postmate.js. This will also be the origin used for communication.
});

// When parent <-> child handshake is complete, data may be requested from the child
handshake.then(child => {
  setIframeAttributes(child);
  fetchHeight(child);

  // Listen to a particular event from the child
  child.on('resize', data => console.log(data)); // Logs "Hello, World!"
});
<|endoftext|>


<commit_before>/*
 * Graph API.
 *
 * Graphs is dagre are always directed. It is possible to simulate an
 * undirected graph by creating identical edges in both directions. It is also
 * possible to do undirected graph traversal on a directed graph using the
 * `neighbors` function.
 *
 * Dagre graphs have attributes at the graph, node, and edge levels.
 */

dagre.graph = {};

/*
 * Creates a new directed graph. This should be invoked with
 * `var g = dagre.graph.create()` and _not_ `var g = new dagre.graph.create()`.
 */
dagre.graph.create = function() {
  /*
   * Returns graph level attributes.
   */
  function attrs() {
    return _attrs;
  }

  /*
   * Adds a or updates a node in the graph with the given id. It only makes
   * sense to use primitive values as ids. This function also optionally takes
   * an object that will be used as attributes for the node.
   *
   * If the node already exists in the graph then the supplied attributes will
   * merged with the nodes attributes. Where there are overlapping keys, the
   * new attribute will replace the current attribute.
   *
   * If a new node was added to the graph this function returns `true`. If the
   * node updated in the graph then this function returns `false`.
   */
  function addNode(id, attrs) {
    var created = false;
    if (!(id in _nodes)) {
      created = true;
      _nodes[id] = {
        id: id,
        attrs: {}
      };
    }
    if (arguments.length > 1) {
      _mergeAttrs(attrs, _nodes[id].attrs);
    }
    return created;
  }

  /*
   * Returns a node view for the given node id. If the node is not in the graph
   * this function will raise an error.
   */
  function node(id) {
    var u = _nodes[id];
    if (u === undefined) {
      throw new Error("Node is not in graph: " + id);
    }

    return {
      id: id,
      attrs: u.attrs
    }
  }

  /*
   * Copies attributes from `src` to `dst`. If an attribute name is in both
   * `src` and `dst` then the attribute value from `src` takes precedence.
   */
  function _mergeAttrs(src, dst) {
    Object.keys(src).forEach(function(k) { dst[k] = src[k]; });
  }

  _attrs = {};
  _nodes = {};

  // Public API is defined here
  return {
    attrs: attrs,
    addNode: addNode,
    node: node
  };
}
<commit_msg>Add support for edges<commit_after>/*
 * Graph API.
 *
 * Graphs is dagre are always directed. It is possible to simulate an
 * undirected graph by creating identical edges in both directions. It is also
 * possible to do undirected graph traversal on a directed graph using the
 * `neighbors` function.
 *
 * Dagre graphs have attributes at the graph, node, and edge levels.
 */

dagre.graph = {};

/*
 * Creates a new directed graph. This should be invoked with
 * `var g = dagre.graph.create()` and _not_ `var g = new dagre.graph.create()`.
 */
dagre.graph.create = function() {
  /*
   * Returns graph level attributes.
   */
  function attrs() {
    return _attrs;
  }

  /*
   * Adds a or updates a node in the graph with the given id. It only makes
   * sense to use primitive values as ids. This function also optionally takes
   * an object that will be used as attributes for the node.
   *
   * If the node already exists in the graph then the supplied attributes will
   * merged with the nodes attributes. Where there are overlapping keys, the
   * new attribute will replace the current attribute.
   *
   * If a new node was added to the graph this function returns `true`. If the
   * node was updated in the graph then this function returns `false`.
   */
  function addNode(id, attrs) {
    var created = false;
    if (!(id in _nodes)) {
      created = true;
      _nodes[id] = {
        id: id,
        attrs: {},
        successors: [],
        predecessors: []
      };
    }
    if (arguments.length > 1) {
      _mergeAttributes(attrs, _nodes[id].attrs);
    }
    return created;
  }

  function addNodes() {
    for (var i = 0; i < arguments.length; ++i) {
      addNode(arguments[i]);
    }
  }

  /*
   * Returns a node view for the given node id. If the node is not in the graph
   * this function will raise an error.
   */
  function node(id) {
    var u = _nodes[id];
    if (u === undefined) {
      throw new Error("Node is not in graph: " + id);
    }

    function addSuccessor(sucId, attrs) {
      _addEdge(id, sucId, attrs);
    }

    function addPredecessor(predId, attrs) {
      _addEdge(predId, id, attrs);
    }

    function successors() {
      return u.successors.map(function(sucId) { return node(sucId); });
    }

    function predecessors() {
      return u.predecessors.map(function(predId) { return node(predId); });
    }

    function neighbors() {
      return successors().concat(predecessors());
    }

    function outEdges() {
      return u.successors.map(function(sucId) { return _edge(id, sucId); });
    }

    function inEdges() {
      return u.predecessors.map(function(predId) { return _edge(predId, id); });
    }

    function edges() {
      return inEdges().concat(outEdges());
    }

    return {
      id: function() { return id; },
      attrs: u.attrs,
      addSuccessor: addSuccessor,
      addPredecessor: addPredecessor,
      successors: successors,
      predecessors: predecessors,
      neighbors: neighbors,
      outEdges: outEdges,
      inEdges: inEdges,
      edges: edges
    }
  }

  function nodes() {
    return Object.keys(_nodes).map(function(id) { return node(id); });
  }

  function edges() {
    return Object.keys(_edges).map(function(id) { return _edgeById(id); });
  }

  /*
   * Adds a new edge to the graph. Nodes for `tailId` and `headId` must already
   * exist in the graph or an error will be thrown. Optionally attributes can be
   * added to the edge.
   *
   * If a new edge was added to the graph this function returns `true`. If the
   * edge was updated then this function returns `false`.
   */
  function _addEdge(tailId, headId, attrs) {
    var created = false;
    var id = _edgeId(tailId, headId);
    if (!(id in _edges)) {
      created = true;
      _edges[id] = {
        tailId: tailId,
        headId: headId,
        attrs: {}
      };
      _nodes[tailId].successors.push(headId);
      _nodes[headId].predecessors.push(tailId);
    }
    if (attrs) {
      _mergeAttributes(attrs, _edges[id].attrs);
    }
    return created;
  }

  function _edge(tailId, headId) {
    return _edgeById(_edgeId(tailId, headId));
  }

  function _edgeById(id) {
    var e = _edges[id];

    return {
      id:    function() { return id; },
      tail:  function() { return node(e.tailId); },
      head:  function() { return node(e.headId); },
      attrs: e.attrs
    };
  }

  /*
   * Creates a unique primitive identifier from the given `tailId` and `headId`.
   */
  function _edgeId(tailId, headId) {
    return (tailId.toString().length) + ":" + tailId + '->' + headId;
  }

  /*
   * Copies attributes from `src` to `dst`. If an attribute name is in both
   * `src` and `dst` then the attribute value from `src` takes precedence.
   */
  function _mergeAttributes(src, dst) {
    Object.keys(src).forEach(function(k) { dst[k] = src[k]; });
  }

  _attrs = {};
  _nodes = {};
  _edges = {};

  // Public API is defined here
  return {
    attrs: attrs,
    addNode: addNode,
    addNodes: addNodes,
    node: node,
    nodes: nodes,
    edges: edges
  };
}
<|endoftext|>


<commit_before>import WebSocketClient from 'websocket.js'
import msgpack from 'msgpack-lite'
import jsonpatch from 'fast-json-patch'

import protocol from './protocol'
import { createRoom } from './room'

class Colyseus extends WebSocketClient {

  constructor (url, protocols = null, options = {}) {
    super(url, protocols, options)
    this.binaryType = "arraybuffer"

    this.roomStates = {}
    this.rooms = {}
    this._enqueuedCalls = []
  }

  onOpenCallback (event) {
    if (this._enqueuedCalls.length > 0) {
      for (var i=0; i<this._enqueuedCalls.length; i++) {
        let [ method, args ] = this._enqueuedCalls[i]
        this[ method ].apply(this, args)
      }
    }
  }

  send (data) {
    return super.send( msgpack.encode(data) )
  }

  join (roomName, options) {
    if (this.ws.readyState == WebSocket.OPEN) {
      this.send([protocol.JOIN_ROOM, roomName, options || {}])

    } else {
      // WebSocket not connected.
      // Enqueue it to be called when readyState == OPEN
      this._enqueuedCalls.push(['join', arguments])
    }

    if (!this.rooms[ roomName ]) {
      this.rooms[ roomName ] = createRoom(this, roomName)
    }

    return this.rooms[ roomName ]
  }

  leave (roomNameOrId) {
    if (typeof(roomNameOrId)!=="number" && this.rooms[ roomNameOrId ]) {
      roomNameOrId = this.rooms[ roomNameOrId ]
    }
    this.send([protocol.LEAVE_ROOM, roomName])
  }

  /**
   * @override
   */
  onMessageCallback (event) {
    var message = msgpack.decode( new Uint8Array(event.data) )

    if (typeof(message[0]) === "number") {
      let roomId = message[1]

      if (message[0] == protocol.USER_ID) {
        this.id = message[1]
        if (this.listeners['onopen']) this.listeners['onopen'].apply(null)
        return true

      } else if (message[0] == protocol.JOIN_ROOM) {
        // first room message received, keep association only with roomId
        this.rooms[ roomId ] = this.rooms[ message[2] ]
        this.rooms[ roomId ].roomId = roomId
        this.rooms[ roomId ].emit('join')
        // delete this.rooms[ message[2] ]
        return true

      } else if (message[0] == protocol.JOIN_ERROR) {
        this.rooms[ roomId ].emit('error', message[2])
        delete this.rooms[ roomId ]
        return true

      } else if (message[0] == protocol.LEAVE_ROOM) {
        this.rooms[ roomId ].emit('leave')
        return true

      } else if (message[0] == protocol.ROOM_STATE) {
        let roomState = message[2]

        this.rooms[ roomId ].state = roomState
        this.rooms[ roomId ].emit('setup', this.rooms[ roomId ].state)

        this.roomStates[ roomId ] = roomState
        return true

      } else if (message[0] == protocol.ROOM_STATE_PATCH) {
        this.rooms[ roomId ].emit('patch', message[2])
        jsonpatch.apply(this.roomStates[ roomId ], message[2])
        this.rooms[ roomId ].emit('update', this.roomStates[ roomId ])

        return true

      } else if (message[0] == protocol.ROOM_DATA) {
        this.rooms[ roomId ].emit('data', message[2])
        message = [ message[2] ]
      }

    }

    if (this.listeners['onmessage']) this.listeners['onmessage'].apply(null, message)
  }

}

module.exports = Colyseus
<commit_msg>joining rooms by room id<commit_after>import WebSocketClient from 'websocket.js'
import msgpack from 'msgpack-lite'
import jsonpatch from 'fast-json-patch'

import protocol from './protocol'
import { createRoom } from './room'

class Colyseus extends WebSocketClient {

  constructor (url, protocols = null, options = {}) {
    super(url, protocols, options)
    this.binaryType = "arraybuffer"

    this.roomStates = {}
    this.rooms = {}
    this._enqueuedCalls = []
  }

  onOpenCallback (event) {
    if (this._enqueuedCalls.length > 0) {
      for (var i=0; i<this._enqueuedCalls.length; i++) {
        let [ method, args ] = this._enqueuedCalls[i]
        this[ method ].apply(this, args)
      }
    }
  }

  send (data) {
    return super.send( msgpack.encode(data) )
  }

  join (roomName, options) {
    if (this.ws.readyState == WebSocket.OPEN) {
      this.send([protocol.JOIN_ROOM, roomName, options || {}])

    } else {
      // WebSocket not connected.
      // Enqueue it to be called when readyState == OPEN
      this._enqueuedCalls.push(['join', arguments])
    }

    if (!this.rooms[ roomName ]) {
      this.rooms[ roomName ] = createRoom(this, roomName)
    }

    return this.rooms[ roomName ]
  }

  leave (roomNameOrId) {
    if (typeof(roomNameOrId)!=="number" && this.rooms[ roomNameOrId ]) {
      roomNameOrId = this.rooms[ roomNameOrId ]
    }
    this.send([protocol.LEAVE_ROOM, roomName])
  }

  /**
   * @override
   */
  onMessageCallback (event) {
    var message = msgpack.decode( new Uint8Array(event.data) )

    if (typeof(message[0]) === "number") {
      let roomId = message[1]

      if (message[0] == protocol.USER_ID) {
        this.id = message[1]
        if (this.listeners['onopen']) this.listeners['onopen'].apply(null)
        return true

      } else if (message[0] == protocol.JOIN_ROOM) {
        // joining room from room name:
        // when first room message is received, keep only roomId association on `rooms` object
        if (this.rooms[ message[2] ]) {
          this.rooms[ roomId ] = this.rooms[ message[2] ]
        }
        this.rooms[ roomId ].roomId = roomId
        this.rooms[ roomId ].emit('join')
        return true

      } else if (message[0] == protocol.JOIN_ERROR) {
        this.rooms[ roomId ].emit('error', message[2])
        delete this.rooms[ roomId ]
        return true

      } else if (message[0] == protocol.LEAVE_ROOM) {
        this.rooms[ roomId ].emit('leave')
        return true

      } else if (message[0] == protocol.ROOM_STATE) {
        let roomState = message[2]

        this.rooms[ roomId ].state = roomState
        this.rooms[ roomId ].emit('setup', this.rooms[ roomId ].state)

        this.roomStates[ roomId ] = roomState
        return true

      } else if (message[0] == protocol.ROOM_STATE_PATCH) {
        this.rooms[ roomId ].emit('patch', message[2])
        jsonpatch.apply(this.roomStates[ roomId ], message[2])
        this.rooms[ roomId ].emit('update', this.roomStates[ roomId ])

        return true

      } else if (message[0] == protocol.ROOM_DATA) {
        this.rooms[ roomId ].emit('data', message[2])
        message = [ message[2] ]
      }

    }

    if (this.listeners['onmessage']) this.listeners['onmessage'].apply(null, message)
  }

}

module.exports = Colyseus
<|endoftext|>


<commit_before>import React from 'react'
import ReactDOM from 'react-dom'

function Square(props) {
  return (
    <button className="square" onClick={() => props.onClick()}>
      {props.value}
    </button>
  );
}

class Board extends React.Component {
  renderSquare(i) {
    const squares = this.props.squares;
    return <Square value={squares[i]} onClick={() => this.props.onClick(i)} />;
  }
  render() {
    return (

          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}

          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}

          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}

    );
  }
}

class Game extends React.Component {
  constructor() {
    super();
    this.state = {
      history: [{
        squares: Array(9).fill(null),
      }],
      stepNumber: 0,
      xIsNext: true,
    };
  }
  handleClick(i) {
    var history = this.state.history.slice(0, this.state.stepNumber + 1);
    var current = history[history.length - 1];
    const squares = current.squares.slice();
    if (calculateWinner(squares) || squares[i]) {
      return;
    }

    squares[i] = this.state.xIsNext ? 'X' : 'O';

    this.setState({
      history: history.concat([{
        squares: squares
      }]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext,
    });
  }
  jumpTo(step) {
    this.setState({
      stepNumber: step,
      xIsNext: (step % 2) ? false : true,
    });
  }
  render() {
    const history = this.state.history;
    const current = history[this.state.stepNumber];

    const winner = calculateWinner(current.squares);
    let status;
    if (winner) {
      status = 'Winner: ' + winner;
    } else {
      status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
    }

    const moves = history.map((step, move) => {
      const desc = move ?
        'Move #' + move :
        'Game start';
      return (

           this.jumpTo(move)}>{desc}

      );
    });

    return (

          <Board
            squares={current.squares}
            onClick={(i) => this.handleClick(i)}
          />

{status}

{moves}

    );
  }
}

ReactDOM.render(
  <Game />,
  document.getElementById('container')
);

function calculateWinner(squares) {
  const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];
  for (let i = 0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
      return squares[a];
    }
  }
  return null;
}

<commit_msg>remove extra line at end of file<commit_after>import React from 'react'
import ReactDOM from 'react-dom'

function Square(props) {
  return (
    <button className="square" onClick={() => props.onClick()}>
      {props.value}
    </button>
  );
}

class Board extends React.Component {
  renderSquare(i) {
    const squares = this.props.squares;
    return <Square value={squares[i]} onClick={() => this.props.onClick(i)} />;
  }
  render() {
    return (

          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}

          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}

          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}

    );
  }
}

class Game extends React.Component {
  constructor() {
    super();
    this.state = {
      history: [{
        squares: Array(9).fill(null),
      }],
      stepNumber: 0,
      xIsNext: true,
    };
  }
  handleClick(i) {
    var history = this.state.history.slice(0, this.state.stepNumber + 1);
    var current = history[history.length - 1];
    const squares = current.squares.slice();
    if (calculateWinner(squares) || squares[i]) {
      return;
    }

    squares[i] = this.state.xIsNext ? 'X' : 'O';

    this.setState({
      history: history.concat([{
        squares: squares
      }]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext,
    });
  }
  jumpTo(step) {
    this.setState({
      stepNumber: step,
      xIsNext: (step % 2) ? false : true,
    });
  }
  render() {
    const history = this.state.history;
    const current = history[this.state.stepNumber];

    const winner = calculateWinner(current.squares);
    let status;
    if (winner) {
      status = 'Winner: ' + winner;
    } else {
      status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
    }

    const moves = history.map((step, move) => {
      const desc = move ?
        'Move #' + move :
        'Game start';
      return (

           this.jumpTo(move)}>{desc}

      );
    });

    return (

          <Board
            squares={current.squares}
            onClick={(i) => this.handleClick(i)}
          />

{status}

{moves}

    );
  }
}

ReactDOM.render(
  <Game />,
  document.getElementById('container')
);

function calculateWinner(squares) {
  const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];
  for (let i = 0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
      return squares[a];
    }
  }
  return null;
}
<|endoftext|>


<commit_before>import {
  getRgba,
  hexString,
  rgbString,
  percentString,
  keyword,
  hslString
} from 'color-string'
import assert from './util/assert'

const WHITE = [ 255, 255, 255, 1 ]

function boundary(val, min = 0, max = 255) {
  return Math.min(max, Math.max(val, min))
}

const proto = {
  // Manually set RGBA
  red(val) {
    const x = this.data
    return createColor([
      boundary(val), x[1], x[2], x[3]
    ])
  },
  green(val) {
    const x = this.data
    return createColor([
      x[0], boundary(val), x[2], x[3]
    ])
  },
  blue(val) {
    const x = this.data
    return createColor([
      x[0], x[1], boundary(val), x[3]
    ])
  },
  opacity(val) {
    const x = this.data
    return createColor([
      x[0], x[1], x[2], boundary(val, 0, 1)
    ])
  },

  // Factor opacity
  clearer(factor) {
    const [ r, g, b, a ] = this.data
    return createColor([
      r, g, b, boundary(a * factor, 0, 1)
    ])
  },
  opaquer(factor) {
    const [ r, g, b, a ] = this.data
    return createColor([
      r, g, b, boundary(a / factor, 0, 1)
    ])
  },

  // Factor RGB
  darken(factor) {
    const [ r, g, b, a ] = this.data
    return createColor([
      ...[ r, g, b ].map(x => boundary(x * (1 - factor))),
      a
    ])
  },
  lighten(factor) {
    const [ r, g, b, a ] = this.data
    return createColor([
      ...[ r, g, b ].map(x => boundary(x + (255 - x) * (1 - factor))),
      a
    ])
  },

  // Raw return values
  getRaw() {
    return this.data.slice()
  },
  raw() {
    return this.data.slice()
  },

  // Convert to object
  toRGB() {
    const x = this.data
    return { r: x[0], g: x[1], b: x[2], a: x[3] }
  },
  toRGBA() {
    return this.toRGB()
  },
  toObject() {
    return this.toRGB()
  },

  // Convert to String
  toString(mode) {
    if (mode === 'hex') {
      return hexString(this.data)
    } else if (mode === 'percent') {
      return percentString(this.data)
    } else if (mode === 'keyword') {
      return keyword(this.data)
    } else if (mode === 'hsl') {
      return hslString(this.data)
    }

    return rgbString(this.data)
  },

  // Compatibility
  hexString() {
    return this.toString('hex')
  },
  rgbString() {
    return this.toString()
  },

  // Automatically display a hex string
  valueOf() {
    return this.toString()
  }
}

function isRGB(x) {
  return typeof x === 'number' && x >= 0 && x < 256
}

function isRGBArray(arr) {
  return arr.reduce(
    (state = true, x) => state && isRGB(x)
  )
}

function createColor(tupel) {
  const res = Object.create(proto)
  res.data = tupel || WHITE.slice()
  return res
}

export default function Color(init) {
  if (typeof init === 'string') {
    return createColor(getRgba(init))
  } else if (Array.isArray(init)) {
    assert((
      init.length === 3 || init.length === 4
    ) && isRGBArray(init), 'Expected array to only contain RGB numbers.')

    if (init.length === 3) {
      return createColor([ ...init, 1 ])
    }
    return createColor(init.slice())
  } else if (typeof init === 'object') {
    assert(
      isRGB(init.r) && isRGB(init.g) && isRGB(init.b),
      'Expected object to contain RGB properties.'
    )
    return createColor([ init.r, init.g, init.b, boundary(init.a || 1, 0, 1) ])
  }

  return createColor()
}
<commit_msg>Floor all boundary values<commit_after>import {
  getRgba,
  hexString,
  rgbString,
  percentString,
  keyword,
  hslString
} from 'color-string'
import assert from './util/assert'

const WHITE = [ 255, 255, 255, 1 ]

function boundary(val, min = 0, max = 255) {
  return Math.floor(Math.min(max, Math.max(val, min)))
}

const proto = {
  // Manually set RGBA
  red(val) {
    const x = this.data
    return createColor([
      boundary(val), x[1], x[2], x[3]
    ])
  },
  green(val) {
    const x = this.data
    return createColor([
      x[0], boundary(val), x[2], x[3]
    ])
  },
  blue(val) {
    const x = this.data
    return createColor([
      x[0], x[1], boundary(val), x[3]
    ])
  },
  opacity(val) {
    const x = this.data
    return createColor([
      x[0], x[1], x[2], boundary(val, 0, 1)
    ])
  },

  // Factor opacity
  clearer(factor) {
    const [ r, g, b, a ] = this.data
    return createColor([
      r, g, b, boundary(a * factor, 0, 1)
    ])
  },
  opaquer(factor) {
    const [ r, g, b, a ] = this.data
    return createColor([
      r, g, b, boundary(a / factor, 0, 1)
    ])
  },

  // Factor RGB
  darken(factor) {
    const [ r, g, b, a ] = this.data
    return createColor([
      ...[ r, g, b ].map(x => boundary(x * (1 - factor))),
      a
    ])
  },
  lighten(factor) {
    const [ r, g, b, a ] = this.data
    return createColor([
      ...[ r, g, b ].map(x => boundary(x + (255 - x) * (1 - factor))),
      a
    ])
  },

  // Raw return values
  getRaw() {
    return this.data.slice()
  },
  raw() {
    return this.data.slice()
  },

  // Convert to object
  toRGB() {
    const x = this.data
    return { r: x[0], g: x[1], b: x[2], a: x[3] }
  },
  toRGBA() {
    return this.toRGB()
  },
  toObject() {
    return this.toRGB()
  },

  // Convert to String
  toString(mode) {
    if (mode === 'hex') {
      return hexString(this.data)
    } else if (mode === 'percent') {
      return percentString(this.data)
    } else if (mode === 'keyword') {
      return keyword(this.data)
    } else if (mode === 'hsl') {
      return hslString(this.data)
    }

    return rgbString(this.data)
  },

  // Compatibility
  hexString() {
    return this.toString('hex')
  },
  rgbString() {
    return this.toString()
  },

  // Automatically display a hex string
  valueOf() {
    return this.toString()
  }
}

function isRGB(x) {
  return typeof x === 'number' && x >= 0 && x < 256
}

function isRGBArray(arr) {
  return arr.reduce(
    (state = true, x) => state && isRGB(x)
  )
}

function createColor(tupel) {
  const res = Object.create(proto)
  res.data = tupel || WHITE.slice()
  return res
}

export default function Color(init) {
  if (typeof init === 'string') {
    return createColor(getRgba(init))
  } else if (Array.isArray(init)) {
    assert((
      init.length === 3 || init.length === 4
    ) && isRGBArray(init), 'Expected array to only contain RGB numbers.')

    if (init.length === 3) {
      return createColor([ ...init, 1 ])
    }
    return createColor(init.slice())
  } else if (typeof init === 'object') {
    assert(
      isRGB(init.r) && isRGB(init.g) && isRGB(init.b),
      'Expected object to contain RGB properties.'
    )
    return createColor([ init.r, init.g, init.b, boundary(init.a || 1, 0, 1) ])
  }

  return createColor()
}
<|endoftext|>


<commit_before>import { app, BrowserWindow } from 'electron';

import configureApp from './main/configureApp';
import generateBrowserConfig from './main/configureBrowser';

import EmitterClass from './main/utils/Emitter';
import SettingsClass from './main/utils/Settings';
import WindowManagerClass from './main/utils/WindowManager';
import PlaybackAPIClass from './main/utils/PlaybackAPI';

import { handleStartupEvent } from './squirrel';

(() => {
  if (handleStartupEvent()) {
    return;
  }

  configureApp(app);
  global.Emitter = new EmitterClass();
  global.WindowManager = new WindowManagerClass();
  global.Settings = new SettingsClass();
  global.PlaybackAPI = new PlaybackAPIClass();

  // Keep a global reference of the window object, if you don't, the window will
  // be closed automatically when the JavaScript object is garbage collected.
  let mainWindow = null;

  // Quit when all windows are closed.
  app.on('window-all-closed', () => {
    // On OS X it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform !== 'darwin') {
      app.quit();
    }
  });

  // This method will be called when Electron has finished
  // initialization and is ready to create browser windows.
  app.on('ready', () => {
    // mainWindow = new BrowserWindow(require('./lib/configureBrowser')(electron, app));
    mainWindow = new BrowserWindow(generateBrowserConfig());
    global.mainWindowID = WindowManager.add(mainWindow, 'main');

    const position = Settings.get('position');
    let size = Settings.get('size');
    size = size || [1200, 800];

    if (position) {
      mainWindow.setPosition(...position);
    } else {
      mainWindow.center();
    }
    mainWindow.setSize(...size);

    // and load the index.html of the app.
    mainWindow.loadURL(`file://${__dirname}/public_html/index.html`);
    require('./main/features');
    require('./old_win32');

    // Emitted when the window is closed.
    mainWindow.on('closed', () => {
      // Dereference the window object, usually you would store windows
      // in an array if your app supports multi windows, this is the time
      // when you should delete the corresponding element.
      mainWindow = null;
      PlaybackAPI.reset();
    });
  });

  app.on('before-quit', () => {
    global.quiting = true;
  });
})();
<commit_msg>Implement singleInstance mode for the player<commit_after>import { app, BrowserWindow } from 'electron';

import configureApp from './main/configureApp';
import generateBrowserConfig from './main/configureBrowser';

import EmitterClass from './main/utils/Emitter';
import SettingsClass from './main/utils/Settings';
import WindowManagerClass from './main/utils/WindowManager';
import PlaybackAPIClass from './main/utils/PlaybackAPI';

import { handleStartupEvent } from './squirrel';

(() => {
  if (handleStartupEvent()) {
    return;
  }

  configureApp(app);

  // Keep a global reference of the window object, if you don't, the window will
  // be closed automatically when the JavaScript object is garbage collected.
  let mainWindow = null;

  // DEV: Make the app single instance
  const shouldQuit = app.makeSingleInstance(() => {
    if (mainWindow) {
      if (mainWindow.isMinimized()) mainWindow.restore();
      mainWindow.focus();
    }
  });

  if (shouldQuit) {
    app.quit();
    return;
  }

  global.Emitter = new EmitterClass();
  global.WindowManager = new WindowManagerClass();
  global.Settings = new SettingsClass();
  global.PlaybackAPI = new PlaybackAPIClass();

  // Quit when all windows are closed.
  app.on('window-all-closed', () => {
    // On OS X it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform !== 'darwin') {
      app.quit();
    }
  });

  // This method will be called when Electron has finished
  // initialization and is ready to create browser windows.
  app.on('ready', () => {
    // mainWindow = new BrowserWindow(require('./lib/configureBrowser')(electron, app));
    mainWindow = new BrowserWindow(generateBrowserConfig());
    global.mainWindowID = WindowManager.add(mainWindow, 'main');

    const position = Settings.get('position');
    let size = Settings.get('size');
    size = size || [1200, 800];

    if (position) {
      mainWindow.setPosition(...position);
    } else {
      mainWindow.center();
    }
    mainWindow.setSize(...size);

    // and load the index.html of the app.
    mainWindow.loadURL(`file://${__dirname}/public_html/index.html`);
    require('./main/features');
    require('./old_win32');

    // Emitted when the window is closed.
    mainWindow.on('closed', () => {
      // Dereference the window object, usually you would store windows
      // in an array if your app supports multi windows, this is the time
      // when you should delete the corresponding element.
      mainWindow = null;
      PlaybackAPI.reset();
    });
  });

  app.on('before-quit', () => {
    global.quiting = true;
  });
})();
<|endoftext|>


<commit_before>const browserify = require('browserify');
const budo = require('budo');
const babelify = require('babelify');
const path = require('path');
const {
  dirname,
  isAbsolute,
  join,
  parse,
} = path;
const compile = require('idyll-compiler');
const fs = require('fs');
const chokidar = require('chokidar');
const changeCase = require('change-case');
const brfs = require('brfs');
const reactPreset = require('babel-preset-react');
const es2015Preset = require('babel-preset-es2015');
const compression = require('compression');
const resolve = require('resolve');
const Mustache = require('mustache');
const ReactDOMServer = require('react-dom/server');
const React = require('react');
const Baby = require('babyparse');
const UglifyJS = require("uglify-js");
const htmlTags = require('html-tags');

const css = require('./assets/css');
const filterAST = require('./assets/ast');

require('babel-core/register')({
    presets: ['react']
});

const getPathFactory = (basedir) => (p) => {
  if (!p) return undefined;
  if (isAbsolute(p)) return p;
  return join(basedir, p);
}

const idyll = (options = {}, cb) => {
  const inputDir = options.inputFile
    ? isAbsolute(options.inputFile)
      ? dirname(options.inputFile)
      : dirname(join(process.cwd(), options.inputFile))
    : process.cwd();
  const getPath = getPathFactory(inputDir);
  const inputPkg = require(getPath('package.json'));
  const inputCfg = (inputPkg.idyll || {components: {}});
  for (let key in inputCfg.components) {
    inputCfg.components[changeCase.paramCase(key)] = inputCfg.components[key];
    delete inputCfg.components[key];
  };

  const opts = Object.assign(
    {},
    {
      build: false,
      components: 'components',
      datasets: 'data',
      defaultComponents: path.join('components', 'default'),
      layout: 'blog',
      output: 'build',
      template: '_index.html',
      theme: 'idyll',
      compilerOptions: {
        spellcheck: true
      },
    },
    inputCfg,
    options
  );

  // input paths
  const IDL_FILE = getPath(opts.inputFile);
  const HTML_TEMPLATE = getPath(opts.template);
  const CSS_INPUT = getPath(opts.css);
  const CUSTOM_COMPONENTS_FOLDER = getPath(opts.components);
  const DEFAULT_COMPONENTS_FOLDER = getPath(opts.defaultComponents);
  const DATA_FOLDER = getPath(opts.datasets);

  // output paths
  const BUILD_PATH = getPath(opts.output);
  if (!fs.existsSync(BUILD_PATH)) fs.mkdirSync(BUILD_PATH);
  const HTML_OUTPUT = join(BUILD_PATH, 'index.html');
  const CSS_OUTPUT = join(BUILD_PATH, 'styles.css');
  const JAVASCRIPT_OUTPUT = join(BUILD_PATH, 'index.js');

  const TMP_PATH = getPath('.idyll');
  if (!fs.existsSync(TMP_PATH)) fs.mkdirSync(TMP_PATH);
  const AST_FILE = join(TMP_PATH, 'ast.json');
  const COMPONENTS_FILE = join(TMP_PATH, 'components.js');
  const DATA_FILE = join(TMP_PATH, 'data.js');

  let componentFiles = [];
  let customComponentFiles = [];
  const readComponents = () => {
    componentFiles = fs.readdirSync(DEFAULT_COMPONENTS_FOLDER);
    customComponentFiles = CUSTOM_COMPONENTS_FOLDER
      ? fs.readdirSync(CUSTOM_COMPONENTS_FOLDER)
      : [];
  }

  const writeAST = (ast) => {
    fs.writeFileSync(AST_FILE, JSON.stringify(filterAST(ast)));
  };

  const writeCSS = (css) => {
    fs.writeFileSync(CSS_OUTPUT, css);
  };

  const writeData = (data) => {
    fs.writeFileSync(DATA_FILE, `module.exports = ${JSON.stringify(data)}`);
  };

  const writeComponents = (components) => {
    const src = Object.keys(components)
      .map((key) => {
        return `'${key}': require('${components[key]}')`;
      })
      .join(',\n\t');
    fs.writeFileSync(COMPONENTS_FILE, `module.exports = {\n\t${src}\n}\n`);
  };

  const writeHTML = (meta) => {
    // const InteractiveDocument = require('./client/component');
    // tree.meta.idyllContent = ReactDOMServer.renderToString(React.createElement(InteractiveDocument));
    const output = Mustache.render(fs.readFileSync(HTML_TEMPLATE, 'utf8'), meta);
    fs.writeFileSync(HTML_OUTPUT, output);
  };

  const interpretAST = (ast) => {
    const getNodesByName = (name, tree) => {
      const predicate = typeof name === 'string' ? (s) => s === name : name;

      const byName = (acc, val) => {
        if (typeof val === 'string') return acc;
        if (predicate(val[0])) acc.push(val);

        if (val[2] && typeof val[2] !== 'string') acc = val[2].reduce(byName, acc);

        return acc;
      }

      return tree.reduce(
        byName,
        []
      )
    }

    const getMeta = (ast) => {
      // there should only be one meta node
      const metaNodes = getNodesByName('meta', ast);

      if (!metaNodes.length) {
        return {};
      }
      // data is stored in props, hence [1]
      return metaNodes[0][1].reduce(
        (acc, prop) => {
          acc[prop[0]] = prop[1][1];
          return acc;
        },
        {}
      )
    }

    const getData = (ast) => {
      // can be multiple data nodes
      const dataNodes = getNodesByName('data', ast);

      // turn each data node into a field on an object
      // whose key is the name prop
      // and whose value is the parsed data
      return dataNodes.reduce(
        (acc, dataNode) => {
          const props = dataNode[1];
          const { name, source } = props.reduce(
            (hash, val) => {
              hash[val[0]] = val[1][1];
              return hash;
            },
            {}
          );

          if (source.endsWith('.csv')) {
            acc[name] = Baby.parseFiles(path.join(DATA_FOLDER, source), { header: true }).data;
          } else {
            acc[name] = require(path.join(DATA_FOLDER, source));
          }

          return acc;
        },
        {}
      );
    }

    const getComponents = (ast) => {
      const ignoreNames = ['var', 'data', 'meta', 'derived'];
      const componentNodes = getNodesByName(s => !ignoreNames.includes(s), ast);

      return componentNodes.reduce(
        (acc, node) => {
          const name = changeCase.paramCase(node[0].split('.')[0]);

          if (!acc[name]) {
            if (inputCfg.components[name]) {
              const compPath = path.parse(path.join(inputDir, inputCfg.components[name]));
              acc[name] = path.join(path.relative(TMP_PATH, compPath.dir), compPath.base).replace(/\\/g, '/');
            } else if (customComponentFiles.indexOf(name + '.js') > -1) {
              acc[name] = path.relative(TMP_PATH, path.join(CUSTOM_COMPONENTS_FOLDER, name)).replace(/\\/g, '/');
            } else if (componentFiles.indexOf(name + '.js') > -1) {
              acc[name] = path.relative(TMP_PATH, path.join(DEFAULT_COMPONENTS_FOLDER, name)).replace(/\\/g, '/');
            } else {
              try {
                // npm modules are required via relative paths to support working with a locally linked idyll
                const compPath = path.parse(resolve.sync(name, {basedir: inputDir}));
                acc[name] = path.join(path.relative(TMP_PATH, compPath.dir), compPath.base).replace(/\\/g, '/');
              } catch (err) {
                if (htmlTags.indexOf(node[0].toLowerCase()) === -1) {
                  throw new Error(`Component named ${node[0]} could not be found.`)
                }
              }
            }
          }

          return acc;
        },
        {}
      )
    }

    return {
      ast,
      components: getComponents(ast),
      data: getData(ast),
      meta: getMeta(ast)
    }
  };

  const browserifyOpts = {
    transform: [
      [ babelify, { presets: [ reactPreset, es2015Preset ] } ],
      [ brfs ]
    ],
    plugin: [
      (b) => b.require([
        {file: AST_FILE, expose: '__IDYLL_AST__'},
        {file: COMPONENTS_FILE, expose: '__IDYLL_COMPONENTS__'},
        {file: DATA_FILE, expose: '__IDYLL_DATA__'}
      ])
    ]
  };

  const build = (callback) => {
    process.env['NODE_ENV'] = 'production';
    var b = browserify(path.join(__dirname, 'client', 'build.js'), browserifyOpts);
    b.bundle(function(err, buff) {
      if (err) {
        console.error('Error creating index.js bundle:');
        console.error(err);
        process.exit(1);
      }
      callback(buff.toString('utf8'));
    });
  }

  const start = () => {
    let watchedFiles = [];
    if (CSS_INPUT) watchedFiles.push(CSS_INPUT);
    if (IDL_FILE) watchedFiles.push(IDL_FILE);

    chokidar.watch(watchedFiles).on('all', (event, path) => {
      if (path.indexOf('.css') !== -1) {
        writeCSS(css(options));
      } else {
        compileAndWriteFiles();
      }
    });
    const watchedComponentFolders = [DEFAULT_COMPONENTS_FOLDER, CUSTOM_COMPONENTS_FOLDER];
    const handleComponentAddRemove = () => {
      readComponents();
      compileAndWriteFiles();
    };
    chokidar.watch(watchedComponentFolders).on('add', handleComponentAddRemove).on('unlink', handleComponentAddRemove);

    budo(path.resolve(path.join(__dirname, 'client', 'live.js')), {
      live: true,
      open: true,
      forceDefaultIndex: true,
      css: CSS_OUTPUT,
      middleware: compression(),
      watchGlob: '**/*.{html,css,json,js}',
      browserify: browserifyOpts
    });
    compileAndWriteFiles();
  }

  const compileAndWriteFiles = () => {
    const idlInput = IDL_FILE
      ? fs.readFileSync(IDL_FILE, 'utf8')
      : opts.inputString;

    try {
      const ast = compile(idlInput, opts.compilerOptions);
      const tree = interpretAST(ast);
      tree.css = css(opts);

      writeAST(ast);
      writeComponents(tree.components);
      writeData(tree.data);
      writeHTML(tree.meta);
      writeCSS(tree.css);
      return tree;
    } catch(err) {
      console.error('Error writing artifacts to disk:');
      console.error(err.message);
    }
  }

  readComponents();
  if (opts.build) {
    const tree = compileAndWriteFiles();
    build(function (js) {
      const jsOutput = UglifyJS.minify(js, {fromString: true});
      tree.js = jsOutput.code;
      fs.writeFileSync(JAVASCRIPT_OUTPUT, tree.js);
      if (cb) cb(tree);
    });
  } else {
    start();
  }
};

module.exports = idyll;
<commit_msg>package.json config should not/cannot be used to override options from CLI/API because of different semantics<commit_after>const browserify = require('browserify');
const budo = require('budo');
const babelify = require('babelify');
const path = require('path');
const {
  dirname,
  isAbsolute,
  join,
  parse,
} = path;
const compile = require('idyll-compiler');
const fs = require('fs');
const chokidar = require('chokidar');
const changeCase = require('change-case');
const brfs = require('brfs');
const reactPreset = require('babel-preset-react');
const es2015Preset = require('babel-preset-es2015');
const compression = require('compression');
const resolve = require('resolve');
const Mustache = require('mustache');
const ReactDOMServer = require('react-dom/server');
const React = require('react');
const Baby = require('babyparse');
const UglifyJS = require("uglify-js");
const htmlTags = require('html-tags');

const css = require('./assets/css');
const filterAST = require('./assets/ast');

require('babel-core/register')({
    presets: ['react']
});

const getPathFactory = (basedir) => (p) => {
  if (!p) return undefined;
  if (isAbsolute(p)) return p;
  return join(basedir, p);
}

const idyll = (options = {}, cb) => {
  const inputDir = options.inputFile
    ? isAbsolute(options.inputFile)
      ? dirname(options.inputFile)
      : dirname(join(process.cwd(), options.inputFile))
    : process.cwd();
  const getPath = getPathFactory(inputDir);
  const inputPkg = require(getPath('package.json'));
  const inputCfg = (inputPkg.idyll || {components: {}});
  for (let key in inputCfg.components) {
    inputCfg.components[changeCase.paramCase(key)] = inputCfg.components[key];
    delete inputCfg.components[key];
  };

  const opts = Object.assign(
    {},
    {
      build: false,
      components: 'components',
      datasets: 'data',
      defaultComponents: path.join('components', 'default'),
      layout: 'blog',
      output: 'build',
      template: '_index.html',
      theme: 'idyll',
      compilerOptions: {
        spellcheck: true
      },
    },
    options
  );

  // input paths
  const IDL_FILE = getPath(opts.inputFile);
  const HTML_TEMPLATE = getPath(opts.template);
  const CSS_INPUT = getPath(opts.css);
  const CUSTOM_COMPONENTS_FOLDER = getPath(opts.components);
  const DEFAULT_COMPONENTS_FOLDER = getPath(opts.defaultComponents);
  const DATA_FOLDER = getPath(opts.datasets);

  // output paths
  const BUILD_PATH = getPath(opts.output);
  if (!fs.existsSync(BUILD_PATH)) fs.mkdirSync(BUILD_PATH);
  const HTML_OUTPUT = join(BUILD_PATH, 'index.html');
  const CSS_OUTPUT = join(BUILD_PATH, 'styles.css');
  const JAVASCRIPT_OUTPUT = join(BUILD_PATH, 'index.js');

  const TMP_PATH = getPath('.idyll');
  if (!fs.existsSync(TMP_PATH)) fs.mkdirSync(TMP_PATH);
  const AST_FILE = join(TMP_PATH, 'ast.json');
  const COMPONENTS_FILE = join(TMP_PATH, 'components.js');
  const DATA_FILE = join(TMP_PATH, 'data.js');

  let componentFiles = [];
  let customComponentFiles = [];
  const readComponents = () => {
    componentFiles = fs.readdirSync(DEFAULT_COMPONENTS_FOLDER);
    customComponentFiles = CUSTOM_COMPONENTS_FOLDER
      ? fs.readdirSync(CUSTOM_COMPONENTS_FOLDER)
      : [];
  }

  const writeAST = (ast) => {
    fs.writeFileSync(AST_FILE, JSON.stringify(filterAST(ast)));
  };

  const writeCSS = (css) => {
    fs.writeFileSync(CSS_OUTPUT, css);
  };

  const writeData = (data) => {
    fs.writeFileSync(DATA_FILE, `module.exports = ${JSON.stringify(data)}`);
  };

  const writeComponents = (components) => {
    const src = Object.keys(components)
      .map((key) => {
        return `'${key}': require('${components[key]}')`;
      })
      .join(',\n\t');
    fs.writeFileSync(COMPONENTS_FILE, `module.exports = {\n\t${src}\n}\n`);
  };

  const writeHTML = (meta) => {
    // const InteractiveDocument = require('./client/component');
    // tree.meta.idyllContent = ReactDOMServer.renderToString(React.createElement(InteractiveDocument));
    const output = Mustache.render(fs.readFileSync(HTML_TEMPLATE, 'utf8'), meta);
    fs.writeFileSync(HTML_OUTPUT, output);
  };

  const interpretAST = (ast) => {
    const getNodesByName = (name, tree) => {
      const predicate = typeof name === 'string' ? (s) => s === name : name;

      const byName = (acc, val) => {
        if (typeof val === 'string') return acc;
        if (predicate(val[0])) acc.push(val);

        if (val[2] && typeof val[2] !== 'string') acc = val[2].reduce(byName, acc);

        return acc;
      }

      return tree.reduce(
        byName,
        []
      )
    }

    const getMeta = (ast) => {
      // there should only be one meta node
      const metaNodes = getNodesByName('meta', ast);

      if (!metaNodes.length) {
        return {};
      }
      // data is stored in props, hence [1]
      return metaNodes[0][1].reduce(
        (acc, prop) => {
          acc[prop[0]] = prop[1][1];
          return acc;
        },
        {}
      )
    }

    const getData = (ast) => {
      // can be multiple data nodes
      const dataNodes = getNodesByName('data', ast);

      // turn each data node into a field on an object
      // whose key is the name prop
      // and whose value is the parsed data
      return dataNodes.reduce(
        (acc, dataNode) => {
          const props = dataNode[1];
          const { name, source } = props.reduce(
            (hash, val) => {
              hash[val[0]] = val[1][1];
              return hash;
            },
            {}
          );

          if (source.endsWith('.csv')) {
            acc[name] = Baby.parseFiles(path.join(DATA_FOLDER, source), { header: true }).data;
          } else {
            acc[name] = require(path.join(DATA_FOLDER, source));
          }

          return acc;
        },
        {}
      );
    }

    const getComponents = (ast) => {
      const ignoreNames = ['var', 'data', 'meta', 'derived'];
      const componentNodes = getNodesByName(s => !ignoreNames.includes(s), ast);

      return componentNodes.reduce(
        (acc, node) => {
          const name = changeCase.paramCase(node[0].split('.')[0]);

          if (!acc[name]) {
            if (inputCfg.components[name]) {
              const compPath = path.parse(path.join(inputDir, inputCfg.components[name]));
              acc[name] = path.join(path.relative(TMP_PATH, compPath.dir), compPath.base).replace(/\\/g, '/');
            } else if (customComponentFiles.indexOf(name + '.js') > -1) {
              acc[name] = path.relative(TMP_PATH, path.join(CUSTOM_COMPONENTS_FOLDER, name)).replace(/\\/g, '/');
            } else if (componentFiles.indexOf(name + '.js') > -1) {
              acc[name] = path.relative(TMP_PATH, path.join(DEFAULT_COMPONENTS_FOLDER, name)).replace(/\\/g, '/');
            } else {
              try {
                // npm modules are required via relative paths to support working with a locally linked idyll
                const compPath = path.parse(resolve.sync(name, {basedir: inputDir}));
                acc[name] = path.join(path.relative(TMP_PATH, compPath.dir), compPath.base).replace(/\\/g, '/');
              } catch (err) {
                if (htmlTags.indexOf(node[0].toLowerCase()) === -1) {
                  throw new Error(`Component named ${node[0]} could not be found.`)
                }
              }
            }
          }

          return acc;
        },
        {}
      )
    }

    return {
      ast,
      components: getComponents(ast),
      data: getData(ast),
      meta: getMeta(ast)
    }
  };

  const browserifyOpts = {
    transform: [
      [ babelify, { presets: [ reactPreset, es2015Preset ] } ],
      [ brfs ]
    ],
    plugin: [
      (b) => b.require([
        {file: AST_FILE, expose: '__IDYLL_AST__'},
        {file: COMPONENTS_FILE, expose: '__IDYLL_COMPONENTS__'},
        {file: DATA_FILE, expose: '__IDYLL_DATA__'}
      ])
    ]
  };

  const build = (callback) => {
    process.env['NODE_ENV'] = 'production';
    var b = browserify(path.join(__dirname, 'client', 'build.js'), browserifyOpts);
    b.bundle(function(err, buff) {
      if (err) {
        console.error('Error creating index.js bundle:');
        console.error(err);
        process.exit(1);
      }
      callback(buff.toString('utf8'));
    });
  }

  const start = () => {
    let watchedFiles = [];
    if (CSS_INPUT) watchedFiles.push(CSS_INPUT);
    if (IDL_FILE) watchedFiles.push(IDL_FILE);

    chokidar.watch(watchedFiles).on('all', (event, path) => {
      if (path.indexOf('.css') !== -1) {
        writeCSS(css(options));
      } else {
        compileAndWriteFiles();
      }
    });
    const watchedComponentFolders = [DEFAULT_COMPONENTS_FOLDER, CUSTOM_COMPONENTS_FOLDER];
    const handleComponentAddRemove = () => {
      readComponents();
      compileAndWriteFiles();
    };
    chokidar.watch(watchedComponentFolders).on('add', handleComponentAddRemove).on('unlink', handleComponentAddRemove);

    budo(path.resolve(path.join(__dirname, 'client', 'live.js')), {
      live: true,
      open: true,
      forceDefaultIndex: true,
      css: CSS_OUTPUT,
      middleware: compression(),
      watchGlob: '**/*.{html,css,json,js}',
      browserify: browserifyOpts
    });
    compileAndWriteFiles();
  }

  const compileAndWriteFiles = () => {
    const idlInput = IDL_FILE
      ? fs.readFileSync(IDL_FILE, 'utf8')
      : opts.inputString;

    try {
      const ast = compile(idlInput, opts.compilerOptions);
      const tree = interpretAST(ast);
      tree.css = css(opts);

      writeAST(ast);
      writeComponents(tree.components);
      writeData(tree.data);
      writeHTML(tree.meta);
      writeCSS(tree.css);
      return tree;
    } catch(err) {
      console.error('Error writing artifacts to disk:');
      console.error(err.message);
    }
  }

  readComponents();
  if (opts.build) {
    const tree = compileAndWriteFiles();
    build(function (js) {
      const jsOutput = UglifyJS.minify(js, {fromString: true});
      tree.js = jsOutput.code;
      fs.writeFileSync(JAVASCRIPT_OUTPUT, tree.js);
      if (cb) cb(tree);
    });
  } else {
    start();
  }
};

module.exports = idyll;
<|endoftext|>


<commit_before>/**
 * @license
 * resol-vbus - A JavaScript library for processing RESOL VBus data
 */
'use strict';

var extend = require('./extend');

var Specification = require('./specification');

var Header = require('./header');
var Packet = require('./packet');
var Datagram = require('./datagram');
// var Telegram = require('./telegram');

var HeaderSet = require('./header-set');

var Logger = require('./logger');

var Connection = require('./connection');

// var TcpDataSourceProvider = require('./tcp-data-source-provider');
// var TcpConnection = require('./tcp-connection');

module.exports = {
    extend: extend,

    Specification: Specification,

    Header: Header,
    Packet: Packet,
    Datagram: Datagram,
    // Telegram: Telegram,

    HeaderSet: HeaderSet,

    Logger: Logger,

    Connection: Connection,

    // TcpDataSourceProvider: TcpDataSourceProvider,
    // TcpConnection: TcpConnection,

};
<commit_msg>- Added version information to module exports<commit_after>/**
 * @license
 * resol-vbus - A JavaScript library for processing RESOL VBus data
 */
'use strict';

var packageInfo = require('../package.json');

var extend = require('./extend');

var Specification = require('./specification');

var Header = require('./header');
var Packet = require('./packet');
var Datagram = require('./datagram');
// var Telegram = require('./telegram');

var HeaderSet = require('./header-set');

var Logger = require('./logger');

var Connection = require('./connection');

// var TcpDataSourceProvider = require('./tcp-data-source-provider');
// var TcpConnection = require('./tcp-connection');

module.exports = {

    VERSION: packageInfo.version,

    extend: extend,

    Specification: Specification,

    Header: Header,
    Packet: Packet,
    Datagram: Datagram,
    // Telegram: Telegram,

    HeaderSet: HeaderSet,

    Logger: Logger,

    Connection: Connection,

    // TcpDataSourceProvider: TcpDataSourceProvider,
    // TcpConnection: TcpConnection,

};
<|endoftext|>


<commit_before>'use strict';

var TBF = function(){
	this._setupListeners();
	this._setupWebsocket();
};

TBF.prototype._setupWebsocket = function(){
	this._websocket = new WebSocket('ws://' + window.location.host + '/websocket');
	var self = this;
	this._websocket.onmessage = function(event){
		var jsons = JSON.parse(event.data);
		jsons.forEach(function(json){
			self._handleResponse(json);
		})
	};
};

TBF.prototype._augmentInterface = function(){
	var tags = document.getElementsByTagName('BUTTON');
	for(var i = 0; i < tags.length; i++){
		this._augmentButton(tags.item(i));
	}
	tags = document.getElementsByTagName('FORM');
	for(var i = 0; i < tags.length; i++){
		this._augmentForm(tags.item(i))
	}

};

TBF.prototype._augmentButton = function(ele){
	if(!ele.dataset.url){
		return;
	}
	if(ele.onclick){	// already done
		return;
	}
	console.log('augmenting button: ', ele);
	var self = this;
	ele.onclick = function(){
		self._elementActivated(ele);
	}
};

TBF.prototype._augmentForm = function(ele){
	if(ele.onsubmit){	// already done
		return;
	}
	console.log('augmenting form: ', ele);
	var self = this;
	ele.onsubmit = function(){
		self._elementActivated(ele);
		return false;
	}
};

TBF.prototype._elementActivated = function(ele){
	console.log('element activated:', ele);
	var self = this;
	this._websocket.send(this._getActionURL(ele));
};

TBF.prototype._getActionURL = function(ele){
	if(ele.tagName === 'BUTTON'){
		return ele.dataset.url;
	}
	else if(ele.tagName === 'FORM'){
		var kvPairs = [];
		for(var i = 0; i < ele.elements.length; i++){
			var e = ele.elements[i];
			kvPairs.push(encodeURIComponent(e.name) + '=' + encodeURIComponent(e.value));
		}
		var queryString = kvPairs.join('&');
		return ele.action + '?' + queryString;
	}
	throw new Error('Unknown element type');
};

TBF.prototype._handleResponse = function(json){
	console.log('got json:', json);
	var container = document.getElementById(json.container);
	if(!container){
		throw new Error('container not found: ' + json.container);
	}
	if(json.action === 'replace'){
		container.innerHTML = json.content;
	}
	else if(json.action === 'append'){
		var template = document.createElement('template');
		template.innerHTML = json.content;
		for(var i = 0; i < template.content.childNodes.length; i++){
			container.appendChild(template.content.childNodes.item(i));
		}
	}
	else{
		throw new Error('Unknown action: ', json.action);
	}
};

TBF.prototype._setupListeners = function(){
	var self = this;
	document.addEventListener('DOMContentLoaded', function(event) {
		self._augmentInterface();
	});
	document.addEventListener('DOMSubtreeModified', function(event) {
		self._augmentInterface();
	});
};

window.tbfInstance = new TBF();
<commit_msg>now supporting secure websockets<commit_after>'use strict';

var TBF = function(){
	this._setupListeners();
	this._setupWebsocket();
};

TBF.prototype._setupWebsocket = function(){
	var socketProto = window.location.protocol.replace('http', 'ws');
	this._websocket = new WebSocket(socketProto + '//' + window.location.host + '/websocket');
	var self = this;
	this._websocket.onmessage = function(event){
		var jsons = JSON.parse(event.data);
		jsons.forEach(function(json){
			self._handleResponse(json);
		})
	};
};

TBF.prototype._augmentInterface = function(){
	var tags = document.getElementsByTagName('BUTTON');
	for(var i = 0; i < tags.length; i++){
		this._augmentButton(tags.item(i));
	}
	tags = document.getElementsByTagName('FORM');
	for(var i = 0; i < tags.length; i++){
		this._augmentForm(tags.item(i))
	}

};

TBF.prototype._augmentButton = function(ele){
	if(!ele.dataset.url){
		return;
	}
	if(ele.onclick){	// already done
		return;
	}
	console.log('augmenting button: ', ele);
	var self = this;
	ele.onclick = function(){
		self._elementActivated(ele);
	}
};

TBF.prototype._augmentForm = function(ele){
	if(ele.onsubmit){	// already done
		return;
	}
	console.log('augmenting form: ', ele);
	var self = this;
	ele.onsubmit = function(){
		self._elementActivated(ele);
		return false;
	}
};

TBF.prototype._elementActivated = function(ele){
	console.log('element activated:', ele);
	var self = this;
	this._websocket.send(this._getActionURL(ele));
};

TBF.prototype._getActionURL = function(ele){
	if(ele.tagName === 'BUTTON'){
		return ele.dataset.url;
	}
	else if(ele.tagName === 'FORM'){
		var kvPairs = [];
		for(var i = 0; i < ele.elements.length; i++){
			var e = ele.elements[i];
			kvPairs.push(encodeURIComponent(e.name) + '=' + encodeURIComponent(e.value));
		}
		var queryString = kvPairs.join('&');
		return ele.action + '?' + queryString;
	}
	throw new Error('Unknown element type');
};

TBF.prototype._handleResponse = function(json){
	console.log('got json:', json);
	var container = document.getElementById(json.container);
	if(!container){
		throw new Error('container not found: ' + json.container);
	}
	if(json.action === 'replace'){
		container.innerHTML = json.content;
	}
	else if(json.action === 'append'){
		var template = document.createElement('template');
		template.innerHTML = json.content;
		for(var i = 0; i < template.content.childNodes.length; i++){
			container.appendChild(template.content.childNodes.item(i));
		}
	}
	else{
		throw new Error('Unknown action: ', json.action);
	}
};

TBF.prototype._setupListeners = function(){
	var self = this;
	document.addEventListener('DOMContentLoaded', function(event) {
		self._augmentInterface();
	});
	document.addEventListener('DOMSubtreeModified', function(event) {
		self._augmentInterface();
	});
};

window.tbfInstance = new TBF();
<|endoftext|>


<commit_before>import createDispatcher from './createDispatcher'
import withActions from './withActions'
import withStore from './withStore'
import connectStore from './connectStore'
import wrapActions from './util/wrapActions'

export {
  createDispatcher,
  withActions,
  withStore,
  connectStore,
  wrapActions
}
<commit_msg>Export Provider<commit_after>import createDispatcher from './createDispatcher'
import withActions from './withActions'
import withStore from './withStore'
import connectStore from './connectStore'
import wrapActions from './util/wrapActions'
import Provider from './Provider'

export {
  createDispatcher,
  withActions,
  withStore,
  connectStore,
  wrapActions,
  Provider
}
<|endoftext|>


<commit_before>// For Bootstrap 4
const bootstrap4Breakpoints = {
  xs: {
    min: -1,
    max: 543
  },
  sm: {
    min: 544,
    max: 767
  },
  md: {
    min: 768,
    max: 991
  },
  lg: {
    min: 992,
    max: 1199
  },
  xl: {
    min: 1200,
    max: Infinity
  }
}

// For Bootstrap 3
const bootstrap3Breakpoints = {
  xs: {
    min: -1,
    max: 767
  },
  sm: {
    min: 768,
    max: 991
  },
  md: {
    min: 992,
    max: 1199
  },
  lg: {
    min: 1200,
    max: Infinity
  }
}

const self = {
  idIncrement: 1,
  resizeListeners: null,
  init: false,
  _rPermissions: {
    bs4: bootstrap4Breakpoints,
    bs3: bootstrap3Breakpoints
  },
  allProperties: {} // id: {lastBp:'', pointsName: '', dataset: {}}
}

var vueResponsive = {
  bind: function (el, binding, vnode) {
    // Bootstrap 4 Repsonsive Utils default
    var componentHasDefault = !!self._rPermissions.default
    let useClass = !!binding.modifiers.class
    if (!self.init) {
      for (let i in vnode.context.$data) {
        if (i.indexOf('responsiveMarks$$') === 0) {
          var name = String(i).replace('responsiveMarks$$', '').toLowerCase()
          self._rPermissions[name] = {}

          for (let ii in vnode.context.$data[i]) self._rPermissions[name][ii] = vnode.context.$data[i][ii]
        }
        if (i === 'responsiveDefault$$') componentHasDefault = vnode.context.$data[i]
      }
      // Set bs4 as default if not default is explicitly set
      self._rPermissions.undefined = componentHasDefault ? self._rPermissions[componentHasDefault] : self._rPermissions.bs4
      self.init++
    }
    var validInputs = ['hidden-all']
    let validPositiv = []
    let choosenBPointsName = componentHasDefault ? self._rPermissions.defaultName : (binding.arg || 'bs4')
    for (let key in self._rPermissions[binding.arg]) {
      validInputs.push(key)
      validPositiv.push(key)
      validInputs.push(`hidden-${key}`)
    }

    // if this is the first element with this directive that gets bound add the resize listener
    if (!self.resizeListeners) {
      self.resizeListeners = {}

      // adds a single resize listener for all elements
      window.addEventListener('resize', function () {
        // calls the checkDisplay function for all elements that are active in the DOM and use this directive
        for (let i in self.resizeListeners) if (!isNaN(i)) self.resizeListeners[i]()
      })
    }

    // if the element has a user defined css-value, save it!
    if (el.style.display) el.dataset.initialDisplay = el.style.display ? el.style.display : getComputedStyle(el, null).display

    let preParams = []

    // need a case for the short syntax
    // are the modifiers decisive?
    let modifiers = window.Object.keys(binding.modifiers)
    if (useClass);
    else if (modifiers.some(k => ~validPositiv.indexOf(k.replace(/\+|-/g, '')))) {
      modifiers.forEach(m => {
        // if (/^(\+|-)|(\+|-)$/g.test(modifiers))
      })
      preParams.push(...modifiers)
      preParams.push('hidden-all')
      preParams.sort()
    } else if (Array.isArray(binding.value) || (typeof binding.expression === 'string' && binding.expression.match(/[*]/))) {
      if (Array.isArray(binding.value)) {
        preParams = binding.value
      } else {
        var stringArray = binding.expression.replace(/'/g, '"')
        preParams = JSON.parse(stringArray)
      }
      preParams.sort()
    } else if (binding.value instanceof Object) {
      for (let i in binding.value) {
        if (binding.value[i]) preParams.push(i)
      }
    } else if (typeof binding.value === 'string' || typeof binding.expression === 'string') { // a single parameter
      var val = binding.value || binding.expression.replace(/'"/g, '')
      preParams = new Array(val)
      preParams.sort()
    } else {
      return // no parameter given, no work :/
    }
    // init the permission object with an id
    let rId = String(self.idIncrement++)

    // save the settings for this element in it's dataset
    el.dataset.responsives = rId
    var rPermissions = { lastBp: '', bpSet: choosenBPointsName, useClass }

    let hiddenAllIndex = preParams.indexOf('hidden-all')
    if (~hiddenAllIndex) {
      preParams.splice(hiddenAllIndex, 1)
      // disallow all breakpoints as initial value
      for (let i in self._rPermissions[binding.arg]) rPermissions[i] = 0
    } else {
      // allow all breakpoints as initial value
      for (let k in self._rPermissions[binding.arg]) rPermissions[k] = 1
    }

    for (let i = 0; i < preParams.length; i++) {
      let item = preParams[i]
      if (!~validInputs.indexOf(item)) continue
      if (item.indexOf('hidden') === 0) { // hidden-..
        var key = item.split('-')[1]
        rPermissions[key] = 0 // show = false
      } else {
        rPermissions[item] = 1 // show = true
      }
    }

    self.allProperties[rId] = rPermissions
  },

  /**
   * Is callend when the element is inserted into the DOM
   *
   * @param  {object} el      html element
   * @param  {object} binding the parameters of the mixin
   * @param  {object} vnode   the virtual html elment
   */
  inserted: function (el, binding, vnode) {
    if (el.dataset.responsives == null) return
    // todo: throw error if isNaN
    let resizeListenerId = el.dataset.responsives

    /**
     * This function checks the current breakpoint constraints for this element
     */
    function checkDisplay () {
      var myPermissions = self.allProperties[resizeListenerId] // JSON.parse(el.dataset.responsives)
      var curWidth = window.innerWidth
      var initial = el.dataset.initialDisplay ? el.dataset.initialDisplay : ''
      var parameters = self._rPermissions[binding.arg]
      for (let i in parameters) {
        if (curWidth >= parameters[i].min && curWidth <= parameters[i].max) {
          if (myPermissions.lastBp !== i) {
            if (self.allProperties[resizeListenerId].useClass) {
              el.classList.add(myPermissions.bpSet + '-' + i)
              el.classList.remove(myPermissions.bpSet + '-' + myPermissions.lastBp)
            } else {
              el.style.display = myPermissions[i] ? initial : 'none'
            }

            self.allProperties[resizeListenerId].lastBp = i
          }
          break
        }
      }
    }
    checkDisplay()
    self.resizeListeners[resizeListenerId] = checkDisplay
  },

  /**
   * Is called when the html element is removed from DOM
   *
   * @param  {object} el      html element
   * @param  {object} binding the parameters of the mixin
   * @param  {object} vnode   the virtual html elment
   */
  unbind: function (el, binding, vnode) {
    let resizeListenerId = el.dataset.responsives
    delete self.resizeListeners[resizeListenerId]
  }
}

/**
 * Install vue-responsive globally to Vue.js
 *
 * @param  {object} Vue     the constructor of the framework
 * @param  {object} options parameter to modify the behavior of the plugin
 * @return {void}         returns nothing
 */
vueResponsive.install = function (Vue, options) {
  if (typeof (options) === 'object' && options.breakpoints) {
    self._rPermissions.default = options.breakpoints
  }
  Vue.directive('responsive', vueResponsive)
}

// https://babeljs.io/docs/plugins/transform-es2015-modules-umd/
export {vueResponsive}
export default vueResponsive

// Check if the directive should be used globally
try {
  var notGlobal = false
  var currScriptFn = document.currentScript
  currScriptFn = currScriptFn || (function () {
    var scripts = document.getElementsByTagName('script')
    return scripts[scripts.length - 1]
  })()
  notGlobal = Boolean(currScriptFn.getAttribute('notGlobal'))
  if (!notGlobal && typeof window !== 'undefined' && typeof window.Vue === 'function') window.Vue.use(vueResponsive)
} catch (idk) { console.error(idk) }
<commit_msg>Update index.js<commit_after>// For Bootstrap 4
const bootstrap4Breakpoints = {
  xs: {
    min: -1,
    max: 543
  },
  sm: {
    min: 544,
    max: 767
  },
  md: {
    min: 768,
    max: 991
  },
  lg: {
    min: 992,
    max: 1199
  },
  xl: {
    min: 1200,
    max: Infinity
  }
}

// For Bootstrap 3
const bootstrap3Breakpoints = {
  xs: {
    min: -1,
    max: 767
  },
  sm: {
    min: 768,
    max: 991
  },
  md: {
    min: 992,
    max: 1199
  },
  lg: {
    min: 1200,
    max: Infinity
  }
}

const self = {
  idIncrement: 1,
  resizeListeners: null,
  init: false,
  _rPermissions: {
    bs4: bootstrap4Breakpoints,
    bs3: bootstrap3Breakpoints
  },
  allProperties: {} // id: {lastBp:'', pointsName: '', dataset: {}}
}

var vueResponsive = {
  bind: function (el, binding, vnode) {
    // Bootstrap 4 Repsonsive Utils default
    var componentHasDefault = !!self._rPermissions.default
    let useClass = !!binding.modifiers.class
    if (!self.init) {
      for (let i in vnode.context.$data) {
        if (i.indexOf('responsiveMarks$$') === 0) {
          var name = String(i).replace('responsiveMarks$$', '').toLowerCase()
          self._rPermissions[name] = {}

          for (let ii in vnode.context.$data[i]) self._rPermissions[name][ii] = vnode.context.$data[i][ii]
        }
        if (i === 'responsiveDefault$$') componentHasDefault = vnode.context.$data[i]
      }
      // Set bs4 as default if not default is explicitly set
      self._rPermissions.undefined = componentHasDefault ? self._rPermissions[componentHasDefault] : self._rPermissions.bs4
      self.init++
    }
    var validInputs = ['hidden-all']
    let validPositiv = []
    let choosenBPointsName = componentHasDefault ? self._rPermissions.defaultName : (binding.arg || 'bs4')
    for (let key in self._rPermissions[binding.arg]) {
      validInputs.push(key)
      validPositiv.push(key)
      validInputs.push("hidden-"+key)
    }

    // if this is the first element with this directive that gets bound add the resize listener
    if (!self.resizeListeners) {
      self.resizeListeners = {}

      // adds a single resize listener for all elements
      window.addEventListener('resize', function () {
        // calls the checkDisplay function for all elements that are active in the DOM and use this directive
        for (let i in self.resizeListeners) if (!isNaN(i)) self.resizeListeners[i]()
      })
    }

    // if the element has a user defined css-value, save it!
    if (el.style.display) el.dataset.initialDisplay = el.style.display ? el.style.display : getComputedStyle(el, null).display

    let preParams = []

    // need a case for the short syntax
    // are the modifiers decisive?
    let modifiers = window.Object.keys(binding.modifiers)
    if (useClass);
    else if (modifiers.some(k => ~validPositiv.indexOf(k.replace(/\+|-/g, '')))) {
      modifiers.forEach(m => {
        // if (/^(\+|-)|(\+|-)$/g.test(modifiers))
      })
      preParams.push(...modifiers)
      preParams.push('hidden-all')
      preParams.sort()
    } else if (Array.isArray(binding.value) || (typeof binding.expression === 'string' && binding.expression.match(/[*]/))) {
      if (Array.isArray(binding.value)) {
        preParams = binding.value
      } else {
        var stringArray = binding.expression.replace(/'/g, '"')
        preParams = JSON.parse(stringArray)
      }
      preParams.sort()
    } else if (binding.value instanceof Object) {
      for (let i in binding.value) {
        if (binding.value[i]) preParams.push(i)
      }
    } else if (typeof binding.value === 'string' || typeof binding.expression === 'string') { // a single parameter
      var val = binding.value || binding.expression.replace(/'"/g, '')
      preParams = new Array(val)
      preParams.sort()
    } else {
      return // no parameter given, no work :/
    }
    // init the permission object with an id
    let rId = String(self.idIncrement++)

    // save the settings for this element in it's dataset
    el.dataset.responsives = rId
    var rPermissions = { lastBp: '', bpSet: choosenBPointsName, useClass }

    let hiddenAllIndex = preParams.indexOf('hidden-all')
    if (~hiddenAllIndex) {
      preParams.splice(hiddenAllIndex, 1)
      // disallow all breakpoints as initial value
      for (let i in self._rPermissions[binding.arg]) rPermissions[i] = 0
    } else {
      // allow all breakpoints as initial value
      for (let k in self._rPermissions[binding.arg]) rPermissions[k] = 1
    }

    for (let i = 0; i < preParams.length; i++) {
      let item = preParams[i]
      if (!~validInputs.indexOf(item)) continue
      if (item.indexOf('hidden') === 0) { // hidden-..
        var key = item.split('-')[1]
        rPermissions[key] = 0 // show = false
      } else {
        rPermissions[item] = 1 // show = true
      }
    }

    self.allProperties[rId] = rPermissions
  },

  /**
   * Is callend when the element is inserted into the DOM
   *
   * @param  {object} el      html element
   * @param  {object} binding the parameters of the mixin
   * @param  {object} vnode   the virtual html elment
   */
  inserted: function (el, binding, vnode) {
    if (el.dataset.responsives == null) return
    // todo: throw error if isNaN
    let resizeListenerId = el.dataset.responsives

    /**
     * This function checks the current breakpoint constraints for this element
     */
    function checkDisplay () {
      var myPermissions = self.allProperties[resizeListenerId] // JSON.parse(el.dataset.responsives)
      var curWidth = window.innerWidth
      var initial = el.dataset.initialDisplay ? el.dataset.initialDisplay : ''
      var parameters = self._rPermissions[binding.arg]
      for (let i in parameters) {
        if (curWidth >= parameters[i].min && curWidth <= parameters[i].max) {
          if (myPermissions.lastBp !== i) {
            if (self.allProperties[resizeListenerId].useClass) {
              el.classList.add(myPermissions.bpSet + '-' + i)
              el.classList.remove(myPermissions.bpSet + '-' + myPermissions.lastBp)
            } else {
              el.style.display = myPermissions[i] ? initial : 'none'
            }

            self.allProperties[resizeListenerId].lastBp = i
          }
          break
        }
      }
    }
    checkDisplay()
    self.resizeListeners[resizeListenerId] = checkDisplay
  },

  /**
   * Is called when the html element is removed from DOM
   *
   * @param  {object} el      html element
   * @param  {object} binding the parameters of the mixin
   * @param  {object} vnode   the virtual html elment
   */
  unbind: function (el, binding, vnode) {
    let resizeListenerId = el.dataset.responsives
    delete self.resizeListeners[resizeListenerId]
  }
}

/**
 * Install vue-responsive globally to Vue.js
 *
 * @param  {object} Vue     the constructor of the framework
 * @param  {object} options parameter to modify the behavior of the plugin
 * @return {void}         returns nothing
 */
vueResponsive.install = function (Vue, options) {
  if (typeof (options) === 'object' && options.breakpoints) {
    self._rPermissions.default = options.breakpoints
  }
  Vue.directive('responsive', vueResponsive)
}

// https://babeljs.io/docs/plugins/transform-es2015-modules-umd/
export {vueResponsive}
export default vueResponsive

// Check if the directive should be used globally
try {
  var notGlobal = false
  var currScriptFn = document.currentScript
  currScriptFn = currScriptFn || (function () {
    var scripts = document.getElementsByTagName('script')
    return scripts[scripts.length - 1]
  })()
  notGlobal = Boolean(currScriptFn.getAttribute('notGlobal'))
  if (!notGlobal && typeof window !== 'undefined' && typeof window.Vue === 'function') window.Vue.use(vueResponsive)
} catch (idk) { console.error(idk) }
<|endoftext|>