<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import omit from 'lodash/omit';
import { Map } from 'immutable';
import { cmfConnect } from '@talend/react-cmf';
import { HeaderBar as Component } from '@talend/react-components';

import { fetchProducts, openProduct } from './HeaderBar.actions';

import Constants from './HeaderBar.constant';

export const DEFAULT_STATE = new Map({
	productsFetchState: Constants.PRODUCTS_NOT_LOADED,
});

function sortProductsByLabel(a, b) {
	return a.label > b.label ? 1 : -1;
}

class HeaderBar extends React.Component {
	static displayName = 'Container(HeaderBar)';

	static propTypes = {
		productsUrl: PropTypes.string,
		productsItems: PropTypes.arrayOf(
			PropTypes.shape({
				icon: PropTypes.string,
				uri: PropTypes.string,
				label: PropTypes.string,
			}),
		),
		...cmfConnect.propTypes,
	};

	componentDidUpdate(prevProps) {
		// Trigger product fetch when there's an URL and
		// products URL has changed or products have not been loaded yet
		const hasProductsUrlChanged = this.props.productsUrl !== prevProps.productsUrl;
		const hasProductsNotBeenLoaded =
			this.props.state.get('productsFetchState') === Constants.PRODUCTS_NOT_LOADED;

		if (this.props.productsUrl && (hasProductsNotBeenLoaded || hasProductsUrlChanged)) {
			this.props.dispatch(fetchProducts(this.props.productsUrl));
		}
	}

	render() {
		const { productsItems, ...props } = this.props;

		const hasFetchedProducts =
			this.props.state.get('productsFetchState') === Constants.FETCH_PRODUCTS_SUCCESS;

		if (hasFetchedProducts && productsItems) {
			const items = productsItems
				.map(product => ({
					'data-feature': `product.${(product.id || '').toLowerCase()}`,
					label: product.name,
					icon: `talend-${product.icon}-colored`,
					onClickDispatch: openProduct(product),
				}))
				.sort(sortProductsByLabel);

			props.products = Object.assign({}, props.products || {}, { items });
		}

		return <Component {...omit(props, cmfConnect.INJECTED_PROPS)} />;
	}
}

export default HeaderBar;
<commit_msg>fix(containers): PropTypes for app switcher (#1786)<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import omit from 'lodash/omit';
import { Map } from 'immutable';
import { cmfConnect } from '@talend/react-cmf';
import { HeaderBar as Component } from '@talend/react-components';

import { fetchProducts, openProduct } from './HeaderBar.actions';

import Constants from './HeaderBar.constant';

export const DEFAULT_STATE = new Map({
	productsFetchState: Constants.PRODUCTS_NOT_LOADED,
});

function sortProductsByLabel(a, b) {
	return a.label > b.label ? 1 : -1;
}

class HeaderBar extends React.Component {
	static displayName = 'Container(HeaderBar)';

	static propTypes = {
		productsUrl: PropTypes.string,
		productsItems: PropTypes.arrayOf(
			PropTypes.shape({
				icon: PropTypes.string,
				id: PropTypes.string,
				name: PropTypes.string,
				url: PropTypes.string,
			}),
		),
		...cmfConnect.propTypes,
	};

	componentDidUpdate(prevProps) {
		// Trigger product fetch when there's an URL and
		// products URL has changed or products have not been loaded yet
		const hasProductsUrlChanged = this.props.productsUrl !== prevProps.productsUrl;
		const hasProductsNotBeenLoaded =
			this.props.state.get('productsFetchState') === Constants.PRODUCTS_NOT_LOADED;

		if (this.props.productsUrl && (hasProductsNotBeenLoaded || hasProductsUrlChanged)) {
			this.props.dispatch(fetchProducts(this.props.productsUrl));
		}
	}

	render() {
		const { productsItems, ...props } = this.props;

		const hasFetchedProducts =
			this.props.state.get('productsFetchState') === Constants.FETCH_PRODUCTS_SUCCESS;

		if (hasFetchedProducts && productsItems) {
			const items = productsItems
				.map(product => ({
					'data-feature': `product.${(product.id || '').toLowerCase()}`,
					label: product.name,
					icon: `talend-${product.icon}-colored`,
					onClickDispatch: openProduct(product),
				}))
				.sort(sortProductsByLabel);

			props.products = Object.assign({}, props.products || {}, { items });
		}

		return <Component {...omit(props, cmfConnect.INJECTED_PROPS)} />;
	}
}

export default HeaderBar;
<|endoftext|>


<commit_before>'use strict';

(function() {

    describe("voteeHome", function() {

        beforeEach(module('mean.voteeHome'));

        var $controller;

        beforeEach(inject(function(_$controller_){
            // The injector unwraps the underscores (_) from around the parameter names when matching
            $controller = _$controller_;
        }));

        describe("voteeHome controller", function() {
            beforeEach(function() {
                var $scope = {};
                var controller = $controller('VoteeHomeController', { $scope: $scope });
            });

            it("stub", function() {
                expect(true).toBe(true);
            });
        });

        describe("header controller", function() {

            beforeEach(function() {
                var $scope = {};
                var controller = $controller('VoteeHeaderController', { $scope: $scope });
            });

            it("Has a menu",
            function() {
                expect($scope.menus).toBeDefined();
                expect($scope.menus).not.toBeNull();
                expect($scope.menus.length).not.toBe(0);
            });
        });
    });

}());
<commit_msg>Fix injection errors<commit_after>'use strict';

(function() {

    describe("voteeHome", function() {

        beforeEach(function() {
            module('mean');
            module('mean.voteeHome');
        });

        var $controller;

        beforeEach(inject(function(_$controller_){
            // The injector unwraps the underscores (_) from around the parameter names when matching
            $controller = _$controller_;
        }));

        describe("voteeHome controller", function() {
            beforeEach(function() {
                var $scope = {};
                var controller = $controller('VoteeHomeController', { $scope: $scope });
            });

            it("stub", function() {
                expect(true).toBe(true);
            });
        });

        describe("header controller", function() {

            beforeEach(function() {
                var $scope = {};
                var controller = $controller('VoteeHeaderController', { $scope: $scope });
            });

            it("Has a menu",
            function() {
                expect($scope.menus).toBeDefined();
                expect($scope.menus).not.toBeNull();
                expect($scope.menus.length).not.toBe(0);
            });
        });
    });

}());
<|endoftext|>


<commit_before>require("ember-data/system/model/model");

/**
  @module ember-data
*/

var get = Ember.get, set = Ember.set, setProperties = Ember.setProperties;

function asyncHasMany(type, options, meta) {
  return Ember.computed(function(key, value) {
    if (this._relationships[key]) { return this._relationships[key]; }

    var resolver = Ember.RSVP.defer();

    var relationship = buildRelationship(this, key, options, function(store, data) {
      var link = data.links && data.links[key];

      if (link) {
        return store.findHasMany(this, link, meta, resolver);
      } else {
        return store.findMany(this, data[key], meta.type, resolver);
      }
    });

    var promise = resolver.promise.then(function() {
      return relationship;
    });

    return DS.PromiseArray.create({ promise: promise });
  }).property('data').meta(meta);
}

function buildRelationship(record, key, options, callback) {
  var rels = record._relationships;

  if (rels[key]) { return rels[key]; }

  var data = get(record, 'data'),
      store = get(record, 'store');

  var relationship = rels[key] = callback.call(record, store, data);

  return setProperties(relationship, {
    owner: record, name: key, isPolymorphic: options.polymorphic
  });
}

function hasRelationship(type, options) {
  options = options || {};

  var meta = { type: type, isRelationship: true, options: options, kind: 'hasMany' };

  if (options.async) {
    return asyncHasMany(type, options, meta);
  }

  return Ember.computed(function(key, value) {
    return buildRelationship(this, key, options, function(store, data) {
      var records = data[key];
      Ember.assert("You looked up the '" + key + "' relationship on '" + this + "' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.attr({ async: true })`)", Ember.A(records).everyProperty('isEmpty', false));
      return store.findMany(this, data[key], meta.type);
    });
  }).property('data').meta(meta);
}

DS.hasMany = function(type, options) {
  if (typeof type === 'object') {
    options = type;
    type = undefined;
  }
  return hasRelationship(type, options);
};
<commit_msg>Fix typo in error message<commit_after>require("ember-data/system/model/model");

/**
  @module ember-data
*/

var get = Ember.get, set = Ember.set, setProperties = Ember.setProperties;

function asyncHasMany(type, options, meta) {
  return Ember.computed(function(key, value) {
    if (this._relationships[key]) { return this._relationships[key]; }

    var resolver = Ember.RSVP.defer();

    var relationship = buildRelationship(this, key, options, function(store, data) {
      var link = data.links && data.links[key];

      if (link) {
        return store.findHasMany(this, link, meta, resolver);
      } else {
        return store.findMany(this, data[key], meta.type, resolver);
      }
    });

    var promise = resolver.promise.then(function() {
      return relationship;
    });

    return DS.PromiseArray.create({ promise: promise });
  }).property('data').meta(meta);
}

function buildRelationship(record, key, options, callback) {
  var rels = record._relationships;

  if (rels[key]) { return rels[key]; }

  var data = get(record, 'data'),
      store = get(record, 'store');

  var relationship = rels[key] = callback.call(record, store, data);

  return setProperties(relationship, {
    owner: record, name: key, isPolymorphic: options.polymorphic
  });
}

function hasRelationship(type, options) {
  options = options || {};

  var meta = { type: type, isRelationship: true, options: options, kind: 'hasMany' };

  if (options.async) {
    return asyncHasMany(type, options, meta);
  }

  return Ember.computed(function(key, value) {
    return buildRelationship(this, key, options, function(store, data) {
      var records = data[key];
      Ember.assert("You looked up the '" + key + "' relationship on '" + this + "' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", Ember.A(records).everyProperty('isEmpty', false));
      return store.findMany(this, data[key], meta.type);
    });
  }).property('data').meta(meta);
}

DS.hasMany = function(type, options) {
  if (typeof type === 'object') {
    options = type;
    type = undefined;
  }
  return hasRelationship(type, options);
};
<|endoftext|>


<commit_before>import { RenderingTest, moduleFor } from '../utils/test-case';
import { applyMixins } from '../utils/abstract-test-case';
import { set } from 'ember-metal/property_set';
import { computed } from 'ember-metal/computed';
import EmberObject from 'ember-runtime/system/object';

moduleFor('Static content tests', class extends RenderingTest {

  ['@test it can render a static text node']() {
    this.render('hello');
    let text1 = this.assertTextNode(this.firstChild, 'hello');

    this.runTask(() => this.rerender());

    let text2 = this.assertTextNode(this.firstChild, 'hello');

    this.assertSameNode(text1, text2);
  }

  ['@test it can render a static element']() {
    this.render('
hello
');
    let p1 = this.assertElement(this.firstChild, { tagName: 'p' });
    let text1 = this.assertTextNode(this.firstChild.firstChild, 'hello');

    this.runTask(() => this.rerender());

    let p2 = this.assertElement(this.firstChild, { tagName: 'p' });
    let text2 = this.assertTextNode(this.firstChild.firstChild, 'hello');

    this.assertSameNode(p1, p2);
    this.assertSameNode(text1, text2);
  }

  ['@test it can render a static template']() {
    let template = `

Welcome to Ember.js

Why you should use Ember.js?

It's great

It's awesome

It's Ember.js

        Ember.js is free, open source and always will be.

    `;

    this.render(template);
    this.assertHTML(template);

    this.runTask(() => this.rerender());

    this.assertHTML(template);
  }

});

class DynamicContentTest extends RenderingTest {

  /* abstract */
  renderPath(path, context = {}) {
    throw new Error('Not implemented: `renderValues`');
  }

  assertIsEmpty() {
    this.assert.strictEqual(this.firstChild, null);
  }

  /* abstract */
  assertContent(content) {
    throw new Error('Not implemented: `assertContent`');
  }

  ['@test it can render a dynamic path']() {
    this.renderPath('message', { message: 'hello' });

    this.assertContent('hello');

    this.assertStableRerender();

    this.runTask(() => set(this.context, 'message', 'goodbye'));

    this.assertContent('goodbye');
    this.assertInvariants();

    this.runTask(() => set(this.context, 'message', 'hello'));

    this.assertContent('hello');
    this.assertInvariants();
  }

  ['@test it can render a capitalized path with no deprication']() {
    expectNoDeprecation();

    this.renderPath('CaptializedPath', { CaptializedPath: 'noDeprication' });

    this.assertContent('noDeprication');

    this.assertStableRerender();

    this.runTask(() => set(this.context, 'CaptializedPath', 'stillNoDeprication'));

    this.assertContent('stillNoDeprication');
    this.assertInvariants();

    this.runTask(() => set(this.context, 'CaptializedPath', 'noDeprication'));

    this.assertContent('noDeprication');
    this.assertInvariants();
  }

  ['@test it can render a deeply nested dynamic path']() {
    this.renderPath('a.b.c.d.e.f', {
      a: { b: { c: { d: { e: { f: 'hello' } } } } }
    });

    this.assertContent('hello');

    this.assertStableRerender();

    this.runTask(() => set(this.context, 'a.b.c.d.e.f', 'goodbye'));

    this.assertContent('goodbye');
    this.assertInvariants();

    this.runTask(() => set(this.context, 'a.b.c.d', { e: { f: 'aloha' } }));

    this.assertContent('aloha');
    this.assertInvariants();

    this.runTask(() => {
      set(this.context, 'a',
        { b: { c: { d: { e: { f: 'hello' } } } } }
      );
    });

    this.assertContent('hello');
    this.assertInvariants();
  }

  ['@test it can render a computed property']() {
    let Formatter = EmberObject.extend({
      formattedMessage: computed('message', function() {
        return this.get('message').toUpperCase();
      })
    });

    let m = Formatter.create({ message: 'hello' });

    this.renderPath('m.formattedMessage', { m });

    this.assertContent('HELLO');

    this.assertStableRerender();

    this.runTask(() => set(m, 'message', 'goodbye'));

    this.assertContent('GOODBYE');
    this.assertInvariants();

    this.runTask(() => set(this.context, 'm', Formatter.create({ message: 'hello' })));

    this.assertContent('HELLO');
    this.assertInvariants();
  }

  ['@test it can read from a null object']() {
    let nullObject = Object.create(null);
    nullObject['message'] = 'hello';

    this.renderPath('nullObject.message', { nullObject });

    this.assertContent('hello');

    this.assertStableRerender();

    this.runTask(() => set(nullObject, 'message', 'goodbye'));

    this.assertContent('goodbye');
    this.assertInvariants();

    nullObject = Object.create(null);
    nullObject['message'] = 'hello';

    this.runTask(() => set(this.context, 'nullObject', nullObject));

    this.assertContent('hello');
    this.assertInvariants();
  }

}

const EMPTY = {};

class ContentTestGenerator {
  constructor(cases, tag = '@test') {
    this.cases = cases;
    this.tag = tag;
  }

  generate([ value, expected, label ]) {
    let tag = this.tag;
    label = label || value;

    if (expected === EMPTY) {
      return {

        [`${tag} rendering ${label}`]() {
          this.renderPath('value', { value });

          this.assertIsEmpty();

          this.runTask(() => set(this.context, 'value', 'hello'));

          this.assertContent('hello');

          this.runTask(() => set(this.context, 'value', value));

          this.assertIsEmpty();
        }

      };
    } else {
      return {

        [`${tag} rendering ${label}`]() {
          this.renderPath('value', { value });

          this.assertContent(expected);

          this.assertStableRerender();

          this.runTask(() => set(this.context, 'value', 'hello'));

          this.assertContent('hello');
          this.assertInvariants();

          this.runTask(() => set(this.context, 'value', value));

          this.assertContent(expected);
          this.assertInvariants();
        }

      };
    }
  }
}

const SharedContentTestCases = new ContentTestGenerator([

  ['foo', 'foo'],
  [0, '0'],
  [-0, '0', '-0'],
  [1, '1'],
  [-1, '-1'],
  [0.0, '0', '0.0'],
  [0.5, '0.5'],
  [undefined, EMPTY],
  [null, EMPTY],
  [true, 'true'],
  [false, 'false'],
  [NaN, 'NaN'],
  [new Date(2000, 0, 1), String(new Date(2000, 0, 1)), 'a Date object'],
  [Infinity, 'Infinity'],
  [(1 / -0), '-Infinity'],
  [{ foo: 'bar' }, '[object Object]', `{ foo: 'bar' }`],
  [{ toString() { return 'foo'; } }, 'foo', 'an object with a custom toString function'],
  [{ valueOf() { return 1; } }, '[object Object]', 'an object with a custom valueOf function'],

  // Escaping tests
  ['MaxJames', 'MaxJames']

]);

let GlimmerContentTestCases = new ContentTestGenerator([

  [Object.create(null), EMPTY, 'an object with no toString']

], '@glimmer');

if (typeof Symbol !== 'undefined') {
  GlimmerContentTestCases.cases.push([Symbol('debug'), 'Symbol(debug)', 'a symbol']);
}

applyMixins(DynamicContentTest, SharedContentTestCases, GlimmerContentTestCases);

moduleFor('Dynamic content tests (content position)', class extends DynamicContentTest {

  renderPath(path, context = {}) {
    this.render(`{{${path}}}`, context);
  }

  assertContent(content) {
    this.assert.strictEqual(this.nodesCount, 1, 'It should render exactly one text node');
    this.assertTextNode(this.firstChild, content);
  }

});

moduleFor('Dynamic content tests (content concat)', class extends DynamicContentTest {

  renderPath(path, context = {}) {
    this.render(`{{concat "" ${path} ""}}`, context);
  }

  assertContent(content) {
    this.assert.strictEqual(this.nodesCount, 1, 'It should render exactly one text node');
    this.assertTextNode(this.firstChild, content);
  }

});

moduleFor('Dynamic content tests (inside an element)', class extends DynamicContentTest {

  renderPath(path, context = {}) {
    this.render(`<p>{{${path}}}</p>`, context);
  }

  assertIsEmpty() {
    this.assert.strictEqual(this.nodesCount, 1, 'It should render exactly one
 tag');
    this.assertElement(this.firstChild, { tagName: 'p' });
    this.assertText('');
  }

  assertContent(content) {
    this.assert.strictEqual(this.nodesCount, 1, 'It should render exactly one
 tag');
    this.assertElement(this.firstChild, { tagName: 'p' });
    this.assertText(content);
  }

});

moduleFor('Dynamic content tests (attribute position)', class extends DynamicContentTest {

  renderPath(path, context = {}) {
    this.render(`<div data-foo="{{${path}}}"></div>`, context);
  }

  assertIsEmpty() {
    this.assert.strictEqual(this.nodesCount, 1, 'It should render exactly one
 tag');
    this.assertElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo': '' }, content: '' });
  }

  assertContent(content) {
    this.assert.strictEqual(this.nodesCount, 1, 'It should render exactly one
 tag');
    this.assertElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo': content }, content: '' });
  }

});

class TrustedContentTest extends DynamicContentTest {

  assertIsEmpty() {
    this.assert.strictEqual(this.firstChild, null);
  }

  assertContent(content) {
    this.assertHTML(content);
  }

  assertStableRerender() {
    this.takeSnapshot();
    this.runTask(() => this.rerender());
    super.assertInvariants();
  }

  assertInvariants() {
    // If it's not stable, we will wipe out all the content and replace them,
    // so there are no invariants
  }

}

moduleFor('Dynamic content tests (trusted)', class extends TrustedContentTest {

  renderPath(path, context = {}) {
    this.render(`{{{${path}}}}`, context);
  }

  ['@test updating trusted curlies']() {
    this.render('{{{htmlContent}}}{{{nested.htmlContent}}}', {
      htmlContent: 'Max',
      nested: { htmlContent: 'James' }
    });

    this.assertContent('MaxJames');

    this.runTask(() => this.rerender());

    this.assertStableRerender();

    this.runTask(() => set(this.context, 'htmlContent', 'Ma<s>x</s>'));

    this.assertContent('Ma<s>x</s>James');

    this.runTask(() => set(this.context, 'nested.htmlContent', 'Jammie'));

    this.assertContent('Ma<s>x</s>Jammie');

    this.runTask(() => {
      set(this.context, 'htmlContent', 'Max');
      set(this.context, 'nested', { htmlContent: 'James' });
    });

    this.assertContent('MaxJames');
  }

});

moduleFor('Dynamic content tests (integration)', class extends RenderingTest {

  ['@test it can render a dynamic template']() {
    let template = `

Welcome to {{framework}}

Why you should use {{framework}}?

It's great

It's awesome

It's {{framework}}

        {{framework}} is free, open source and always will be.

    `;

    let ember = `

Welcome to Ember.js

Why you should use Ember.js?

It's great

It's awesome

It's Ember.js

        Ember.js is free, open source and always will be.

    `;

    let react = `

Welcome to React

Why you should use React?

It's great

It's awesome

It's React

        React is free, open source and always will be.

    `;

    this.render(template, {
      framework: 'Ember.js'
    });
    this.assertHTML(ember);

    this.runTask(() => this.rerender());

    this.assertHTML(ember);

    this.runTask(() => set(this.context, 'framework', 'React'));

    this.assertHTML(react);

    this.runTask(() => set(this.context, 'framework', 'Ember.js'));

    this.assertHTML(ember);
  }

});
<commit_msg>Fix typos<commit_after>import { RenderingTest, moduleFor } from '../utils/test-case';
import { applyMixins } from '../utils/abstract-test-case';
import { set } from 'ember-metal/property_set';
import { computed } from 'ember-metal/computed';
import EmberObject from 'ember-runtime/system/object';

moduleFor('Static content tests', class extends RenderingTest {

  ['@test it can render a static text node']() {
    this.render('hello');
    let text1 = this.assertTextNode(this.firstChild, 'hello');

    this.runTask(() => this.rerender());

    let text2 = this.assertTextNode(this.firstChild, 'hello');

    this.assertSameNode(text1, text2);
  }

  ['@test it can render a static element']() {
    this.render('
hello
');
    let p1 = this.assertElement(this.firstChild, { tagName: 'p' });
    let text1 = this.assertTextNode(this.firstChild.firstChild, 'hello');

    this.runTask(() => this.rerender());

    let p2 = this.assertElement(this.firstChild, { tagName: 'p' });
    let text2 = this.assertTextNode(this.firstChild.firstChild, 'hello');

    this.assertSameNode(p1, p2);
    this.assertSameNode(text1, text2);
  }

  ['@test it can render a static template']() {
    let template = `

Welcome to Ember.js

Why you should use Ember.js?

It's great

It's awesome

It's Ember.js

        Ember.js is free, open source and always will be.

    `;

    this.render(template);
    this.assertHTML(template);

    this.runTask(() => this.rerender());

    this.assertHTML(template);
  }

});

class DynamicContentTest extends RenderingTest {

  /* abstract */
  renderPath(path, context = {}) {
    throw new Error('Not implemented: `renderValues`');
  }

  assertIsEmpty() {
    this.assert.strictEqual(this.firstChild, null);
  }

  /* abstract */
  assertContent(content) {
    throw new Error('Not implemented: `assertContent`');
  }

  ['@test it can render a dynamic path']() {
    this.renderPath('message', { message: 'hello' });

    this.assertContent('hello');

    this.assertStableRerender();

    this.runTask(() => set(this.context, 'message', 'goodbye'));

    this.assertContent('goodbye');
    this.assertInvariants();

    this.runTask(() => set(this.context, 'message', 'hello'));

    this.assertContent('hello');
    this.assertInvariants();
  }

  ['@test it can render a capitalized path with no deprecation']() {
    expectNoDeprecation();

    this.renderPath('CaptializedPath', { CaptializedPath: 'no deprecation' });

    this.assertContent('no deprecation');

    this.assertStableRerender();

    this.runTask(() => set(this.context, 'CaptializedPath', 'still no deprecation'));

    this.assertContent('still no deprecation');
    this.assertInvariants();

    this.runTask(() => set(this.context, 'CaptializedPath', 'no deprecation'));

    this.assertContent('no deprecation');
    this.assertInvariants();
  }

  ['@test it can render a deeply nested dynamic path']() {
    this.renderPath('a.b.c.d.e.f', {
      a: { b: { c: { d: { e: { f: 'hello' } } } } }
    });

    this.assertContent('hello');

    this.assertStableRerender();

    this.runTask(() => set(this.context, 'a.b.c.d.e.f', 'goodbye'));

    this.assertContent('goodbye');
    this.assertInvariants();

    this.runTask(() => set(this.context, 'a.b.c.d', { e: { f: 'aloha' } }));

    this.assertContent('aloha');
    this.assertInvariants();

    this.runTask(() => {
      set(this.context, 'a',
        { b: { c: { d: { e: { f: 'hello' } } } } }
      );
    });

    this.assertContent('hello');
    this.assertInvariants();
  }

  ['@test it can render a computed property']() {
    let Formatter = EmberObject.extend({
      formattedMessage: computed('message', function() {
        return this.get('message').toUpperCase();
      })
    });

    let m = Formatter.create({ message: 'hello' });

    this.renderPath('m.formattedMessage', { m });

    this.assertContent('HELLO');

    this.assertStableRerender();

    this.runTask(() => set(m, 'message', 'goodbye'));

    this.assertContent('GOODBYE');
    this.assertInvariants();

    this.runTask(() => set(this.context, 'm', Formatter.create({ message: 'hello' })));

    this.assertContent('HELLO');
    this.assertInvariants();
  }

  ['@test it can read from a null object']() {
    let nullObject = Object.create(null);
    nullObject['message'] = 'hello';

    this.renderPath('nullObject.message', { nullObject });

    this.assertContent('hello');

    this.assertStableRerender();

    this.runTask(() => set(nullObject, 'message', 'goodbye'));

    this.assertContent('goodbye');
    this.assertInvariants();

    nullObject = Object.create(null);
    nullObject['message'] = 'hello';

    this.runTask(() => set(this.context, 'nullObject', nullObject));

    this.assertContent('hello');
    this.assertInvariants();
  }

}

const EMPTY = {};

class ContentTestGenerator {
  constructor(cases, tag = '@test') {
    this.cases = cases;
    this.tag = tag;
  }

  generate([ value, expected, label ]) {
    let tag = this.tag;
    label = label || value;

    if (expected === EMPTY) {
      return {

        [`${tag} rendering ${label}`]() {
          this.renderPath('value', { value });

          this.assertIsEmpty();

          this.runTask(() => set(this.context, 'value', 'hello'));

          this.assertContent('hello');

          this.runTask(() => set(this.context, 'value', value));

          this.assertIsEmpty();
        }

      };
    } else {
      return {

        [`${tag} rendering ${label}`]() {
          this.renderPath('value', { value });

          this.assertContent(expected);

          this.assertStableRerender();

          this.runTask(() => set(this.context, 'value', 'hello'));

          this.assertContent('hello');
          this.assertInvariants();

          this.runTask(() => set(this.context, 'value', value));

          this.assertContent(expected);
          this.assertInvariants();
        }

      };
    }
  }
}

const SharedContentTestCases = new ContentTestGenerator([

  ['foo', 'foo'],
  [0, '0'],
  [-0, '0', '-0'],
  [1, '1'],
  [-1, '-1'],
  [0.0, '0', '0.0'],
  [0.5, '0.5'],
  [undefined, EMPTY],
  [null, EMPTY],
  [true, 'true'],
  [false, 'false'],
  [NaN, 'NaN'],
  [new Date(2000, 0, 1), String(new Date(2000, 0, 1)), 'a Date object'],
  [Infinity, 'Infinity'],
  [(1 / -0), '-Infinity'],
  [{ foo: 'bar' }, '[object Object]', `{ foo: 'bar' }`],
  [{ toString() { return 'foo'; } }, 'foo', 'an object with a custom toString function'],
  [{ valueOf() { return 1; } }, '[object Object]', 'an object with a custom valueOf function'],

  // Escaping tests
  ['MaxJames', 'MaxJames']

]);

let GlimmerContentTestCases = new ContentTestGenerator([

  [Object.create(null), EMPTY, 'an object with no toString']

], '@glimmer');

if (typeof Symbol !== 'undefined') {
  GlimmerContentTestCases.cases.push([Symbol('debug'), 'Symbol(debug)', 'a symbol']);
}

applyMixins(DynamicContentTest, SharedContentTestCases, GlimmerContentTestCases);

moduleFor('Dynamic content tests (content position)', class extends DynamicContentTest {

  renderPath(path, context = {}) {
    this.render(`{{${path}}}`, context);
  }

  assertContent(content) {
    this.assert.strictEqual(this.nodesCount, 1, 'It should render exactly one text node');
    this.assertTextNode(this.firstChild, content);
  }

});

moduleFor('Dynamic content tests (content concat)', class extends DynamicContentTest {

  renderPath(path, context = {}) {
    this.render(`{{concat "" ${path} ""}}`, context);
  }

  assertContent(content) {
    this.assert.strictEqual(this.nodesCount, 1, 'It should render exactly one text node');
    this.assertTextNode(this.firstChild, content);
  }

});

moduleFor('Dynamic content tests (inside an element)', class extends DynamicContentTest {

  renderPath(path, context = {}) {
    this.render(`<p>{{${path}}}</p>`, context);
  }

  assertIsEmpty() {
    this.assert.strictEqual(this.nodesCount, 1, 'It should render exactly one
 tag');
    this.assertElement(this.firstChild, { tagName: 'p' });
    this.assertText('');
  }

  assertContent(content) {
    this.assert.strictEqual(this.nodesCount, 1, 'It should render exactly one
 tag');
    this.assertElement(this.firstChild, { tagName: 'p' });
    this.assertText(content);
  }

});

moduleFor('Dynamic content tests (attribute position)', class extends DynamicContentTest {

  renderPath(path, context = {}) {
    this.render(`<div data-foo="{{${path}}}"></div>`, context);
  }

  assertIsEmpty() {
    this.assert.strictEqual(this.nodesCount, 1, 'It should render exactly one
 tag');
    this.assertElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo': '' }, content: '' });
  }

  assertContent(content) {
    this.assert.strictEqual(this.nodesCount, 1, 'It should render exactly one
 tag');
    this.assertElement(this.firstChild, { tagName: 'div', attrs: { 'data-foo': content }, content: '' });
  }

});

class TrustedContentTest extends DynamicContentTest {

  assertIsEmpty() {
    this.assert.strictEqual(this.firstChild, null);
  }

  assertContent(content) {
    this.assertHTML(content);
  }

  assertStableRerender() {
    this.takeSnapshot();
    this.runTask(() => this.rerender());
    super.assertInvariants();
  }

  assertInvariants() {
    // If it's not stable, we will wipe out all the content and replace them,
    // so there are no invariants
  }

}

moduleFor('Dynamic content tests (trusted)', class extends TrustedContentTest {

  renderPath(path, context = {}) {
    this.render(`{{{${path}}}}`, context);
  }

  ['@test updating trusted curlies']() {
    this.render('{{{htmlContent}}}{{{nested.htmlContent}}}', {
      htmlContent: 'Max',
      nested: { htmlContent: 'James' }
    });

    this.assertContent('MaxJames');

    this.runTask(() => this.rerender());

    this.assertStableRerender();

    this.runTask(() => set(this.context, 'htmlContent', 'Ma<s>x</s>'));

    this.assertContent('Ma<s>x</s>James');

    this.runTask(() => set(this.context, 'nested.htmlContent', 'Jammie'));

    this.assertContent('Ma<s>x</s>Jammie');

    this.runTask(() => {
      set(this.context, 'htmlContent', 'Max');
      set(this.context, 'nested', { htmlContent: 'James' });
    });

    this.assertContent('MaxJames');
  }

});

moduleFor('Dynamic content tests (integration)', class extends RenderingTest {

  ['@test it can render a dynamic template']() {
    let template = `

Welcome to {{framework}}

Why you should use {{framework}}?

It's great

It's awesome

It's {{framework}}

        {{framework}} is free, open source and always will be.

    `;

    let ember = `

Welcome to Ember.js

Why you should use Ember.js?

It's great

It's awesome

It's Ember.js

        Ember.js is free, open source and always will be.

    `;

    let react = `

Welcome to React

Why you should use React?

It's great

It's awesome

It's React

        React is free, open source and always will be.

    `;

    this.render(template, {
      framework: 'Ember.js'
    });
    this.assertHTML(ember);

    this.runTask(() => this.rerender());

    this.assertHTML(ember);

    this.runTask(() => set(this.context, 'framework', 'React'));

    this.assertHTML(react);

    this.runTask(() => set(this.context, 'framework', 'Ember.js'));

    this.assertHTML(ember);
  }

});
<|endoftext|>


<commit_before>#!/usr/bin/env node

let spawn = require('child_process').spawn;

//
//USE: ./index.js <ms npm can be idle> <number of attempts> [... NPM ARGS]
//

let timeout = process.argv[2] || 60000;
let attempts = process.argv[3] || 3;
let args = process.argv.slice(4);
if (args.length === 0) {
  args = ['install'];
}

(function npm() {
  let timer;
  args.push('--verbose');
  let proc = spawn('npm', args);
  proc.stdout.pipe(process.stdout);
  proc.stderr.pipe(process.stderr);
  proc.stdin.end();
  proc.stdout.on('data', () => {
    setTimer();
  });
  proc.stderr.on('data', () => {
    setTimer();
  });

  // side effect: this also restarts when npm exits with a bad code even if it
  // didnt timeout
  proc.on('close', (code, signal) => {
    clearTimeout(timer);
    if (code || signal) {
      console.log('[npm-are-you-sleeping] npm exited with code ' + code + '');

      if (--attempts) {
        console.log('[npm-are-you-sleeping] restarting');
        npm();
      } else {
        console.log('[npm-are-you-sleeping] i tried lots of times. giving up.');
        throw new Error("npm install fails");
      }
    }
  });

  function setTimer() {
    clearTimeout(timer);
    timer = setTimeout(() => {
      console.log('[npm-are-you-sleeping] killing npm with SIGTERM');
      proc.kill('SIGTERM');
      // wait a couple seconds
      timer = setTimeout(() => {
        // its it's still not closed sigkill
        console.log('[npm-are-you-sleeping] killing npm with SIGKILL');
        proc.kill('SIGKILL');
      }, 2000);
    }, timeout);
  }
})();
<commit_msg>Update the CI config (#80)<commit_after>#!/usr/bin/env node

let spawn = require('child_process').spawn;

//
//USE: ./index.js <ms npm can be idle> <number of attempts> [... NPM ARGS]
//

let timeout = process.argv[2] || process.env.NPM_INSTALL_TIMEOUT || 60000;
let attempts = process.argv[3] || 3;
let args = process.argv.slice(4);
if (args.length === 0) {
  args = ['install'];
}

(function npm() {
  let timer;
  args.push('--verbose');
  let proc = spawn('npm', args);
  proc.stdout.pipe(process.stdout);
  proc.stderr.pipe(process.stderr);
  proc.stdin.end();
  proc.stdout.on('data', () => {
    setTimer();
  });
  proc.stderr.on('data', () => {
    setTimer();
  });

  // side effect: this also restarts when npm exits with a bad code even if it
  // didnt timeout
  proc.on('close', (code, signal) => {
    clearTimeout(timer);
    if (code || signal) {
      console.log('[npm-are-you-sleeping] npm exited with code ' + code + '');

      if (--attempts) {
        console.log('[npm-are-you-sleeping] restarting');
        npm();
      } else {
        console.log('[npm-are-you-sleeping] i tried lots of times. giving up.');
        throw new Error("npm install fails");
      }
    }
  });

  function setTimer() {
    clearTimeout(timer);
    timer = setTimeout(() => {
      console.log('[npm-are-you-sleeping] killing npm with SIGTERM');
      proc.kill('SIGTERM');
      // wait a couple seconds
      timer = setTimeout(() => {
        // its it's still not closed sigkill
        console.log('[npm-are-you-sleeping] killing npm with SIGKILL');
        proc.kill('SIGKILL');
      }, 2000);
    }, timeout);
  }
})();
<|endoftext|>


<commit_before>import {
  flatTable,
  flatTableHeaderCells,
  flatTableBodyRowByPosition,
  flatTableCell,
  flatTableClickableRow,
  flatTableSortable,
  flatTableBodyRows,
  flatTableCaption,
  flatTableSubrowByPosition,
  flatTableSubrows,
  flatTablePageSizeSelect,
  flatTablePageSelectListPosition,
  pageSelectDataComponent,
} from "../../locators/flat-table";

import DEBUG_FLAG from "..";
import { positionOfElement } from "../helper";
import { icon } from "../../locators";

const gold = "rgb(255, 181, 0)";

Then("FlatTable body rows are sticky", () => {
  cy.wait(500);
  for (let i = 0; i <= 3; i++) {
    const color = "rgb(204, 214, 219)";
    flatTableClickableRow(i)
      .find("th")
      .should("have.css", "border-right-color", color)
      .and("have.css", "border-left-color", color)
      .and("have.css", "border-bottom-color", color)
      .and("have.css", "position", "sticky")
      .and("be.visible");
  }
});

Then("FlatTable header first cell is sticky", () => {
  cy.wait(500);
  flatTableHeaderCells()
    .first()
    .should("have.css", "position", "sticky")
    .and("be.visible");
});

Then("FlatTable has sticky header", () => {
  cy.wait(300, { log: DEBUG_FLAG }); // required because element needs to be loaded
  flatTableHeaderCells().each(($el) => {
    cy.wrap($el).should("have.css", "position", "sticky").and("be.visible");
  });
});

Then("First/Last {int} header cells {word} visible", (count, state) => {
  if (state === "are") {
    for (let i = 6; i > 6 - count; i--) {
      flatTableHeaderCells().eq(i).should("be.visible");
    }
  } else {
    for (let i = 1; i <= count; i++) {
      flatTableHeaderCells().eq(i).should("not.be.visible");
    }
  }
});

When("I scroll table content to bottom right", () => {
  cy.viewport(625, 450);
  flatTable().parent().parent().scrollTo("100%", "100%");
});

Then("First/Last {int} FlatTable rows {word} visible", (count, state) => {
  if (state === "are") {
    for (let i = 8; i > 8 - count; i--) {
      flatTableBodyRowByPosition(i).should("be.visible");
    }
  } else {
    for (let i = 0; i < count; i++) {
      flatTableBodyRowByPosition(i).should("not.be.visible");
    }
  }
});

Then("I click on {int} body row", (index) => {
  flatTableBodyRowByPosition(index).click({ force: true });
});

Then(
  "I focus {int} row and focused row element has golden border on focus",
  (index) => {
    cy.wait(500, { log: DEBUG_FLAG }); // wait was added due to changing animation
    flatTableBodyRowByPosition(index)
      .focus()
      .should("have.css", "outline-color", gold);
  }
);

Then("press Enter key on the row element", () => {
  flatTableBodyRowByPosition(2)
    .focus()
    .trigger("keydown", { keyCode: 13, which: 13, force: true });
});

Then("I click on {string} header {int} times", (position, times) => {
  for (let i = 0; i < times; i++) {
    flatTableSortable().eq(positionOfElement(position)).click();
  }
});

When("{string} column is sorted in {string} order", (position, sortOrder) => {
  const valueOne = "Tyler Webb";
  const valueTwo = "Monty Parker";
  const valueThree = "Jason Atkinson";
  const valueFour = "Blake Sutton";
  const totalOne = "280";
  const totalTwo = "1349";
  const totalThree = "849";
  const totalFour = "3840";
  if (position === "first" && sortOrder === "desc") {
    icon().should("have.attr", "data-element", "sort_down").and("be.visible");
    flatTableCell(positionOfElement("first"))
      .should("have.text", valueOne)
      .and("be.visible");
    flatTableCell(positionOfElement("third"))
      .should("have.text", valueTwo)
      .and("be.visible");
    flatTableCell(positionOfElement("fifth"))
      .should("have.text", valueThree)
      .and("be.visible");
    flatTableCell(positionOfElement("seventh"))
      .should("have.text", valueFour)
      .and("be.visible");
  } else if (position === "first" && sortOrder === "asc") {
    icon().should("have.attr", "data-element", "sort_up").and("be.visible");
    flatTableCell(positionOfElement("first"))
      .should("have.text", valueFour)
      .and("be.visible");
    flatTableCell(positionOfElement("third"))
      .should("have.text", valueThree)
      .and("be.visible");
    flatTableCell(positionOfElement("fifth"))
      .should("have.text", valueTwo)
      .and("be.visible");
    flatTableCell(positionOfElement("seventh"))
      .should("have.text", valueOne)
      .and("be.visible");
  } else if (position === "second" && sortOrder === "desc") {
    icon().should("have.attr", "data-element", "sort_down").and("be.visible");
    flatTableCell(positionOfElement("second"))
      .should("have.text", totalFour)
      .and("be.visible");
    flatTableCell(positionOfElement("fourth"))
      .should("have.text", totalTwo)
      .and("be.visible");
    flatTableCell(positionOfElement("sixth"))
      .should("have.text", totalThree)
      .and("be.visible");
    flatTableCell(positionOfElement("eighth"))
      .should("have.text", totalOne)
      .and("be.visible");
  } else {
    icon().should("have.attr", "data-element", "sort_up").and("be.visible");
    flatTableCell(positionOfElement("second"))
      .should("have.text", totalOne)
      .and("be.visible");
    flatTableCell(positionOfElement("fourth"))
      .should("have.text", totalThree)
      .and("be.visible");
    flatTableCell(positionOfElement("sixth"))
      .should("have.text", totalTwo)
      .and("be.visible");
    flatTableCell(positionOfElement("eighth"))
      .should("have.text", totalFour)
      .and("be.visible");
  }
});

Then("{string} header has focus", (position) => {
  flatTableSortable()
    .eq(positionOfElement(position))
    .should("have.css", "outline-color", gold);
});

Then("I focus {string} header cell", (position) => {
  flatTableSortable().eq(positionOfElement(position)).focus();
});

Then(
  "I press {string} on {string} header {int} time(s)",
  (key, position, count) => {
    for (let i = 0; i < count; i++) {
      if (key === "Enter") {
        flatTableSortable()
          .eq(positionOfElement(position))
          .focus()
          .trigger("keydown", { keyCode: 13, which: 13, force: true });
      } else if (key === "Space") {
        flatTableSortable()
          .eq(positionOfElement(position))
          .focus()
          .trigger("keydown", { keyCode: 32, which: 32, force: true });
      } else {
        throw new Error("Only Enter or Space key can be applied");
      }
    }
  }
);

When("I click on the first row", () => {
  flatTableBodyRows().first().click();
});

Then("The whole row is highlighted", () => {
  flatTableBodyRows()
    .first()
    .children()
    .should("have.css", "background-color", "rgb(230, 235, 237)");
});

Then("Flat table caption is set to {word}", (text) => {
  flatTableCaption().should("have.text", text);
});

When("I click on the {word} cell in the first row", (position) => {
  flatTableCell(positionOfElement(position)).click();
});

Then("The subrows are visible", () => {
  flatTableSubrows().should("be.visible");
});

Then("The subrows are not visible", () => {
  flatTableSubrows().should("not.exist");
});

When("I click on the first cell", () => {
  flatTableCell(0).click();
});

Then("The first cell in the third content row has focus", () => {
  flatTableCell(8).should("have.css", "outline-color", gold);
});

Then("The {word} content row has focus", (position) => {
  flatTableBodyRowByPosition(positionOfElement(position))
    .should("have.focus")
    .and("have.css", "outline-color", gold);
});

Then("The {word} subrow action popover has focus", (position) => {
  flatTableSubrowByPosition(positionOfElement(position))
    .find('[data-component="action-popover-button"]')
    .should("have.focus")
    .and("have.css", "outline", `${gold} solid 2px`);
});

When("I have a large viewport", () => {
  cy.viewport(700, 345);
});

When("I have a small viewport", () => {
  cy.viewport(700, 240);
});

When("pageSize select list is opened", () => {
  flatTablePageSizeSelect().click();
});

Then("pageSizeSelectList is visible at the {word}", (position) => {
  flatTablePageSelectListPosition()
    .should("have.attr", "data-popper-placement", `${position}-start`)
    .and("be.visible");
});

Then("{int} row/rows is/are visible", (int) => {
  flatTableBodyRows().should("have.length", int).and("be.visible");
});

Then("I type {int} in pagination input", (value) => {
  pageSelectDataComponent().find("input").type(value);
});

Then("Pagination input should have {int} value", (value) => {
  pageSelectDataComponent().find("input").should("have.value", value);
});
<commit_msg>test(flat-table): update component cypress tests<commit_after>import {
  flatTable,
  flatTableHeaderCells,
  flatTableBodyRowByPosition,
  flatTableCell,
  flatTableClickableRow,
  flatTableSortable,
  flatTableBodyRows,
  flatTableCaption,
  flatTableSubrowByPosition,
  flatTableSubrows,
  flatTablePageSizeSelect,
  flatTablePageSelectListPosition,
  pageSelectDataComponent,
} from "../../locators/flat-table";

import DEBUG_FLAG from "..";
import { positionOfElement } from "../helper";
import { icon } from "../../locators";

const gold = "rgb(255, 181, 0)";

Then("FlatTable body rows are sticky", () => {
  cy.wait(500);
  for (let i = 0; i <= 3; i++) {
    const color = "rgb(204, 214, 219)";
    flatTableClickableRow(i)
      .find("th")
      .should("have.css", "border-right-color", color)
      .and("have.css", "border-left-color", color)
      .and("have.css", "border-bottom-color", color)
      .and("have.css", "position", "sticky")
      .and("be.visible");
  }
});

Then("FlatTable header first cell is sticky", () => {
  cy.wait(500);
  flatTableHeaderCells()
    .first()
    .should("have.css", "position", "sticky")
    .and("be.visible");
});

Then("FlatTable has sticky header", () => {
  cy.wait(300, { log: DEBUG_FLAG }); // required because element needs to be loaded
  flatTableHeaderCells().each(($el) => {
    cy.wrap($el).should("have.css", "position", "sticky").and("be.visible");
  });
});

Then("First/Last {int} header cells {word} visible", (count, state) => {
  if (state === "are") {
    for (let i = 6; i > 6 - count; i--) {
      flatTableHeaderCells().eq(i).should("be.visible");
    }
  } else {
    for (let i = 1; i <= count; i++) {
      flatTableHeaderCells().eq(i).should("not.be.visible");
    }
  }
});

When("I scroll table content to bottom right", () => {
  cy.viewport(625, 450);
  flatTable().parent().scrollTo("100%", "100%");
});

Then("First/Last {int} FlatTable rows {word} visible", (count, state) => {
  if (state === "are") {
    for (let i = 8; i > 8 - count; i--) {
      flatTableBodyRowByPosition(i).should("be.visible");
    }
  } else {
    for (let i = 0; i < count; i++) {
      flatTableBodyRowByPosition(i).should("not.be.visible");
    }
  }
});

Then("I click on {int} body row", (index) => {
  flatTableBodyRowByPosition(index).click({ force: true });
});

Then(
  "I focus {int} row and focused row element has golden border on focus",
  (index) => {
    cy.wait(500, { log: DEBUG_FLAG }); // wait was added due to changing animation
    flatTableBodyRowByPosition(index)
      .focus()
      .should("have.css", "outline-color", gold);
  }
);

Then("press Enter key on the row element", () => {
  flatTableBodyRowByPosition(2)
    .focus()
    .trigger("keydown", { keyCode: 13, which: 13, force: true });
});

Then("I click on {string} header {int} times", (position, times) => {
  for (let i = 0; i < times; i++) {
    flatTableSortable().eq(positionOfElement(position)).click();
  }
});

When("{string} column is sorted in {string} order", (position, sortOrder) => {
  const valueOne = "Tyler Webb";
  const valueTwo = "Monty Parker";
  const valueThree = "Jason Atkinson";
  const valueFour = "Blake Sutton";
  const totalOne = "280";
  const totalTwo = "1349";
  const totalThree = "849";
  const totalFour = "3840";
  if (position === "first" && sortOrder === "desc") {
    icon().should("have.attr", "data-element", "sort_down").and("be.visible");
    flatTableCell(positionOfElement("first"))
      .should("have.text", valueOne)
      .and("be.visible");
    flatTableCell(positionOfElement("third"))
      .should("have.text", valueTwo)
      .and("be.visible");
    flatTableCell(positionOfElement("fifth"))
      .should("have.text", valueThree)
      .and("be.visible");
    flatTableCell(positionOfElement("seventh"))
      .should("have.text", valueFour)
      .and("be.visible");
  } else if (position === "first" && sortOrder === "asc") {
    icon().should("have.attr", "data-element", "sort_up").and("be.visible");
    flatTableCell(positionOfElement("first"))
      .should("have.text", valueFour)
      .and("be.visible");
    flatTableCell(positionOfElement("third"))
      .should("have.text", valueThree)
      .and("be.visible");
    flatTableCell(positionOfElement("fifth"))
      .should("have.text", valueTwo)
      .and("be.visible");
    flatTableCell(positionOfElement("seventh"))
      .should("have.text", valueOne)
      .and("be.visible");
  } else if (position === "second" && sortOrder === "desc") {
    icon().should("have.attr", "data-element", "sort_down").and("be.visible");
    flatTableCell(positionOfElement("second"))
      .should("have.text", totalFour)
      .and("be.visible");
    flatTableCell(positionOfElement("fourth"))
      .should("have.text", totalTwo)
      .and("be.visible");
    flatTableCell(positionOfElement("sixth"))
      .should("have.text", totalThree)
      .and("be.visible");
    flatTableCell(positionOfElement("eighth"))
      .should("have.text", totalOne)
      .and("be.visible");
  } else {
    icon().should("have.attr", "data-element", "sort_up").and("be.visible");
    flatTableCell(positionOfElement("second"))
      .should("have.text", totalOne)
      .and("be.visible");
    flatTableCell(positionOfElement("fourth"))
      .should("have.text", totalThree)
      .and("be.visible");
    flatTableCell(positionOfElement("sixth"))
      .should("have.text", totalTwo)
      .and("be.visible");
    flatTableCell(positionOfElement("eighth"))
      .should("have.text", totalFour)
      .and("be.visible");
  }
});

Then("{string} header has focus", (position) => {
  flatTableSortable()
    .eq(positionOfElement(position))
    .should("have.css", "outline-color", gold);
});

Then("I focus {string} header cell", (position) => {
  flatTableSortable().eq(positionOfElement(position)).focus();
});

Then(
  "I press {string} on {string} header {int} time(s)",
  (key, position, count) => {
    for (let i = 0; i < count; i++) {
      if (key === "Enter") {
        flatTableSortable()
          .eq(positionOfElement(position))
          .focus()
          .trigger("keydown", { keyCode: 13, which: 13, force: true });
      } else if (key === "Space") {
        flatTableSortable()
          .eq(positionOfElement(position))
          .focus()
          .trigger("keydown", { keyCode: 32, which: 32, force: true });
      } else {
        throw new Error("Only Enter or Space key can be applied");
      }
    }
  }
);

When("I click on the first row", () => {
  flatTableBodyRows().first().click();
});

Then("The whole row is highlighted", () => {
  flatTableBodyRows()
    .first()
    .children()
    .should("have.css", "background-color", "rgb(230, 235, 237)");
});

Then("Flat table caption is set to {word}", (text) => {
  flatTableCaption().should("have.text", text);
});

When("I click on the {word} cell in the first row", (position) => {
  flatTableCell(positionOfElement(position)).click();
});

Then("The subrows are visible", () => {
  flatTableSubrows().should("be.visible");
});

Then("The subrows are not visible", () => {
  flatTableSubrows().should("not.exist");
});

When("I click on the first cell", () => {
  flatTableCell(0).click();
});

Then("The first cell in the third content row has focus", () => {
  flatTableCell(8).should("have.css", "outline-color", gold);
});

Then("The {word} content row has focus", (position) => {
  flatTableBodyRowByPosition(positionOfElement(position))
    .should("have.focus")
    .and("have.css", "outline-color", gold);
});

Then("The {word} subrow action popover has focus", (position) => {
  flatTableSubrowByPosition(positionOfElement(position))
    .find('[data-component="action-popover-button"]')
    .should("have.focus")
    .and("have.css", "outline", `${gold} solid 2px`);
});

When("I have a large viewport", () => {
  cy.viewport(700, 345);
});

When("I have a small viewport", () => {
  cy.viewport(700, 240);
});

When("pageSize select list is opened", () => {
  flatTablePageSizeSelect().click();
});

Then("pageSizeSelectList is visible at the {word}", (position) => {
  flatTablePageSelectListPosition()
    .should("have.attr", "data-popper-placement", `${position}-start`)
    .and("be.visible");
});

Then("{int} row/rows is/are visible", (int) => {
  flatTableBodyRows().should("have.length", int).and("be.visible");
});

Then("I type {int} in pagination input", (value) => {
  pageSelectDataComponent().find("input").type(value);
});

Then("Pagination input should have {int} value", (value) => {
  pageSelectDataComponent().find("input").should("have.value", value);
});
<|endoftext|>


<commit_before>import { findDOMNode } from 'react-dom';
import { width } from 'dom-helpers/query';

export function hover(props, monitor, component) {
  const item = monitor.getItem();
  const dragIndex = item.rowIndex;
  const dragListIndex = item.listIndex;
  const hoverIndex = props.rowIndex;
  const hoverListIndex = props.listIndex;

  // Hovering over the same item
  if (dragIndex === hoverIndex && dragListIndex === hoverListIndex) {
    return;
  }

  // Sometimes component may be null (probably is being unmounted?)
  if (!component) {
    console.warn(`null component for #${item.rowId}`);
    return;
  }

  // Determine rectangle on screen
  const node = findDOMNode(component);
  const hoverBoundingRect = node.getBoundingClientRect();

  // Get vertical middle
  const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;

  // Determine mouse position
  const clientOffset = monitor.getClientOffset();

  // Get pixels to the top
  const hoverClientY = clientOffset.y - hoverBoundingRect.top;

  // Dragging horizontaly between lists
  if (hoverBoundingRect.left < clientOffset.x &&
      clientOffset.x < hoverBoundingRect.right &&
      dragListIndex !== hoverListIndex) {
    item.rowIndex = hoverIndex;
    item.listIndex = hoverListIndex;
    item.containerWidth = width(node);

    props.moveRow(
      {rowIndex: dragIndex, listIndex: dragListIndex},
      {rowIndex: hoverIndex, listIndex: hoverListIndex}
    );
    return;
  }

  // Dragging downwards
  if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
    return;
  }

  // Dragging upwards
  if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
    return;
  }

  item.rowIndex = hoverIndex;
  item.listIndex = hoverListIndex;
  item.containerWidth = width(node);

  props.moveRow(
    {rowIndex: dragIndex, listIndex: dragListIndex},
    {rowIndex: hoverIndex, listIndex: hoverListIndex}
  );
}

export function drop(props) {
  const { rowId, listId, rowIndex, listIndex } = props;

  props.dropRow({rowId, listId, rowIndex, listIndex});
}
<commit_msg>Add canDrop implementation for SortableItem component (#7)<commit_after>import { findDOMNode } from 'react-dom';
import { width } from 'dom-helpers/query';

export function hover(props, monitor, component) {
  const item = monitor.getItem();
  const dragIndex = item.rowIndex;
  const dragListIndex = item.listIndex;
  const hoverIndex = props.rowIndex;
  const hoverListIndex = props.listIndex;

  // Hovering over the same item
  if (dragIndex === hoverIndex && dragListIndex === hoverListIndex) {
    return;
  }

  // Sometimes component may be null (probably is being unmounted?)
  if (!component) {
    console.warn(`null component for #${item.rowId}`);
    return;
  }

  // Determine rectangle on screen
  const node = findDOMNode(component);
  const hoverBoundingRect = node.getBoundingClientRect();

  // Get vertical middle
  const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;

  // Determine mouse position
  const clientOffset = monitor.getClientOffset();

  // Get pixels to the top
  const hoverClientY = clientOffset.y - hoverBoundingRect.top;

  // Dragging horizontaly between lists
  if (hoverBoundingRect.left < clientOffset.x &&
      clientOffset.x < hoverBoundingRect.right &&
      dragListIndex !== hoverListIndex) {
    item.rowIndex = hoverIndex;
    item.listIndex = hoverListIndex;
    item.containerWidth = width(node);

    props.moveRow(
      {rowIndex: dragIndex, listIndex: dragListIndex},
      {rowIndex: hoverIndex, listIndex: hoverListIndex}
    );
    return;
  }

  // Dragging downwards
  if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
    return;
  }

  // Dragging upwards
  if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
    return;
  }

  item.rowIndex = hoverIndex;
  item.listIndex = hoverListIndex;
  item.containerWidth = width(node);

  props.moveRow(
    {rowIndex: dragIndex, listIndex: dragListIndex},
    {rowIndex: hoverIndex, listIndex: hoverListIndex}
  );
}

export function canDrop(props, monitor) {
  const item = monitor.getItem();

  return item.rowId === props.rowId;
}

export function drop(props) {
  const { rowId, listId, rowIndex, listIndex } = props;

  props.dropRow({rowId, listId, rowIndex, listIndex});
}
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */

var express = require('express');
var api = require('lib/db-api');
var utils = require('lib/utils');
var accepts = require('lib/accepts');
var restrict = utils.restrict;
var staff = utils.staff;
var pluck = utils.pluck;
var expose = utils.expose;
var log = require('debug')('democracyos:law');

var app = module.exports = express();

/**
 * Limit request to json format only
 */

app.use(accepts('application/json'));

app.get('/law/all', function (req, res) {
  log('Request /law/all');

  api.law.all(function(err, lawDocs) {
    if (err) return _handleError(err, req, res);

    // filter only public documents
    lawDocs = lawDocs.filter(function(law) {
      return law.public || (req.user && req.user.staff)
    });

    // add voted flag to returning documents
    lawDocs.forEach(function(law) {
      if (!req.user) return law.voted = false;
      law.voted = law.votedBy(req.user);
    });

    log('Serving laws %j', pluck(lawDocs, "id"));

    var keys = [
      'id lawId mediaTitle status open closed public draft deleted',
      'tag participants voted createdAt updatedAt closingAt',
      'publishedAt deletedAt votable clauseTruncationText links author authorUrl'
    ].join(' ');

    res.json(lawDocs.map(expose(keys)));
  });
});

app.get('/law/:id', function (req, res) {
  log('Request GET /law/%s', req.params.id);

  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);
    if (!lawDoc) return res.send(404);

    log('Serving law %s', lawDoc.id);
    var keys = [
      'id lawId title mediaTitle summary clauses source status open closed public draft deleted',
      'satus state tag participants',
      'upvotes downvotes abstentions createdAt updatedAt closingAt',
      'publishedAt deletedAt votable clauseTruncationText links author authorUrl'
    ].join(' ');

    res.json(expose(keys)(lawDoc.toJSON()));
  });
});

app.get('/law/:id/summary-comments', function (req, res) {
  log('Request /law/%s/summary-comments', req.params.id);

  api.law.get(req.params.id, function (err, law) {
    if (err) return _handleError(err, req, res);

    var re = new RegExp(req.params.id + '\-\\d');
    api.comment.getFor({context: 'summary', reference: re}, null, function (err, comments) {
      if (err) return _handleError(err, req, res);

      log('Serving law %s summary\'s comments %j', req.params.id, pluck(comments, 'id'));

      var keys = [
        'id text createdAt editedAt context reference',
        'author.id author.fullName author.gravatar() author.profilePictureUrl',
        'flags upvotes downvotes votes replies.length'
      ].join(' ');

      res.json(comments.map(expose(keys)));
    });

  });
});

app.get('/law/:id/clause-comments', function (req, res) {
  log('Request /law/%s/clause-comments', req.params.id);

  api.law.get(req.params.id, function (err, law) {
    if (err) return _handleError(err, req, res);

    var clauses = law.clauses.map(function (clause) { return clause.id });

    api.comment.getFor({context: 'clause', reference: { $in: clauses } }, null, function (err, comments) {
      if (err) return _handleError(err, req, res);

      log('Serving law %s clauses\' comments %j', req.params.id, pluck(comments, 'id'));

      var keys = [
        'id text createdAt editedAt context reference',
        'author.id author.fullName author.gravatar() author.profilePictureUrl',
        'flags upvotes downvotes votes replies.length'
      ].join(' ');

      res.json(comments.map(expose(keys)));
    });

  });
});

app.get('/law/:id/comments', function (req, res) {
  log('Request /law/%s/comments', req.params.id);

  var sort = '';
  if (~['-score', '-createdAt', 'createdAt'].indexOf(req.query.sort)) {
    sort = req.query.sort;
  } else {
    sort = '-score';
  }

  var paging = {
    page: req.query.page || 0,
    limit: req.query.limit || 0,
    sort: sort,
    exclude_user: req.query.exclude_user || null
  };

  api.law.comments(req.params.id, paging, function (err, comments) {
    if (err) return _handleError(err, req, res);

    if (!req.query.count) {
      log('Serving law %s comments %j', req.params.id, pluck(comments, 'id'));

      var keys = [
        "id text createdAt editedAt context reference",
        "author.id author.fullName author.gravatar() author.profilePictureUrl",
        "flags upvotes downvotes votes replies.length"
      ].join(' ');

      res.json(comments.map(expose(keys)));
    } else {
      log('Serving law %s comments count: %d', req.params.id, comments.length);

      res.json(comments.length);
    }
  });
});

app.get('/law/:id/my-comments', restrict, function (req, res) {
  log('Request /law/%s/my-comments', req.params.id);

  api.law.citizenComments(req.params.id, req.user.id, function (err, comments) {
    if (err) return _handleError(err, req, res);

    log('Serving law %s comments %j for citizen %s', req.params.id, pluck(comments, 'id'), req.user.id);

    var keys = [
      "id text createdAt editedAt context reference",
      "author.id author.fullName author.gravatar() author.profilePictureUrl",
      "flags upvotes downvotes votes replies.length"
    ].join(' ');

    res.json(comments.map(expose(keys)));
  });
});

app.post('/law/:id/comment', restrict, function (req, res) {
  log('Request /law/%s/comment %j', req.params.id, req.body.comment);

  var comment = req.body.comment;
  // This must be uncommented on production!
  comment.author = req.user;

  api.law.comment(comment, function (err, commentDoc) {
    if (err) return _handleError(err, req, res);

    var keys = [
      'id text',
      'author.id author.fullName author.gravatar() author.profilePictureUrl',
      'upvotes downvotes flags',
      'createdAt replies context reference'
    ].join(' ');

    res.json(200, expose(keys)(commentDoc));
  });
});

app.post('/law/:id/vote', function (req, res) {
  log('Request /law/%s/vote', req.param('id'));

  api.law
  .vote(
    req.param('id'),
    req.user,
    req.param('value'),
    function (err, comments) {
      if (err) return _handleError(err, req, res);

      log('Serving 200 OK response');
      res.send(200);
    }
  );
});

app.post('/law/create', restrict, staff, function (req, res, next) {
  log('Request /law/create %j', req.body.law);

  api.law.create(req.body, function (err, lawDoc) {
    if (err) return next(err);
    var keys = [
      'id lawId title mediaTitle summary clauses source state',
      'status open closed public draft deleted tag participants',
      'upvotes downvotes abstentions createdAt updatedAt closingAt',
      'publishedAt deletedAt votable clauseTruncationText links author authorUrl'
    ].join(' ');
    res.json(expose(keys)(lawDoc));
  });
});

app.post('/law/:id', restrict, staff, function (req, res) {
  log('Request POST /law/%s', req.params.id);

  api.law.update(req.params.id, req.body, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    log('Serving law %s', lawDoc.id);
    var keys = [
      'id lawId title mediaTitle summary clauses source state',
      'status open closed public draft deleted tag participants',
      'upvotes downvotes abstentions createdAt updatedAt closingAt',
      'publishedAt deletedAt votable clauseTruncationText links author authorUrl'
    ].join(' ');

    res.json(expose(keys)(lawDoc.toJSON()));
  });
});

app.post('/law/:id/clause', restrict, staff, function (req, res) {
  log('Request POST /law/%s/clause', req.params.id);

  var clause = req.body.clause;
  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    var clauseDoc = clause && clause.id
      ? lawDoc.clauses.id(clause.id)
      : lawDoc.clauses.create();

    clauseDoc.update(clause);
    if (clauseDoc.isNew) lawDoc.clauses.push(clauseDoc);

    lawDoc.save(function (err, saved) {
      if (err) return _handleError(err, req, res);

      res.json(200, expose('id order clauseName text centered')(clauseDoc));
    });
  });
});

app.del('/law/:id/clause', restrict, staff, function (req, res) {
  log('Request DELETE /law/%s/clause', req.params.id);

  var clause = req.body.clause;
  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    lawDoc.clauses.remove(clause);
    log('removed clause %s from law %s', clause, lawDoc.id);

    lawDoc.save(function (err, saved) {
      if (err) return _handleError(err, req, res);

      res.json(200);
    });
  });
});

app.post('/law/:id/link', restrict, staff, function (req, res) {
  log('Request POST /law/%s/link', req.params.id);

  var link = req.body.link;
  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    var linkDoc = link && link.id
      ? lawDoc.links.id(link.id)
      : lawDoc.links.create();

    linkDoc.update(link);
    if (linkDoc.isNew) lawDoc.links.push(linkDoc);

    lawDoc.save(function (err, saved) {
      if (err) return _handleError(err, req, res);

      res.json(200, expose('id text url')(linkDoc));
    });
  });
});

app.del('/law/:id/link', restrict, staff, function (req, res) {
  log('Request DELETE /law/%s/link', req.params.id);

  var link = req.body.link;
  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    lawDoc.links.remove(link);
    log('removed link %s from law %s', link, lawDoc.id);

    lawDoc.save(function (err, saved) {
      if (err) return _handleError(err, req, res);

      res.json(200);
    });
  });
});

app.post('/law/:id/publish', restrict, staff, function (req, res) {
  log('Request POST /law/%s/publish', req.params.id);

  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    lawDoc.publishedAt = new Date;
    lawDoc.save(function (err, saved) {
      if (err) return _handleError(err, req, res);
      log('publish law %s at %s', lawDoc.id, lawDoc.publishedAt);
      res.json(200);
    });
  });
});

app.post('/law/:id/unpublish', restrict, staff, function (req, res) {
  log('Request POST /law/%s/unpublish', req.params.id);

  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    lawDoc.publishedAt = null;
    lawDoc.save(function (err, saved) {
      if (err) return _handleError(err, req, res);
      log('unpublished law %s', lawDoc.id);
      res.json(200);
    });
  });
});

app.post('/law/:id/delete', restrict, staff, function (req, res) {
  log('Request POST /law/%s/delete', req.params.id);

  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    lawDoc.deletedAt = new Date;
    lawDoc.save(function (err, saved) {
      if (err) return _handleError(err, req, res);
      log('deleted law %s', lawDoc.id);
      res.json(200);
    });
  });
});

function _handleError (err, req, res) {
  log("Error found: %s", err);
  var error = err;
  if (err.errors && err.errors.text) error = err.errors.text;
  if (error.type) error = error.type;

  res.json(400, { error: error });
}<commit_msg>[law-api] Add restrict middleware to vote endpoint. Closes #490.<commit_after>/**
 * Module dependencies.
 */

var express = require('express');
var api = require('lib/db-api');
var utils = require('lib/utils');
var accepts = require('lib/accepts');
var restrict = utils.restrict;
var staff = utils.staff;
var pluck = utils.pluck;
var expose = utils.expose;
var log = require('debug')('democracyos:law');

var app = module.exports = express();

/**
 * Limit request to json format only
 */

app.use(accepts('application/json'));

app.get('/law/all', function (req, res) {
  log('Request /law/all');

  api.law.all(function(err, lawDocs) {
    if (err) return _handleError(err, req, res);

    // filter only public documents
    lawDocs = lawDocs.filter(function(law) {
      return law.public || (req.user && req.user.staff)
    });

    // add voted flag to returning documents
    lawDocs.forEach(function(law) {
      if (!req.user) return law.voted = false;
      law.voted = law.votedBy(req.user);
    });

    log('Serving laws %j', pluck(lawDocs, "id"));

    var keys = [
      'id lawId mediaTitle status open closed public draft deleted',
      'tag participants voted createdAt updatedAt closingAt',
      'publishedAt deletedAt votable clauseTruncationText links author authorUrl'
    ].join(' ');

    res.json(lawDocs.map(expose(keys)));
  });
});

app.get('/law/:id', function (req, res) {
  log('Request GET /law/%s', req.params.id);

  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);
    if (!lawDoc) return res.send(404);

    log('Serving law %s', lawDoc.id);
    var keys = [
      'id lawId title mediaTitle summary clauses source status open closed public draft deleted',
      'satus state tag participants',
      'upvotes downvotes abstentions createdAt updatedAt closingAt',
      'publishedAt deletedAt votable clauseTruncationText links author authorUrl'
    ].join(' ');

    res.json(expose(keys)(lawDoc.toJSON()));
  });
});

app.get('/law/:id/summary-comments', function (req, res) {
  log('Request /law/%s/summary-comments', req.params.id);

  api.law.get(req.params.id, function (err, law) {
    if (err) return _handleError(err, req, res);

    var re = new RegExp(req.params.id + '\-\\d');
    api.comment.getFor({context: 'summary', reference: re}, null, function (err, comments) {
      if (err) return _handleError(err, req, res);

      log('Serving law %s summary\'s comments %j', req.params.id, pluck(comments, 'id'));

      var keys = [
        'id text createdAt editedAt context reference',
        'author.id author.fullName author.gravatar() author.profilePictureUrl',
        'flags upvotes downvotes votes replies.length'
      ].join(' ');

      res.json(comments.map(expose(keys)));
    });

  });
});

app.get('/law/:id/clause-comments', function (req, res) {
  log('Request /law/%s/clause-comments', req.params.id);

  api.law.get(req.params.id, function (err, law) {
    if (err) return _handleError(err, req, res);

    var clauses = law.clauses.map(function (clause) { return clause.id });

    api.comment.getFor({context: 'clause', reference: { $in: clauses } }, null, function (err, comments) {
      if (err) return _handleError(err, req, res);

      log('Serving law %s clauses\' comments %j', req.params.id, pluck(comments, 'id'));

      var keys = [
        'id text createdAt editedAt context reference',
        'author.id author.fullName author.gravatar() author.profilePictureUrl',
        'flags upvotes downvotes votes replies.length'
      ].join(' ');

      res.json(comments.map(expose(keys)));
    });

  });
});

app.get('/law/:id/comments', function (req, res) {
  log('Request /law/%s/comments', req.params.id);

  var sort = '';
  if (~['-score', '-createdAt', 'createdAt'].indexOf(req.query.sort)) {
    sort = req.query.sort;
  } else {
    sort = '-score';
  }

  var paging = {
    page: req.query.page || 0,
    limit: req.query.limit || 0,
    sort: sort,
    exclude_user: req.query.exclude_user || null
  };

  api.law.comments(req.params.id, paging, function (err, comments) {
    if (err) return _handleError(err, req, res);

    if (!req.query.count) {
      log('Serving law %s comments %j', req.params.id, pluck(comments, 'id'));

      var keys = [
        "id text createdAt editedAt context reference",
        "author.id author.fullName author.gravatar() author.profilePictureUrl",
        "flags upvotes downvotes votes replies.length"
      ].join(' ');

      res.json(comments.map(expose(keys)));
    } else {
      log('Serving law %s comments count: %d', req.params.id, comments.length);

      res.json(comments.length);
    }
  });
});

app.get('/law/:id/my-comments', restrict, function (req, res) {
  log('Request /law/%s/my-comments', req.params.id);

  api.law.citizenComments(req.params.id, req.user.id, function (err, comments) {
    if (err) return _handleError(err, req, res);

    log('Serving law %s comments %j for citizen %s', req.params.id, pluck(comments, 'id'), req.user.id);

    var keys = [
      "id text createdAt editedAt context reference",
      "author.id author.fullName author.gravatar() author.profilePictureUrl",
      "flags upvotes downvotes votes replies.length"
    ].join(' ');

    res.json(comments.map(expose(keys)));
  });
});

app.post('/law/:id/comment', restrict, function (req, res) {
  log('Request /law/%s/comment %j', req.params.id, req.body.comment);

  var comment = req.body.comment;
  // This must be uncommented on production!
  comment.author = req.user;

  api.law.comment(comment, function (err, commentDoc) {
    if (err) return _handleError(err, req, res);

    var keys = [
      'id text',
      'author.id author.fullName author.gravatar() author.profilePictureUrl',
      'upvotes downvotes flags',
      'createdAt replies context reference'
    ].join(' ');

    res.json(200, expose(keys)(commentDoc));
  });
});

app.post('/law/:id/vote', restrict, function (req, res) {
  log('Request /law/%s/vote', req.param('id'));

  api.law
  .vote(
    req.param('id'),
    req.user,
    req.param('value'),
    function (err, comments) {
      if (err) return _handleError(err, req, res);

      log('Serving 200 OK response');
      res.send(200);
    }
  );
});

app.post('/law/create', restrict, staff, function (req, res, next) {
  log('Request /law/create %j', req.body.law);

  api.law.create(req.body, function (err, lawDoc) {
    if (err) return next(err);
    var keys = [
      'id lawId title mediaTitle summary clauses source state',
      'status open closed public draft deleted tag participants',
      'upvotes downvotes abstentions createdAt updatedAt closingAt',
      'publishedAt deletedAt votable clauseTruncationText links author authorUrl'
    ].join(' ');
    res.json(expose(keys)(lawDoc));
  });
});

app.post('/law/:id', restrict, staff, function (req, res) {
  log('Request POST /law/%s', req.params.id);

  api.law.update(req.params.id, req.body, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    log('Serving law %s', lawDoc.id);
    var keys = [
      'id lawId title mediaTitle summary clauses source state',
      'status open closed public draft deleted tag participants',
      'upvotes downvotes abstentions createdAt updatedAt closingAt',
      'publishedAt deletedAt votable clauseTruncationText links author authorUrl'
    ].join(' ');

    res.json(expose(keys)(lawDoc.toJSON()));
  });
});

app.post('/law/:id/clause', restrict, staff, function (req, res) {
  log('Request POST /law/%s/clause', req.params.id);

  var clause = req.body.clause;
  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    var clauseDoc = clause && clause.id
      ? lawDoc.clauses.id(clause.id)
      : lawDoc.clauses.create();

    clauseDoc.update(clause);
    if (clauseDoc.isNew) lawDoc.clauses.push(clauseDoc);

    lawDoc.save(function (err, saved) {
      if (err) return _handleError(err, req, res);

      res.json(200, expose('id order clauseName text centered')(clauseDoc));
    });
  });
});

app.del('/law/:id/clause', restrict, staff, function (req, res) {
  log('Request DELETE /law/%s/clause', req.params.id);

  var clause = req.body.clause;
  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    lawDoc.clauses.remove(clause);
    log('removed clause %s from law %s', clause, lawDoc.id);

    lawDoc.save(function (err, saved) {
      if (err) return _handleError(err, req, res);

      res.json(200);
    });
  });
});

app.post('/law/:id/link', restrict, staff, function (req, res) {
  log('Request POST /law/%s/link', req.params.id);

  var link = req.body.link;
  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    var linkDoc = link && link.id
      ? lawDoc.links.id(link.id)
      : lawDoc.links.create();

    linkDoc.update(link);
    if (linkDoc.isNew) lawDoc.links.push(linkDoc);

    lawDoc.save(function (err, saved) {
      if (err) return _handleError(err, req, res);

      res.json(200, expose('id text url')(linkDoc));
    });
  });
});

app.del('/law/:id/link', restrict, staff, function (req, res) {
  log('Request DELETE /law/%s/link', req.params.id);

  var link = req.body.link;
  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    lawDoc.links.remove(link);
    log('removed link %s from law %s', link, lawDoc.id);

    lawDoc.save(function (err, saved) {
      if (err) return _handleError(err, req, res);

      res.json(200);
    });
  });
});

app.post('/law/:id/publish', restrict, staff, function (req, res) {
  log('Request POST /law/%s/publish', req.params.id);

  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    lawDoc.publishedAt = new Date;
    lawDoc.save(function (err, saved) {
      if (err) return _handleError(err, req, res);
      log('publish law %s at %s', lawDoc.id, lawDoc.publishedAt);
      res.json(200);
    });
  });
});

app.post('/law/:id/unpublish', restrict, staff, function (req, res) {
  log('Request POST /law/%s/unpublish', req.params.id);

  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    lawDoc.publishedAt = null;
    lawDoc.save(function (err, saved) {
      if (err) return _handleError(err, req, res);
      log('unpublished law %s', lawDoc.id);
      res.json(200);
    });
  });
});

app.post('/law/:id/delete', restrict, staff, function (req, res) {
  log('Request POST /law/%s/delete', req.params.id);

  api.law.get(req.params.id, function (err, lawDoc) {
    if (err) return _handleError(err, req, res);

    lawDoc.deletedAt = new Date;
    lawDoc.save(function (err, saved) {
      if (err) return _handleError(err, req, res);
      log('deleted law %s', lawDoc.id);
      res.json(200);
    });
  });
});

function _handleError (err, req, res) {
  log("Error found: %s", err);
  var error = err;
  if (err.errors && err.errors.text) error = err.errors.text;
  if (error.type) error = error.type;

  res.json(400, { error: error });
}<|endoftext|>


<commit_before>Collections = require('collections');
FastMap = Collections.FastMap;
AuthList = new FastMap();

var Auth = {

};

/**
 * A Maybe Monad - Allows chainable calls and encapsulates empty/null/undefined values verification
 * @see http://sean.voisen.org/blog/2013/10/intro-monads-maybe/
 *
 * @param value Some value of any type
 * @return MaybeMonad Can be 'something' or 'nothing'
 */
var MaybeMonad = function(value){
    var nothing = {

        /**
         *
         *
         */
        bind : function(fn){
            return this;
        },

        /**
         *
         * @param def A default value to be returned in case of nothing
         * @param fn A transformation to be applied over the value in case of something
         */
         maybe : function(def, fn){
          return def;
        }
    };

    /**
     *
     *@param value
     *@return
     */
    var something = function(value){
        return {
            /**
             *
             *
             */
            bind : function(fn){
                MaybeMonad(fn.call(this, value));
            },

            /**
             *
             *
             */
            maybe : function(def, fn){
                return fn.call(this, value);
            }
        };
    };

    if(value === null || value === undefined || typeof value === 'undefined' || value.lenght && value.lenght <= 0)
      return nothing;

    return something(value);
};

var StateMonad = function(value){

};

var saveAuthorization = function(list, action, context, authorization, resource_provider, authorized_resource_provider){
    auth = new Auth();
    auth.action = action;
    auth.auth = authorization;
    auth.resource_provider = resource_provider;
    auth.authorized_resource_provider = authorized_resource_provider;

    if(!list.has(context)){
        list.set(context, auth);
    } else {
        // throw a exception or return some kind of error
    }

};

/**
 *
 *
 *@param action
 *@param context
 *@param authorization
 *@param app_context_provider
 *@param app_resource_provider
 */
var can = function(action, context, authorization, resource_provider, authorized_resource_provider){
    saveAuthorization(AuthList, action, context, authorization, resource_provider, authorized_resource_provider);
};

/**
 *
 *
 */
var and = function(){
    return function(user, app_context, app_resource){
        return arguments.reduce(function(acc, curr){
            return acc && curr(user, app_context, app_resource);
        }, true);
    };
};

/**
 *
 *
 */
var or = function(){
    return function(user, app_context, app_resource){
        return arguments.reduce(function(acc, curr){
            return acc || curr(user, app_context, app_resource);
        }, false);
    };
};

/**
 *
 *
 */
var not = function(authorization){
    return function(user, app_context, app_resource){
        return true && !authorization(user, app_context, app_resource);
    };
};

/**
 *
 *
 */
var revoke = function(action, context){};

/**
 *
 *
 */
var override = function(action, context, app){

};

/**
 *
 *
 */
var can_i = function(action, context, user, app_context){

    return {
        result : true,

    };
};

/**
 *
 *
 *@param action
 *@param context
 *@param user
 *@param app_context
 *
 *@return MaybeMonad
 */
var authorize = function(action, context, user, app_context){

    return MaybeMonad(resource);
};

exports.authorize = authorize;
exports.can = can;
exports.cannot = cannot;
exports.and = and;
exports.or = or;
exports.not = not;
exports.revoke = revoke;
exports.override = override;
<commit_msg>Fixing module exporting in `nocando.js`<commit_after>var FastMap = require('collections').FastMap;
var AuthList = new FastMap();

var Auth = {

};

/**
 * A Maybe Monad - Allows chainable calls and encapsulates empty/null/undefined values verification
 * @see http://sean.voisen.org/blog/2013/10/intro-monads-maybe/
 *
 * @param value Some value of any type
 * @return MaybeMonad Can be 'something' or 'nothing'
 */
var MaybeMonad = function(value){
    var nothing = {

        /**
         *
         *
         */
        bind : function(fn){
            return this;
        },

        /**
         *
         * @param def A default value to be returned in case of nothing
         * @param fn A transformation to be applied over the value in case of something
         */
         maybe : function(def, fn){
          return def;
        }
    };

    /**
     *
     *@param value
     *@return
     */
    var something = function(value){
        return {
            /**
             *
             *
             */
            bind : function(fn){
                MaybeMonad(fn.call(this, value));
            },

            /**
             *
             *
             */
            maybe : function(def, fn){
                return fn.call(this, value);
            }
        };
    };

    if(value === null || value === undefined || typeof value === 'undefined' || value.lenght && value.lenght <= 0)
      return nothing;

    return something(value);
};

var StateMonad = function(value){

};

var saveAuthorization = function(list, action, context, authorization, resource_provider, authorized_resource_provider){
    auth = new Auth();
    auth.action = action;
    auth.auth = authorization;
    auth.resource_provider = resource_provider;
    auth.authorized_resource_provider = authorized_resource_provider;

    if(!list.has(context)){
        list.set(context, auth);
    } else {
        // throw a exception or return some kind of error
    }
};

/**
 *
 *
 *@param action
 *@param context
 *@param authorization
 *@param app_context_provider
 *@param app_resource_provider
 */
var can = function(action, context, authorization, resource_provider, authorized_resource_provider){
    saveAuthorization(AuthList, action, context, authorization, resource_provider, authorized_resource_provider);
};

/**
 *
 *
 */
var and = function(){
    return function(user, app_context, app_resource){
        return arguments.reduce(function(acc, curr){
            return acc && curr(user, app_context, app_resource);
        }, true);
    };
};

/**
 *
 *
 */
var or = function(){
    return function(user, app_context, app_resource){
        return arguments.reduce(function(acc, curr){
            return acc || curr(user, app_context, app_resource);
        }, false);
    };
};

/**
 *
 *
 */
var not = function(authorization){
    return function(user, app_context, app_resource){
        return true && !authorization(user, app_context, app_resource);
    };
};

/**
 *
 *
 */
var revoke = function(action, context){};

/**
 *
 *
 */
var override = function(action, context, app){

};

/**
 *
 *
 */
var can_i = function(action, context, user, app_context){

    return {
        result : true,

    };
};

/**
 *
 *
 *@param action
 *@param context
 *@param user
 *@param app_context
 *
 *@return MaybeMonad
 */
var authorize = function(action, context, user, app_context){

    return MaybeMonad(resource);
};

module.exports.authorize = authorize;
module.exports.can = can;
module.exports.and = and;
module.exports.or = or;
module.exports.not = not;
module.exports.revoke = revoke;
module.exports.override = override;
<|endoftext|>


<commit_before>var promisify = require('promisify-node');
var descriptors = require('../generate/v0.20.0.json');
var rawApi;

// Attempt to load the production release first, if it fails fall back to the
// debug release.
try {
  rawApi = require('../build/Release/nodegit');
}
catch (e) {
  rawApi = require('../build/Debug/nodegit');
}

// Set the exports prototype to the raw API.
exports.__proto__ = rawApi;

// Import extensions
require('./commit.js');
require('./diff.js');
require('./blob.js');
require('./object.js');
require('./signature.js');
require('./odb.js');
require('./oid.js');
require('./index.js');
require('./repository.js');
require('./reference.js');
require('./revwalk.js');
require('./tree.js');

// Wrap asynchronous methods to return promises.
promisify(exports);

// Native methods do not return an identifiable function, so this function will
// filter down the function identity to match the libgit2 descriptor.
promisify(rawApi, function(func, keyName, parentKeyName) {
  // Find the correct descriptor.
  var descriptor = descriptors.filter(function(descriptor) {
    var key = parentKeyName ? parentKeyName.slice(0, -1) : keyName;
    return descriptor.jsClassName === key;
  })[0];

  // If this is a top level construct, recurse into.
  if (!parentKeyName) {
    return true;
  }

  // Determine if this is a prototype method.
  var isPrototypeMethod = parentKeyName.slice(-1) === "#";

  if (descriptor && descriptor.functions) {
    // Find the nested function in the descriptor.
    if (parentKeyName.indexOf("Repo") > -1) { console.log(arguments); }
    var nestedFunction = descriptor.functions.filter(function(nestedFunction) {
      var test = keyName || func.name || parentKeyName;

      if (nestedFunction.jsFunctionName === keyName) {
        return func.isPrototypeMethod === isPrototypeMethod;
      }
    })[0];

    // Verify it is an asynchronous method.
    //console.log(nestedFunction && nestedFunction.isAsync);
    return nestedFunction && nestedFunction.isAsync;
  }
});

// Set version.
exports.version = require('./package').version;

// Initialize threads.
exports.Threads.init();
<commit_msg>A better way of wrapping native methods<commit_after>var promisify = require("promisify-node");
var descriptors = require("../generate/idefs.json");
var rawApi;

// Attempt to load the production release first, if it fails fall back to the
// debug release.
try {
  rawApi = require("../build/Release/nodegit");
}
catch (e) {
  rawApi = require("../build/Debug/nodegit");
}

// Set the exports prototype to the raw API.
exports.__proto__ = rawApi;

// Import extensions
require("./commit.js");
require("./diff.js");
require("./blob.js");
require("./object.js");
require("./signature.js");
require("./odb.js");
require("./oid.js");
require("./index.js");
require("./repository.js");
require("./reference.js");
require("./revwalk.js");
require("./tree.js");

// Wrap asynchronous methods to return promises.
promisify(exports);

// Native methods do not return an identifiable function, so this function will
// filter down the function identity to match the libgit2 descriptor.
descriptors.forEach(function(descriptor) {
  var Ctor =  rawApi[descriptor.jsClassName];

  // Iterate over each function in the file.
  descriptor.functions.filter(function(func) {
    return func.isAsync;
  }).forEach(function(asyncFunc) {
    var original = null;

    // Special case when you have a prototype method.
    if (asyncFunc.isPrototypeMethod) {
      original = Ctor.prototype[asyncFunc.jsFunctionName];
      Ctor.prototype[asyncFunc.jsFunctionName] = promisify(original);
    }
    else {
      original = Ctor[asyncFunc.jsFunctionName];
      Ctor[asyncFunc.jsFunctionName] = promisify(original);
    }
  });
});

// Set version.
exports.version = require("../package").version;

// Initialize threads.
exports.Threads.threadsInit();
<|endoftext|>