<commit_before>'use strict';

// var Pusher = require('pusher-js');
// var PusherNative = require('pusher-js/react-native');
// on the one hand having global state is ugly, on the other it is easier to use it from anywhere
var config = {
  socket: null,
  store: null,
  apiKey: null,
  options: {},
  subscriptions: {},
  PusherClient: null
};

module.exports.setPusherClient = function (PusherClient) {
  config.PusherClient = PusherClient;
};

// create redux action
var pusherAction = function pusherAction(_ref) {
  var actionType = _ref.actionType;
  var channelName = _ref.channelName;
  var eventName = _ref.eventName;
  var data = _ref.data;

  return {
    type: actionType,
    channel: channelName,
    event: eventName,
    data: data
  };
};

// we need to wait before pusher connects until we can subscribe
// so gonna queue actions here
var pendingFunctions = [];
var isConnected = false;

var addToQueue = function addToQueue(func) {
  pendingFunctions.push(func);
  runPending();
};

var successfullyConnected = function successfullyConnected() {
  isConnected = true;
  runPending();
};

var runPending = function runPending() {
  // that's like a promise, but I don't want to depend on promises
  while (isConnected && pendingFunctions.length > 0) {
    pendingFunctions.shift()();
  }
};

module.exports.configurePusher = function (store, apiKey) {
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

  config.socket = new config.PusherClient(apiKey, options);
  config.store = store;
  config.apiKey = apiKey;
  config.socket.connection.bind('connected', successfullyConnected);
};

module.exports.delayConfiguration = function (store, apiKey) {
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

  config.store = store;
  config.apiKey = apiKey;
  Object.assign(config.options, options);
};

module.exports.startConfiguration = function () {
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

  config.socket = new config.PusherClient(config.apiKey, Object.assign({}, config.options, options));
  config.socket.connection.bind('connected', successfullyConnected);
};

module.exports.subscribe = function (channelName, eventName, actionType) {
  addToQueue(function () {
    var channel = config.socket.channel(channelName) || config.socket.subscribe(channelName);
    if (!config.subscriptions[channelName]) {
      config.subscriptions[channelName] = {};
    }
    var channelSubs = config.subscriptions[channelName];
    if (!channelSubs[eventName]) {
      channelSubs[eventName] = {};
    }
    var eventSubs = channelSubs[eventName];
    if (!eventSubs[actionType]) {
      eventSubs[actionType] = function (data) {
        config.store.dispatch(pusherAction({ actionType: actionType, channelName: channelName, eventName: eventName, data: data }));
      };
      channel.bind(eventName, eventSubs[actionType]);
    }
  });
};

module.exports.unsubscribe = function (channelName, eventName, actionType) {
  addToQueue(function () {
    var channel = config.socket.channel(channelName);
    if (!channel) {
      console.log('Not subscribed to \'' + channelName + '\'');
      return;
    }
    var channelSubs = config.subscriptions[channelName];
    if (!channelSubs[eventName]) {
      console.log('Not subscribed event \'' + eventName + '\' from \'' + channelName + '\'');
      return;
    }
    var eventSubs = channelSubs[eventName];
    if (!eventSubs[actionType]) {
      console.log('Handler ' + actionType + ' not registered for event \'' + eventName + '\' from \'' + channelName + '\'');
      return;
    }
    channel.unbind(eventName, eventSubs[actionType]);
    delete eventSubs[actionType];
  });
};
<commit_msg>Add custom payload for action dispatcher<commit_after>'use strict';

// var Pusher = require('pusher-js');
// var PusherNative = require('pusher-js/react-native');
// on the one hand having global state is ugly, on the other it is easier to use it from anywhere
var config = {
  socket: null,
  store: null,
  apiKey: null,
  options: {},
  subscriptions: {},
  PusherClient: null
};

module.exports.setPusherClient = function (PusherClient) {
  config.PusherClient = PusherClient;
};

// create redux action
var pusherAction = function pusherAction(_ref) {
  var actionType = _ref.actionType;
  var channelName = _ref.channelName;
  var eventName = _ref.eventName;
  var data = _ref.data;

  if (actionType !== null && typeof actionType === 'object') {
    return _extends({
      channel: channelName,
      event: eventName,
      data: data
    }, actionType)
  }
  else {
    return {
      type: actionType,
      channel: channelName,
      event: eventName,
      data: data
    }
  }
};

// we need to wait before pusher connects until we can subscribe
// so gonna queue actions here
var pendingFunctions = [];
var isConnected = false;

var addToQueue = function addToQueue(func) {
  pendingFunctions.push(func);
  runPending();
};

var successfullyConnected = function successfullyConnected() {
  isConnected = true;
  runPending();
};

var runPending = function runPending() {
  // that's like a promise, but I don't want to depend on promises
  while (isConnected && pendingFunctions.length > 0) {
    pendingFunctions.shift()();
  }
};

module.exports.configurePusher = function (store, apiKey) {
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

  config.socket = new config.PusherClient(apiKey, options);
  config.store = store;
  config.apiKey = apiKey;
  config.socket.connection.bind('connected', successfullyConnected);
};

module.exports.delayConfiguration = function (store, apiKey) {
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

  config.store = store;
  config.apiKey = apiKey;
  Object.assign(config.options, options);
};

module.exports.startConfiguration = function () {
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

  config.socket = new config.PusherClient(config.apiKey, Object.assign({}, config.options, options));
  config.socket.connection.bind('connected', successfullyConnected);
};

module.exports.subscribe = function (channelName, eventName, actionType) {
  addToQueue(function () {
    var channel = config.socket.channel(channelName) || config.socket.subscribe(channelName);
    if (!config.subscriptions[channelName]) {
      config.subscriptions[channelName] = {};
    }
    var channelSubs = config.subscriptions[channelName];
    if (!channelSubs[eventName]) {
      channelSubs[eventName] = {};
    }
    var eventSubs = channelSubs[eventName];
    if (!eventSubs[actionType]) {
      eventSubs[actionType] = function (data) {
        config.store.dispatch(pusherAction({ actionType: actionType, channelName: channelName, eventName: eventName, data: data }));
      };
      channel.bind(eventName, eventSubs[actionType]);
    }
  });
};

module.exports.unsubscribe = function (channelName, eventName, actionType) {
  addToQueue(function () {
    var channel = config.socket.channel(channelName);
    if (!channel) {
      console.log('Not subscribed to \'' + channelName + '\'');
      return;
    }
    var channelSubs = config.subscriptions[channelName];
    if (!channelSubs[eventName]) {
      console.log('Not subscribed event \'' + eventName + '\' from \'' + channelName + '\'');
      return;
    }
    var eventSubs = channelSubs[eventName];
    if (!eventSubs[actionType]) {
      console.log('Handler ' + actionType + ' not registered for event \'' + eventName + '\' from \'' + channelName + '\'');
      return;
    }
    channel.unbind(eventName, eventSubs[actionType]);
    delete eventSubs[actionType];
  });
};
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
<|endoftext|>


<commit_before>(function() {

	var id = 0;
	var undef;

	/**
	 * A LinkedList implemented in pure JavaScript.
	 *
	 * Use this class when adding/removing/contains is more performance critical to you than iterating.
	 * LinkedLists beat native array performance especially on checking for containment and removing of objects.
	 * It adds somewhat of a memory overhead though as every object refers the previous/next objects.
	 * Through the nature of having fast contains checks and position storage it can be used when both
	 * positions and fast containsment checks are required (a mix of array/hashmap)
	 */
	Class("core.collection.LinkedList",
	{

		construct: function(array)
		{

			// Field to store data in each object
			// Keeps an array with [prev, next]
			this.__id = "$ll" + id++;

			// Import array
			if (array) {

				var id = this.__id;
				var length = array.length;

				if (length > 0) {

					var current = array[0];
					var prev, next;

					this.__first = current;
					this.__length = length;

					for (var i=0; i<length; i++) {

						if (current[id]) {
							throw new Error("Duplicated object during import: " + obj);
						}

						next = array[i+1];

						current[id] = [prev, next];

						prev = current;
						current = next;

					}
				}
			}
		},

		members:
		{

			__first: undef,
			__last: undef,
			__length: 0,

			/**
			 * Adds the given object to the list
			 *
			 * Performance behavior: O(1)
			 *
			 * @param obj {Object} Object to add
			 * @return {LinkedList} Returns this object for further operations
			 */
			add: function(obj) {

				var self = this;

				if (obj[self.__id]) {
					throw new Error("Object is already in the list: " + obj);
				}

				var id = self.__id;

				var prev = self.__last;
				if (prev) {

					// append after previous last one
					obj[id] = [prev];
					prev[id][1] = obj;

				} else {

					// insert as the first object
					obj[id] = [];
					self.__first = obj;

				}

				self.__length++;
				self.__last = obj;

				return self;

			},

			/**
			 * Removes the given object from the list
			 *
			 * Performance behavior: O(1)
			 *
			 * @param obj {Object} Object to remove
			 * @return {LinkedList} Returns this object for further operations
			 */
			remove: function(obj) {

				var self = this;

				if (!obj[self.__id]) {
					throw new Error("Object is not in the list: " + obj);
				}

				var id = self.__id;
				var store = obj[id];

				var prev = store[0];
				var next = store[1];

				if (prev && next) {

					// Conntext previous and next child
					prev[1] = next;
					next[0] = prev;

				} else if (prev) {

					// Free previous child from reference to this object
					prev[1] = undef;
					self.__last = prev;

				} else if (next) {

					// We seem to be the first
					// Make following child the first
					next[0] = undef;
					self.__first = next;

				} else {

					self.__first = undef;
					self.__last = undef;

				}

				obj[id] = undef;
				self.__length--;

				return self;

			},

			/**
			 * Whether the list contains the given object
			 *
			 * Performance behavior: O(1)
			 *
			 * @param obj {Object} Object to check for
			 * @return {Boolean} Whether the object is in the list
			 */
			has: function(obj) {
				return !!obj[this.__id];
			},

			/**
			 * Returns the position of the object in the list
			 *
			 * Performance behavior: O(n); in negative cases just O(1)
			 *
			 * @param obj {Object} Object to check for
			 * @return {Integer} The position of the object in the list. `-1` when object was not found.
			 */
			indexOf: function(obj) {

				var self = this;
				var id = self.__id;

				if (!obj[id]) {
					return -1;
				}

				var current = self.__first;
				var pos = 0;

				for(;;) {

					if (current === obj) {
						return pos;
					}

					pos++;
					current = current[id][1];

				}
			},

			/**
			 * Whether the LinkedList is empty
			 *
			 * Performance behavior: O(1)
			 *
			 * @return {Boolean} Whether the list is empty
			 */
			isEmpty: function() {
				return this.__length > 0;
			},

			/**
			 * Returns the length of the list
			 *
			 * Performance behavior: O(1)
			 *
			 * @return {Integer} Length of the list
			 */
			getLength: function() {
				return this.__length;
			},

			/**
			 * Returns an array copy of the list
			 *
			 * Performance behavior: O(n)
			 *
			 * @return {Array} Current list converted to an array
			 */
			toArray: function() {

				var self = this;
				var length = self.__length;
				var array = [];

				var current = self.__first;
				for (var i=0; i<length; i++) {
					array.push(current);
					current = current[id][1];
				}

				return array;

			}
		}
	});
})();
<commit_msg>Minor tweaks<commit_after>(function() {

	var unique = 0;
	var undef;

	/**
	 * A LinkedList implemented in pure JavaScript.
	 *
	 * Use this class when adding/removing/contains is more performance critical to you than iterating.
	 * LinkedLists beat native array performance especially on checking for containment and removing of objects.
	 * It adds somewhat of a memory overhead though as every object refers the previous/next objects.
	 * Through the nature of having fast contains checks and position storage it can be used when both
	 * positions and fast containsment checks are required (a mix of array/hashmap)
	 */
	Class("core.collection.LinkedList",
	{

		construct: function(array)
		{

			// Field to store data in each object
			// Keeps an array with [prev, next]
			var id = this.__id = "$ll" + unique++;

			// Import array
			if (array) {

				var length = array.length;
				if (length > 0) {

					var current = array[0];
					var prev, next;

					this.__first = current;
					this.__length = length;

					for (var i=0; i<length; i++) {

						if (current[id]) {
							throw new Error("Duplicated object during import: " + obj);
						}

						next = array[i+1];

						current[id] = [prev, next];

						prev = current;
						current = next;

					}
				}
			}
		},

		members:
		{

			__first: undef,
			__last: undef,
			__length: 0,

			/**
			 * Adds the given object to the list
			 *
			 * Performance behavior: O(1)
			 *
			 * @param obj {Object} Object to add
			 * @return {LinkedList} Returns this object for further operations
			 */
			add: function(obj) {

				var self = this;

				if (obj[self.__id]) {
					throw new Error("Object is already in the list: " + obj);
				}

				var id = self.__id;

				var prev = self.__last;
				if (prev) {

					// append after previous last one
					obj[id] = [prev];
					prev[id][1] = obj;

				} else {

					// insert as the first object
					obj[id] = [];
					self.__first = obj;

				}

				self.__length++;
				self.__last = obj;

				return self;

			},

			/**
			 * Removes the given object from the list
			 *
			 * Performance behavior: O(1)
			 *
			 * @param obj {Object} Object to remove
			 * @return {LinkedList} Returns this object for further operations
			 */
			remove: function(obj) {

				var self = this;

				if (!obj[self.__id]) {
					throw new Error("Object is not in the list: " + obj);
				}

				var id = self.__id;
				var store = obj[id];

				var prev = store[0];
				var next = store[1];

				if (prev && next) {

					// Conntext previous and next child
					prev[1] = next;
					next[0] = prev;

				} else if (prev) {

					// Free previous child from reference to this object
					prev[1] = undef;
					self.__last = prev;

				} else if (next) {

					// We seem to be the first
					// Make following child the first
					next[0] = undef;
					self.__first = next;

				} else {

					self.__first = undef;
					self.__last = undef;

				}

				obj[id] = undef;
				self.__length--;

				return self;

			},

			/**
			 * Whether the list contains the given object
			 *
			 * Performance behavior: O(1)
			 *
			 * @param obj {Object} Object to check for
			 * @return {Boolean} Whether the object is in the list
			 */
			has: function(obj) {
				return !!obj[this.__id];
			},

			/**
			 * Returns the position of the object in the list
			 *
			 * Performance behavior: O(n); in negative cases just O(1)
			 *
			 * @param obj {Object} Object to check for
			 * @return {Integer} The position of the object in the list. `-1` when object was not found.
			 */
			indexOf: function(obj) {

				var self = this;
				var id = self.__id;

				if (!obj[id]) {
					return -1;
				}

				var current = self.__first;
				var pos = 0;

				for(;;) {

					if (current === obj) {
						return pos;
					}

					pos++;
					current = current[id][1];

				}
			},

			/**
			 * Whether the LinkedList is empty
			 *
			 * Performance behavior: O(1)
			 *
			 * @return {Boolean} Whether the list is empty
			 */
			isEmpty: function() {
				return this.__length > 0;
			},

			/**
			 * Returns the length of the list
			 *
			 * Performance behavior: O(1)
			 *
			 * @return {Integer} Length of the list
			 */
			getLength: function() {
				return this.__length;
			},

			/**
			 * Returns an array copy of the list
			 *
			 * Performance behavior: O(n)
			 *
			 * @return {Array} Current list converted to an array
			 */
			toArray: function() {

				var self = this;
				var length = self.__length;
				var array = [];

				var current = self.__first;
				for (var i=0; i<length; i++) {
					array.push(current);
					current = current[id][1];
				}

				return array;

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


<commit_before>import React, { Component } from 'react';
import { mount, shallow } from 'enzyme';
import PluginEditor, { createEditorStateWithText } from '../../index';
import { expect } from 'chai';
import { EditorState } from 'draft-js';
import sinon from 'sinon';

/* For use in integration tests, as in where you need to test the
 * Editor component as well */
class TestEditor extends Component {
  state = { };

  componentWillMount() {
    this.state.editorState = createEditorStateWithText(this.props.text);
  }

  onChange = (editorState) => {
    this.setState({
      editorState,
    });
  };

  render() {
    return (
      <PluginEditor
        {...this.props}
        editorState={ this.state.editorState }
        onChange={ this.onChange }
      />
    );
  }
}

describe('Editor', () => {
  describe('renders the Editor', () => {
    const onChange = sinon.spy();
    let editorState;

    beforeEach(() => {
      editorState = EditorState.createEmpty();
    });

    it('with an empty plugins list provided', () => {
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ [] }
        />
      );
      expect(result).to.have.ref('editor');
    });

    it('without the plugins property provided', () => {
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
        />
      );
      expect(result).to.have.ref('editor');
    });

    it('with a plugin provided', () => {
      const createCustomPlugin = () => ({});
      const customPlugin = createCustomPlugin();
      const plugins = [customPlugin];
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ plugins }
        />
      );
      expect(result).to.have.ref('editor');
    });

    it('and by default adds the defaultKeyBindings plugin', () => {
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
        />
      );
      const pluginEditor = result.instance();
      expect(pluginEditor.resolvePlugins()[0]).to.include.keys('keyBindingFn');
    });

    it('without the defaultKeyBindings plugin if deactivated', () => {
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          defaultKeyBindings={ false }
        />
      );
      const pluginEditor = result.instance();
      expect(pluginEditor.resolvePlugins()).to.have.lengthOf(0);
    });
  });

  describe('with plugins', () => {
    let onChange;
    let editorState;

    beforeEach(() => {
      editorState = EditorState.createEmpty();
      onChange = sinon.spy();
    });

    it('calls the on-hooks of the plugin', () => {
      const plugins = [
        {
          onUpArrow: sinon.spy(),
          onDragEnter: sinon.spy(),
          onEscape: sinon.spy(),
          onTab: sinon.spy(),
          onChange: sinon.spy(),
        },
      ];
      const result = shallow(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ plugins }
        />
      );

      const draftEditor = result.node;
      const plugin = plugins[0];
      draftEditor.props.onUpArrow();
      expect(plugin.onUpArrow).has.been.calledOnce();
      draftEditor.props.onDragEnter();
      expect(plugin.onDragEnter).has.been.calledOnce();
      draftEditor.props.onEscape();
      expect(plugin.onEscape).has.been.calledOnce();
      draftEditor.props.onTab();
      expect(plugin.onTab).has.been.calledOnce();
      draftEditor.props.onChange(editorState);

      // is called twice since componentWillMount injects the decorators and calls onChange again
      expect(plugin.onChange).has.been.calledTwice();
    });

    it('calls the handle-hooks of the plugin', () => {
      const plugins = [
        {
          handleKeyCommand: sinon.spy(),
          handlePastedText: sinon.spy(),
          handleReturn: sinon.spy(),
          handleDrop: sinon.spy(),
        },
      ];
      const result = shallow(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ plugins }
        />
      );

      const pluginEditor = result.instance();
      const draftEditor = result.node;
      const plugin = plugins[0];
      const expectedSecondArgument = {
        getEditorState: pluginEditor.getEditorState,
        setEditorState: pluginEditor.onChange,
      };
      draftEditor.props.handleKeyCommand('command');
      expect(plugin.handleKeyCommand).has.been.calledOnce();
      expect(plugin.handleKeyCommand).has.been.calledWith('command', expectedSecondArgument);
      draftEditor.props.handlePastedText('command');
      expect(plugin.handlePastedText).has.been.calledOnce();
      expect(plugin.handlePastedText).has.been.calledWith('command', expectedSecondArgument);
      draftEditor.props.handleReturn('command');
      expect(plugin.handleReturn).has.been.calledOnce();
      expect(plugin.handleReturn).has.been.calledWith('command', expectedSecondArgument);
      draftEditor.props.handleDrop('command');
      expect(plugin.handleDrop).has.been.calledOnce();
      expect(plugin.handleDrop).has.been.calledWith('command', expectedSecondArgument);
    });

    it('calls the handle- and on-hooks of the first plugin and not the second in case it was handeled', () => {
      const plugins = [
        {
          handleKeyCommand: sinon.stub().returns(true),
          onUpArrow: sinon.stub().returns(true),
        },
        {
          handleKeyCommand: sinon.spy(),
          onUpArrow: sinon.spy(),
        },
      ];
      const result = shallow(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ plugins }
        />
      );

      const draftEditor = result.node;
      draftEditor.props.handleKeyCommand('command');
      expect(plugins[0].handleKeyCommand).has.been.calledOnce();
      expect(plugins[1].handleKeyCommand).has.not.been.called();

      draftEditor.props.onUpArrow();
      expect(plugins[0].onUpArrow).has.been.calledOnce();
      expect(plugins[1].onUpArrow).has.not.been.called();
    });

    it('calls the handle- and on-hooks of all plugins in case none handeles the command', () => {
      const plugins = [
        {
          handleKeyCommand: sinon.spy(),
          onUpArrow: sinon.spy(),
        },
        {
          handleKeyCommand: sinon.spy(),
          onUpArrow: sinon.spy(),
        },
        {
          handleKeyCommand: sinon.spy(),
          onUpArrow: sinon.spy(),
        },
      ];
      const result = shallow(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ plugins }
        />
      );

      const draftEditor = result.node;
      draftEditor.props.handleKeyCommand('command');
      expect(plugins[0].handleKeyCommand).has.been.calledOnce();
      expect(plugins[1].handleKeyCommand).has.been.calledOnce();
      expect(plugins[2].handleKeyCommand).has.been.calledOnce();

      draftEditor.props.onUpArrow();
      expect(plugins[0].onUpArrow).has.been.calledOnce();
      expect(plugins[1].onUpArrow).has.been.calledOnce();
      expect(plugins[2].onUpArrow).has.been.calledOnce();
    });

    it('calls the fn-hooks of the plugin', () => {
      const plugins = [
        {
          blockRendererFn: sinon.spy(),
          keyBindingFn: sinon.spy(),
        },
      ];
      const result = shallow(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ plugins }
        />
      );

      const pluginEditor = result.instance();
      const draftEditor = result.node;
      const plugin = plugins[0];
      const expectedSecondArgument = {
        getEditorState: pluginEditor.getEditorState,
        setEditorState: pluginEditor.onChange,
      };
      draftEditor.props.blockRendererFn('command');
      expect(plugin.blockRendererFn).has.been.calledOnce();
      expect(plugin.blockRendererFn).has.been.calledWith('command', expectedSecondArgument);
      draftEditor.props.keyBindingFn('command');
      expect(plugin.keyBindingFn).has.been.calledOnce();
      expect(plugin.keyBindingFn).has.been.calledWith('command', expectedSecondArgument);
    });

    it('combines the customStyleMaps from all plugins', () => {
      const plugins = [
        {
          customStyleMap: {
            orange: {
              color: 'rgba(255, 127, 0, 1.0)',
            },
          },
        },
        {
          customStyleMap: {
            yellow: {
              color: 'rgba(180, 180, 0, 1.0)',
            },
          },
        },
      ];
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ plugins }
        />
      );
      const expected = {
        orange: {
          color: 'rgba(255, 127, 0, 1.0)',
        },
        yellow: {
          color: 'rgba(180, 180, 0, 1.0)',
        },
      };
      const pluginEditor = result.instance();
      expect(pluginEditor.resolveCustomStyleMap()).to.deep.equal(expected);
    });

    it('combines customStyleMap props from plugins and the editor', () => {
      const plugins = [
        {
          customStyleMap: {
            orange: {
              color: 'rgba(255, 127, 0, 1.0)',
            },
          },
        },
        {
          customStyleMap: {
            yellow: {
              color: 'rgba(180, 180, 0, 1.0)',
            },
          },
        },
      ];

      const customStyleMap = {
        blue: {
          color: 'blue',
        },
      };

      const result = mount(
        <PluginEditor
          editorState={ editorState }
          customStyleMap={ customStyleMap }
          onChange={ onChange }
          plugins={ plugins }
        />
      );

      const expected = {
        orange: {
          color: 'rgba(255, 127, 0, 1.0)',
        },
        yellow: {
          color: 'rgba(180, 180, 0, 1.0)',
        },
        blue: {
          color: 'blue',
        },
      };
      const pluginEditor = result.instance();
      expect(pluginEditor.resolveCustomStyleMap()).to.deep.equal(expected);
    });
  });

  describe('passed proxy to DraftEditor', () => {
    let draftEditor;
    let pluginEditor;

    beforeEach(() => {
      const onChange = sinon.spy();
      const editorState = EditorState.createEmpty();
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ [] }
        />
      );
      draftEditor = result.node;
      pluginEditor = result.instance();
    });

    it('focus', () => {
      draftEditor.focus = sinon.spy();
      pluginEditor.focus();
      expect(draftEditor.focus).has.been.calledOnce();
    });

    it('blur', () => {
      draftEditor.blur = sinon.spy();
      pluginEditor.blur();
      expect(draftEditor.blur).has.been.calledOnce();
    });
  });

  describe('custom prop overwrites plugin hook', () => {
    const onChange = sinon.spy();
    let editorState;
    let customHook;

    beforeEach(() => {
      editorState = EditorState.createEmpty();
      customHook = sinon.spy();
    });

    it('onUpArrow', () => {
      const plugin = {
        onUpArrow: sinon.spy(),
      };
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ [plugin] }
          onUpArrow={ customHook }
        />
      );
      const draftEditor = result.node;
      draftEditor.props.onUpArrow();
      expect(plugin.onUpArrow).has.not.been.called();
      expect(customHook).has.been.calledOnce();
    });

    it('renders block component using blockRenderFn prop', () => {
      const plugin = {
        blockRendererFn: sinon.spy(),
      };
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ [plugin] }
          blockRendererFn={ customHook }
        />
      );
      const draftEditor = result.node;
      draftEditor.props.blockRendererFn();
      expect(plugin.blockRendererFn).has.been.called();
      expect(customHook).has.been.called();
    });

    it('renders block component using blockRenderFn prop and decorators', () => {
      const decorator = (Comp) => (props) =>
<Comp {...props} />
;
      const component = () => null;

      const plugin = {
        blockRendererFn: () => ({
          decorators: [decorator],
          props: { pluginProp: true },
        }),
      };

      customHook = () => ({
        component,
        props: { editorProp: true },
      });

      const wrapper = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ [plugin] }
          blockRendererFn={ customHook }
        />
      );

      const decorators = wrapper.findWhere(n => n.hasClass('decorator'));
      expect(decorators.length).to.equal(1);
      expect(wrapper.find(component).length).to.equal(1);
    });
  });

  describe('decorators prop', () => {
    let text;
    let decorator;
    let plugin;
    let plugins;
    let decorators;

    before(() => {
      text = "Hello there how's it going fella";

      decorator = {
        strategy: (block, cb) => cb(1, 3),
        component: () => ,
      };

      plugin = {
        decorators: [
          {
            strategy: (block, cb) => cb(4, 7),
            component: () => ,
          },
        ],
      };

      plugins = [plugin];
      decorators = [decorator];
    });

    it('uses strategies from both decorators and plugins together', () => {
      const pluginStrategy = sinon.spy(plugin.decorators[0], 'strategy');
      const decoratorStrategy = sinon.spy(decorator, 'strategy');

      mount(<TestEditor { ...{ plugins, decorators, text } } />);

      expect(decoratorStrategy).has.been.called();
      expect(pluginStrategy).has.been.called();
    });

    it('uses components from both decorators and plugins together', () => {
      const pluginComponent = sinon.spy(plugin.decorators[0], 'component');
      const decoratorComponent = sinon.spy(decorator, 'component');

      const wrapper = mount(<TestEditor { ...{ plugins, decorators, text } } />);
      const decoratorComponents = wrapper.findWhere(n => n.hasClass('decorator'));
      const pluginComponents = wrapper.findWhere(n => n.hasClass('plugin'));

      expect(decoratorComponent).has.been.called();
      expect(pluginComponent).has.been.called();
      expect(decoratorComponents.length).to.equal(1);
      expect(pluginComponents.length).to.equal(1);
    });
  });
});
<commit_msg>fix test description<commit_after>import React, { Component } from 'react';
import { mount, shallow } from 'enzyme';
import PluginEditor, { createEditorStateWithText } from '../../index';
import { expect } from 'chai';
import { EditorState } from 'draft-js';
import sinon from 'sinon';

/* For use in integration tests, as in where you need to test the
 * Editor component as well */
class TestEditor extends Component {
  state = { };

  componentWillMount() {
    this.state.editorState = createEditorStateWithText(this.props.text);
  }

  onChange = (editorState) => {
    this.setState({
      editorState,
    });
  };

  render() {
    return (
      <PluginEditor
        {...this.props}
        editorState={ this.state.editorState }
        onChange={ this.onChange }
      />
    );
  }
}

describe('Editor', () => {
  describe('renders the Editor', () => {
    const onChange = sinon.spy();
    let editorState;

    beforeEach(() => {
      editorState = EditorState.createEmpty();
    });

    it('with an empty plugins list provided', () => {
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ [] }
        />
      );
      expect(result).to.have.ref('editor');
    });

    it('without the plugins property provided', () => {
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
        />
      );
      expect(result).to.have.ref('editor');
    });

    it('with a plugin provided', () => {
      const createCustomPlugin = () => ({});
      const customPlugin = createCustomPlugin();
      const plugins = [customPlugin];
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ plugins }
        />
      );
      expect(result).to.have.ref('editor');
    });

    it('and by default adds the defaultKeyBindings plugin', () => {
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
        />
      );
      const pluginEditor = result.instance();
      expect(pluginEditor.resolvePlugins()[0]).to.include.keys('keyBindingFn');
    });

    it('without the defaultKeyBindings plugin if deactivated', () => {
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          defaultKeyBindings={ false }
        />
      );
      const pluginEditor = result.instance();
      expect(pluginEditor.resolvePlugins()).to.have.lengthOf(0);
    });
  });

  describe('with plugins', () => {
    let onChange;
    let editorState;

    beforeEach(() => {
      editorState = EditorState.createEmpty();
      onChange = sinon.spy();
    });

    it('calls the on-hooks of the plugin', () => {
      const plugins = [
        {
          onUpArrow: sinon.spy(),
          onDragEnter: sinon.spy(),
          onEscape: sinon.spy(),
          onTab: sinon.spy(),
          onChange: sinon.spy(),
        },
      ];
      const result = shallow(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ plugins }
        />
      );

      const draftEditor = result.node;
      const plugin = plugins[0];
      draftEditor.props.onUpArrow();
      expect(plugin.onUpArrow).has.been.calledOnce();
      draftEditor.props.onDragEnter();
      expect(plugin.onDragEnter).has.been.calledOnce();
      draftEditor.props.onEscape();
      expect(plugin.onEscape).has.been.calledOnce();
      draftEditor.props.onTab();
      expect(plugin.onTab).has.been.calledOnce();
      draftEditor.props.onChange(editorState);

      // is called twice since componentWillMount injects the decorators and calls onChange again
      expect(plugin.onChange).has.been.calledTwice();
    });

    it('calls the handle-hooks of the plugin', () => {
      const plugins = [
        {
          handleKeyCommand: sinon.spy(),
          handlePastedText: sinon.spy(),
          handleReturn: sinon.spy(),
          handleDrop: sinon.spy(),
        },
      ];
      const result = shallow(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ plugins }
        />
      );

      const pluginEditor = result.instance();
      const draftEditor = result.node;
      const plugin = plugins[0];
      const expectedSecondArgument = {
        getEditorState: pluginEditor.getEditorState,
        setEditorState: pluginEditor.onChange,
      };
      draftEditor.props.handleKeyCommand('command');
      expect(plugin.handleKeyCommand).has.been.calledOnce();
      expect(plugin.handleKeyCommand).has.been.calledWith('command', expectedSecondArgument);
      draftEditor.props.handlePastedText('command');
      expect(plugin.handlePastedText).has.been.calledOnce();
      expect(plugin.handlePastedText).has.been.calledWith('command', expectedSecondArgument);
      draftEditor.props.handleReturn('command');
      expect(plugin.handleReturn).has.been.calledOnce();
      expect(plugin.handleReturn).has.been.calledWith('command', expectedSecondArgument);
      draftEditor.props.handleDrop('command');
      expect(plugin.handleDrop).has.been.calledOnce();
      expect(plugin.handleDrop).has.been.calledWith('command', expectedSecondArgument);
    });

    it('calls the handle- and on-hooks of the first plugin and not the second in case it was handeled', () => {
      const plugins = [
        {
          handleKeyCommand: sinon.stub().returns(true),
          onUpArrow: sinon.stub().returns(true),
        },
        {
          handleKeyCommand: sinon.spy(),
          onUpArrow: sinon.spy(),
        },
      ];
      const result = shallow(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ plugins }
        />
      );

      const draftEditor = result.node;
      draftEditor.props.handleKeyCommand('command');
      expect(plugins[0].handleKeyCommand).has.been.calledOnce();
      expect(plugins[1].handleKeyCommand).has.not.been.called();

      draftEditor.props.onUpArrow();
      expect(plugins[0].onUpArrow).has.been.calledOnce();
      expect(plugins[1].onUpArrow).has.not.been.called();
    });

    it('calls the handle- and on-hooks of all plugins in case none handeles the command', () => {
      const plugins = [
        {
          handleKeyCommand: sinon.spy(),
          onUpArrow: sinon.spy(),
        },
        {
          handleKeyCommand: sinon.spy(),
          onUpArrow: sinon.spy(),
        },
        {
          handleKeyCommand: sinon.spy(),
          onUpArrow: sinon.spy(),
        },
      ];
      const result = shallow(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ plugins }
        />
      );

      const draftEditor = result.node;
      draftEditor.props.handleKeyCommand('command');
      expect(plugins[0].handleKeyCommand).has.been.calledOnce();
      expect(plugins[1].handleKeyCommand).has.been.calledOnce();
      expect(plugins[2].handleKeyCommand).has.been.calledOnce();

      draftEditor.props.onUpArrow();
      expect(plugins[0].onUpArrow).has.been.calledOnce();
      expect(plugins[1].onUpArrow).has.been.calledOnce();
      expect(plugins[2].onUpArrow).has.been.calledOnce();
    });

    it('calls the fn-hooks of the plugin', () => {
      const plugins = [
        {
          blockRendererFn: sinon.spy(),
          keyBindingFn: sinon.spy(),
        },
      ];
      const result = shallow(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ plugins }
        />
      );

      const pluginEditor = result.instance();
      const draftEditor = result.node;
      const plugin = plugins[0];
      const expectedSecondArgument = {
        getEditorState: pluginEditor.getEditorState,
        setEditorState: pluginEditor.onChange,
      };
      draftEditor.props.blockRendererFn('command');
      expect(plugin.blockRendererFn).has.been.calledOnce();
      expect(plugin.blockRendererFn).has.been.calledWith('command', expectedSecondArgument);
      draftEditor.props.keyBindingFn('command');
      expect(plugin.keyBindingFn).has.been.calledOnce();
      expect(plugin.keyBindingFn).has.been.calledWith('command', expectedSecondArgument);
    });

    it('combines the customStyleMaps from all plugins', () => {
      const plugins = [
        {
          customStyleMap: {
            orange: {
              color: 'rgba(255, 127, 0, 1.0)',
            },
          },
        },
        {
          customStyleMap: {
            yellow: {
              color: 'rgba(180, 180, 0, 1.0)',
            },
          },
        },
      ];
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ plugins }
        />
      );
      const expected = {
        orange: {
          color: 'rgba(255, 127, 0, 1.0)',
        },
        yellow: {
          color: 'rgba(180, 180, 0, 1.0)',
        },
      };
      const pluginEditor = result.instance();
      expect(pluginEditor.resolveCustomStyleMap()).to.deep.equal(expected);
    });

    it('combines customStyleMap props from plugins and the editor', () => {
      const plugins = [
        {
          customStyleMap: {
            orange: {
              color: 'rgba(255, 127, 0, 1.0)',
            },
          },
        },
        {
          customStyleMap: {
            yellow: {
              color: 'rgba(180, 180, 0, 1.0)',
            },
          },
        },
      ];

      const customStyleMap = {
        blue: {
          color: 'blue',
        },
      };

      const result = mount(
        <PluginEditor
          editorState={ editorState }
          customStyleMap={ customStyleMap }
          onChange={ onChange }
          plugins={ plugins }
        />
      );

      const expected = {
        orange: {
          color: 'rgba(255, 127, 0, 1.0)',
        },
        yellow: {
          color: 'rgba(180, 180, 0, 1.0)',
        },
        blue: {
          color: 'blue',
        },
      };
      const pluginEditor = result.instance();
      expect(pluginEditor.resolveCustomStyleMap()).to.deep.equal(expected);
    });
  });

  describe('passed proxy to DraftEditor', () => {
    let draftEditor;
    let pluginEditor;

    beforeEach(() => {
      const onChange = sinon.spy();
      const editorState = EditorState.createEmpty();
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ [] }
        />
      );
      draftEditor = result.node;
      pluginEditor = result.instance();
    });

    it('focus', () => {
      draftEditor.focus = sinon.spy();
      pluginEditor.focus();
      expect(draftEditor.focus).has.been.calledOnce();
    });

    it('blur', () => {
      draftEditor.blur = sinon.spy();
      pluginEditor.blur();
      expect(draftEditor.blur).has.been.calledOnce();
    });
  });

  describe('custom prop comes before plugin hook', () => {
    const onChange = sinon.spy();
    let editorState;
    let customHook;

    beforeEach(() => {
      editorState = EditorState.createEmpty();
      customHook = sinon.spy();
    });

    it('onUpArrow', () => {
      const plugin = {
        onUpArrow: sinon.spy(),
      };
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ [plugin] }
          onUpArrow={ customHook }
        />
      );
      const draftEditor = result.node;
      draftEditor.props.onUpArrow();
      expect(plugin.onUpArrow).has.not.been.called();
      expect(customHook).has.been.calledOnce();
    });

    it('renders block component using blockRenderFn prop', () => {
      const plugin = {
        blockRendererFn: sinon.spy(),
      };
      const result = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ [plugin] }
          blockRendererFn={ customHook }
        />
      );
      const draftEditor = result.node;
      draftEditor.props.blockRendererFn();
      expect(plugin.blockRendererFn).has.been.called();
      expect(customHook).has.been.called();
    });

    it('renders block component using blockRenderFn prop and decorators', () => {
      const decorator = (Comp) => (props) =>
<Comp {...props} />
;
      const component = () => null;

      const plugin = {
        blockRendererFn: () => ({
          decorators: [decorator],
          props: { pluginProp: true },
        }),
      };

      customHook = () => ({
        component,
        props: { editorProp: true },
      });

      const wrapper = mount(
        <PluginEditor
          editorState={ editorState }
          onChange={ onChange }
          plugins={ [plugin] }
          blockRendererFn={ customHook }
        />
      );

      const decorators = wrapper.findWhere(n => n.hasClass('decorator'));
      expect(decorators.length).to.equal(1);
      expect(wrapper.find(component).length).to.equal(1);
    });
  });

  describe('decorators prop', () => {
    let text;
    let decorator;
    let plugin;
    let plugins;
    let decorators;

    before(() => {
      text = "Hello there how's it going fella";

      decorator = {
        strategy: (block, cb) => cb(1, 3),
        component: () => ,
      };

      plugin = {
        decorators: [
          {
            strategy: (block, cb) => cb(4, 7),
            component: () => ,
          },
        ],
      };

      plugins = [plugin];
      decorators = [decorator];
    });

    it('uses strategies from both decorators and plugins together', () => {
      const pluginStrategy = sinon.spy(plugin.decorators[0], 'strategy');
      const decoratorStrategy = sinon.spy(decorator, 'strategy');

      mount(<TestEditor { ...{ plugins, decorators, text } } />);

      expect(decoratorStrategy).has.been.called();
      expect(pluginStrategy).has.been.called();
    });

    it('uses components from both decorators and plugins together', () => {
      const pluginComponent = sinon.spy(plugin.decorators[0], 'component');
      const decoratorComponent = sinon.spy(decorator, 'component');

      const wrapper = mount(<TestEditor { ...{ plugins, decorators, text } } />);
      const decoratorComponents = wrapper.findWhere(n => n.hasClass('decorator'));
      const pluginComponents = wrapper.findWhere(n => n.hasClass('plugin'));

      expect(decoratorComponent).has.been.called();
      expect(pluginComponent).has.been.called();
      expect(decoratorComponents.length).to.equal(1);
      expect(pluginComponents.length).to.equal(1);
    });
  });
});
<|endoftext|>


<commit_before>/* eslint-env mocha */
const assert = require('assert')
const {
  CucumberExpression,
  ParameterTypeRegistry,
  ParameterType,
} = require('../src/index')

describe('CucumberExpression', () => {
  it('documents match arguments', () => {
    const parameterTypeRegistry = new ParameterTypeRegistry()

    /// [capture-match-arguments]
    const expr = 'I have {int} cuke(s)'
    const expression = new CucumberExpression(expr, parameterTypeRegistry)
    const args = expression.match('I have 7 cukes')
    assert.equal(7, args[0].getValue(null))
    /// [capture-match-arguments]
  })

  it('matches word', () => {
    assert.deepEqual(match('three {word} mice', 'three blind mice'), ['blind'])
  })

  it('matches double quoted string', () => {
    assert.deepEqual(match('three {string} mice', 'three "blind" mice'), [
      'blind',
    ])
  })

  it('matches single quoted string', () => {
    assert.deepEqual(match('three {string} mice', "three 'blind' mice"), [
      'blind',
    ])
  })

  it('does not match misquoted string', () => {
    assert.deepEqual(match('three {string} mice', 'three "blind\' mice'), null)
  })

  it('matches single quoted string with double quotes', () => {
    assert.deepEqual(match('three {string} mice', 'three \'"blind"\' mice'), [
      '"blind"',
    ])
  })

  it('matches double quoted string with single quotes', () => {
    assert.deepEqual(match('three {string} mice', 'three "\'blind\'" mice'), [
      "'blind'",
    ])
  })

  it('matches double quoted string with escaped double quote', () => {
    assert.deepEqual(match('three {string} mice', 'three "bl\\"nd" mice'), [
      'bl"nd',
    ])
  })

  it('matches single quoted string with escaped single quote', () => {
    assert.deepEqual(match('three {string} mice', "three 'bl\\'nd' mice"), [
      "bl'nd",
    ])
  })

  it('matches int', () => {
    assert.deepEqual(match('{int}', '22'), [22])
  })

  it("doesn't match float as int", () => {
    assert.deepEqual(match('{int}', '1.22'), null)
  })

  it('matches float', () => {
    assert.deepEqual(match('{float}', '0.22'), [0.22])
    assert.deepEqual(match('{float}', '.22'), [0.22])
  })

  it('throws unknown parameter type', () => {
    try {
      match('{unknown}', 'something')
      assert.fail()
    } catch (expected) {
      assert.equal(expected.message, 'Undefined parameter type {unknown}')
    }
  })

  it('exposes source', () => {
    const expr = 'I have {int} cuke(s)'
    assert.equal(
      new CucumberExpression(expr, new ParameterTypeRegistry()).source,
      expr
    )
  })

  it('delegates transform to custom object', () => {
    const parameterTypeRegistry = new ParameterTypeRegistry()
    parameterTypeRegistry.defineParameterType(
      new ParameterType(
        'widget',
        /\w+/,
        null,
        function(s) {
          return this.createWidget(s)
        },
        false,
        true
      )
    )
    const expression = new CucumberExpression(
      'I have a {widget}',
      parameterTypeRegistry
    )

    const world = {
      createWidget(s) {
        return `widget:${s}`
      },
    }

    const args = expression.match(`I have a bolt`)
    assert.equal(args[0].getValue(world), 'widget:bolt')
  })

  describe('escapes special characters', () => {
    ;['\\', '[', ']', '^', '$', '.', '|', '?', '*', '+'].forEach(character => {
      it(`escapes ${character}`, () => {
        const expr = `I have {int} cuke(s) and ${character}`
        const expression = new CucumberExpression(
          expr,
          new ParameterTypeRegistry()
        )
        const arg1 = expression.match(`I have 800 cukes and ${character}`)[0]
        assert.equal(arg1.getValue(null), 800)
      })
    })

    it(`escapes .`, () => {
      const expr = `I have {int} cuke(s) and .`
      const expression = new CucumberExpression(
        expr,
        new ParameterTypeRegistry()
      )
      assert.equal(expression.match(`I have 800 cukes and 3`), null)
      const arg1 = expression.match(`I have 800 cukes and .`)[0]
      assert.equal(arg1.getValue(null), 800)
    })

    it(`escapes |`, () => {
      const expr = `I have {int} cuke(s) and a|b`
      const expression = new CucumberExpression(
        expr,
        new ParameterTypeRegistry()
      )
      assert.equal(expression.match(`I have 800 cukes and a`), null)
      assert.equal(expression.match(`I have 800 cukes and b`), null)
      const arg1 = expression.match(`I have 800 cukes and a|b`)[0]
      assert.equal(arg1.getValue(null), 800)
    })
  })
})

const match = (expression, text) => {
  const cucumberExpression = new CucumberExpression(
    expression,
    new ParameterTypeRegistry()
  )
  const args = cucumberExpression.match(text)
  if (!args) return null
  return args.map(arg => arg.getValue(null))
}
<commit_msg>cucumber-expressions: javascript: add missing tests<commit_after>/* eslint-env mocha */
const assert = require('assert')
const {
  CucumberExpression,
  ParameterTypeRegistry,
  ParameterType,
} = require('../src/index')

describe('CucumberExpression', () => {
  it('documents match arguments', () => {
    const parameterTypeRegistry = new ParameterTypeRegistry()

    /// [capture-match-arguments]
    const expr = 'I have {int} cuke(s)'
    const expression = new CucumberExpression(expr, parameterTypeRegistry)
    const args = expression.match('I have 7 cukes')
    assert.equal(7, args[0].getValue(null))
    /// [capture-match-arguments]
  })

  it('matches word', () => {
    assert.deepEqual(match('three {word} mice', 'three blind mice'), ['blind'])
  })

  it('matches double quoted string', () => {
    assert.deepEqual(match('three {string} mice', 'three "blind" mice'), [
      'blind',
    ])
  })

  it('matches multiple double quoted strings', () => {
    assert.deepEqual(
      match(
        'three {string} and {string} mice',
        'three "blind" and "crippled" mice'
      ),
      ['blind', 'crippled']
    )
  })

  it('matches single quoted string', () => {
    assert.deepEqual(match('three {string} mice', "three 'blind' mice"), [
      'blind',
    ])
  })

  it('matches multiple single quoted strings', () => {
    assert.deepEqual(
      match(
        'three {string} and {string} mice',
        "three 'blind' and 'crippled' mice"
      ),
      ['blind', 'crippled']
    )
  })

  it('does not match misquoted string', () => {
    assert.deepEqual(match('three {string} mice', 'three "blind\' mice'), null)
  })

  it('matches single quoted string with double quotes', () => {
    assert.deepEqual(match('three {string} mice', 'three \'"blind"\' mice'), [
      '"blind"',
    ])
  })

  it('matches double quoted string with single quotes', () => {
    assert.deepEqual(match('three {string} mice', 'three "\'blind\'" mice'), [
      "'blind'",
    ])
  })

  it('matches double quoted string with escaped double quote', () => {
    assert.deepEqual(match('three {string} mice', 'three "bl\\"nd" mice'), [
      'bl"nd',
    ])
  })

  it('matches single quoted string with escaped single quote', () => {
    assert.deepEqual(match('three {string} mice', "three 'bl\\'nd' mice"), [
      "bl'nd",
    ])
  })

  it('matches int', () => {
    assert.deepEqual(match('{int}', '22'), [22])
  })

  it("doesn't match float as int", () => {
    assert.deepEqual(match('{int}', '1.22'), null)
  })

  it('matches float', () => {
    assert.deepEqual(match('{float}', '0.22'), [0.22])
    assert.deepEqual(match('{float}', '.22'), [0.22])
  })

  it('throws unknown parameter type', () => {
    try {
      match('{unknown}', 'something')
      assert.fail()
    } catch (expected) {
      assert.equal(expected.message, 'Undefined parameter type {unknown}')
    }
  })

  it('exposes source', () => {
    const expr = 'I have {int} cuke(s)'
    assert.equal(
      new CucumberExpression(expr, new ParameterTypeRegistry()).source,
      expr
    )
  })

  it('delegates transform to custom object', () => {
    const parameterTypeRegistry = new ParameterTypeRegistry()
    parameterTypeRegistry.defineParameterType(
      new ParameterType(
        'widget',
        /\w+/,
        null,
        function(s) {
          return this.createWidget(s)
        },
        false,
        true
      )
    )
    const expression = new CucumberExpression(
      'I have a {widget}',
      parameterTypeRegistry
    )

    const world = {
      createWidget(s) {
        return `widget:${s}`
      },
    }

    const args = expression.match(`I have a bolt`)
    assert.equal(args[0].getValue(world), 'widget:bolt')
  })

  describe('escapes special characters', () => {
    ;['\\', '[', ']', '^', '$', '.', '|', '?', '*', '+'].forEach(character => {
      it(`escapes ${character}`, () => {
        const expr = `I have {int} cuke(s) and ${character}`
        const expression = new CucumberExpression(
          expr,
          new ParameterTypeRegistry()
        )
        const arg1 = expression.match(`I have 800 cukes and ${character}`)[0]
        assert.equal(arg1.getValue(null), 800)
      })
    })

    it(`escapes .`, () => {
      const expr = `I have {int} cuke(s) and .`
      const expression = new CucumberExpression(
        expr,
        new ParameterTypeRegistry()
      )
      assert.equal(expression.match(`I have 800 cukes and 3`), null)
      const arg1 = expression.match(`I have 800 cukes and .`)[0]
      assert.equal(arg1.getValue(null), 800)
    })

    it(`escapes |`, () => {
      const expr = `I have {int} cuke(s) and a|b`
      const expression = new CucumberExpression(
        expr,
        new ParameterTypeRegistry()
      )
      assert.equal(expression.match(`I have 800 cukes and a`), null)
      assert.equal(expression.match(`I have 800 cukes and b`), null)
      const arg1 = expression.match(`I have 800 cukes and a|b`)[0]
      assert.equal(arg1.getValue(null), 800)
    })
  })
})

const match = (expression, text) => {
  const cucumberExpression = new CucumberExpression(
    expression,
    new ParameterTypeRegistry()
  )
  const args = cucumberExpression.match(text)
  if (!args) return null
  return args.map(arg => arg.getValue(null))
}
<|endoftext|>


<commit_before>describe("<application module specs>", function () {

    it("Test appBundleFolder property", function () {
        expect(Rho.Application.appBundleFolder).isNotEmptyString();
    });

    it("Test appsBundleFolder proeprty", function () {
        expect(Rho.Application.appsBundleFolder).isNotEmptyString();
    });

    it("Test userFolder property", function () {
        expect(Rho.Application.userFolder).isNotEmptyString();
    });

    xit("Test configPath property", function () {
        expect(Rho.Application.configPath).isNotEmptyString();
    });

    it("Test modelsManifestPath property", function () {
        expect(Rho.Application.modelsManifestPath).isNotEmptyString(0);
    });

    it("Test databaseBlobFolder property", function () {
        expect(Rho.Application.databaseBlobFolder).isNotEmptyString(0);
    });

    it("Test publicFolder property", function () {
        expect(Rho.Application.publicFolder).isNotEmptyString();
    });

    it("Test startURI property", function () {
        Rho.Application.startURI = 'index.html';
        expect(Rho.Application.startURI).toEqual('index.html');
    });

    it("Test settingsPageURI property", function () {
        Rho.Application.settingsPageURI = 'settings.html';
        expect(Rho.Application.settingsPageURI).toEqual('settings.html');
    });

    it("Test splash property", function () {
        expect(Rho.Application.splash).isNotEmptyString();
    });

    it("Test version property", function () {
        expect(Rho.Application.version).isNotEmptyString();
    });

    it("Test name property", function () {
        expect(Rho.Application.getName()).isNotEmptyString();
    });

    //TODO: Implement Localization for Javascript app
    //it("Current application locale.Like 'en', 'ru' etc", function(){
    //	expect(Rho.Application.getLocale()).isNotEmptyString();
    //});

    //TODO: Implement Country for Javascript app
    //it("Current application country code", function(){
    //	expect(Rho.Application.getCountry()).isNotEmptyString();
    //});

    //TODO: implement modelFolderPath method

    //TODO: implement databaseFilePath method

    //TODO: implement expandDatabaseBlobFilePath method

    //TODO: implement quit method

    //TODO: implement modelFolderPath method

    it("Test minimize method", function () {
        expect(Rho.Application.minimize).not.toThrow();
    });

    it("Test restore method", function () {
        expect(Rho.Application.restore).not.toThrow();
    });

    //TODO: implement spec for setActivationNotify with callback

    //TODO: implement spec for getRhoPlatformVersion with callback

    if(isWindowsMobileOrAndroidPlatform()){
        it("Bad link URI to navigate in browser", function () {
            Rho.Application.badLinkURI = 'badLink.html';
            expect(Rho.Application.badLinkURI).toEqual('badLink.html');
        });
    }

    if (['WINDOWS_DESKTOP', 'WINDOWS'].indexOf(Rho.System.platform) != -1) {

        it("Test title property", function () {
            expect(Rho.Application.title()).isNotEmptyString();

            Rho.Application.title = 'Title';
            expect(Rho.Application.title).toEqual('Title');
        });

    }

});<commit_msg>application spec add notification tests<commit_after>var appEventsTest = {};

appEventsTest.ajax = function(url)
{
	var ajax = new XMLHttpRequest();
	//ajax.onreadystatechange = function () {} //Async call
	ajax.open("GET", url, false); //Sync Call
	ajax.send();
	return ajax.responseText;
};

appEventsTest.eventCallback = function(event,eventData)
{
	appEventsTest.lastEvent = event;
    appEventsTest.lastEventData = eventData;
	appEventsTest.eventList.push(event);
	appEventsTest.callbackFired = true;
};

appEventsTest.setCallback = function ()
{
	appEventsTest.ajax('/app/AppEventsTest/set_callback');
};

describe("<application module specs>", function () {

    it("Test appBundleFolder property", function () {
        expect(Rho.Application.appBundleFolder).isNotEmptyString();
    });

    it("Test appsBundleFolder proeprty", function () {
        expect(Rho.Application.appsBundleFolder).isNotEmptyString();
    });

    it("Test userFolder property", function () {
        expect(Rho.Application.userFolder).isNotEmptyString();
    });

    xit("Test configPath property", function () {
        expect(Rho.Application.configPath).isNotEmptyString();
    });

    it("Test modelsManifestPath property", function () {
        expect(Rho.Application.modelsManifestPath).isNotEmptyString(0);
    });

    it("Test databaseBlobFolder property", function () {
        expect(Rho.Application.databaseBlobFolder).isNotEmptyString(0);
    });

    it("Test publicFolder property", function () {
        expect(Rho.Application.publicFolder).isNotEmptyString();
    });

    it("Test startURI property", function () {
        Rho.Application.startURI = 'index.html';
        expect(Rho.Application.startURI).toEqual('index.html');
    });

    it("Test settingsPageURI property", function () {
        Rho.Application.settingsPageURI = 'settings.html';
        expect(Rho.Application.settingsPageURI).toEqual('settings.html');
    });

    it("Test splash property", function () {
        expect(Rho.Application.splash).isNotEmptyString();
    });

    it("Test version property", function () {
        expect(Rho.Application.version).isNotEmptyString();
    });

    it("Test name property", function () {
        expect(Rho.Application.getName()).isNotEmptyString();
    });

    //TODO: Implement Localization for Javascript app
    //it("Current application locale.Like 'en', 'ru' etc", function(){
    //	expect(Rho.Application.getLocale()).isNotEmptyString();
    //});

    //TODO: Implement Country for Javascript app
    //it("Current application country code", function(){
    //	expect(Rho.Application.getCountry()).isNotEmptyString();
    //});

    //TODO: implement modelFolderPath method

    //TODO: implement databaseFilePath method

    //TODO: implement expandDatabaseBlobFilePath method

    //TODO: implement quit method

    //TODO: implement modelFolderPath method

    it("Test minimize method", function () {
        expect(Rho.Application.minimize).not.toThrow();
    });

    it("Test restore method", function () {
        expect(Rho.Application.restore).not.toThrow();
    });

    //TODO: implement spec for setActivationNotify with callback on all platforms

    //TODO: implement spec for getRhoPlatformVersion with callback

    if(isWindowsMobileOrAndroidPlatform()){
        it("Bad link URI to navigate in browser", function () {
            Rho.Application.badLinkURI = 'badLink.html';
            expect(Rho.Application.badLinkURI).toEqual('badLink.html');
        });
    }

    if (['WINDOWS_DESKTOP', 'WINDOWS'].indexOf(Rho.System.platform) != -1) {

        it("Test title property", function () {
            expect(Rho.Application.title()).isNotEmptyString();

            Rho.Application.title = 'Title';
            expect(Rho.Application.title).toEqual('Title');
        });

    }

});

describe('<application module events specs>', function() {
    if (isApplePlatform()) {
        beforeEach(function() {
            Rho.AppEvents.simulateEvent(Rho.AppEvents.APP_EVENT_ACTIVATED);
            Rho.AppEvents.simulateEvent(Rho.AppEvents.APP_EVENT_UICREATED);
            appEventsTest.callbackFired = false;
            appEventsTest.lastEvent = "";
            appEventsTest.lastEventData = {};
            appEventsTest.eventList = [];
        });

        it('Should fire callback', function(){
            runs(function ()
            {
                appEventsTest.setCallback();
                // state is "activated" should be changed
                Rho.AppEvents.simulateEvent(Rho.AppEvents.APP_EVENT_DEACTIVATED);
            });

            waitsFor(function ()
            {
                return appEventsTest.callbackFired;
            }, "the callback didnt fire", 750);

            runs(function ()
            {
                expect(appEventsTest.lastEvent).toEqual(Rho.AppEvents.APP_EVENT_DEACTIVATED);
            });
        });

        it('Should fire callback not once', function(){
            events = [
                Rho.AppEvents.APP_EVENT_DEACTIVATED,
                Rho.AppEvents.APP_EVENT_UIDESTROYED,
                Rho.AppEvents.APP_EVENT_UICREATED,
                Rho.AppEvents.APP_EVENT_ACTIVATED
            ];

            runs(function ()
            {
                appEventsTest.setCallback();
                for(var i = 0; i < events.length; i++)
                {
                    Rho.AppEvents.simulateEvent(events[i]);
                }
            });

            waitsFor(function ()
            {
                return appEventsTest.eventList.length == events.length;
            }, "the callback didnt fire", 750);

            runs(function ()
            {
                expect(appEventsTest.eventList).toEqual(events);
            });
        });

        it('Should not duplicate callbacks', function(){
            events = [
                Rho.AppEvents.APP_EVENT_DEACTIVATED,
                Rho.AppEvents.APP_EVENT_UIDESTROYED,
                Rho.AppEvents.APP_EVENT_ACTIVATED,
                Rho.AppEvents.APP_EVENT_UICREATED
            ];

            runs(function ()
            {
                appEventsTest.setCallback();
                for(var i = 0; i < events.length; i++)
                {
                    Rho.AppEvents.simulateEvent(events[i]);
                    Rho.AppEvents.simulateEvent(events[i]);
                }
            });

            waitsFor(function ()
            {
                return appEventsTest.eventList.length == events.length;
            }, "the callback didnt fire", 750);

            runs(function ()
            {
                expect(appEventsTest.eventList).toEqual(events);
            });
        });

        it('Should handle conflicts', function(){
            template = {
              "intProp" : ['128', '42'],
              "stringProp" : ["ohr","abc"]
            };

            runs(function ()
            {
                appEventsTest.setCallback();
                Rho.AppEvents.addConflictInt("intProp",64,128);
                Rho.AppEvents.addConflictString("stringProp","rho","ohr");
                Rho.AppEvents.simulateConflicts();
            });

            waitsFor(function ()
            {
                return appEventsTest.callbackFired;
            }, "the callback didnt fire", 750);

            runs(function ()
            {
                expect(appEventsTest.lastEventData).toEqual(template);
            });
        });
    }
});
<|endoftext|>


<commit_before>

$(document).ready(function () {
    new WOW().init();
    $("[data-toggle=popover]").popover({ trigger: "hover" });
    $('.counter').counterUp();
    $.stellar();

    (function(d, s, id) {
        var js, fjs = d.getElementsByTagName(s)[0];
        if (d.getElementById(id)) return;
        js = d.createElement(s); js.id = id;
        js.src = "//connect.facebook.net/pt_BR/sdk.js#xfbml=1&version=v2.5&appId=222520191136295";
        fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));
});

var lang = document.documentElement.lang

if (lang == 'pt') {
    lang = 'pt-BR';
} else if (lang == 'en') {
    lang = 'en-US';
}

var summernoteConfig = {
    lang: lang,
    fontNames: [
        'Arial', 'Arial Black', 'Comic Sans MS', 'Courier New',
        'Helvetica Neue', 'Helvetica', 'Impact', 'Lucida Grande',
        'Open Sans', 'Tahoma', 'Times New Roman', 'Verdana'
      ],
    toolbar: [
        ['style', ['style']],
        ['font', ['bold', 'italic', 'underline', 'clear']],
        ['fontname', ['fontname']],
        ['fontsize', ['fontsize']],
        ['color', ['color']],
        ['para', ['ul', 'ol', 'paragraph']],
        ['table', ['table']],
        ['insert', ['link', 'picture', 'video']],
        ['view', ['fullscreen', 'codeview', 'help']]
      ],
    placeholder: 'Escreva aqui o conteúdo desta publicação'
}

function selectorCallback(id, event) {
    url = window.location.origin + window.location.pathname + '?bra_id='+id;
    window.location = url;
}

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    url = url.toLowerCase();
    name = name.replace(/[\[\]]/g, "\\$&").toLowerCase();

    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}

function cropInput(crop, input, callback) {
    if (window.FileReader) {
        input.change(function() {
            var fileReader = new FileReader(),
                    files = this.files,
                    file;

            if (!files.length) {
                return;
            }

            file = files[0];

            if (/^image\/\w+$/.test(file.type)) {
                fileReader.readAsDataURL(file);
                fileReader.onload = function () {
                    input.val("");
                    crop.cropper("reset", true).cropper("replace", this.result);
                };

            if (callback !== null) {
                callback();
            }

            } else {
                showMessage("Please choose an image file.");
            }
        });
    } else {
        input.addClass("hide");
    }
}
<commit_msg>Adds new CRUD flow to the javascript<commit_after>$(document).ready(function () {
    new WOW().init();
    $("[data-toggle=popover]").popover({ trigger: "hover" });
    $('.counter').counterUp();
    $.stellar();

    $( ".js-switch" ).each(function() {
      var switchery = new Switchery(this);
    });

    (function(d, s, id) {
        var js, fjs = d.getElementsByTagName(s)[0];
        if (d.getElementById(id)) return;
        js = d.createElement(s); js.id = id;
        js.src = "//connect.facebook.net/pt_BR/sdk.js#xfbml=1&version=v2.5&appId=222520191136295";
        fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));
});

var lang = document.documentElement.lang

if (lang == 'pt') {
    lang_code = 'pt-BR';
} else if (lang == 'en') {
    lang_code = 'en-US';
}

var summernoteConfig = {
    lang: lang_code,
    fontNames: [
        'Arial', 'Arial Black', 'Comic Sans MS', 'Courier New',
        'Helvetica Neue', 'Helvetica', 'Impact', 'Lucida Grande',
        'Open Sans', 'Tahoma', 'Times New Roman', 'Verdana'
      ],
    toolbar: [
        ['style', ['style']],
        ['font', ['bold', 'italic', 'underline', 'clear']],
        ['fontname', ['fontname']],
        ['fontsize', ['fontsize']],
        ['color', ['color']],
        ['para', ['ul', 'ol', 'paragraph']],
        ['table', ['table']],
        ['insert', ['link', 'picture', 'video']],
        ['view', ['fullscreen', 'codeview', 'help']]
      ],
    placeholder: 'Escreva aqui o conteúdo desta publicação'
}

function selectorCallback(id, event) {
    url = window.location.origin + window.location.pathname + '?bra_id='+id;
    window.location = url;
}

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    url = url.toLowerCase();
    name = name.replace(/[\[\]]/g, "\\$&").toLowerCase();

    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}

function cropInput(crop, input, callback) {
    if (window.FileReader) {
        input.change(function() {
            var fileReader = new FileReader(),
                    files = this.files,
                    file;

            if (!files.length) {
                return;
            }

            file = files[0];

            if (/^image\/\w+$/.test(file.type)) {
                fileReader.readAsDataURL(file);
                fileReader.onload = function () {
                    input.val("");
                    crop.cropper("reset", true).cropper("replace", this.result);
                };

            if (callback !== null) {
                callback();
            }

            } else {
                showMessage("Please choose an image file.");
            }
        });
    } else {
        input.addClass("hide");
    }
}
<|endoftext|>


<commit_before>$(document).ready(function(){
	if($('#content .container').hasClass('home'))
		twitterIni();
	$.cookie.defaults.path = '/';
	$('.jscrollpane').jScrollPane();
	$('.custom-select').customSelect();
	$('.calificacion-form').validate();
	$('.reporte-form').validate();
	$('.petition-form').validate();
	$('.contacto-form').validate();
	$('form.newsletter').validate();

	$('#ver-en-mapa').click(function(e){
		e.preventDefault();
		$('#general-search').attr('action',$(this).attr('href'));
		$('#general-search').submit();
	});

	$('.compara-tabs a').click(function(e){
		e.preventDefault();
		var index = $(this).index();
		$('.compara-tabs a.on').removeClass('on');
		$(this).addClass('on');
		$('.compara-tab-container .tab.on').removeClass('on');
		$('.compara-tab-container .tab').eq(index).addClass('on');
	})

	$('.compara-escuela').on('click',function(e){
		e.preventDefault();
		var tr = $(this).parent().parent().toggleClass('on');
		var cct = $(this).attr('href');
		toggle_escuela(cct);
	});

	$('#content .perfil .tabs li a').click(function(e){
		e.preventDefault();
		var index = 4 - $(this).parent().index();
		$('#content .perfil .tabs li.on').removeClass('on');
		$(this).parent().addClass('on');
		$('#content .perfil .tab-container .tab.on').removeClass('on');
		$('#content .perfil .tab-container .tab').eq(index).addClass('on').jScrollPane();
		if($(this).html() == 'Resultados Educativos' ) drawCharts();
	})
	/*$('#rank-bar').mousemove(function(e){
		set_rank_bar(e.pageX - $(this).offset().left);
	});*/
	/*$('#rank-bar').click(function(e){
		var rank = set_rank_bar(e.pageX - $(this).offset().left);
		$('#rank-value').val(rank);
	});*/
	/*$('#rank-bar').mouseout(function(e){
		var max = $('.container').hasClass('B')?173:336;
		var x = e.pageX - $(this).offset().left;
		var y = e.pageY - $(this).offset().top;
		if((y >= 10 || y < 0) || (x < 0 || x > max)){
			var val = $('#rank-value').val();
			if(val != ''){
				set_rank_bar(Math.round(val/100*max));
			}else{
				$('#rank-bar .bar').hide();
				$('#rank-label').hide();
			}
		}
	});*/
	if($("#name-input") .length)
	$( "#name-input" ).autocomplete({
  		source: function(request,response){
  			$.post("/main/get_escuelas/",{
  				term : request.term,
  				entidad : $("#state-input").val(),
  				municipio : $("#municipio-input").val(),
  				localidad : $("#localidad-input").val(),
  				nivel : $("#nivel-input").val(),
  				json : true
  			},response,'json');
  		},
  		minLength: 3,
		select: function( event, ui ) {
			window.location = "/escuelas/index/"+ui.item.cct;
			return false;
		}
	}).data( "ui-autocomplete" )._renderItem = function( ul, item ){
      return $("
").append(""+item.label+""+item.address+"").appendTo(ul);
    };

	$('#map-button').click(function(e){
		e.preventDefault();
		$('#general-search').attr('action','/mapa/');
		$('#general-search').submit();

	});
	$('#state-input').change(function(e){
		$("#localidad-input").prop('disabled', true).next().addClass('customSelectDisabled');
		load_location_options(
			$("#municipio-input"),
			'load_municipios',
			{entidad:$(this).val(),json:true},
			"Municipio"
		);
	});

	$('#municipio-input').change(function(){
		if($(this).val() != "" || ($("#state-input option:selected").val() != "" && $("#state-input option:selected").val() != 7 && $("#state-input option:selected").val() != 20 && $("#state-input option:selected").val() != 30)){
			load_location_options(
				$("#localidad-input"),
				'load_localidades',
				{municipio:$(this).val(),entidad:$("#state-input option:selected").val(),json:true},
				"Localidad"
			);
		}else{
			$("#localidad-input").prop('disabled', true).next().addClass('customSelectDisabled');
			$("#localidad-input").html('<option value="">Localidad</option>');
		}
	});

	$('#content .home .circle a.line').hover(function(){
		var x=[27,23,19];
		var i=$(this).index();
		var xP=$(this).position().left;
		$(this).parent().find('.line1').css({'left':xP+x[i-1] + 'px','display':'block'});
		$(this).parent().find('.line2').css({'left':89+xP+x[i-1]+'px','display':'block'});
	},function(){
			$(this).parent().find('.line1').css('display','none');
			$(this).parent().find('.line2').css('display','none');
	});

	$('#content .share-bt a.button-frame').click(function(e){
		e.preventDefault();
		$('#content .share-bt .social').toggleClass('on');
	});

	$('.wrap_cal span').click(function(){
		var span =  $(this).parent().find('span');
		if($(this).hasClass('on') && $(this).index()==0){
			span.removeClass('on');
		}else{
			span.removeClass('on');
			for(var i=0;i<=$(this).index();i++){
				$(span[i]).addClass('on');
			}
		}
		var promedio = $('.wrap_cal span.on').size() / $('.wrap_cal').size();
		promedio = promedio.toString().length>3?promedio.toFixed(1):promedio;
		$('.promedio span').html(promedio);
		$('#rank-value').val(promedio);
	});

	$('.menu a.logo + a + a').click(function(e){
		e.preventDefault();
		var cookie = $.cookie('escuelas'),
		    url = '/compara/escuelas/'+ (cookie != undefined ? cookie:'');
		location.href = url;
	});

	$('.search-estado select.custom-select').change(function(){
		var id;
		if((id = $(this).val())!=''){
			location.href = '/resultados-nacionales/entidad/'+id;
		}
	});

	$('.peticion h1').click(function(){
		$('.wrap_peticion, .social.on').removeClass('on');
		var next = $(this).next();
		next.addClass('on');
		if(!(next.find('.content').hasClass('jscrollpane'))){
			next.find('.content').addClass('jscrollpane').jScrollPane();
		}
	});
	if($('#content .container').hasClass('peticion')){
		$('.wrap_peticion.on .content').addClass('jscrollpane').jScrollPane();
	}

	if($('#content .container').hasClass('perfil')){
		$('.menu a.logo + a + a + a').click(function(e){
			e.preventDefault();
			location.href = $('.califica a.title').attr('href');
		});

		$('.tabs a.result').click(function(){
		var texts = $('text[text-anchor="start"]'),
		    text;
		for(var i=0;i<texts.length;i++){
			text = $(texts[i]);
			text.text(text.text()+' grado');
		}
		});

	}

	if($('.container').hasClass('perfil')){
		var cct = $('span.CCT').html();
		var escuelas = $.cookie('escuelas') && $.cookie('escuelas').split('-') || [];
		if(escuelas.indexOf(cct)==-1){
			escuelas.push(cct);
			escuelas.sort();
			$.cookie('escuelas',escuelas.join('-'));
			$('a[href="'+cct+'"]').parent().parent().addClass('on');
		}
		/*if(!($.cookie('escuelas')) || $.cookie('escuelas').split('-').indexOf(cct)==-1){
			$('a[href="'+cct+'"]').trigger('click');
			if(!$('a[href="'+cct+'"]').size()){
				toggle_escuela(cct);
			}
		}*/

	}

	if($('.container').hasClass('comparar')){
		$('#general-search').submit(function(e){
			e.preventDefault();
			var url='';
			$(this).find('[name]').each(function(i,val){
				url +='&'+$(val).attr('name')+'='+$(val).val();
			});
			window.location = $(this).attr('action')+url;
		});
	}

	if($('.container').hasClass('resultados')){
		$(window).unload(add_escuelas_cookie);
	}

	$('#compara-main-button').click(function(e){
		e.preventDefault();
		add_escuelas_cookie();
		$(window).off();
		location.href = '/compara/escuelas/' + $.cookie('escuelas');
	});

	$('#content .comparar.resultados table tr.on .compara-escuela').click(function(e){
		e.preventDefault();
		var cct = $(this).attr('href'),
		url=document.URL.replace(new RegExp('-*'+cct),''),
		escuelas = $.cookie('escuelas') && $.cookie('escuelas').split('-') || [];
		escuelas.splice(escuelas.indexOf(cct),1);
		$.cookie('escuelas',escuelas.join('-'));
		if(document.URL != url)
			location.href = url;

	});

	$('.perfil .sort').click(function(e){
		e.preventDefault();
		var comments = $('.comment').remove(),
		temp = $(this).attr('href');
		$('.perfil .sort.on').removeClass('on');
		$(this).addClass('on');
		if($(this).hasClass('recientes')){
			comments.sort(function(a,b){
				var t1 = new Date($(a).find('.timestamp').html()),
				t2 = new Date($(b).find('.timestamp').html());
				if(temp=='top')
					return t1>t2?-1:1;
				else
					return t1>t2?1:-1;
			})
		}else{
			comments.sort(function(a,b){
				var l1 = parseFloat($(a).find('.likes').html()),
				l2 = parseFloat($(b).find('.likes').html());
				if(temp=='top')
					return l1>l2?-1:1;
				else
					return l1>l2?1:-1;

			})
		}
		$(this).attr('href',$(this).attr('href')=='top'?'bottom':'top');
		$('[name="calificaciones"]').parent().append(comments);
	});

});

function load_location_options(input,directive,options,name){
	input.prop('disabled', true);
	input.next().addClass('customSelectDisabled');
	$.post('/main/'+directive,options,function(data){
		input.html('<option value="">'+name+'</option>');
		for(x in data){
			var item = data[x];
			item.nombre = item.nombre[0].toLocaleUpperCase() + item.nombre.substr(1);
			input.append('<option value="'+item.id+'">'+item.nombre+'</option>');
		}
		input.prop('disabled', false);
		input.next().removeClass('customSelectDisabled');
		input.trigger('change');
	},'json');
}
/*function set_rank_bar(x){
	var max = $('.container').hasClass('B')?173:336;
	var rank = Math.round(x/max * 100);
	var offset = x - 12;
	$('#rank-bar .bar').css('width',x+'px').show();
	$('#rank-label').html(rank+'%').css('left',offset+'px').show();
	return rank;
}*/
function toggle_escuela(cct){
	var escuelas = $.cookie('escuelas') && $.cookie('escuelas').split('-') || [],
	index;
	if((index = escuelas.indexOf(cct)) != -1){
		escuelas.splice(index,1);
		escuelas.sort();
		$.cookie('escuelas',escuelas.join('-'));
	}
	//$('#compara-main-button').attr('href','/compara/escuelas/'+escuelas.join('-') || '');
	/*
	if(typeof($.cookie('escuelas')) == 'undefined'){
		$.cookie('escuelas',[cct]);
	}else{
		var escuelas = $.cookie('escuelas').split('-');
		var index = escuelas.indexOf(cct);
		if(index != -1){
			escuelas.pop(index);
		}else{
			escuelas.push(cct);
		}
		//escuelas.sort();
		$.cookie('escuelas',escuelas.join('-'));
		if( $('.container.resultados').hasClass('comparar')){
			var url=document.URL.replace(new RegExp('-*'+cct),'');
			if(document.URL != url)
				location.href = url;
		}
	}
	*/
}
function twitterIni(){
    var username =  "mejoratuescuela",
	page_proxy = '/home/twitter';
	$("#tweets .tweet p").html("cargando tweets...");
	$.getJSON(page_proxy, function(data){
		$("#tweets .tweet").css('display','none');
		$("#tweets").append('

');
		for(d in data){
			var x = data[d];
			$("#tweets ul").append('

@'+username+' '+x.text+'

');
	    	}
	    })
}

function add_escuelas_cookie(){
	var selector_table = $('.resultados.container table'),
	on = selector_table.find('tr.on'),
	cookie = $.cookie('escuelas'),
	escuelas = cookie && cookie.split('-') || [];
	for(var i=0;i<on.length;i++){
		var val = $(on[i]),
		cct = val.find('.compara-escuela').attr('href');
		if(escuelas.indexOf(cct)==-1)
			escuelas.push(cct);
	}
	escuelas.sort();
	if(escuelas.length){
		$.cookie('escuelas',escuelas.join('-'));
	}
}
<commit_msg>test de agregar quitar a la cookie en califica<commit_after>$(document).ready(function(){
	if($('#content .container').hasClass('home'))
		twitterIni();
	$.cookie.defaults.path = '/';
	$('.jscrollpane').jScrollPane();
	$('.custom-select').customSelect();
	$('.calificacion-form').validate();
	$('.reporte-form').validate();
	$('.petition-form').validate();
	$('.contacto-form').validate();
	$('form.newsletter').validate();

	$('#ver-en-mapa').click(function(e){
		e.preventDefault();
		$('#general-search').attr('action',$(this).attr('href'));
		$('#general-search').submit();
	});

	$('.compara-tabs a').click(function(e){
		e.preventDefault();
		var index = $(this).index();
		$('.compara-tabs a.on').removeClass('on');
		$(this).addClass('on');
		$('.compara-tab-container .tab.on').removeClass('on');
		$('.compara-tab-container .tab').eq(index).addClass('on');
	})

	$('.compara-escuela').on('click',function(e){
		e.preventDefault();
		var tr = $(this).parent().parent().toggleClass('on');
		var cct = $(this).attr('href');
		toggle_escuela(cct);
	});

	$('#content .perfil .tabs li a').click(function(e){
		e.preventDefault();
		var index = 4 - $(this).parent().index();
		$('#content .perfil .tabs li.on').removeClass('on');
		$(this).parent().addClass('on');
		$('#content .perfil .tab-container .tab.on').removeClass('on');
		$('#content .perfil .tab-container .tab').eq(index).addClass('on').jScrollPane();
		if($(this).html() == 'Resultados Educativos' ) drawCharts();
	})
	/*$('#rank-bar').mousemove(function(e){
		set_rank_bar(e.pageX - $(this).offset().left);
	});*/
	/*$('#rank-bar').click(function(e){
		var rank = set_rank_bar(e.pageX - $(this).offset().left);
		$('#rank-value').val(rank);
	});*/
	/*$('#rank-bar').mouseout(function(e){
		var max = $('.container').hasClass('B')?173:336;
		var x = e.pageX - $(this).offset().left;
		var y = e.pageY - $(this).offset().top;
		if((y >= 10 || y < 0) || (x < 0 || x > max)){
			var val = $('#rank-value').val();
			if(val != ''){
				set_rank_bar(Math.round(val/100*max));
			}else{
				$('#rank-bar .bar').hide();
				$('#rank-label').hide();
			}
		}
	});*/
	if($("#name-input") .length)
	$( "#name-input" ).autocomplete({
  		source: function(request,response){
  			$.post("/main/get_escuelas/",{
  				term : request.term,
  				entidad : $("#state-input").val(),
  				municipio : $("#municipio-input").val(),
  				localidad : $("#localidad-input").val(),
  				nivel : $("#nivel-input").val(),
  				json : true
  			},response,'json');
  		},
  		minLength: 3,
		select: function( event, ui ) {
			window.location = "/escuelas/index/"+ui.item.cct;
			return false;
		}
	}).data( "ui-autocomplete" )._renderItem = function( ul, item ){
      return $("
").append(""+item.label+""+item.address+"").appendTo(ul);
    };

	$('#map-button').click(function(e){
		e.preventDefault();
		$('#general-search').attr('action','/mapa/');
		$('#general-search').submit();

	});
	$('#state-input').change(function(e){
		$("#localidad-input").prop('disabled', true).next().addClass('customSelectDisabled');
		load_location_options(
			$("#municipio-input"),
			'load_municipios',
			{entidad:$(this).val(),json:true},
			"Municipio"
		);
	});

	$('#municipio-input').change(function(){
		if($(this).val() != "" || ($("#state-input option:selected").val() != "" && $("#state-input option:selected").val() != 7 && $("#state-input option:selected").val() != 20 && $("#state-input option:selected").val() != 30)){
			load_location_options(
				$("#localidad-input"),
				'load_localidades',
				{municipio:$(this).val(),entidad:$("#state-input option:selected").val(),json:true},
				"Localidad"
			);
		}else{
			$("#localidad-input").prop('disabled', true).next().addClass('customSelectDisabled');
			$("#localidad-input").html('<option value="">Localidad</option>');
		}
	});

	$('#content .home .circle a.line').hover(function(){
		var x=[27,23,19];
		var i=$(this).index();
		var xP=$(this).position().left;
		$(this).parent().find('.line1').css({'left':xP+x[i-1] + 'px','display':'block'});
		$(this).parent().find('.line2').css({'left':89+xP+x[i-1]+'px','display':'block'});
	},function(){
			$(this).parent().find('.line1').css('display','none');
			$(this).parent().find('.line2').css('display','none');
	});

	$('#content .share-bt a.button-frame').click(function(e){
		e.preventDefault();
		$('#content .share-bt .social').toggleClass('on');
	});

	$('.wrap_cal span').click(function(){
		var span =  $(this).parent().find('span');
		if($(this).hasClass('on') && $(this).index()==0){
			span.removeClass('on');
		}else{
			span.removeClass('on');
			for(var i=0;i<=$(this).index();i++){
				$(span[i]).addClass('on');
			}
		}
		var promedio = $('.wrap_cal span.on').size() / $('.wrap_cal').size();
		promedio = promedio.toString().length>3?promedio.toFixed(1):promedio;
		$('.promedio span').html(promedio);
		$('#rank-value').val(promedio);
	});

	$('.menu a.logo + a + a').click(function(e){
		e.preventDefault();
		var cookie = $.cookie('escuelas'),
		    url = '/compara/escuelas/'+ (cookie != undefined ? cookie:'');
		location.href = url;
	});

	$('.search-estado select.custom-select').change(function(){
		var id;
		if((id = $(this).val())!=''){
			location.href = '/resultados-nacionales/entidad/'+id;
		}
	});

	$('.peticion h1').click(function(){
		$('.wrap_peticion, .social.on').removeClass('on');
		var next = $(this).next();
		next.addClass('on');
		if(!(next.find('.content').hasClass('jscrollpane'))){
			next.find('.content').addClass('jscrollpane').jScrollPane();
		}
	});
	if($('#content .container').hasClass('peticion')){
		$('.wrap_peticion.on .content').addClass('jscrollpane').jScrollPane();
	}

	if($('#content .container').hasClass('perfil')){
		$('.menu a.logo + a + a + a').click(function(e){
			e.preventDefault();
			location.href = $('.califica a.title').attr('href');
		});

		$('.tabs a.result').click(function(){
		var texts = $('text[text-anchor="start"]'),
		    text;
		for(var i=0;i<texts.length;i++){
			text = $(texts[i]);
			text.text(text.text()+' grado');
		}
		});

	}

	if($('.container').hasClass('perfil')){
		var cct = $('span.CCT').html();
		var escuelas = $.cookie('escuelas') && $.cookie('escuelas').split('-') || [];
		if(escuelas.indexOf(cct)==-1){
			escuelas.push(cct);
			escuelas.sort();
			$.cookie('escuelas',escuelas.join('-'));
			$('a[href="'+cct+'"]').parent().parent().addClass('on');
		}
		/*if(!($.cookie('escuelas')) || $.cookie('escuelas').split('-').indexOf(cct)==-1){
			$('a[href="'+cct+'"]').trigger('click');
			if(!$('a[href="'+cct+'"]').size()){
				toggle_escuela(cct);
			}
		}*/

	}

	if($('.container').hasClass('comparar')){
		$('#general-search').submit(function(e){
			e.preventDefault();
			var url='';
			$(this).find('[name]').each(function(i,val){
				url +='&'+$(val).attr('name')+'='+$(val).val();
			});
			window.location = $(this).attr('action')+url;
		});
	}

	if($('.container').hasClass('resultados') || $('.container').hasClass('califica_select')){
		$(window).unload(add_escuelas_cookie);
	}

	$('#compara-main-button').click(function(e){
		e.preventDefault();
		add_escuelas_cookie();
		$(window).off();
		location.href = '/compara/escuelas/' + $.cookie('escuelas');
	});

	$('#content .comparar.resultados table tr.on .compara-escuela').click(function(e){
		e.preventDefault();
		var cct = $(this).attr('href'),
		url=document.URL.replace(new RegExp('-*'+cct),''),
		escuelas = $.cookie('escuelas') && $.cookie('escuelas').split('-') || [];
		escuelas.splice(escuelas.indexOf(cct),1);
		$.cookie('escuelas',escuelas.join('-'));
		if(document.URL != url)
			location.href = url;

	});

	$('.perfil .sort').click(function(e){
		e.preventDefault();
		var comments = $('.comment').remove(),
		temp = $(this).attr('href');
		$('.perfil .sort.on').removeClass('on');
		$(this).addClass('on');
		if($(this).hasClass('recientes')){
			comments.sort(function(a,b){
				var t1 = new Date($(a).find('.timestamp').html()),
				t2 = new Date($(b).find('.timestamp').html());
				if(temp=='top')
					return t1>t2?-1:1;
				else
					return t1>t2?1:-1;
			})
		}else{
			comments.sort(function(a,b){
				var l1 = parseFloat($(a).find('.likes').html()),
				l2 = parseFloat($(b).find('.likes').html());
				if(temp=='top')
					return l1>l2?-1:1;
				else
					return l1>l2?1:-1;

			})
		}
		$(this).attr('href',$(this).attr('href')=='top'?'bottom':'top');
		$('[name="calificaciones"]').parent().append(comments);
	});

});

function load_location_options(input,directive,options,name){
	input.prop('disabled', true);
	input.next().addClass('customSelectDisabled');
	$.post('/main/'+directive,options,function(data){
		input.html('<option value="">'+name+'</option>');
		for(x in data){
			var item = data[x];
			item.nombre = item.nombre[0].toLocaleUpperCase() + item.nombre.substr(1);
			input.append('<option value="'+item.id+'">'+item.nombre+'</option>');
		}
		input.prop('disabled', false);
		input.next().removeClass('customSelectDisabled');
		input.trigger('change');
	},'json');
}
/*function set_rank_bar(x){
	var max = $('.container').hasClass('B')?173:336;
	var rank = Math.round(x/max * 100);
	var offset = x - 12;
	$('#rank-bar .bar').css('width',x+'px').show();
	$('#rank-label').html(rank+'%').css('left',offset+'px').show();
	return rank;
}*/
function toggle_escuela(cct){
	var escuelas = $.cookie('escuelas') && $.cookie('escuelas').split('-') || [],
	index;
	if((index = escuelas.indexOf(cct)) != -1){
		escuelas.splice(index,1);
		escuelas.sort();
		$.cookie('escuelas',escuelas.join('-'));
	}
	//$('#compara-main-button').attr('href','/compara/escuelas/'+escuelas.join('-') || '');
	/*
	if(typeof($.cookie('escuelas')) == 'undefined'){
		$.cookie('escuelas',[cct]);
	}else{
		var escuelas = $.cookie('escuelas').split('-');
		var index = escuelas.indexOf(cct);
		if(index != -1){
			escuelas.pop(index);
		}else{
			escuelas.push(cct);
		}
		//escuelas.sort();
		$.cookie('escuelas',escuelas.join('-'));
		if( $('.container.resultados').hasClass('comparar')){
			var url=document.URL.replace(new RegExp('-*'+cct),'');
			if(document.URL != url)
				location.href = url;
		}
	}
	*/
}
function twitterIni(){
    var username =  "mejoratuescuela",
	page_proxy = '/home/twitter';
	$("#tweets .tweet p").html("cargando tweets...");
	$.getJSON(page_proxy, function(data){
		$("#tweets .tweet").css('display','none');
		$("#tweets").append('

');
		for(d in data){
			var x = data[d];
			$("#tweets ul").append('

@'+username+' '+x.text+'

');
	    	}
	    })
}

function add_escuelas_cookie(){
	//var selector_table = $('.resultados.container table'),
	var selector_table = $('.resultados table'),
	on = selector_table.find('tr.on'),
	cookie = $.cookie('escuelas'),
	escuelas = cookie && cookie.split('-') || [];
	for(var i=0;i<on.length;i++){
		var val = $(on[i]),
		cct = val.find('.compara-escuela').attr('href');
		if(escuelas.indexOf(cct)==-1)
			escuelas.push(cct);
	}
	escuelas.sort();
	if(escuelas.length){
		$.cookie('escuelas',escuelas.join('-'));
	}
}
<|endoftext|>


<commit_before>module.exports = {
  test: [
    /\.bmp$/,
    /\.gif$/,
    /\.jpe?g$/,
    /\.png$/,
    /\.tiff$/,
    /\.ico$/,
    /\.avif$/,
    /\.webp$/,
    /\.eot$/,
    /\.otf$/,
    /\.ttf$/,
    /\.woff$/,
    /\.woff2$/,
    /\.svg$/
  ],
  exclude: [/\.(js|mjs|jsx|ts|tsx)$/],
  type: 'asset/resource',
  generator: {
    filename: 'static/[hash][ext][query]'
  }
}
<commit_msg>Adding name in static files path (#3147)<commit_after>module.exports = {
  test: [
    /\.bmp$/,
    /\.gif$/,
    /\.jpe?g$/,
    /\.png$/,
    /\.tiff$/,
    /\.ico$/,
    /\.avif$/,
    /\.webp$/,
    /\.eot$/,
    /\.otf$/,
    /\.ttf$/,
    /\.woff$/,
    /\.woff2$/,
    /\.svg$/
  ],
  exclude: [/\.(js|mjs|jsx|ts|tsx)$/],
  type: 'asset/resource',
  generator: {
    filename: 'static/[name]-[hash][ext][query]'
  }
}
<|endoftext|>