<commit_before>(function () {
  'use strict';

  define(function (require) {
    var languages = require('cs!configs/languages');

    return {
      // Directory from which webview is served
      root: '/',

      // Hostname and port for the cnx-archive server
      cnxarchive: {
        host: 'archive.cnx.org',
        port: 80
      },

      // Hostname and port for the cnx-authoring server
      cnxauthoring: {
        host: location.hostname,
        port: 8080
      },

      // Prefix to prepend to page titles
      titlePrefix: 'OpenStax CNX - ',

      // Google Analytics tracking ID
      analyticsID: 'UA-7903479-1',

      // Supported languages
      languages: languages,

      // Legacy URL
      // URLs are concatenated using the following logic: location.protocol + '//' + legacy + '/' + view.url
      //   Example: 'http:' + '//' + 'cnx.org' + '/' + 'contents'
      // Do not include the protocol or a trailing slash
      legacy: 'cnx.org',

      // Webmaster E-mail address
      webmaster: 'cnx@cnx.org',

      // Content shortcodes
      shortcodes: {
        'college_physics': 'e4c0f2e3-82f0-4701-a485-c1b9b362a49f@7.1',
        'college_introduction_to_sociology': '451881d9-86f9-458b-83a3-a29de227a6f7@7.1',
        'biology': '6ba2ac5d-d53d-4df5-ae2f-9362add7a01a@9.1',
        'concepts_of_biology': '4779de9d-4524-49cb-88a3-3ad9e062fcb2@8.1',
        'anatomy_and_physiology': 'a7103b93-c07b-419d-8b74-3f429af4c378@6.1',
        'introductory_statistics': '5886a723-20a7-4410-b204-d70161feb416@6.1',
      }
    };

  });

})();
<commit_msg>Default to local install settings<commit_after>(function () {
  'use strict';

  define(function (require) {
    var languages = require('cs!configs/languages');

    return {
      // Directory from which webview is served
      root: '/',

      // Hostname and port for the cnx-archive server
      cnxarchive: {
        host: location.hostname,
        port: 6543
      },

      // Hostname and port for the cnx-authoring server
      cnxauthoring: {
        host: location.hostname,
        port: 8080
      },

      // Prefix to prepend to page titles
      titlePrefix: 'OpenStax CNX - ',

      // Google Analytics tracking ID
      analyticsID: 'UA-7903479-1',

      // Supported languages
      languages: languages,

      // Legacy URL
      // URLs are concatenated using the following logic: location.protocol + '//' + legacy + '/' + view.url
      //   Example: 'http:' + '//' + 'cnx.org' + '/' + 'contents'
      // Do not include the protocol or a trailing slash
      legacy: 'cnx.org',

      // Webmaster E-mail address
      webmaster: 'cnx@cnx.org',

      // Content shortcodes
      shortcodes: {
        'college_physics': 'e4c0f2e3-82f0-4701-a485-c1b9b362a49f@7.1',
        'college_introduction_to_sociology': '451881d9-86f9-458b-83a3-a29de227a6f7@7.1',
        'biology': '6ba2ac5d-d53d-4df5-ae2f-9362add7a01a@9.1',
        'concepts_of_biology': '4779de9d-4524-49cb-88a3-3ad9e062fcb2@8.1',
        'anatomy_and_physiology': 'a7103b93-c07b-419d-8b74-3f429af4c378@6.1',
        'introductory_statistics': '5886a723-20a7-4410-b204-d70161feb416@6.1',
      }
    };

  });

})();
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import isNodeInRoot from './nodeInRoot';
import getBoundsForNode from './getBoundsForNode';
import doObjectsCollide from './doObjectsCollide';

class SelectableGroup extends React.Component {

	constructor (props) {
		super(props);

		this.state = {
			isBoxSelecting: false,
			boxWidth: 0,
			boxHeight: 0
		}

		this._mouseDownData = null;
		this._registry = [];

		this._openSelector = this._openSelector.bind(this);
		this._mouseDown = this._mouseDown.bind(this);
		this._mouseUp = this._mouseUp.bind(this);
		this._selectElements = this._selectElements.bind(this);
		this._registerSelectable = this._registerSelectable.bind(this);
		this._unregisterSelectable = this._unregisterSelectable.bind(this);
	}

	getChildContext () {
		return {
			selectable: {
				register: this._registerSelectable,
				unregister: this._unregisterSelectable
			}
		};
	}

	componentDidMount () {
		ReactDOM.findDOMNode(this).addEventListener('mousedown', this._mouseDown);
	}

	/**
	 * Remove global event listeners
	 */
	componentWillUnmount () {
		ReactDOM.findDOMNode(this).removeEventListener('mousedown', this._mouseDown);
	}

	_registerSelectable (key, domNode) {
		this._registry.push({key, domNode});
	}

	_unregisterSelectable (key) {
		this._registry = this._registry.filter(data => data.key !== key);
	}

	/**
	 * Called while moving the mouse with the button down. Changes the boundaries
	 * of the selection box
	 */
	_openSelector (e) {
	    const w = Math.abs(this._mouseDownData.initialW - e.pageX);
	    const h = Math.abs(this._mouseDownData.initialH - e.pageY);

	    this.setState({
	    	isBoxSelecting: true,
	    	boxWidth: w,
	    	boxHeight: h,
	    	boxLeft: Math.min(e.pageX, this._mouseDownData.initialW),
	    	boxTop: Math.min(e.pageY, this._mouseDownData.initialH)
	    });
	}

	/**
	 * Called when a user presses the mouse button. Determines if a select box should
	 * be added, and if so, attach event listeners
	 */
	_mouseDown (e) {
		const node = ReactDOM.findDOMNode(this);
		let collides, offsetData, distanceData;
		ReactDOM.findDOMNode(this).addEventListener('mouseup', this._mouseUp);

		// Right clicks
		if(e.which === 3 || e.button === 2) return;

		if(!isNodeInRoot(e.target, node)) {
			offsetData = getBoundsForNode(node);
			collides = doObjectsCollide(
				{
					top: offsetData.top,
					left: offsetData.left,
					bottom: offsetData.offsetHeight,
					right: offsetData.offsetWidth
				},
				{
					top: e.pageY,
					left: e.pageX,
					offsetWidth: 0,
					offsetHeight: 0
				}
			);
			if(!collides) return;
		}

		this._mouseDownData = {
			boxLeft: e.pageX,
			boxTop: e.pageY,
	        initialW: e.pageX,
        	initialH: e.pageY
		};

		e.preventDefault();

		ReactDOM.findDOMNode(this).addEventListener('mousemove', this._openSelector);
	}

	/**
	 * Called when the user has completed selection
	 */
	_mouseUp (e) {
	    ReactDOM.findDOMNode(this).removeEventListener('mousemove', this._openSelector);
	    ReactDOM.findDOMNode(this).removeEventListener('mouseup', this._mouseUp);

	    if(!this._mouseDownData) return;

		return this._selectElements(e);
	}

	/**
	 * Selects multiple children given x/y coords of the mouse
	 */
	_selectElements (e) {
	    this._mouseDownData = null;
	    const currentItems = [],
		      selectbox = ReactDOM.findDOMNode(this.refs.selectbox),
		      {tolerance} = this.props;

		if(!selectbox) return;

		this._registry.forEach(itemData => {
			if(itemData.domNode && doObjectsCollide(selectbox, itemData.domNode, tolerance)) {
				currentItems.push(itemData.key);
			}
		});

		this.setState({
			isBoxSelecting: false,
			boxWidth: 0,
			boxHeight: 0
		});

		this.props.onSelection(currentItems);
	}

	/**
	 * Renders the component
	 * @return {ReactComponent}
	 */
	render () {

		const boxStyle = {
			left: this.state.boxLeft,
			top: this.state.boxTop,
			width: this.state.boxWidth,
			height: this.state.boxHeight,
			zIndex: 9000,
			position: this.props.fixedPosition ? 'fixed' : 'absolute',
			cursor: 'default'
		};

		const spanStyle = {
			backgroundColor: 'transparent',
			border: '1px dashed #999',
			width: '100%',
			height: '100%',
			float: 'left'
		};

		return (
			<this.props.component {...this.props}>
				{this.state.isBoxSelecting &&

				}
				{this.props.children}
			</this.props.component>
		);
	}
}

SelectableGroup.propTypes = {

	/**
	 * Event that will fire when items are selected. Passes an array of keys
	 */
	onSelection: React.PropTypes.func,

	/**
	 * The component that will represent the Selectable DOM node
	 */
	component: React.PropTypes.node,

	/**
	 * Amount of forgiveness an item will offer to the selectbox before registering
	 * a selection, i.e. if only 1px of the item is in the selection, it shouldn't be
	 * included.
	 */
	tolerance: React.PropTypes.number,

	/**
	 * In some cases, it the bounding box may need fixed positioning, if your layout
	 * is relying on fixed positioned elements, for instance.
	 * @type boolean
	 */
	fixedPosition: React.PropTypes.bool

};

SelectableGroup.defaultProps = {
	onSelection: () => {},
	component: 'div',
	tolerance: 0,
	fixedPosition: false
};

SelectableGroup.childContextTypes = {
	selectable: React.PropTypes.object
};

export default SelectableGroup;
<commit_msg>Move state reset to mouseUp event handler<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import isNodeInRoot from './nodeInRoot';
import getBoundsForNode from './getBoundsForNode';
import doObjectsCollide from './doObjectsCollide';

class SelectableGroup extends React.Component {

	constructor (props) {
		super(props);

		this.state = {
			isBoxSelecting: false,
			boxWidth: 0,
			boxHeight: 0
		}

		this._mouseDownData = null;
		this._registry = [];

		this._openSelector = this._openSelector.bind(this);
		this._mouseDown = this._mouseDown.bind(this);
		this._mouseUp = this._mouseUp.bind(this);
		this._selectElements = this._selectElements.bind(this);
		this._registerSelectable = this._registerSelectable.bind(this);
		this._unregisterSelectable = this._unregisterSelectable.bind(this);
	}

	getChildContext () {
		return {
			selectable: {
				register: this._registerSelectable,
				unregister: this._unregisterSelectable
			}
		};
	}

	componentDidMount () {
		ReactDOM.findDOMNode(this).addEventListener('mousedown', this._mouseDown);
	}

	/**
	 * Remove global event listeners
	 */
	componentWillUnmount () {
		ReactDOM.findDOMNode(this).removeEventListener('mousedown', this._mouseDown);
	}

	_registerSelectable (key, domNode) {
		this._registry.push({key, domNode});
	}

	_unregisterSelectable (key) {
		this._registry = this._registry.filter(data => data.key !== key);
	}

	/**
	 * Called while moving the mouse with the button down. Changes the boundaries
	 * of the selection box
	 */
	_openSelector (e) {
	    const w = Math.abs(this._mouseDownData.initialW - e.pageX);
	    const h = Math.abs(this._mouseDownData.initialH - e.pageY);

	    this.setState({
	    	isBoxSelecting: true,
	    	boxWidth: w,
	    	boxHeight: h,
	    	boxLeft: Math.min(e.pageX, this._mouseDownData.initialW),
	    	boxTop: Math.min(e.pageY, this._mouseDownData.initialH)
	    });
	}

	/**
	 * Called when a user presses the mouse button. Determines if a select box should
	 * be added, and if so, attach event listeners
	 */
	_mouseDown (e) {
		const node = ReactDOM.findDOMNode(this);
		let collides, offsetData, distanceData;
		ReactDOM.findDOMNode(this).addEventListener('mouseup', this._mouseUp);

		// Right clicks
		if(e.which === 3 || e.button === 2) return;

		if(!isNodeInRoot(e.target, node)) {
			offsetData = getBoundsForNode(node);
			collides = doObjectsCollide(
				{
					top: offsetData.top,
					left: offsetData.left,
					bottom: offsetData.offsetHeight,
					right: offsetData.offsetWidth
				},
				{
					top: e.pageY,
					left: e.pageX,
					offsetWidth: 0,
					offsetHeight: 0
				}
			);
			if(!collides) return;
		}

		this._mouseDownData = {
			boxLeft: e.pageX,
			boxTop: e.pageY,
	        initialW: e.pageX,
        	initialH: e.pageY
		};

		e.preventDefault();

		ReactDOM.findDOMNode(this).addEventListener('mousemove', this._openSelector);
	}

	/**
	 * Called when the user has completed selection
	 */
	_mouseUp (e) {
	    ReactDOM.findDOMNode(this).removeEventListener('mousemove', this._openSelector);
	    ReactDOM.findDOMNode(this).removeEventListener('mouseup', this._mouseUp);

	    if(!this._mouseDownData) return;

		this._selectElements(e);

		this._mouseDownData = null;
		this.setState({
			isBoxSelecting: false,
			boxWidth: 0,
			boxHeight: 0
		});
	}

	/**
	 * Selects multiple children given x/y coords of the mouse
	 */
	_selectElements (e) {
	    const currentItems = [],
		      selectbox = ReactDOM.findDOMNode(this.refs.selectbox),
		      {tolerance} = this.props;

		if(!selectbox) return;

		this._registry.forEach(itemData => {
			if(itemData.domNode && doObjectsCollide(selectbox, itemData.domNode, tolerance)) {
				currentItems.push(itemData.key);
			}
		});

		this.props.onSelection(currentItems);
	}

	/**
	 * Renders the component
	 * @return {ReactComponent}
	 */
	render () {

		const boxStyle = {
			left: this.state.boxLeft,
			top: this.state.boxTop,
			width: this.state.boxWidth,
			height: this.state.boxHeight,
			zIndex: 9000,
			position: this.props.fixedPosition ? 'fixed' : 'absolute',
			cursor: 'default'
		};

		const spanStyle = {
			backgroundColor: 'transparent',
			border: '1px dashed #999',
			width: '100%',
			height: '100%',
			float: 'left'
		};

		return (
			<this.props.component {...this.props}>
				{this.state.isBoxSelecting &&

				}
				{this.props.children}
			</this.props.component>
		);
	}
}

SelectableGroup.propTypes = {

	/**
	 * Event that will fire when items are selected. Passes an array of keys
	 */
	onSelection: React.PropTypes.func,

	/**
	 * The component that will represent the Selectable DOM node
	 */
	component: React.PropTypes.node,

	/**
	 * Amount of forgiveness an item will offer to the selectbox before registering
	 * a selection, i.e. if only 1px of the item is in the selection, it shouldn't be
	 * included.
	 */
	tolerance: React.PropTypes.number,

	/**
	 * In some cases, it the bounding box may need fixed positioning, if your layout
	 * is relying on fixed positioned elements, for instance.
	 * @type boolean
	 */
	fixedPosition: React.PropTypes.bool

};

SelectableGroup.defaultProps = {
	onSelection: () => {},
	component: 'div',
	tolerance: 0,
	fixedPosition: false
};

SelectableGroup.childContextTypes = {
	selectable: React.PropTypes.object
};

export default SelectableGroup;
<|endoftext|>


<commit_before>import Route from '@ember/routing/route';

export default Route.extend({
  model() {
    const job = this.modelFor('jobs.job');
    return job.get('versions').then(() => job);
  },
});
<commit_msg>Watch job versions<commit_after>import Route from '@ember/routing/route';
import { watchRelationship } from 'nomad-ui/utils/properties/watch';

export default Route.extend({
  model() {
    const job = this.modelFor('jobs.job');
    return job.get('versions').then(() => job);
  },

  setupController(controller, model) {
    controller.set('watcher', this.get('watchVersions').perform(model));
    return this._super(...arguments);
  },

  deactivate() {
    this.get('watchVersions').cancelAll();
    return this._super(...arguments);
  },

  watchVersions: watchRelationship('versions'),
});
<|endoftext|>


<commit_before>var URL_MATCH = /^(file|ftp|http|https):\/\/(\w+:{0,1}\w*@)?([\w\.-]*)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,
    HASH_MATCH = /^([^\?]*)?(\?([^\?]*))?$/,
    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp':21};

/**
 * @workInProgress
 * @ngdoc service
 * @name angular.service.$location
 * @requires $browser
 *
 * @property {string} href
 * @property {string} protocol
 * @property {string} host
 * @property {number} port
 * @property {string} path
 * @property {Object.<string|boolean>} search
 * @property {string} hash
 * @property {string} hashPath
 * @property {Object.<string|boolean>} hashSearch
 *
 * @description
 * Parses the browser location url and makes it available to your application.
 * Any changes to the url are reflected into $location service and changes to
 * $location are reflected to url.
 * Notice that using browser's forward/back buttons changes the $location.
 *
 * @example
   <doc:example>
     <doc:source>
       clear hash |
       test hash

       <input type='text' name="$location.hash"/>

$location = {{$location}}

     </doc:source>
     <doc:scenario>
     </doc:scenario>
    </doc:example>
 */
angularServiceInject("$location", function($browser) {
  var scope = this,
      location = {update:update, updateHash: updateHash},
      lastLocation = {};

  $browser.onHashChange(function() { //register
    update($browser.getUrl());
    copy(location, lastLocation);
    scope.$eval();
  })(); //initialize

  this.$onEval(PRIORITY_FIRST, sync);
  this.$onEval(PRIORITY_LAST, updateBrowser);

  return location;

  // PUBLIC METHODS

  /**
   * @workInProgress
   * @ngdoc method
   * @name angular.service.$location#update
   * @methodOf angular.service.$location
   *
   * @description
   * Update location object
   * Does not immediately update the browser
   * Browser is updated at the end of $eval()
   *
   * @example
    <doc:example>
      <doc:source>
        scope.$location.update('http://www.angularjs.org/path#hash?search=x');
        scope.$location.update({host: 'www.google.com', protocol: 'https'});
        scope.$location.update({hashPath: '/path', hashSearch: {a: 'b', x: true}});
      </doc:source>
      <doc:scenario>
      </doc:scenario>
    </doc:example>
   *
   * @param {(string|Object)} href Full href as a string or object with properties
   */
  function update(href) {
    if (isString(href)) {
      extend(location, parseHref(href));
    } else {
      if (isDefined(href.hash)) {
        extend(href, isString(href.hash) ? parseHash(href.hash) : href.hash);
      }

      extend(location, href);

      if (isDefined(href.hashPath || href.hashSearch)) {
        location.hash = composeHash(location);
      }

      location.href = composeHref(location);
    }
  }

  /**
   * @workInProgress
   * @ngdoc method
   * @name angular.service.$location#updateHash
   * @methodOf angular.service.$location
   *
   * @description
   * Update location hash part
   * @see update()
   *
   * @example
    <doc:example>
      <doc:source>
        scope.$location.updateHash('/hp')
         ==> update({hashPath: '/hp'})
        scope.$location.updateHash({a: true, b: 'val'})
         ==> update({hashSearch: {a: true, b: 'val'}})
        scope.$location.updateHash('/hp', {a: true})
         ==> update({hashPath: '/hp', hashSearch: {a: true}})
      </doc:source>
      <doc:scenario>
      </doc:scenario>
    </doc:example>
   *
   * @param {(string|Object)} path A hashPath or hashSearch object
   * @param {Object=} search A hashSearch object
   */
  function updateHash(path, search) {
    var hash = {};

    if (isString(path)) {
      hash.hashPath = path;
      hash.hashSearch = search || {};
    } else
      hash.hashSearch = path;

    hash.hash = composeHash(hash);

    update({hash: hash});
  }

  // INNER METHODS

  /**
   * Synchronizes all location object properties.
   *
   * User is allowed to change properties, so after property change,
   * location object is not in consistent state.
   *
   * Properties are synced with the following precedence order:
   *
   * - `$location.href`
   * - `$location.hash`
   * - everything else
   *
   * @example
   *

   *   scope.$location.href = 'http://www.angularjs.org/path#a/b'
   *

   * immediately after this call, other properties are still the old ones...
   *
   * This method checks the changes and update location to the consistent state
   */
  function sync() {
    if (!equals(location, lastLocation)) {
      if (location.href != lastLocation.href) {
        update(location.href);
        return;
      }
      if (location.hash != lastLocation.hash) {
        var hash = parseHash(location.hash);
        updateHash(hash.hashPath, hash.hashSearch);
      } else {
        location.hash = composeHash(location);
        location.href = composeHref(location);
      }
      update(location.href);
    }
  }

  /**
   * If location has changed, update the browser
   * This method is called at the end of $eval() phase
   */
  function updateBrowser() {
    sync();

    if ($browser.getUrl() != location.href) {
      $browser.setUrl(location.href);
      copy(location, lastLocation);
    }
  }

  /**
   * Compose href string from a location object
   *
   * @param {Object} loc The location object with all properties
   * @return {string} Composed href
   */
  function composeHref(loc) {
    var url = toKeyValue(loc.search);
    var port = (loc.port == DEFAULT_PORTS[loc.protocol] ? null : loc.port);

    return loc.protocol  + '://' + loc.host +
          (port ? ':' + port : '') + loc.path +
          (url ? '?' + url : '') + (loc.hash ? '#' + loc.hash : '');
  }

  /**
   * Compose hash string from location object
   *
   * @param {Object} loc Object with hashPath and hashSearch properties
   * @return {string} Hash string
   */
  function composeHash(loc) {
    var hashSearch = toKeyValue(loc.hashSearch);
    //TODO: temporary fix for issue #158
    return escape(loc.hashPath).replace(/%21/gi, '!').replace(/%3A/gi, ':').replace(/%24/gi, '$') +
          (hashSearch ? '?' + hashSearch : '');
  }

  /**
   * Parse href string into location object
   *
   * @param {string} href
   * @return {Object} The location object
   */
  function parseHref(href) {
    var loc = {};
    var match = URL_MATCH.exec(href);

    if (match) {
      loc.href = href.replace(/#$/, '');
      loc.protocol = match[1];
      loc.host = match[3] || '';
      loc.port = match[5] || DEFAULT_PORTS[loc.protocol] || null;
      loc.path = match[6] || '';
      loc.search = parseKeyValue(match[8]);
      loc.hash = match[10] || '';

      extend(loc, parseHash(loc.hash));
    }

    return loc;
  }

  /**
   * Parse hash string into object
   *
   * @param {string} hash
   */
  function parseHash(hash) {
    var h = {};
    var match = HASH_MATCH.exec(hash);

    if (match) {
      h.hash = hash;
      h.hashPath = unescape(match[1] || '');
      h.hashSearch = parseKeyValue(match[3]);
    }

    return h;
  }
}, ['$browser']);
<commit_msg>fix $location service docs and examples<commit_after>var URL_MATCH = /^(file|ftp|http|https):\/\/(\w+:{0,1}\w*@)?([\w\.-]*)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,
    HASH_MATCH = /^([^\?]*)?(\?([^\?]*))?$/,
    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp':21};

/**
 * @workInProgress
 * @ngdoc service
 * @name angular.service.$location
 * @requires $browser
 *
 * @property {string} href The full URL of the current location.
 * @property {string} protocol The protocol part of the URL (e.g. http or https).
 * @property {string} host The host name, ip address or FQDN of the current location.
 * @property {number} port The port number of the current location (e.g. 80, 443, 8080).
 * @property {string} path The path of the current location (e.g. /myapp/inbox).
 * @property {Object.<string|boolean>} search Map of query parameters (e.g. {user:"foo", page:23}).
 * @property {string} hash The fragment part of the URL of the current location (e.g. #foo).
 * @property {string} hashPath Similar to `path`, but located in the `hash` fragment
 *     (e.g. ../foo#/some/path  => /some/path).
 * @property {Object.<string|boolean>} hashSearch Similar to `search` but located in `hash`
 *     fragment (e.g. .../foo#/some/path?hashQuery=param  =>  {hashQuery: "param"}).
 *
 * @description
 * Parses the browser location url and makes it available to your application.
 * Any changes to the url are reflected into `$location` service and changes to
 * `$location` are reflected in the browser location url.
 *
 * Notice that using browser's forward/back buttons changes the $location.
 *
 * @example
   <doc:example>
     <doc:source>

         test hash|
         reset hash

         <input type='text' name="$location.hash" size="30">

$location = {{$location}}

     </doc:source>
     <doc:scenario>
       it('should initialize the input field', function() {
         expect(using('.doc-example-live').element('input[name=$location.hash]').val()).
           toBe('!angular.service.$location');
       });

       it('should bind $location.hash to the input field', function() {
         using('.doc-example-live').input('$location.hash').enter('foo');
         expect(browser().location().hash()).toBe('foo');
       });

       it('should set the hash to a test string with test link is presed', function() {
         using('.doc-example-live').element('#ex-test').click();
         expect(using('.doc-example-live').element('input[name=$location.hash]').val()).
           toBe('myPath?name=misko');
       });

       it('should reset $location when reset link is pressed', function() {
         using('.doc-example-live').input('$location.hash').enter('foo');
         using('.doc-example-live').element('#ex-reset').click();
         expect(using('.doc-example-live').element('input[name=$location.hash]').val()).
           toBe('!angular.service.$location');
       });

     </doc:scenario>
    </doc:example>
 */
angularServiceInject("$location", function($browser) {
  var scope = this,
      location = {update:update, updateHash: updateHash},
      lastLocation = {};

  $browser.onHashChange(function() { //register
    update($browser.getUrl());
    copy(location, lastLocation);
    scope.$eval();
  })(); //initialize

  this.$onEval(PRIORITY_FIRST, sync);
  this.$onEval(PRIORITY_LAST, updateBrowser);

  return location;

  // PUBLIC METHODS

  /**
   * @workInProgress
   * @ngdoc method
   * @name angular.service.$location#update
   * @methodOf angular.service.$location
   *
   * @description
   * Updates the location object.
   *
   * Does not immediately update the browser. Instead the browser is updated at the end of $eval()
   * cycle.
   *
   *

       $location.update('http://www.angularjs.org/path#hash?search=x');
       $location.update({host: 'www.google.com', protocol: 'https'});
       $location.update({hashPath: '/path', hashSearch: {a: 'b', x: true}});

   *
   * @param {string|Object} href Full href as a string or object with properties
   */
  function update(href) {
    if (isString(href)) {
      extend(location, parseHref(href));
    } else {
      if (isDefined(href.hash)) {
        extend(href, isString(href.hash) ? parseHash(href.hash) : href.hash);
      }

      extend(location, href);

      if (isDefined(href.hashPath || href.hashSearch)) {
        location.hash = composeHash(location);
      }

      location.href = composeHref(location);
    }
  }

  /**
   * @workInProgress
   * @ngdoc method
   * @name angular.service.$location#updateHash
   * @methodOf angular.service.$location
   *
   * @description
   * Updates the hash fragment part of the url.
   *
   * @see update()
   *
   *

       scope.$location.updateHash('/hp')
         ==> update({hashPath: '/hp'})
       scope.$location.updateHash({a: true, b: 'val'})
         ==> update({hashSearch: {a: true, b: 'val'}})
       scope.$location.updateHash('/hp', {a: true})
         ==> update({hashPath: '/hp', hashSearch: {a: true}})

   *
   * @param {string|Object} path A hashPath or hashSearch object
   * @param {Object=} search A hashSearch object
   */
  function updateHash(path, search) {
    var hash = {};

    if (isString(path)) {
      hash.hashPath = path;
      hash.hashSearch = search || {};
    } else
      hash.hashSearch = path;

    hash.hash = composeHash(hash);

    update({hash: hash});
  }

  // INNER METHODS

  /**
   * Synchronizes all location object properties.
   *
   * User is allowed to change properties, so after property change,
   * location object is not in consistent state.
   *
   * Properties are synced with the following precedence order:
   *
   * - `$location.href`
   * - `$location.hash`
   * - everything else
   *
   * Keep in mind that if the following code is executed:
   *
   * scope.$location.href = 'http://www.angularjs.org/path#a/b'
   *
   * immediately afterwards all other properties are still the old ones...
   *
   * This method checks the changes and update location to the consistent state
   */
  function sync() {
    if (!equals(location, lastLocation)) {
      if (location.href != lastLocation.href) {
        update(location.href);
        return;
      }
      if (location.hash != lastLocation.hash) {
        var hash = parseHash(location.hash);
        updateHash(hash.hashPath, hash.hashSearch);
      } else {
        location.hash = composeHash(location);
        location.href = composeHref(location);
      }
      update(location.href);
    }
  }

  /**
   * If location has changed, update the browser
   * This method is called at the end of $eval() phase
   */
  function updateBrowser() {
    sync();

    if ($browser.getUrl() != location.href) {
      $browser.setUrl(location.href);
      copy(location, lastLocation);
    }
  }

  /**
   * Compose href string from a location object
   *
   * @param {Object} loc The location object with all properties
   * @return {string} Composed href
   */
  function composeHref(loc) {
    var url = toKeyValue(loc.search);
    var port = (loc.port == DEFAULT_PORTS[loc.protocol] ? null : loc.port);

    return loc.protocol  + '://' + loc.host +
          (port ? ':' + port : '') + loc.path +
          (url ? '?' + url : '') + (loc.hash ? '#' + loc.hash : '');
  }

  /**
   * Compose hash string from location object
   *
   * @param {Object} loc Object with hashPath and hashSearch properties
   * @return {string} Hash string
   */
  function composeHash(loc) {
    var hashSearch = toKeyValue(loc.hashSearch);
    //TODO: temporary fix for issue #158
    return escape(loc.hashPath).replace(/%21/gi, '!').replace(/%3A/gi, ':').replace(/%24/gi, '$') +
          (hashSearch ? '?' + hashSearch : '');
  }

  /**
   * Parse href string into location object
   *
   * @param {string} href
   * @return {Object} The location object
   */
  function parseHref(href) {
    var loc = {};
    var match = URL_MATCH.exec(href);

    if (match) {
      loc.href = href.replace(/#$/, '');
      loc.protocol = match[1];
      loc.host = match[3] || '';
      loc.port = match[5] || DEFAULT_PORTS[loc.protocol] || null;
      loc.path = match[6] || '';
      loc.search = parseKeyValue(match[8]);
      loc.hash = match[10] || '';

      extend(loc, parseHash(loc.hash));
    }

    return loc;
  }

  /**
   * Parse hash string into object
   *
   * @param {string} hash
   */
  function parseHash(hash) {
    var h = {};
    var match = HASH_MATCH.exec(hash);

    if (match) {
      h.hash = hash;
      h.hashPath = unescape(match[1] || '');
      h.hashSearch = parseKeyValue(match[3]);
    }

    return h;
  }
}, ['$browser']);
<|endoftext|>


<commit_before>const semver = require('semver');
const fs = require("fs");

let messageList = {};

function updateMessageList() {
    try {
        let content = fs.readFileSync("versionmessage.json");
        if (content) {
                messageList = JSON.parse(content);
                console.log(messageList);
        }
    } catch (e) {
        console.log("versionmessage.json Error: ", e);
        console.log("------------- Continue!");
        // gracefully continue without messages
    }

    // update table every hour
    setTimeout(updateMessageList, 1000 * 60 * 60);
}
updateMessageList();

const message = {
    getForVersion(versionTag) {
        let filteredMsgs = {};

        let myKeys = Object.keys(messageList);
        let matchingKeys = myKeys.filter(semVersionOfMsg => { return semver.satisfies(versionTag, semVersionOfMsg)});
        matchingKeys.map(key => { filteredMsgs[key] = messageList[key] });
        // for "1.0.2" may e.g., return something like:
        // {"1.0.x":"10x - xxx","1.0.2":"102 - yyyy"}
        return filteredMsgs;
    }
};

module.exports = message;
<commit_msg>Dump content of messagelist only once at startup<commit_after>const semver = require('semver');
const fs = require("fs");

let messageList = {};

function updateMessageList(dumpContent) {
    try {
        let content = fs.readFileSync("versionmessage.json");
        if (content) {
                messageList = JSON.parse(content);
                if (dumpContent) {
                    console.log(messageList);
                }
        }
    } catch (e) {
        console.log("versionmessage.json Error: ", e);
        console.log("------------- Continue!");
        // gracefully continue without messages
    }

    // update table every hour
    setTimeout(updateMessageList, 1000 * 60 * 60);
}
updateMessageList(true);

const message = {
    getForVersion(versionTag) {
        let filteredMsgs = {};

        let myKeys = Object.keys(messageList);
        let matchingKeys = myKeys.filter(semVersionOfMsg => { return semver.satisfies(versionTag, semVersionOfMsg)});
        matchingKeys.map(key => { filteredMsgs[key] = messageList[key] });
        // for "1.0.2" may e.g., return something like:
        // {"1.0.x":"10x - xxx","1.0.2":"102 - yyyy"}
        return filteredMsgs;
    }
};

module.exports = message;
<|endoftext|>


<commit_before>process.env.NODE_ENV = 'test';

var should    = require('should'),
    assert    = require('assert'),
    request   = require('supertest'),
    mongoose  = require('mongoose'),
    async     = require('async'),
    fs        = require('fs'),
    uuid      = require('node-uuid'),
    app       = require('./../app.js'),
    apimodel  = require('./../model'),
    test_data;

describe('API routing', function() {

  before(function(done) {
    done();
  });

  after(function(done) {
      done();
  });

  // GET /api/search/venues'
  describe('GET /api/search/venues', function() {

    beforeEach(function (done) {
      // read the json file into test_data, then insert into db with async
      fs.readFile('./test/fixtures/venue-list.json', 'utf-8', function (err, data) {
        if(err) {
          throw err;
        }

        test_data = JSON.parse(data);

        async.mapSeries(test_data, function (venueItem, callback) {
          apimodel.venue.create({
            id: uuid.v4(),
            name: venueItem.name,
            foursquare_id: venueItem.foursquare_id,
            location: [Number(venueItem.lng), Number(venueItem.lat)]
          }, function (err, venue) {
            if(err) {
              callback(err);
            }

            venueItem.id = venue.id;
            callback(null);
          });
        }, function (err, results) {
          if(err) {
            throw err;
          }
          done();
        });

      });
    });

    afterEach(function (done) {
      apimodel.venue.remove(function (err) {
        done();
      });
    });

    it('should respond with JSON', function (done) {
      request(app)
        .get('/api/search/venues?lng=28.985136662087776&lat=41.03652447338111&radius=50')
        .set('Accept', 'application/json')
        .expect('Content-Type', /json/)
        .expect(200, done);
    });

    it('should return more results for a larger radius', function (done) {
      var small_radius, large_radius;
      request(app)
        .get('/api/search/venues?lng=28.985136662087776&lat=41.03652447338111&radius=50')
        .set('Accept', 'application/json')
        .end(function (err, res) {
           if (err) {
            throw err;
          }

          small_radius = res.body.length;

          request(app)
            .get('/api/search/venues?lng=28.985136662087776&lat=41.03652447338111&radius=5000')
            .set('Accept', 'application/json')
            .end(function (err, res) {
              if (err) {
                throw err;
              }

              large_radius = res.body.length;

              large_radius.should.be.above(small_radius);
              done();
            });
        });
    });

    it('should return max 20 results', function (done) {
      request(app)
        .get('/api/search/venues?lng=28.985136662087776&lat=41.03652447338111&radius=5000&limit=20')
        .set('Accept', 'application/json')
        .end(function (err, res) {
           if (err) {
            throw err;
          }

          res.body.length.should.not.be.above(20);
          done();
        });
    });

    it('should return exactly 1 result', function (done) {
      request(app)
        .get('/api/search/venues?lng=28.985136662087776&lat=41.03652447338111&radius=5000&limit=1')
        .set('Accept', 'application/json')
        .end(function (err, res) {
           if (err) {
            throw err;
          }

          res.body.length.should.eql(1);
          done();
        });
    });
  });
});<commit_msg>added tests for max_date param<commit_after>process.env.NODE_ENV = 'test';

var should    = require('should'),
    assert    = require('assert'),
    request   = require('supertest'),
    mongoose  = require('mongoose'),
    async     = require('async'),
    fs        = require('fs'),
    uuid      = require('node-uuid'),
    app       = require('./../app.js'),
    apimodel  = require('./../model'),
    test_data;

describe('API routing', function() {

  before(function(done) {
    done();
  });

  after(function(done) {
      done();
  });

  // GET /api/search/venues'
  describe('GET /api/search/venues', function() {

    beforeEach(function (done) {
      // read the json file into test_data, then insert into db with async
      fs.readFile('./test/fixtures/venue-list.json', 'utf-8', function (err, data) {
        if(err) {
          throw err;
        }

        test_data = JSON.parse(data);
        var latest_date = Date.now();

        async.mapSeries(test_data, function (venueItem, callback) {
          apimodel.venue.create({
            id: uuid.v4(),
            name: venueItem.name,
            foursquare_id: venueItem.foursquare_id,
            location: [Number(venueItem.lng), Number(venueItem.lat)],
            date_added: latest_date
          }, function (err, venue) {
            if(err) {
              callback(err);
            }

            venueItem.id = venue.id;
            venueItem.date_added = latest_date;

            latest_date = latest_date - 43200000;

            callback(null);
          });
        }, function (err, results) {
          if(err) {
            throw err;
          }
          done();
        });

      });
    });

    afterEach(function (done) {
      apimodel.venue.remove(function (err) {
        done();
      });
    });

    it('should respond with JSON', function (done) {
      request(app)
        .get('/api/search/venues?lng=28.985136662087776&lat=41.03652447338111&radius=50')
        .set('Accept', 'application/json')
        .expect('Content-Type', /json/)
        .expect(200, done);
    });

    it('should return more results for a larger radius', function (done) {
      var small_radius, large_radius;
      request(app)
        .get('/api/search/venues?lng=28.985136662087776&lat=41.03652447338111&radius=50')
        .set('Accept', 'application/json')
        .end(function (err, res) {
           if (err) {
            throw err;
          }

          small_radius = res.body.length;

          request(app)
            .get('/api/search/venues?lng=28.985136662087776&lat=41.03652447338111&radius=5000')
            .set('Accept', 'application/json')
            .end(function (err, res) {
              if (err) {
                throw err;
              }

              large_radius = res.body.length;

              large_radius.should.be.above(small_radius);
              done();
            });
        });
    });

    it('should return max 20 results', function (done) {
      request(app)
        .get('/api/search/venues?lng=28.985136662087776&lat=41.03652447338111&radius=5000&limit=20')
        .set('Accept', 'application/json')
        .end(function (err, res) {
           if (err) {
            throw err;
          }

          res.body.length.should.not.be.above(20);
          done();
        });
    });

    it('should return exactly 1 result', function (done) {
      request(app)
        .get('/api/search/venues?lng=28.985136662087776&lat=41.03652447338111&radius=5000&limit=1')
        .set('Accept', 'application/json')
        .end(function (err, res) {
           if (err) {
            throw err;
          }

          res.body.length.should.eql(1);
          done();
        });
    });

    it('should return venues in descending order', function (done) {
      request(app)
        .get('/api/search/venues?limit=30')
        .end(function(err, res) {
          if (err) {
            throw err;
          }

          for(var i = 1, len = res.body.length; i < len; ++i) {
            res.body[i].date_added.should.not.be.above(res.body[i-1].date_added);
          }

          done();
        });
    });

    it('should return venues inserted before the specified date', function (done) {
      request(app)
        .get('/api/search/venues?max_date=' + test_data[10].date_added)
        .end(function(err, res) {
          if (err) {
            throw err;
          }

          test_data[10].date_added.should.not.be.above(res.body[0].date_added)

          for(var i = 1, len = res.body.length; i < len; ++i) {
            res.body[i].date_added.should.not.be.above(res.body[i-1].date_added);
          }

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


<commit_before>import * as xmlTesting from './xmlTesting.js';

describe('Jamilih - Other Methods', function () {
  beforeEach(() => {
    if ($('#mapTest')) {
      $('#mapTest').remove();
    }
  });
  it('jml.toJMLString()', () => {
    const br = document.createElement('br');
    const expected = '["br",{"xmlns":"http://www.w3.org/1999/xhtml"}]';
    const result = jml.toJMLString(br);
    assert.deepEqual(result, expected, 'Empty element with no attributes');
  });
  it('jml.toHTML()', () => {
    const expected = '
';
    const result = jml.toHTML('br');
    assert.deepEqual(result, expected, 'Empty element with no attributes');
  });
  it('jml.toXML()', () => {
    const expected = '
';
    const result = jml.toXML('br');
    assert.deepEqual(result, expected, 'Empty element with no attributes');
  });
  it('jml.toDOM()', () => {
    const expected = jml('br');
    const result = jml.toDOM('br');
    assert.deepEqual(expected.nodeName, result.nodeName, '`nodeName` equal');
  });
  it('jml.toXMLDOMString()', () => {
    const expected = jml.toXMLDOMString('br');
    const result = jml.toXML('br');
    assert.deepEqual(result, expected, 'Empty element with no attributes');
  });
  it('jml.toDOMString()', () => {
    const expected = jml.toDOMString('br');
    const result = jml.toHTML('br');
    assert.deepEqual(result, expected, 'Empty element with no attributes');
  });
  ['weak', 'strong'].forEach((mapType) => {
    it(`jml.${mapType}()`, () => {
      const [myMap, elem] = jml[mapType]({
        localVar: 'localValue',
        myMethod (el, arg1) {
          return arg1 + ' ' + this.localVar + ' ' + el.querySelector('input').value;
        }
      }, 'div', {id: 'mapTest'}, [
        ['input', {value: '100', $on: {
          input () {
            xmlTesting.matches(
              myMap.invoke(this.parentNode, 'myMethod', 'internal test'),
              'internal test localValue 1001',
              `Jamilih${mapType === 'weak' ? 'Weak' : ''}Map \`invoke\` method with arguments and \`this\``
            );
          }
        }}],
        ['div', {id: 'clickArea', $data: {
          localVariable: 8,
          test (el, arg1) {
            xmlTesting.matches(
              arg1 + ' ' + el.id + this.localVariable,
              'arg1 clickArea8',
              `Attached Jamilih${mapType === 'weak' ? 'Weak' : ''}Map $data method invoked by click listener with arguments and \`this\``
            );
          }
        }, $on: {
          click () {
            myMap.invoke(this, 'test', 'arg1');
          }
        }}]
      ], body);
      xmlTesting.matches(
        myMap.invoke(elem, 'myMethod', 'external test'),
        'external test localValue 100',
        `Externally invoke Jamilih${mapType === 'weak' ? 'Weak' : ''}Map \`invoke\` method with arguments and \`this\``
      );
      xmlTesting.matches(
        myMap.invoke('#mapTest', 'myMethod', 'external test'),
        'external test localValue 100',
        `Externally invoke Jamilih${mapType === 'weak' ? 'Weak' : ''}Map \`invoke\` method with arguments and \`this\``
      );
      xmlTesting.matches(
        myMap.get('#mapTest').localVar, // Test overridden `get` accepting selectors also
        'localValue',
        `Externally retrieve Jamilih${mapType === 'weak' ? 'Weak' : ''}Map-associated element by selector`
      );

      const mapInput = $('#mapTest').firstElementChild;
      mapInput.value = '1001';
      mapInput.dispatchEvent(
        new window.Event('input')
      );
      const mapDiv = $('#clickArea');
      mapDiv.dispatchEvent(new window.Event('click'));
    });
  });
  describe('setDocument', function () {
    afterEach(() => {
      jml.setDocument(document);
    });
    it('setDocument', function () {
      expect(() => {
        jml.setDocument();
      }).to.not.throw();
    });
  });
});

describe('Jamilih extras', function () {
  let div;
  beforeEach(() => {
    if (div) {
      div.remove();
    }
    div = jml('div', {id: 'extraHolder'}, body);
  });
  it('$', function () {
    body.append(jml('br'), jml('br'));
    const br = $('br');
    expect(br.localName).to.equal('br');
  });
  it('$$', function () {
    body.append(jml('br'), jml('br'));
    const brs = $$('br');
    expect(brs.length).to.equal(2);
  });
  it('nbsp', function () {
    expect(nbsp).to.equal('\u00A0');
  });
});
<commit_msg>- Testing: Fix for browser<commit_after>import * as xmlTesting from './xmlTesting.js';

describe('Jamilih - Other Methods', function () {
  beforeEach(() => {
    if ($('#mapTest')) {
      $('#mapTest').remove();
    }
  });
  it('jml.toJMLString()', () => {
    const br = document.createElement('br');
    const expected = '["br",{"xmlns":"http://www.w3.org/1999/xhtml"}]';
    const result = jml.toJMLString(br);
    assert.deepEqual(result, expected, 'Empty element with no attributes');
  });
  it('jml.toHTML()', () => {
    const expected = '
';
    const result = jml.toHTML('br');
    assert.deepEqual(result, expected, 'Empty element with no attributes');
  });
  it('jml.toXML()', () => {
    const expected = '
';
    const result = jml.toXML('br');
    assert.deepEqual(result, expected, 'Empty element with no attributes');
  });
  it('jml.toDOM()', () => {
    const expected = jml('br');
    const result = jml.toDOM('br');
    assert.deepEqual(expected.nodeName, result.nodeName, '`nodeName` equal');
  });
  it('jml.toXMLDOMString()', () => {
    const expected = jml.toXMLDOMString('br');
    const result = jml.toXML('br');
    assert.deepEqual(result, expected, 'Empty element with no attributes');
  });
  it('jml.toDOMString()', () => {
    const expected = jml.toDOMString('br');
    const result = jml.toHTML('br');
    assert.deepEqual(result, expected, 'Empty element with no attributes');
  });
  ['weak', 'strong'].forEach((mapType) => {
    it(`jml.${mapType}()`, () => {
      const [myMap, elem] = jml[mapType]({
        localVar: 'localValue',
        myMethod (el, arg1) {
          return arg1 + ' ' + this.localVar + ' ' + el.querySelector('input').value;
        }
      }, 'div', {id: 'mapTest'}, [
        ['input', {value: '100', $on: {
          input () {
            xmlTesting.matches(
              myMap.invoke(this.parentNode, 'myMethod', 'internal test'),
              'internal test localValue 1001',
              `Jamilih${mapType === 'weak' ? 'Weak' : ''}Map \`invoke\` method with arguments and \`this\``
            );
          }
        }}],
        ['div', {id: 'clickArea', $data: {
          localVariable: 8,
          test (el, arg1) {
            xmlTesting.matches(
              arg1 + ' ' + el.id + this.localVariable,
              'arg1 clickArea8',
              `Attached Jamilih${mapType === 'weak' ? 'Weak' : ''}Map $data method invoked by click listener with arguments and \`this\``
            );
          }
        }, $on: {
          click () {
            myMap.invoke(this, 'test', 'arg1');
          }
        }}]
      ], body);
      xmlTesting.matches(
        myMap.invoke(elem, 'myMethod', 'external test'),
        'external test localValue 100',
        `Externally invoke Jamilih${mapType === 'weak' ? 'Weak' : ''}Map \`invoke\` method with arguments and \`this\``
      );
      xmlTesting.matches(
        myMap.invoke('#mapTest', 'myMethod', 'external test'),
        'external test localValue 100',
        `Externally invoke Jamilih${mapType === 'weak' ? 'Weak' : ''}Map \`invoke\` method with arguments and \`this\``
      );
      xmlTesting.matches(
        myMap.get('#mapTest').localVar, // Test overridden `get` accepting selectors also
        'localValue',
        `Externally retrieve Jamilih${mapType === 'weak' ? 'Weak' : ''}Map-associated element by selector`
      );

      const mapInput = $('#mapTest').firstElementChild;
      mapInput.value = '1001';
      mapInput.dispatchEvent(
        new window.Event('input')
      );
      const mapDiv = $('#clickArea');
      mapDiv.dispatchEvent(new window.Event('click'));
    });
  });
  describe('setDocument', function () {
    afterEach(() => {
      jml.setDocument(document);
    });
    it('setDocument', function () {
      expect(() => {
        jml.setDocument();
      }).to.not.throw();
    });
  });
});

describe('Jamilih extras', function () {
  let div;
  beforeEach(() => {
    if (div) {
      div.remove();
    }
    div = jml('div', {id: 'extraHolder'}, body);
  });
  it('$', function () {
    body.querySelector('#extraHolder').append(jml('br'), jml('br'));
    const br = $('br');
    expect(br.localName).to.equal('br');
  });
  it('$$', function () {
    body.querySelector('#extraHolder').append(jml('br'), jml('br'));
    const brs = $$('br');
    expect(brs.length).to.equal(2);
  });
  it('nbsp', function () {
    expect(nbsp).to.equal('\u00A0');
  });
});
<|endoftext|>


<commit_before>/* @flow weak */

/**
 * OfflineMobile Android Index
 * Sustainable Solutions (NZ) Ltd. 2016
 */

import React, {
  StyleSheet,
  TextInput,
  View,
} from 'react-native';

import { SearchBar } from '../widgets';
import {
  Cell,
  DataTable,
  Header,
  HeaderCell,
  Row,
} from '../widgets/DataTable';

import { ListView } from 'realm/react-native';

import globalStyles from '../globalStyles';

const OBJECT_TYPES = [
  'Address',
  'Item',
  'ItemLine',
  'ItemDepartment',
  'ItemCategory',
  'Transaction',
  'TransactionLine',
  'TransactionCategory',
  'MasterList',
  'MasterListLine',
  'Name',
  'Requisition',
  'RequisitionLine',
  'Setting',
  'SyncOut',
  'Stocktake',
  'StocktakeLine',
  'User',
];

export class RealmExplorer extends React.Component {
  constructor(props) {
    super(props);
    const dataSource = new ListView.DataSource({
      rowHasChanged: (row1, row2) => row1 !== row2,
    });
    this.state = {
      data: null,
      dataSource: dataSource,
    };
    this.onSearchChange = this.onSearchChange.bind(this);
    this.renderHeader = this.renderHeader.bind(this);
    this.renderRow = this.renderRow.bind(this);
  }

  componentWillMount() {
    const data = this.props.database.objects('User');
    this.setState({
      data: data,
      dataSource: this.state.dataSource.cloneWithRows(data),
    });
  }

  onSearchChange(event) {
    const term = event.nativeEvent.text;
    if (OBJECT_TYPES.indexOf(term) < 0) return;
    const data = this.props.database.objects(term);
    this.setState({
      data: data,
      dataSource: this.state.dataSource.cloneWithRows(data),
    });
  }

  renderHeader() {
    const headerCells = [];
    if (this.state.data && this.state.data.length > 0) {
      const firstObject = this.state.data[0];
      for (let field in firstObject) {
        if (firstObject.hasOwnProperty(field)) {
          headerCells.push(
            <HeaderCell
              key={field}
              style={globalStyles.headerCell}
              textStyle={globalStyles.text}
              width={1}
              text={field}
            />
          );
        }
      }
    }
    return (
      <Header style={globalStyles.header}>
        {headerCells}
      </Header>
    );
  }

  renderRow(item) {
    const cells = [];
    if (this.state.data && this.state.data.length > 0) {
      const firstObject = this.state.data[0];
      for (const field in firstObject) {
        if (firstObject.hasOwnProperty(field)) {
          cells.push(
            <Cell
              key={field}
              style={globalStyles.cell}
              textStyle={globalStyles.text}
              width={1}
            >
              {item[field]
                && ((typeof item[field] === 'string')
                || (typeof item[field] === 'number')
                || (typeof item[field].getMonth === 'function'))
                && item[field]}
            </Cell>
          );
        }
      }
    }
    return (
      <Row style={globalStyles.row}>
        {cells}
      </Row>
    );
  }

  render() {
    return (
      <View style={[globalStyles.container, this.props.style]}>
        <SearchBar onChange={(event) => this.onSearchChange(event)} />
        <DataTable
          style={globalStyles.container}
          listViewStyle={globalStyles.container}
          dataSource={this.state.dataSource}
          renderRow={this.renderRow}
          renderHeader={this.renderHeader}
        />
      </View>
    );
  }
}

RealmExplorer.propTypes = {
  database: React.PropTypes.object.isRequired,
  navigateTo: React.PropTypes.func.isRequired,
  style: View.propTypes.style,
};

const localStyles = StyleSheet.create({
  horizontalContainer: {
    flexDirection: 'row',
  },
});
<commit_msg>Removing unused lines from RealmExplorer.js<commit_after>/* @flow weak */

/**
 * OfflineMobile Android Index
 * Sustainable Solutions (NZ) Ltd. 2016
 */

import React, {
  StyleSheet,
  View,
} from 'react-native';

import { SearchBar } from '../widgets';
import {
  Cell,
  DataTable,
  Header,
  HeaderCell,
  Row,
} from '../widgets/DataTable';

import { ListView } from 'realm/react-native';

import globalStyles from '../globalStyles';

const OBJECT_TYPES = [
  'Address',
  'Item',
  'ItemLine',
  'ItemDepartment',
  'ItemCategory',
  'Transaction',
  'TransactionLine',
  'TransactionCategory',
  'MasterList',
  'MasterListLine',
  'Name',
  'Requisition',
  'RequisitionLine',
  'Setting',
  'SyncOut',
  'Stocktake',
  'StocktakeLine',
  'User',
];

export class RealmExplorer extends React.Component {
  constructor(props) {
    super(props);
    const dataSource = new ListView.DataSource({
      rowHasChanged: (row1, row2) => row1 !== row2,
    });
    this.state = {
      data: null,
      dataSource: dataSource,
    };
    this.onSearchChange = this.onSearchChange.bind(this);
    this.renderHeader = this.renderHeader.bind(this);
    this.renderRow = this.renderRow.bind(this);
  }

  componentWillMount() {
    const data = this.props.database.objects('User');
    this.setState({
      data: data,
      dataSource: this.state.dataSource.cloneWithRows(data),
    });
  }

  onSearchChange(event) {
    const term = event.nativeEvent.text;
    if (OBJECT_TYPES.indexOf(term) < 0) return;
    const data = this.props.database.objects(term);
    this.setState({
      data: data,
      dataSource: this.state.dataSource.cloneWithRows(data),
    });
  }

  renderHeader() {
    const headerCells = [];
    if (this.state.data && this.state.data.length > 0) {
      const firstObject = this.state.data[0];
      for (let field in firstObject) {
        if (firstObject.hasOwnProperty(field)) {
          headerCells.push(
            <HeaderCell
              key={field}
              style={globalStyles.headerCell}
              textStyle={globalStyles.text}
              width={1}
              text={field}
            />
          );
        }
      }
    }
    return (
      <Header style={globalStyles.header}>
        {headerCells}
      </Header>
    );
  }

  renderRow(item) {
    const cells = [];
    if (this.state.data && this.state.data.length > 0) {
      const firstObject = this.state.data[0];
      for (const field in firstObject) {
        if (firstObject.hasOwnProperty(field)) {
          cells.push(
            <Cell
              key={field}
              style={globalStyles.cell}
              textStyle={globalStyles.text}
              width={1}
            >
              {item[field]
                && ((typeof item[field] === 'string')
                || (typeof item[field] === 'number')
                || (typeof item[field].getMonth === 'function'))
                && item[field]}
            </Cell>
          );
        }
      }
    }
    return (
      <Row style={globalStyles.row}>
        {cells}
      </Row>
    );
  }

  render() {
    return (
      <View style={[globalStyles.container, this.props.style]}>
        <SearchBar onChange={(event) => this.onSearchChange(event)} />
        <DataTable
          style={globalStyles.container}
          listViewStyle={globalStyles.container}
          dataSource={this.state.dataSource}
          renderRow={this.renderRow}
          renderHeader={this.renderHeader}
        />
      </View>
    );
  }
}

RealmExplorer.propTypes = {
  database: React.PropTypes.object.isRequired,
  navigateTo: React.PropTypes.func.isRequired,
  style: View.propTypes.style,
};
<|endoftext|>


<commit_before>import {
    GET_LIST,
    GET_MANY,
    GET_MANY_REFERENCE,
    QUERY_TYPES,
} from './constants';

/**
 * @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
 * @param {Object} apolloParams The apollo request params
 * @returns {Object} The key to look for in the response data, depending on the type
 *                   (this is the name of the operation defined in the graphql query or mutation)
 */
const getApolloResultKey = (type, apolloParams) => (
    QUERY_TYPES.includes(type)
    ? apolloParams.query.definitions[0].name.value
    : apolloParams.mutation.definitions[0].selectionSet.selections[0].name.value
);

export const buildGetListErrorMessage = resource =>
    `The data returned by the graphql endpoint for the GET_LIST query on resource ${resource} does not contains a \`totalCount\` property which is needed to build the pagination. The query result must conform to this schema: \`{ totalCount: Int, items: [] }\``; // eslint-disable-line

/**
 * @param {Object} response Apollo response
 * @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
 * @param {String} resource Name of the resource to fetch, e.g. 'posts'
 * @param {Object} apolloParams The apollo request params, depending on the type
 * @returns {Object} REST response
 */
export default (response, type, resource, apolloParams) => {
    const { data } = response;
    const dataKey = getApolloResultKey(type, apolloParams);
    const dataForType = data[dataKey];

    switch (type) {
    case GET_LIST: {
        if (typeof dataForType.totalCount !== 'number') {
            throw new Error(buildGetListErrorMessage(resource));
        }
        return {
            data: dataForType.items.map(x => x),
            total: dataForType.totalCount,
        };
    }

    case GET_MANY:
    case GET_MANY_REFERENCE: {
        if (dataForType.totalCount) {
            return dataForType.items.map(x => x);
        }

        return dataForType;
    }

    default:
        return dataForType;
    }
};
<commit_msg>Fixed bug that used name of the query instead of the name of the query field<commit_after>import {
    GET_LIST,
    GET_MANY,
    GET_MANY_REFERENCE,
    QUERY_TYPES,
} from './constants';

/**
 * @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
 * @param {Object} apolloParams The apollo request params
 * @returns {Object} The key to look for in the response data, depending on the type
 *                   (this is the name of the operation defined in the graphql query or mutation)
 */
const getApolloResultKey = (type, apolloParams) => (
    QUERY_TYPES.includes(type)
    ? apolloParams.query.definitions[0].selectionSet.selections[0].name.value
    : apolloParams.mutation.definitions[0].selectionSet.selections[0].name.value
);

export const buildGetListErrorMessage = resource =>
    `The data returned by the graphql endpoint for the GET_LIST query on resource ${resource} does not contains a \`totalCount\` property which is needed to build the pagination. The query result must conform to this schema: \`{ totalCount: Int, items: [] }\``; // eslint-disable-line

/**
 * @param {Object} response Apollo response
 * @param {String} type One of the constants appearing at the top if this file, e.g. 'UPDATE'
 * @param {String} resource Name of the resource to fetch, e.g. 'posts'
 * @param {Object} apolloParams The apollo request params, depending on the type
 * @returns {Object} REST response
 */
export default (response, type, resource, apolloParams) => {
    const { data } = response;
    const dataKey = getApolloResultKey(type, apolloParams);
    const dataForType = data[dataKey];

    switch (type) {
    case GET_LIST: {
        if (typeof dataForType.totalCount !== 'number') {
            throw new Error(buildGetListErrorMessage(resource));
        }
        return {
            data: dataForType.items.map(x => x),
            total: dataForType.totalCount,
        };
    }

    case GET_MANY:
    case GET_MANY_REFERENCE: {
        if (dataForType.totalCount) {
            return dataForType.items.map(x => x);
        }

        return dataForType;
    }

    default:
        return dataForType;
    }
};
<|endoftext|>


<commit_before>import $ from "jquery";
import Base from "@patternslib/patternslib/src/core/base";
import I18n from "../../core/i18n";
import utils from "../../core/utils";

export default Base.extend({
    name: "select2",
    trigger: ".pat-select2",
    parser: "mockup",
    defaults: {
        separator: ",",
    },
    initializeValues: function () {
        var self = this;
        // Init Selection ---------------------------------------------
        if (self.options.initialValues) {
            self.options.id = function (term) {
                return term.id;
            };
            self.options.initSelection = function ($el, callback) {
                var data = [],
                    value = $el.val(),
                    seldefaults = self.options.initialValues;

                // Create the initSelection value that contains the default selection,
                // but in a javascript object
                if (
                    typeof self.options.initialValues === "string" &&
                    self.options.initialValues !== ""
                ) {
                    // if default selection value starts with a '{', then treat the value as
                    // a JSON object that needs to be parsed
                    if (self.options.initialValues[0] === "{") {
                        seldefaults = JSON.parse(self.options.initialValues);
                    }
                    // otherwise, treat the value as a list, separated by the defaults.separator value of
                    // strings in the format "id:text", and convert it to an object
                    else {
                        seldefaults = {};
                        $(self.options.initialValues.split(self.options.separator)).each(
                            function () {
                                var selection = this.split(":");
                                var id = $.trim(selection[0]);
                                var text = $.trim(selection[1]);
                                seldefaults[id] = text;
                            }
                        );
                    }
                }

                $(value.split(self.options.separator)).each(function () {
                    var text = this;
                    if (seldefaults[this]) {
                        text = seldefaults[this];
                    }
                    data.push({
                        id: utils.removeHTML(this),
                        text: utils.removeHTML(text),
                    });
                });
                callback(data);
            };
        }
    },
    initializeTags: function () {
        var self = this;
        if (self.options.tags && typeof self.options.tags === "string") {
            if (self.options.tags.substr(0, 1) === "[") {
                self.options.tags = JSON.parse(self.options.tags);
            } else {
                self.options.tags = self.options.tags.split(self.options.separator);
            }
        }

        if (self.options.tags && !self.options.allowNewItems) {
            self.options.data = $.map(self.options.tags, function (value, i) {
                return { id: value, text: value };
            });
            self.options.multiple = true;
            delete self.options.tags;
        }
    },
    initializeOrdering: function () {
        if (!this.options.orderable) {
            return;
        }
        // TODO: fix sorting!
        this.$el.on("change", async () => {
            let Sortable = await import("sortablejs");
            Sortable = Sortable.default;

            const sortable_el = this.$select2[0].querySelector(".select2-choices");

            new Sortable(sortable_el, {
                draggable: "li",
                dragClass: "select2-choice-dragging",
                chosenClass: "dragging",
                onStart: () => this.$el.select2("onSortStart"),
                onEnd: () => this.$el.select2("onSortEnd"),
            });
        });
    },
    initializeSelect2: async function () {
        import("select2/select2.css");
        import("./select2.scss");
        await import("select2");
        try {
            await import(`select2/select2_locale_${this.options.language}`);
        } catch {
            console.warn("Language file could not be loaded", this.options.language);
        }

        var self = this;
        self.options.formatResultCssClass = function (ob) {
            if (ob.id) {
                return (
                    "select2-option-" +
                    ob.id.toLowerCase().replace(/[ \:\)\(\[\]\{\}\_\+\=\&\*\%\#]/g, "-")
                );
            }
        };

        function callback(action, e) {
            if (action) {
                if (self.options.debug) {
                    console.debug("callback", action, e);
                }
                if (typeof action === "string") {
                    action = window[action];
                }
                return action(e);
            } else {
                return action;
            }
        }
        $(self.el).select2(self.options);
        self.$el.on("select2-selected", function (e) {
            callback(self.options.onSelected, e);
        });
        self.$el.on("select2-selecting", function (e) {
            callback(self.options.onSelecting, e);
        });
        self.$el.on("select2-deselecting", function (e) {
            callback(self.options.onDeselecting, e);
        });
        self.$el.on("select2-deselected", function (e) {
            callback(self.options.onDeselected, e);
        });
        self.$select2 = self.$el.parent().find(".select2-container");
        self.$el.parent().off("close.plone-modal.patterns");
        if (self.options.orderable) {
            self.$select2.addClass("select2-orderable");
        }
    },
    opened: function () {
        var self = this;
        var isOpen = $(".select2-dropdown-open", self.$el.parent()).length === 1;
        return isOpen;
    },
    init: async function () {
        var self = this;

        var i18n = new I18n();
        self.options.language = i18n.currentLanguage;
        self.options.allowNewItems = self.options.hasOwnProperty("allowNewItems")
            ? JSON.parse(self.options.allowNewItems)
            : true;

        if (self.options.ajax || self.options.vocabularyUrl) {
            if (self.options.vocabularyUrl) {
                self.options.multiple =
                    self.options.multiple === undefined ? true : self.options.multiple;
                self.options.ajax = self.options.ajax || {};
                self.options.ajax.url = self.options.vocabularyUrl;
                // XXX removing the following function does'nt break tests. dead code?
                self.options.initSelection = function ($el, callback) {
                    var data = [],
                        value = $el.val();
                    $(value.split(self.options.separator)).each(function () {
                        var val = utils.removeHTML(this);
                        data.push({ id: val, text: val });
                    });
                    callback(data);
                };
            }

            var queryTerm = "";
            self.options.ajax = $.extend(
                {
                    quietMillis: 300,
                    data: function (term, page) {
                        queryTerm = term;
                        return {
                            query: term,
                            page_limit: 10,
                            page: page,
                        };
                    },
                    results: function (data, page) {
                        var results = data.results;
                        if (self.options.vocabularyUrl) {
                            var dataIds = [];
                            $.each(data.results, function (i, item) {
                                dataIds.push(item.id);
                            });
                            results = [];

                            var haveResult =
                                queryTerm === "" || $.inArray(queryTerm, dataIds) >= 0;
                            if (self.options.allowNewItems && !haveResult) {
                                queryTerm = utils.removeHTML(queryTerm);
                                results.push({
                                    id: queryTerm,
                                    text: queryTerm,
                                });
                            }

                            $.each(data.results, function (i, item) {
                                results.push(item);
                            });
                        }
                        return { results: results };
                    },
                },
                self.options.ajax
            );
        } else if (self.options.multiple && self.$el.is("select")) {
            // Multiselects need to be converted to input[type=hidden]
            // for Select2
            var vals = self.$el.val() || [];
            var options = $.map(self.$el.find("option"), function (o) {
                return { text: $(o).html(), id: o.value };
            });
            var $hidden = $('<input type="hidden" />');
            $hidden.val(vals.join(self.options.separator));
            $hidden.attr("class", self.$el.attr("class"));
            $hidden.attr("name", self.$el.attr("name"));
            $hidden.attr("id", self.$el.attr("id"));
            self.$orig = self.$el;
            self.$el.replaceWith($hidden);
            self.$el = $hidden;
            self.options.data = options;
        }

        self.initializeValues();
        self.initializeTags();
        self.initializeOrdering();
        await self.initializeSelect2();
    },
});
<commit_msg>fix(pat select2): Fix initialization of ordering for pre-populated items. Fixes: #1205.<commit_after>import $ from "jquery";
import Base from "@patternslib/patternslib/src/core/base";
import I18n from "../../core/i18n";
import utils from "../../core/utils";

export default Base.extend({
    name: "select2",
    trigger: ".pat-select2",
    parser: "mockup",
    defaults: {
        separator: ",",
    },
    initializeValues: function () {
        var self = this;
        // Init Selection ---------------------------------------------
        if (self.options.initialValues) {
            self.options.id = function (term) {
                return term.id;
            };
            self.options.initSelection = function ($el, callback) {
                var data = [],
                    value = $el.val(),
                    seldefaults = self.options.initialValues;

                // Create the initSelection value that contains the default selection,
                // but in a javascript object
                if (
                    typeof self.options.initialValues === "string" &&
                    self.options.initialValues !== ""
                ) {
                    // if default selection value starts with a '{', then treat the value as
                    // a JSON object that needs to be parsed
                    if (self.options.initialValues[0] === "{") {
                        seldefaults = JSON.parse(self.options.initialValues);
                    }
                    // otherwise, treat the value as a list, separated by the defaults.separator value of
                    // strings in the format "id:text", and convert it to an object
                    else {
                        seldefaults = {};
                        $(self.options.initialValues.split(self.options.separator)).each(
                            function () {
                                var selection = this.split(":");
                                var id = $.trim(selection[0]);
                                var text = $.trim(selection[1]);
                                seldefaults[id] = text;
                            }
                        );
                    }
                }

                $(value.split(self.options.separator)).each(function () {
                    var text = this;
                    if (seldefaults[this]) {
                        text = seldefaults[this];
                    }
                    data.push({
                        id: utils.removeHTML(this),
                        text: utils.removeHTML(text),
                    });
                });
                callback(data);
            };
        }
    },
    initializeTags: function () {
        var self = this;
        if (self.options.tags && typeof self.options.tags === "string") {
            if (self.options.tags.substr(0, 1) === "[") {
                self.options.tags = JSON.parse(self.options.tags);
            } else {
                self.options.tags = self.options.tags.split(self.options.separator);
            }
        }

        if (self.options.tags && !self.options.allowNewItems) {
            self.options.data = $.map(self.options.tags, function (value, i) {
                return { id: value, text: value };
            });
            self.options.multiple = true;
            delete self.options.tags;
        }
    },
    initializeOrdering: async function () {
        if (!this.options.orderable) {
            return;
        }
        const Sortable = (await import("sortablejs")).default;
        const _initializeOrdering = () => {
            const sortable_el = this.$select2[0].querySelector(".select2-choices");
            new Sortable(sortable_el, {
                draggable: "li",
                dragClass: "select2-choice-dragging",
                chosenClass: "dragging",
                onStart: () => this.$el.select2("onSortStart"),
                onEnd: () => this.$el.select2("onSortEnd"),
            });
        };
        this.$el.on("change", _initializeOrdering.bind(this));
        _initializeOrdering();
    },
    initializeSelect2: async function () {
        import("select2/select2.css");
        import("./select2.scss");
        await import("select2");
        try {
            await import(`select2/select2_locale_${this.options.language}`);
        } catch {
            console.warn("Language file could not be loaded", this.options.language);
        }

        var self = this;
        self.options.formatResultCssClass = function (ob) {
            if (ob.id) {
                return (
                    "select2-option-" +
                    ob.id.toLowerCase().replace(/[ \:\)\(\[\]\{\}\_\+\=\&\*\%\#]/g, "-")
                );
            }
        };

        function callback(action, e) {
            if (action) {
                if (self.options.debug) {
                    console.debug("callback", action, e);
                }
                if (typeof action === "string") {
                    action = window[action];
                }
                return action(e);
            } else {
                return action;
            }
        }
        $(self.el).select2(self.options);
        self.$el.on("select2-selected", function (e) {
            callback(self.options.onSelected, e);
        });
        self.$el.on("select2-selecting", function (e) {
            callback(self.options.onSelecting, e);
        });
        self.$el.on("select2-deselecting", function (e) {
            callback(self.options.onDeselecting, e);
        });
        self.$el.on("select2-deselected", function (e) {
            callback(self.options.onDeselected, e);
        });
        self.$select2 = self.$el.parent().find(".select2-container");
        self.$el.parent().off("close.plone-modal.patterns");
        if (self.options.orderable) {
            self.$select2.addClass("select2-orderable");
        }
    },
    opened: function () {
        var self = this;
        var isOpen = $(".select2-dropdown-open", self.$el.parent()).length === 1;
        return isOpen;
    },
    init: async function () {
        var self = this;

        var i18n = new I18n();
        self.options.language = i18n.currentLanguage;
        self.options.allowNewItems = self.options.hasOwnProperty("allowNewItems")
            ? JSON.parse(self.options.allowNewItems)
            : true;

        if (self.options.ajax || self.options.vocabularyUrl) {
            if (self.options.vocabularyUrl) {
                self.options.multiple =
                    self.options.multiple === undefined ? true : self.options.multiple;
                self.options.ajax = self.options.ajax || {};
                self.options.ajax.url = self.options.vocabularyUrl;
                // XXX removing the following function does'nt break tests. dead code?
                self.options.initSelection = function ($el, callback) {
                    var data = [],
                        value = $el.val();
                    $(value.split(self.options.separator)).each(function () {
                        var val = utils.removeHTML(this);
                        data.push({ id: val, text: val });
                    });
                    callback(data);
                };
            }

            var queryTerm = "";
            self.options.ajax = $.extend(
                {
                    quietMillis: 300,
                    data: function (term, page) {
                        queryTerm = term;
                        return {
                            query: term,
                            page_limit: 10,
                            page: page,
                        };
                    },
                    results: function (data, page) {
                        var results = data.results;
                        if (self.options.vocabularyUrl) {
                            var dataIds = [];
                            $.each(data.results, function (i, item) {
                                dataIds.push(item.id);
                            });
                            results = [];

                            var haveResult =
                                queryTerm === "" || $.inArray(queryTerm, dataIds) >= 0;
                            if (self.options.allowNewItems && !haveResult) {
                                queryTerm = utils.removeHTML(queryTerm);
                                results.push({
                                    id: queryTerm,
                                    text: queryTerm,
                                });
                            }

                            $.each(data.results, function (i, item) {
                                results.push(item);
                            });
                        }
                        return { results: results };
                    },
                },
                self.options.ajax
            );
        } else if (self.options.multiple && self.$el.is("select")) {
            // Multiselects need to be converted to input[type=hidden]
            // for Select2
            var vals = self.$el.val() || [];
            var options = $.map(self.$el.find("option"), function (o) {
                return { text: $(o).html(), id: o.value };
            });
            var $hidden = $('<input type="hidden" />');
            $hidden.val(vals.join(self.options.separator));
            $hidden.attr("class", self.$el.attr("class"));
            $hidden.attr("name", self.$el.attr("name"));
            $hidden.attr("id", self.$el.attr("id"));
            self.$orig = self.$el;
            self.$el.replaceWith($hidden);
            self.$el = $hidden;
            self.options.data = options;
        }

        self.initializeValues();
        self.initializeTags();
        await self.initializeSelect2();
        await self.initializeOrdering();
    },
});
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc service
 * @name polestar.Pills
 * @description
 * # Pills
 * Service in the polestar.
 */
angular.module('vlui')
  .service('Pills', function () {
    var Pills = {
      // Functions
      get: get,
      set: set,
      // Event
      dragStart: dragStart,
      dragStop: dragStop,
      // Event, with handler in the listener
      remove: remove,
      dragDrop: dragDrop,

      // Data
      // TODO: split between encoding related and non-encoding related
      pills: {},
      /** pill being dragged */
      dragging: null,
      /** channelId that's the pill is being dragged from */
      cidDragFrom: null,
      /** Listener  */
      listener: null
    };

    /**
     * Set a fieldDef of a pill of a given channelId
     * @param channelId channel id of the pill to be updated
     * @param fieldDef fieldDef to to be updated
     * @param update whether to propagate change to the channel update listener
     */
    function set(channelId, fieldDef, update) {
      Pills.pills[channelId] = fieldDef;

      if (update && Pills.listener) {
        Pills.listener.set(channelId, fieldDef);
      }
    }

    /**
     * Get a fieldDef of a pill of a given channelId
     */
    function get(channelId) {
      return Pills.pills[channelId];
    }

    function remove(channelId) {
      delete Pills.pills[channelId];
      if (Pills.listener) {
        Pills.listener.remove(channelId);
      }
    }

    /** Updating the pill (e.g., via function select) */
    function update(channelId) {
      if (Pills.listener) {
        Pills.listener.update(channelId, Pills.pills[channelId]);
      }
    }

    /**
     * @param {any} pill pill being dragged
     * @param {any} cidDragFrom channel id that the pill is dragged from
     */
    function dragStart(pill, cidDragFrom) {
      Pills.dragging = pill;
      Pills.cidDragFrom = cidDragFrom;
    }

    /** Stop pill dragging */
    function dragStop() {
      Pills.dragging = null;
    }

    /**
     * When a pill is dropped
     * @param cidDragTo  channelId that's the pill is being dragged to
     */
    function dragDrop(cidDragTo) {
      if (Pills.listener) {
        Pills.listener.dragDrop(cidDragTo, Pills.cidDragFrom);
      }
    }

    return Pills;
  });
<commit_msg>add `update` and `reset`<commit_after>'use strict';

/**
 * @ngdoc service
 * @name polestar.Pills
 * @description
 * # Pills
 * Service in the polestar.
 */
angular.module('vlui')
  .service('Pills', function () {
    var Pills = {
      // Functions
      get: get,
      // Event
      dragStart: dragStart,
      dragStop: dragStop,
      // Event, with handler in the listener
      set: set,
      remove: remove,
      update: update,
      reset: reset,
      dragDrop: dragDrop,

      // Data
      // TODO: split between encoding related and non-encoding related
      pills: {},
      /** pill being dragged */
      dragging: null,
      /** channelId that's the pill is being dragged from */
      cidDragFrom: null,
      /** Listener  */
      listener: null
    };

    /**
     * Set a fieldDef of a pill of a given channelId
     * @param channelId channel id of the pill to be updated
     * @param fieldDef fieldDef to to be updated
     * @param update whether to propagate change to the channel update listener
     */
    function set(channelId, fieldDef, update) {
      Pills.pills[channelId] = fieldDef;

      if (update && Pills.listener) {
        Pills.listener.set(channelId, fieldDef);
      }
    }

    /**
     * Get a fieldDef of a pill of a given channelId
     */
    function get(channelId) {
      return Pills.pills[channelId];
    }

    function remove(channelId) {
      delete Pills.pills[channelId];
      if (Pills.listener) {
        Pills.listener.remove(channelId);
      }
    }
    /**
     * Update the whole pill set
     *
     * @param {any} spec
     */
    function update(spec) {
      if (Pills.listener) {
        Pills.listener.update(spec);
      }
    }

    /** Reset Pills */
    function reset() {
      if (Pills.listener) {
        Pills.listener.reset();
      }
    }

    /**
     * @param {any} pill pill being dragged
     * @param {any} cidDragFrom channel id that the pill is dragged from
     */
    function dragStart(pill, cidDragFrom) {
      Pills.dragging = pill;
      Pills.cidDragFrom = cidDragFrom;
    }

    /** Stop pill dragging */
    function dragStop() {
      Pills.dragging = null;
    }

    /**
     * When a pill is dropped
     * @param cidDragTo  channelId that's the pill is being dragged to
     */
    function dragDrop(cidDragTo) {
      if (Pills.listener) {
        Pills.listener.dragDrop(cidDragTo, Pills.cidDragFrom);
      }
    }

    return Pills;
  });
<|endoftext|>


<commit_before>var expect = require("expect.js")

describe("macro hygiene", function() {

    it("should work for or macro", function() {
        macro or {
            case ($x , $y) => {
                (function($tmp) {
                    return $tmp ? $tmp : $y;
                })($x);
            }
        }

        (function($tmp) {
            var z = or(false, $tmp)
            expect(z).to.be("ok");
        })("ok");

    });

    it("should work for a binding outside of the macro def", function() {

        var z = (function(x) {

            macro m {
                case ($ignore:ident) => {
                    x
                }
            }

            return (function (x) {
                return m(_) + x;
            })(22)

        })(1);
        expect(z).to.be(23)
    });

    it("should not rename object idents if they are the same as vars", function() {
        var o = (function (x) {
            return {
                x: x
            }
        })(42)

        expect(o.x).to.be(42);
    });

    it("should not rename object dot accesses", function() {
        var n = (function (o, x) {
            return o.x;
        })({x: 42})

        expect(n).to.be(42)
    });

    it("should do the correct renaming without macros for vars", function() {
        var z = (function() {
            var x = 42;
            return (function() {
                var y = x;
                var x = "foo"
                return y
            })();
        })();
        expect(z).to.be(undefined)
    });

    it("should do the correct renaming without macros for vars and params", function() {
        var z = (function() {
            return (function(x) {
                var x = "foo"
                var y = x;
                return y
            })(42);
        })();
        expect(z).to.be("foo")
    });

    it("should do the correct renaming with macros for vars", function() {
        macro m {
            case () => { var x = 5; }
        }
        var z = (function(x) {
            m();
            var y = x;
            return y;
        })("foo")
        expect(z).to.be("foo")
    });

    it("should work with vars and catch statements", function() {
        var r;
        var e = 'not error';

        try {
            a();
        } catch(e) {
            sub();
        }

        macro sub {
            case () => {
                r = e
            }
        }

        expect(r === e).to.be(true);
    });

    it("should work with a nested macro", function() {
        macro main {
            case ($a) => {
                (function(foo) {
                    var bar = 1 + foo;
                    return sub($a);
                })(2);
            }
        }
        var foo = 100;
        var bar = 200;
        macro sub {
            case ($a) => {
                foo + bar + $a
            }
        }

        var z = main(3);

        expect(z).to.be(303);
    });

    it("should work with multiple declarations", function() {
        var a = 10;
        var b = 20;
        macro main {
            case () => {
                (function() {
                    var a = 100, b = 200;
                    return sub();
                })();
            }
        }
        macro sub {
            case () => {
                a + b
            }
        }

        var z = main();

        expect(z).to.be(30);
    });

    it("var declarations in nested blocks should be distinct", function() {
        var foo = 100;
        macro sub {
            case () => { foo }
        }
        function bar() {
            if(false) {
                var foo = 10;
            }
            return sub();
        }

        expect(bar()).to.be(100);
    });

    it("should work for vars with hoisting", function() {
      macro m {
        case $x:lit => {
          var tmp = $x;
        }
      }

      var tmp = "outer"
      m "inner"
      expect(tmp).to.be("outer");

    });

    it("should work for vars with hoisting and params", function() {
      function f(tmp) {
        macro m {
          case $x:lit => {
            var tmp = $x;
          }
        }

        var tmp = "outer"
        m "inner"
        expect(tmp).to.be("outer");
      }

      f("call")

    });

    it("should work for var with nested function", function() {
      macro m {
        case $x:lit => {
          var tmp = $x;
        }
      }
      function f() {
        var tmp = "outer"
        m "inner"
        expect(tmp).to.be("outer");
      }
      f();
    });

    it("should handle vars decls introduced by a macro expansion where macro definition is in the same scope level", function() {
        var res = "default";
        var x = undefined;
        macro m {
            case () => {
                var x;
                x = "set";
                res = x;
            }
        }
        m()
        expect(res).to.be("set");
        expect(x).to.be(undefined);
    });

    it("should handle vars decls introduced by a macro expansion where macro definition is NOT in the same scope level", function() {
        macro m {
            case ($res) => {
                var x;
                x = "set";
                $res = x;
            }
        }

        (function() {
            var res = "default";
            var x = undefined;
            m(res)
            expect(res).to.be("set");
            expect(x).to.be(undefined);
        })();
    });

    it("should handle var delcs passed to a macro expansion", function() {
        var res = "default";
        var x = undefined;
        macro m {
            case { $body ... } => {
                $body ...
            }
        }
        m {
            var x;
            x = "set";
            res = x;
        }
        expect(res).to.be("set");
        expect(x).to.be("set");
    });

    // // todo this test needs a better api (syntax-case?)

    // // it("should work for another variant of hygiene", function() {
    // //   (function(x) {

    // //     macro n {
    // //       case ($stx:lit) => {
    // //         function(x) {
    // //           // want a way to distinguish between the two versions of x
    // //           return x + x
    // //         }
    // //       }
    // //     }

    // //   })(42);
    // // });

    it("should work for the or macro with var", function() {
      macro or {
        case ($x:expr, $y:expr) => {
          (function() {
            var $tmp = $x;
            return $tmp ? $tmp : $y;
          })();
        }
      }

      var $tmp = "ok"
      var z = or(false, $tmp);
      expect(z).to.be("ok");
    });

});
<commit_msg>adding some macros for test sweetening<commit_after>var expect = require("expect.js")

macro $describe {
    case $description:lit { $body ... } => {
        describe($description, function() {
            $body ...
        });
    }
}

macro $it {
    case $description:lit { $body ... } => {
        it($description, function() {
            $body ...
        });
    }
}

$describe "macro hygiene" {

    $it "should work for or macro" {
        macro or {
            case ($x , $y) => {
                (function($tmp) {
                    return $tmp ? $tmp : $y;
                })($x);
            }
        }

        (function($tmp) {
            var z = or(false, $tmp)
            expect(z).to.be("ok");
        })("ok");

    }

    $it "should work for a binding outside of the macro def" {

        var z = (function(x) {

            macro m {
                case ($ignore:ident) => {
                    x
                }
            }

            return (function (x) {
                return m(_) + x;
            })(22)

        })(1);
        expect(z).to.be(23)
    }

    $it "should not rename object idents if they are the same as vars" {
        var o = (function (x) {
            return {
                x: x
            }
        })(42)

        expect(o.x).to.be(42);
    }

    $it "should not rename object dot accesses" {
        var n = (function (o, x) {
            return o.x;
        })({x: 42})

        expect(n).to.be(42)
    }

    $it "should do the correct renaming without macros for vars" {
        var z = (function() {
            var x = 42;
            return (function() {
                var y = x;
                var x = "foo"
                return y
            })();
        })();
        expect(z).to.be(undefined)
    }

    $it "should do the correct renaming without macros for vars and params" {
        var z = (function() {
            return (function(x) {
                var x = "foo"
                var y = x;
                return y
            })(42);
        })();
        expect(z).to.be("foo")
    }

    $it "should do the correct renaming with macros for vars" {
        macro m {
            case () => { var x = 5; }
        }
        var z = (function(x) {
            m();
            var y = x;
            return y;
        })("foo")
        expect(z).to.be("foo")
    }

    $it "should work with vars and catch statements" {
        var r;
        var e = 'not error';

        try {
            a();
        } catch(e) {
            sub();
        }

        macro sub {
            case () => {
                r = e
            }
        }

        expect(r === e).to.be(true);
    }

    $it "should work with a nested macro" {
        macro main {
            case ($a) => {
                (function(foo) {
                    var bar = 1 + foo;
                    return sub($a);
                })(2);
            }
        }
        var foo = 100;
        var bar = 200;
        macro sub {
            case ($a) => {
                foo + bar + $a
            }
        }

        var z = main(3);

        expect(z).to.be(303);
    }

    $it "should work with multiple declarations" {
        var a = 10;
        var b = 20;
        macro main {
            case () => {
                (function() {
                    var a = 100, b = 200;
                    return sub();
                })();
            }
        }
        macro sub {
            case () => {
                a + b
            }
        }

        var z = main();

        expect(z).to.be(30);
    }

    $it "var declarations in nested blocks should be distinct" {
        var foo = 100;
        macro sub {
            case () => { foo }
        }
        function bar() {
            if(false) {
                var foo = 10;
            }
            return sub();
        }

        expect(bar()).to.be(100);
    }

    $it "should work for vars with hoisting" {
      macro m {
        case $x:lit => {
          var tmp = $x;
        }
      }

      var tmp = "outer"
      m "inner"
      expect(tmp).to.be("outer");

    }

    $it "should work for vars with hoisting and params" {
      function f(tmp) {
        macro m {
          case $x:lit => {
            var tmp = $x;
          }
        }

        var tmp = "outer"
        m "inner"
        expect(tmp).to.be("outer");
      }

      f("call")

    }

    $it "should work for var with nested function" {
      macro m {
        case $x:lit => {
          var tmp = $x;
        }
      }
      function f() {
        var tmp = "outer"
        m "inner"
        expect(tmp).to.be("outer");
      }
      f();
    }

    $it "should handle vars decls introduced by a macro expansion where macro definition is in the same scope level" {
        var res = "default";
        var x = undefined;
        macro m {
            case () => {
                var x;
                x = "set";
                res = x;
            }
        }
        m()
        expect(res).to.be("set");
        expect(x).to.be(undefined);
    }

    $it "should handle vars decls introduced by a macro expansion where macro definition is NOT in the same scope level" {
        macro m {
            case ($res) => {
                var x;
                x = "set";
                $res = x;
            }
        }

        (function() {
            var res = "default";
            var x = undefined;
            m(res)
            expect(res).to.be("set");
            expect(x).to.be(undefined);
        })();
    }

    $it "should handle var decls passed to a macro expansion" {
        var res = "default";
        var x = undefined;
        macro m {
            case { $body ... } => {
                $body ...
            }
        }
        m {
            var x;
            x = "set";
            res = x;
        }
        expect(res).to.be("set");
        expect(x).to.be("set");
    }

    $it "should work for the or macro with var" {
      macro or {
        case ($x:expr, $y:expr) => {
          (function() {
            var $tmp = $x;
            return $tmp ? $tmp : $y;
          })();
        }
      }

      var $tmp = "ok"
      var z = or(false, $tmp);
      expect(z).to.be("ok");
    }
}
<|endoftext|>