<commit_before>import React from 'react';
import Select, { Option } from 'select';
import { mount } from 'enzyme';

describe('<Select />', () => {
  test('data的传参方式有效', () => {
    const wrapper = mount(<Select data={[1, 2, 3]} />);
    expect(wrapper.find('Select').length).toBe(1);
    wrapper.find('SelectTrigger').simulate('click');
    expect(wrapper.find('Option').length).toBe(3);
  });

  test('Option的传参方式有效', () => {
    let wrapper = mount(
      <Select>
        <Option value="1">选项一</Option>
        <Option value="2">选项二</Option>
      </Select>
    );
    expect(wrapper.find('Select').length).toBe(1);
    wrapper.find('SelectTrigger').simulate('click');
    expect(wrapper.find('Option').length).toBe(2);

    // HACK: branch
    wrapper = mount(
      <Select>
        <Option>选项一</Option>
      </Select>
    );
  });

  test('测试默认属性', () => {
    const wrapper = mount(<Select />);
    expect(wrapper.prop('open')).toBe(false);
    expect(wrapper.prop('disabled')).toBe(false);
    expect(wrapper.prop('optionText')).toBe('text');
    expect(wrapper.prop('optionValue')).toBe('value');
    expect(wrapper.prop('prefix')).toBe('zent');
    expect(wrapper.prop('filter')).toBe(undefined);
    expect(wrapper.prop('selectedItem').value).toBe('');
    expect(wrapper.prop('selectedItem').text).toBe('');
  });

  it('测试SimpleTrigger', () => {
    const wrapper = mount(<Select data={[1, 2, 3]} simple />);
    expect(wrapper.find('SimpleTrigger').length).toBe(1);
  });

  test('选择某个选项', () => {
    const wrapper = mount(<Select data={[1, 2, 3]} />);
    wrapper.find('SelectTrigger').simulate('click');
    wrapper.find('Option').at(1).simulate('click');
    expect(wrapper.state('selectedItem').value).toBe(2);
  });

  test('搜索某个关键字', () => {
    const onEmptyMock = jest.fn();
    const wrapper = mount(
      <Select
        data={[1, 2, 3]}
        search
        onEmptySelected={onEmptyMock}
        filter={(item, keyword) => {
          return `${item.value}` === `${keyword}`;
        }}
      />
    );
    expect(wrapper.find('InputTrigger').length).toBe(1);
    wrapper.find('input').simulate('change', {
      target: {
        value: 4
      }
    });
    wrapper.find('Option').simulate('click');
    expect(onEmptyMock.mock.calls.length).toBe(1);
    wrapper.find('input').simulate('change', {
      target: {
        value: 3
      }
    });
    expect(wrapper.find('Option').length).toBe(1);
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 27 });
    expect(wrapper.find('Option').length).toBe(0);
  });

  it('Popup中的Search(filter and onAsyncFilter)', () => {
    let wrapper = mount(
      <Select
        data={['选项1', '选项2', '选项3']}
        filter={(item, keyword) =>
          keyword &&
          item.value
            .trim()
            .toLowerCase()
            .indexOf(keyword.trim().toLowerCase()) > -1}
        searchPlaceholder="search"
      />
    );
    wrapper.find('SelectTrigger').simulate('click');
    expect(wrapper.find('Option').length).toBe(3);
    wrapper.find('Search').find('input').simulate('change', {
      target: {
        value: '1'
      }
    });
    expect(wrapper.find('Option').length).toBe(1);

    const asyncMock = jest.fn().mockImplementation((keyword, callback) => {
      setTimeout(() => {
        callback(['选项3']);
      }, 1000);
    });

    // BUG: Provide asyncFilter only could not render Search
    wrapper = mount(
      <Select
        data={['选项1', '选项2', '选项3']}
        onAsyncFilter={asyncMock}
        searchPlaceholder="search"
        filter={() => true}
      />
    );
    jest.useFakeTimers();
    wrapper.find('SelectTrigger').simulate('click');
    expect(wrapper.find('Option').length).toBe(3);
    wrapper.find('Search').find('input').simulate('change', {
      target: {
        value: 'anything'
      }
    });
    expect(wrapper.find('Option').length).toBe(3);
    jest.runAllTimers();
    expect(wrapper.find('Option').length).toBe(1);
    expect(wrapper.find('Option').prop('value')).toBe('选项3');
  });

  test('多标签测试', () => {
    const wrapper = mount(<Select data={['1', '2', '3', '']} tags />);
    expect(wrapper.find('TagsTrigger').length).toBe(1);
    wrapper.find('TagsTrigger').simulate('click');
    wrapper.find('Option').at(1).simulate('click');
    wrapper.find('TagsTrigger').simulate('click');
    wrapper.find('Option').at(2).simulate('click');
    expect(wrapper.state('selectedItems').length).toBe(2);
    wrapper.find('Tag').at(0).find('i').simulate('click');
    expect(wrapper.state('selectedItems').length).toBe(1);
    wrapper.find('TagsTrigger').simulate('click');
    wrapper.find('Option').at(2).simulate('click');
    expect(wrapper.state('selectedItems').length).toBe(1);

    // HACK: branch
    wrapper.find('TagsTrigger').simulate('click');
    wrapper.find('Option').at(3).simulate('click');
  });

  it('Popup 按键事件测试', () => {
    const onChangeMock = jest.fn().mockImplementation(evt => {
      evt.preventDefault();
      evt.stopPropagation();
    });
    const onEmptyMock = jest.fn();
    const wrapper = mount(
      <Select
        data={['1', '2', '3', '']}
        tags
        onChange={onChangeMock}
        onEmptySelected={onEmptyMock}
      />
    );
    expect(wrapper.find('TagsTrigger').length).toBe(1);
    expect(wrapper.state('open')).toBe(false);
    wrapper.find('TagsTrigger').simulate('click');
    expect(wrapper.state('open')).toBe(true);
    wrapper.find('.zent-select').simulate('keydown', { keyCode: 27 });
    expect(wrapper.state('open')).toBe(false);
    wrapper.find('TagsTrigger').simulate('click');
    expect(wrapper.find('.current').length).toBe(1);
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 41 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    expect(wrapper.find('.current').length).toBe(1);
    expect(wrapper.find('.current').prop('value')).toBe('2');
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    expect(wrapper.find('.current').prop('value')).toBe('');
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    expect(wrapper.find('.current').prop('value')).toBe('');
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    expect(wrapper.find('.current').prop('value')).toBe('2');
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    expect(wrapper.find('.current').prop('value')).toBe('1');
    expect(wrapper.state('open')).toBe(true);
    expect(onChangeMock.mock.calls.length).toBe(0);
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 13 });
    expect(wrapper.state('open')).toBe(false);
    expect(onChangeMock.mock.calls.length).toBe(1);
    expect(onChangeMock.mock.calls[0][0].target.value).toBe('1');
    expect(onChangeMock.mock.calls[0][0].target.type).toBe('select-multiple');
    expect(onChangeMock.mock.calls[0][1].value).toBe('1');
    wrapper.find('TagsTrigger').simulate('click');
    expect(wrapper.find('.current').length).toBe(1);
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 13 });
    expect(onEmptyMock.mock.calls.length).toBe(0);
  });

  it('Dynamic Select', () => {
    const data = [1, 2, 3];
    const updatedData = [1, 2, 3, 4];
    const wrapper = mount(<Select data={data} />);
    wrapper.find('SelectTrigger').simulate('click');
    wrapper.find('Option').at(1).simulate('click');

    // HACK: branch Select.js line 89
    wrapper.setProps({ data });
    wrapper.setProps({ data, value: [] });
    wrapper.setProps({ data: updatedData, value: [], index: '' });

    wrapper.setProps({ data: updatedData });
    wrapper.setProps({ data, value: [1] });
    expect(wrapper.state('selectedItems')[0].value).toBe(1);

    // BUG: hard to reach Select.js line 129
    // wrapper.setProps({ data: [{ key: 1 }, { key: 2 }], value: { key: 1 } });
    wrapper.setProps({ data: updatedData, value: 2 });
    expect(wrapper.state('selectedItem').value).toBe(2);
  });

  it('Pop focus event and Select blur event popup from Popup', () => {
    jest.useFakeTimers();
    const wrapper = mount(<Select data={['1', '2', '3', '']} />);
    expect(wrapper.state('open')).toBe(false);
    wrapper.find('SelectTrigger').simulate('click');
    expect(wrapper.getNode().focus).toBe(undefined);
    expect(wrapper.state('open')).toBe(true);
    wrapper.find('Popup').simulate('focus');
    expect(wrapper.getNode().focus).toBe(true);
    wrapper.find('Popup').simulate('blur');
    jest.runAllTimers();
    expect(wrapper.state('open')).toBe(false);
  });
});
<commit_msg>feat: popover重构<commit_after>import React from 'react';
import Select, { Option } from 'select';
import { mount } from 'enzyme';

describe('<Select />', () => {
  test('data的传参方式有效', () => {
    const wrapper = mount(<Select data={[1, 2, 3]} />);
    console.log(wrapper.instance());
    expect(wrapper.find('Select').length).toBe(1);
    wrapper.find('SelectTrigger').simulate('click');
    expect(wrapper.find('Option').length).toBe(3);
  });

  test('Option的传参方式有效', () => {
    let wrapper = mount(
      <Select>
        <Option value="1">选项一</Option>
        <Option value="2">选项二</Option>
      </Select>
    );
    expect(wrapper.find('Select').length).toBe(1);
    wrapper.find('SelectTrigger').simulate('click');
    expect(wrapper.find('Option').length).toBe(2);

    // HACK: branch
    wrapper = mount(
      <Select>
        <Option>选项一</Option>
      </Select>
    );
  });

  test('测试默认属性', () => {
    const wrapper = mount(<Select />);
    expect(wrapper.prop('open')).toBe(false);
    expect(wrapper.prop('disabled')).toBe(false);
    expect(wrapper.prop('optionText')).toBe('text');
    expect(wrapper.prop('optionValue')).toBe('value');
    expect(wrapper.prop('prefix')).toBe('zent');
    expect(wrapper.prop('filter')).toBe(undefined);
    expect(wrapper.prop('selectedItem').value).toBe('');
    expect(wrapper.prop('selectedItem').text).toBe('');
  });

  it('测试SimpleTrigger', () => {
    const wrapper = mount(<Select data={[1, 2, 3]} simple />);
    expect(wrapper.find('SimpleTrigger').length).toBe(1);
  });

  test('选择某个选项', () => {
    const wrapper = mount(<Select data={[1, 2, 3]} />);
    wrapper.find('SelectTrigger').simulate('click');
    wrapper.find('Option').at(1).simulate('click');
    expect(wrapper.state('selectedItem').value).toBe(2);
  });

  test('搜索某个关键字', () => {
    const onEmptyMock = jest.fn();
    const wrapper = mount(
      <Select
        data={[1, 2, 3]}
        search
        onEmptySelected={onEmptyMock}
        filter={(item, keyword) => {
          return `${item.value}` === `${keyword}`;
        }}
      />
    );
    expect(wrapper.find('InputTrigger').length).toBe(1);
    wrapper.find('input').simulate('change', {
      target: {
        value: 4
      }
    });
    wrapper.find('Option').simulate('click');
    expect(onEmptyMock.mock.calls.length).toBe(1);
    wrapper.find('input').simulate('change', {
      target: {
        value: 3
      }
    });
    expect(wrapper.find('Option').length).toBe(1);
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 27 });
    expect(wrapper.find('Option').length).toBe(0);
  });

  it('Popup中的Search(filter and onAsyncFilter)', () => {
    let wrapper = mount(
      <Select
        data={['选项1', '选项2', '选项3']}
        filter={(item, keyword) =>
          keyword &&
          item.value
            .trim()
            .toLowerCase()
            .indexOf(keyword.trim().toLowerCase()) > -1}
        searchPlaceholder="search"
      />
    );
    wrapper.find('SelectTrigger').simulate('click');
    expect(wrapper.find('Option').length).toBe(3);
    wrapper.find('Search').find('input').simulate('change', {
      target: {
        value: '1'
      }
    });
    expect(wrapper.find('Option').length).toBe(1);

    const asyncMock = jest.fn().mockImplementation((keyword, callback) => {
      setTimeout(() => {
        callback(['选项3']);
      }, 1000);
    });

    // BUG: Provide asyncFilter only could not render Search
    wrapper = mount(
      <Select
        data={['选项1', '选项2', '选项3']}
        onAsyncFilter={asyncMock}
        searchPlaceholder="search"
        filter={() => true}
      />
    );
    jest.useFakeTimers();
    wrapper.find('SelectTrigger').simulate('click');
    expect(wrapper.find('Option').length).toBe(3);
    wrapper.find('Search').find('input').simulate('change', {
      target: {
        value: 'anything'
      }
    });
    expect(wrapper.find('Option').length).toBe(3);
    jest.runAllTimers();
    expect(wrapper.find('Option').length).toBe(1);
    expect(wrapper.find('Option').prop('value')).toBe('选项3');
  });

  test('多标签测试', () => {
    const wrapper = mount(<Select data={['1', '2', '3', '']} tags />);
    expect(wrapper.find('TagsTrigger').length).toBe(1);
    wrapper.find('TagsTrigger').simulate('click');
    wrapper.find('Option').at(1).simulate('click');
    wrapper.find('TagsTrigger').simulate('click');
    wrapper.find('Option').at(2).simulate('click');
    expect(wrapper.state('selectedItems').length).toBe(2);
    wrapper.find('Tag').at(0).find('i').simulate('click');
    expect(wrapper.state('selectedItems').length).toBe(1);
    wrapper.find('TagsTrigger').simulate('click');
    wrapper.find('Option').at(2).simulate('click');
    expect(wrapper.state('selectedItems').length).toBe(1);

    // HACK: branch
    wrapper.find('TagsTrigger').simulate('click');
    wrapper.find('Option').at(3).simulate('click');
  });

  it('Popup 按键事件测试', () => {
    const onChangeMock = jest.fn().mockImplementation(evt => {
      evt.preventDefault();
      evt.stopPropagation();
    });
    const onEmptyMock = jest.fn();
    const wrapper = mount(
      <Select
        data={['1', '2', '3', '']}
        tags
        onChange={onChangeMock}
        onEmptySelected={onEmptyMock}
      />
    );
    expect(wrapper.find('TagsTrigger').length).toBe(1);
    expect(wrapper.state('open')).toBe(false);
    wrapper.find('TagsTrigger').simulate('click');
    expect(wrapper.state('open')).toBe(true);
    wrapper.find('.zent-select').simulate('keydown', { keyCode: 27 });
    expect(wrapper.state('open')).toBe(false);
    wrapper.find('TagsTrigger').simulate('click');
    expect(wrapper.find('.current').length).toBe(1);
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 41 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    expect(wrapper.find('.current').length).toBe(1);
    expect(wrapper.find('.current').prop('value')).toBe('2');
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    expect(wrapper.find('.current').prop('value')).toBe('');
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    expect(wrapper.find('.current').prop('value')).toBe('');
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    expect(wrapper.find('.current').prop('value')).toBe('2');
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 38 });
    expect(wrapper.find('.current').prop('value')).toBe('1');
    expect(wrapper.state('open')).toBe(true);
    expect(onChangeMock.mock.calls.length).toBe(0);
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 13 });
    expect(wrapper.state('open')).toBe(false);
    expect(onChangeMock.mock.calls.length).toBe(1);
    expect(onChangeMock.mock.calls[0][0].target.value).toBe('1');
    expect(onChangeMock.mock.calls[0][0].target.type).toBe('select-multiple');
    expect(onChangeMock.mock.calls[0][1].value).toBe('1');
    wrapper.find('TagsTrigger').simulate('click');
    expect(wrapper.find('.current').length).toBe(1);
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 40 });
    wrapper
      .find('.zent-select')
      .find('Popup')
      .simulate('keydown', { keyCode: 13 });
    expect(onEmptyMock.mock.calls.length).toBe(0);
  });

  it('Dynamic Select', () => {
    const data = [1, 2, 3];
    const updatedData = [1, 2, 3, 4];
    const wrapper = mount(<Select data={data} />);
    wrapper.find('SelectTrigger').simulate('click');
    wrapper.find('Option').at(1).simulate('click');

    // HACK: branch Select.js line 89
    wrapper.setProps({ data });
    wrapper.setProps({ data, value: [] });
    wrapper.setProps({ data: updatedData, value: [], index: '' });

    wrapper.setProps({ data: updatedData });
    wrapper.setProps({ data, value: [1] });
    expect(wrapper.state('selectedItems')[0].value).toBe(1);

    // BUG: hard to reach Select.js line 129
    // wrapper.setProps({ data: [{ key: 1 }, { key: 2 }], value: { key: 1 } });
    wrapper.setProps({ data: updatedData, value: 2 });
    expect(wrapper.state('selectedItem').value).toBe(2);
  });

  it('Pop focus event and Select blur event popup from Popup', () => {
    jest.useFakeTimers();
    const wrapper = mount(<Select data={['1', '2', '3', '']} />);
    expect(wrapper.state('open')).toBe(false);
    wrapper.find('SelectTrigger').simulate('click');
    expect(wrapper.getNode().focus).toBe(undefined);
    expect(wrapper.state('open')).toBe(true);
    wrapper.find('Popup').simulate('focus');
    expect(wrapper.getNode().focus).toBe(true);
    wrapper.find('Popup').simulate('blur');
    jest.runAllTimers();
    expect(wrapper.state('open')).toBe(false);
  });
});
<|endoftext|>


<commit_before>var blake = require('blakejs');
var nacl = require('tweetnacl');

var binToHex = function(s) {
  var constructor = s.constructor.name || null;

  if (constructor !== 'Uint8Array') {
    throw new TypeError('Expected Uint8Array');
  }

  return Buffer.from(s).toString('hex');
};

var hexToBin = function(h) {
    if (typeof h !== 'string') { throw new TypeError("Expected string: " + h); }
    return new Uint8Array(Buffer.from(h,'hex'));
};

var hashBin = function(s) {
  return blake.blake2b(s);
};

var hash = function(s) {
  return binToHex(hashBin(s));
};

var genKeyPair = function() {
    var kp = nacl.sign.keyPair();
    var pubKey = binToHex(kp.publicKey);
    var secKey = binToHex(kp.secretKey).slice(0,64);
    return {"publicKey": pubKey, "secretKey": secKey};
};

var toTweetNaclSecretKey = function(keyPair) {
    if (!keyPair.hasOwnProperty("publicKey") || !keyPair.hasOwnProperty("secretKey") ) {
        throw new TypeError("Invalid KeyPair: expected to find keys of name 'secretKey' and 'publicKey': " + JSON.stringify(keyPair));
    }
    return hexToBin(keyPair.secretKey + keyPair.publicKey);
};

var sign = function(msg, keyPair) {
    if (!keyPair.hasOwnProperty("publicKey") || !keyPair.hasOwnProperty("secretKey") ) {
        throw new TypeError("Invalid KeyPair: expected to find keys of name 'secretKey' and 'publicKey': " + JSON.stringify(keyPair));
    }
    var hshBin = hashBin(msg);
    var hsh = binToHex(hshBin);
    var sigBin = nacl.sign.detached(hshBin, toTweetNaclSecretKey(keyPair));
    return {"hash": hsh, "sig": binToHex(sigBin), "pubKey":keyPair.publicKey};
};

var pullSigAndPubKey = function(s) {
    if (!s.hasOwnProperty("pubKey") || !s.hasOwnProperty("sig")) {
        throw new TypeError("Expected to find keys of name 'sig' and 'pubKey' in " + JSON.stringify(s));
    }
    return {"sig":s.sig, "pubKey":s.pubKey};
};

var pullAndCheckHashs = function(sigs) {
    var hsh = sigs[0].hash;
    for(var i = 1; i < sigs.length; i++)
    {
        if(sigs[i].hash !== hsh) {
            throw new Error('Sigs for different hashes found: ' + JSON.stringify(sigs));
        }
    }
    return hsh;
};

var mkSingleCmd = function(sigs, cmd) {
    // Lower level API constructor
    // Formats a single command from its parts:
    //   sigs: a list of {hash, pubKey, sig}
    //   cmd: the stringified json blob used to create the hash
    // Throws `PactError` if an issue is found
    if (!Array.isArray(sigs)) {
        throw new TypeError('Expected the first argument (sigs) to be an array of sigs');
    }
    if (typeof cmd !== 'string') {
        throw new TypeError('Expected the second argument (cmd) to be a string');
    }
    return {"hash":pullAndCheckHashs(sigs), "sigs": sigs.map(pullSigAndPubKey), "cmd": cmd};
};

var mkPublicSend = function(cmds) {
    // Lower level API constructor
    // Does the last level of wrapping
    if (Array.isArray(cmds)) {
        return {"cmds":cmds};
    } else {
        return {"cmds":[cmds]};
    }
};

var simpleExecCommand = function(keyPairs, nonce, pactCode, envData) {
    // Input: eithe a single or array of keyPairs, a nonce, pactCode, and an envData object
    // Output: a correctly formatted JSON exec msg for pact, send it to /api/public/send
    // Throws PactError on maleformed inputs
    if (typeof nonce !== 'string') {
        throw new TypeError('nonce must be a string: ' + JSON.stringify(nonce));
    }
    if (typeof pactCode !== 'string') {
        throw new TypeError('pactCode must be a string: ' + JSON.stringify(pactCode));
    }
    var cmd = JSON.stringify({"nonce": nonce,
                              "payload": {"exec": {
                                  "code": pactCode,
                                  "data": envData || {}
                              }}});
    var sigs = [];
    if (Array.isArray(keyPairs)) {
        sigs = keyPairs.map(function(kp) {return sign(cmd, kp);});
    } else {
        sigs = [sign(cmd, keyPairs)];
    }
    var hsh = pullAndCheckHashs(sigs);
    return mkPublicSend({"hash": hsh, "sigs":sigs.map(pullSigAndPubKey), "cmd":cmd});
};

var unique = function(arr) {
	  var n = {},r=[];
	  for(var i = 0; i < arr.length; i++)
	  {
		    if (!n[arr[i]])
		    {
			      n[arr[i]] = true;
			      r.push(arr[i]);
		    }
	  }
	  return r;
};

var simplePollRequestFromExec = function(execMsg) {
    var cmds = execMsg.cmds || TypeError("expected key 'cmds' in object: " + JSON.stringify(execMsg));
    var rks = [];
    if (!cmds.every(function(v){return v.hasOwnProperty("hash");})) {
        throw new TypeError('maleformed object, expected "hash" key in every cmd: ' + JSON.stringify(execMsg));
    } else {
        rks = unique(cmds.map(function(v){return v.hash;}));
    }
    return {"requestKeys": rks};
};

module.exports = {
    crypto: {
        binToHex: binToHex,
        hexToBin: hexToBin,
        hash: hash,
        genKeyPair: genKeyPair,
        sign: sign,
        toTweetNaclSecretKey: toTweetNaclSecretKey
    },
    api: {
        mkSingleCmd: mkSingleCmd,
        mkPublicSend: mkPublicSend
    },
    simple: {
        exec: {
            createCommand: simpleExecCommand,
            createPollRequest: simplePollRequestFromExec
        }
    }
};
<commit_msg>fixed key in api for poll<commit_after>var blake = require('blakejs');
var nacl = require('tweetnacl');

var binToHex = function(s) {
  var constructor = s.constructor.name || null;

  if (constructor !== 'Uint8Array') {
    throw new TypeError('Expected Uint8Array');
  }

  return Buffer.from(s).toString('hex');
};

var hexToBin = function(h) {
    if (typeof h !== 'string') { throw new TypeError("Expected string: " + h); }
    return new Uint8Array(Buffer.from(h,'hex'));
};

var hashBin = function(s) {
  return blake.blake2b(s);
};

var hash = function(s) {
  return binToHex(hashBin(s));
};

var genKeyPair = function() {
    var kp = nacl.sign.keyPair();
    var pubKey = binToHex(kp.publicKey);
    var secKey = binToHex(kp.secretKey).slice(0,64);
    return {"publicKey": pubKey, "secretKey": secKey};
};

var toTweetNaclSecretKey = function(keyPair) {
    if (!keyPair.hasOwnProperty("publicKey") || !keyPair.hasOwnProperty("secretKey") ) {
        throw new TypeError("Invalid KeyPair: expected to find keys of name 'secretKey' and 'publicKey': " + JSON.stringify(keyPair));
    }
    return hexToBin(keyPair.secretKey + keyPair.publicKey);
};

var sign = function(msg, keyPair) {
    if (!keyPair.hasOwnProperty("publicKey") || !keyPair.hasOwnProperty("secretKey") ) {
        throw new TypeError("Invalid KeyPair: expected to find keys of name 'secretKey' and 'publicKey': " + JSON.stringify(keyPair));
    }
    var hshBin = hashBin(msg);
    var hsh = binToHex(hshBin);
    var sigBin = nacl.sign.detached(hshBin, toTweetNaclSecretKey(keyPair));
    return {"hash": hsh, "sig": binToHex(sigBin), "pubKey":keyPair.publicKey};
};

var pullSigAndPubKey = function(s) {
    if (!s.hasOwnProperty("pubKey") || !s.hasOwnProperty("sig")) {
        throw new TypeError("Expected to find keys of name 'sig' and 'pubKey' in " + JSON.stringify(s));
    }
    return {"sig":s.sig, "pubKey":s.pubKey};
};

var pullAndCheckHashs = function(sigs) {
    var hsh = sigs[0].hash;
    for(var i = 1; i < sigs.length; i++)
    {
        if(sigs[i].hash !== hsh) {
            throw new Error('Sigs for different hashes found: ' + JSON.stringify(sigs));
        }
    }
    return hsh;
};

var mkSingleCmd = function(sigs, cmd) {
    // Lower level API constructor
    // Formats a single command from its parts:
    //   sigs: a list of {hash, pubKey, sig}
    //   cmd: the stringified json blob used to create the hash
    // Throws `PactError` if an issue is found
    if (!Array.isArray(sigs)) {
        throw new TypeError('Expected the first argument (sigs) to be an array of sigs');
    }
    if (typeof cmd !== 'string') {
        throw new TypeError('Expected the second argument (cmd) to be a string');
    }
    return {"hash":pullAndCheckHashs(sigs), "sigs": sigs.map(pullSigAndPubKey), "cmd": cmd};
};

var mkPublicSend = function(cmds) {
    // Lower level API constructor
    // Does the last level of wrapping
    if (Array.isArray(cmds)) {
        return {"cmds":cmds};
    } else {
        return {"cmds":[cmds]};
    }
};

var simpleExecCommand = function(keyPairs, nonce, pactCode, envData) {
    // Input: eithe a single or array of keyPairs, a nonce, pactCode, and an envData object
    // Output: a correctly formatted JSON exec msg for pact, send it to /api/public/send
    // Throws PactError on maleformed inputs
    if (typeof nonce !== 'string') {
        throw new TypeError('nonce must be a string: ' + JSON.stringify(nonce));
    }
    if (typeof pactCode !== 'string') {
        throw new TypeError('pactCode must be a string: ' + JSON.stringify(pactCode));
    }
    var cmd = JSON.stringify({"nonce": nonce,
                              "payload": {"exec": {
                                  "code": pactCode,
                                  "data": envData || {}
                              }}});
    var sigs = [];
    if (Array.isArray(keyPairs)) {
        sigs = keyPairs.map(function(kp) {return sign(cmd, kp);});
    } else {
        sigs = [sign(cmd, keyPairs)];
    }
    var hsh = pullAndCheckHashs(sigs);
    return mkPublicSend({"hash": hsh, "sigs":sigs.map(pullSigAndPubKey), "cmd":cmd});
};

var unique = function(arr) {
	  var n = {},r=[];
	  for(var i = 0; i < arr.length; i++)
	  {
		    if (!n[arr[i]])
		    {
			      n[arr[i]] = true;
			      r.push(arr[i]);
		    }
	  }
	  return r;
};

var simplePollRequestFromExec = function(execMsg) {
    var cmds = execMsg.cmds || TypeError("expected key 'cmds' in object: " + JSON.stringify(execMsg));
    var rks = [];
    if (!cmds.every(function(v){return v.hasOwnProperty("hash");})) {
        throw new TypeError('maleformed object, expected "hash" key in every cmd: ' + JSON.stringify(execMsg));
    } else {
        rks = unique(cmds.map(function(v){return v.hash;}));
    }
    return {"requestIds": rks};
};

module.exports = {
    crypto: {
        binToHex: binToHex,
        hexToBin: hexToBin,
        hash: hash,
        genKeyPair: genKeyPair,
        sign: sign,
        toTweetNaclSecretKey: toTweetNaclSecretKey
    },
    api: {
        mkSingleCmd: mkSingleCmd,
        mkPublicSend: mkPublicSend
    },
    simple: {
        exec: {
            createCommand: simpleExecCommand,
            createPollRequest: simplePollRequestFromExec
        }
    }
};
<|endoftext|>


<commit_before>/* eslint-disable promise/always-return */
import { runAuthenticatedQuery } from "schema/v2/test/utils"

describe("FollowGene", () => {
  it("follows a gene", () => {
    const mutation = `
      mutation {
        followGene(input: { gene_id: "pop-art" }) {
          gene {
            id
            name
          }
        }
      }
    `

    const context = {
      followGeneLoader: () =>
        Promise.resolve({
          gene: {
            family: {},
            id: "pop-art",
            name: "Pop Art",
            image_url: "",
            image_urls: {},
            display_name: null,
          },
        }),
      geneLoader: () =>
        Promise.resolve({
          family: {
            id: "styles-and-movements",
          },
          id: "pop-art",
          name: "Pop Art",
          browseable: true,
        }),
    }

    const expectedGeneData = {
      gene: {
        id: "pop-art",
        name: "Pop Art",
      },
    }

    expect.assertions(1)
    return runAuthenticatedQuery(mutation, context).then(({ followGene }) => {
      expect(followGene).toEqual(expectedGeneData)
    })
  })
})
<commit_msg>Fix v2 follow_gene test<commit_after>/* eslint-disable promise/always-return */
import { runAuthenticatedQuery } from "schema/v2/test/utils"

describe("FollowGene", () => {
  it("follows a gene", async () => {
    const mutation = `
      mutation {
        followGene(input: { geneID: "pop-art" }) {
          gene {
            slug
            name
          }
        }
      }
    `

    const context = {
      followGeneLoader: () =>
        Promise.resolve({
          gene: {
            family: {},
            id: "pop-art",
            name: "Pop Art",
            image_url: "",
            image_urls: {},
            display_name: null,
          },
        }),
      geneLoader: () =>
        Promise.resolve({
          family: {
            id: "styles-and-movements",
          },
          id: "pop-art",
          name: "Pop Art",
          browseable: true,
        }),
    }

    const expectedGeneData = {
      gene: {
        slug: "pop-art",
        name: "Pop Art",
      },
    }

    await runAuthenticatedQuery(mutation, context).then(({ followGene }) => {
      expect(followGene).toEqual(expectedGeneData)
    })
  })
})
<|endoftext|>


<commit_before>// Dependencies

let type = require('focus').component.types;
let builder = require('focus').component.builder;

// Components

let SearchBar = require('../../../search/search-bar').component;
let Results = require('../common/component/results').component;

// Mixins

let referenceBehaviour = require('../../../common/form/mixin/reference-behaviour');
let storeBehaviour = require('../../../common/mixin/store-behaviour');

// Actions

let actionBuilder = Focus.search.actionBuilder;

// Stores

let quickSearchStore = Focus.search.builtInStore.quickSearchStore;

/**
 * General search mixin.
 * Contains a search bar, and a results list.
 * @type {Object}
 */
let QuickSearchComponent = {
    /**
     * Component's mixins
     * @type {Array}
     */
    mixins: [referenceBehaviour, storeBehaviour],
    /**
     * Tag name.
     */
    displayName: 'quick-search',
    /**
     * Reference names to be fetched by the reference behaviour
     * @type {Array}
     */
    referenceNames: ['scopes'],
    /**
     * Get the default props
     * @return {object} the default props
     */
    getDefaultProps() {
        return {
            scopeSelectionHandler: this._scopeSelectionHandler,
            store: quickSearchStore,
            scopeFacetKey: 'FCT_SCOPE',
            lineComponentMapper: undefined,
            lineOperationList: undefined,
            groupComponent: undefined,
            service: undefined,
            action: undefined,
            onLineClick: undefined,
            groupMaxRows: undefined
        };
    },
    /**
     * Prop validation
     * @type {Object}
     */
    propTypes: {
        scopeSelectionHandler: type('function'),
        store: type('object'),
        scopeFacetKey: type('string'),
        lineComponentMapper: type('function'),
        groupComponent: type('object'),
        service: type('object'),
        action: type('object'),
        onLineClick: type('function'),
        groupMaxRows: type('number')
    },
    /**
     * Register the store listeners
     */
    componentWillMount() {
        this._action = this.props.action || actionBuilder({
            service: this.props.service,
            identifier: this.props.store.identifier,
            getSearchOptions: () => {return this.props.store.getValue.call(this.props.store); } // Binding the store in the function call
        });
        this._loadReference();
        this.props.store.addQueryChangeListener(this._action.search);
        this.props.store.addScopeChangeListener(this._action.search);
        this.props.store.addResultsChangeListener(this._onResultsChange);
    },
    /**
     * Unregister the store listeners
     */
    componentWillUnmount() {
        this.props.store.removeQueryChangeListener(this._action.search);
        this.props.store.removeScopeChangeListener(this._action.search);
        this.props.store.removeResultsChangeListener(this._onResultsChange);
    },
    /**
     * Results change handler
     */
    _onResultsChange() {
        let resultsMap = this.props.store.getResults();
        let facets = this.props.store.getFacets();
        let totalCount = this.props.store.getTotalCount();
        this.setState({resultsMap, facets, totalCount});
    },
    /**
     * Action on line click.
     * @param {object} item  the item clicked
     */
    _lineClickHandler(item) {
        if (this.props.onLineClick) {
            this.props.onLineClick(item);
        }
    },
    /**
     * redner the SearchBar
     * @returns {HTML} the rendered component
     */
    _renderSearchBar() {
        return (
            <SearchBar
                data-focus='search-bar'
                ref='searchBar'
                scopes={this.state.reference.scopes}
                loading={this.state.isLoading}
                action={this._action}
                store={this.props.store}
                />
        );
    },
    /**
     * redner the results
     * @returns {HTML} the rendered component
     */
    _renderResults() {
        return (
            <Results
                resultsMap={this.state.resultsMap}
                totalCount={this.state.totalCount}
                resultsFacets={this.state.facets}
                groupComponent={this.props.groupComponent}
                lineComponentMapper={this.props.lineComponentMapper}
                isSelection={false}
                lineClickHandler={this._lineClickHandler}
                lineOperationList={this.props.lineOperationList}
                groupingKey={this.props.scopeFacetKey}
                initialRowsCount={this.props.groupMaxRows}
                action={this._action}
            />
        );
    },
    /**
     * Render the component
     * @return {HTML} the rendered component
     */
    render() {
        return (

                {this._renderSearchBar()}
                {this._renderResults()}

        );
    }
};

module.exports = builder(QuickSearchComponent);
<commit_msg>[quick-search] Fix bad call to search action<commit_after>// Dependencies

let type = require('focus').component.types;
let builder = require('focus').component.builder;

// Components

let SearchBar = require('../../../search/search-bar').component;
let Results = require('../common/component/results').component;

// Mixins

let referenceBehaviour = require('../../../common/form/mixin/reference-behaviour');
let storeBehaviour = require('../../../common/mixin/store-behaviour');

// Actions

let actionBuilder = Focus.search.actionBuilder;

// Stores

let quickSearchStore = Focus.search.builtInStore.quickSearchStore;

/**
 * General search mixin.
 * Contains a search bar, and a results list.
 * @type {Object}
 */
let QuickSearchComponent = {
    /**
     * Component's mixins
     * @type {Array}
     */
    mixins: [referenceBehaviour, storeBehaviour],
    /**
     * Tag name.
     */
    displayName: 'quick-search',
    /**
     * Reference names to be fetched by the reference behaviour
     * @type {Array}
     */
    referenceNames: ['scopes'],
    /**
     * Get the default props
     * @return {object} the default props
     */
    getDefaultProps() {
        return {
            scopeSelectionHandler: this._scopeSelectionHandler,
            store: quickSearchStore,
            scopeFacetKey: 'FCT_SCOPE',
            lineComponentMapper: undefined,
            lineOperationList: undefined,
            groupComponent: undefined,
            service: undefined,
            action: undefined,
            onLineClick: undefined,
            groupMaxRows: undefined
        };
    },
    /**
     * Prop validation
     * @type {Object}
     */
    propTypes: {
        scopeSelectionHandler: type('function'),
        store: type('object'),
        scopeFacetKey: type('string'),
        lineComponentMapper: type('function'),
        groupComponent: type('object'),
        service: type('object'),
        action: type('object'),
        onLineClick: type('function'),
        groupMaxRows: type('number')
    },
    /**
     * Register the store listeners
     */
    componentWillMount() {
        this._action = this.props.action || actionBuilder({
            service: this.props.service,
            identifier: this.props.store.identifier,
            getSearchOptions: () => {return this.props.store.getValue.call(this.props.store); } // Binding the store in the function call
        });
        this._loadReference();
        this.props.store.addQueryChangeListener(this._triggerSearch);
        this.props.store.addScopeChangeListener(this._triggerSearch);
        this.props.store.addResultsChangeListener(this._onResultsChange);
    },
    /**
     * Unregister the store listeners
     */
    componentWillUnmount() {
        this.props.store.removeQueryChangeListener(this._triggerSearch);
        this.props.store.removeScopeChangeListener(this._triggerSearch);
        this.props.store.removeResultsChangeListener(this._onResultsChange);
    },
    _triggerSearch() {
        this._action.search();
    },
    /**
     * Results change handler
     */
    _onResultsChange() {
        let resultsMap = this.props.store.getResults();
        let facets = this.props.store.getFacets();
        let totalCount = this.props.store.getTotalCount();
        this.setState({resultsMap, facets, totalCount});
    },
    /**
     * Action on line click.
     * @param {object} item  the item clicked
     */
    _lineClickHandler(item) {
        if (this.props.onLineClick) {
            this.props.onLineClick(item);
        }
    },
    /**
     * redner the SearchBar
     * @returns {HTML} the rendered component
     */
    _renderSearchBar() {
        return (
            <SearchBar
                data-focus='search-bar'
                ref='searchBar'
                scopes={this.state.reference.scopes}
                loading={this.state.isLoading}
                action={this._action}
                store={this.props.store}
                />
        );
    },
    /**
     * redner the results
     * @returns {HTML} the rendered component
     */
    _renderResults() {
        return (
            <Results
                resultsMap={this.state.resultsMap}
                totalCount={this.state.totalCount}
                resultsFacets={this.state.facets}
                groupComponent={this.props.groupComponent}
                lineComponentMapper={this.props.lineComponentMapper}
                isSelection={false}
                lineClickHandler={this._lineClickHandler}
                lineOperationList={this.props.lineOperationList}
                groupingKey={this.props.scopeFacetKey}
                initialRowsCount={this.props.groupMaxRows}
                action={this._action}
            />
        );
    },
    /**
     * Render the component
     * @return {HTML} the rendered component
     */
    render() {
        return (

                {this._renderSearchBar()}
                {this._renderResults()}

        );
    }
};

module.exports = builder(QuickSearchComponent);
<|endoftext|>


<commit_before>// Dependencies

let assign = require('object-assign');
let type = require('focus').component.types;
let builder = require('focus').component.builder;
let React = require('react');

// Components

let SearchBar  = require('../../../search/search-bar').component;

// Mixins

let ScrollInfoMixin = require('../common/scroll-info-mixin').mixin;
let GroupByMixin= require('../common/group-by-mixin').mixin;
let SearchMixin = require('../common/search-mixin').mixin;

/**
 * General search mixin.
 * Contains a search bar, and a results list.
 * @type {Object}
 */
let QuickSearchMixin = {
    mixins: [ScrollInfoMixin, GroupByMixin, SearchMixin],
    /**
     * Tag name.
     */
    displayName: 'quick-search',
    /**
     * Component initialization
     */
    componentDidMount(){
        this._registerListeners();
    },

    /**
     * Actions before component will unmount.
     * @constructor
     */
    componentWillUnmount(){
        this._unRegisterListeners();
    },
    getDefaultProps(){
        return {
            isSelection: false,
            idField: 'id',
            SearchBar: SearchBar,
            groupMaxRows: 3
        };
    },
    /**
     * properties validation
     */
    propTypes: {
        lineMap: type('object'),
        isSelection: type('bool'),
        lineOperationList: type('array'),
        idField: type('string'),
        SearchBar: type('func'),
        groupMaxRows: type('number')
    },
    /**
     * Initial state of the list component.
     * @returns {{list: (*|Array)}} the state
     */
    getInitialState() {
        return {
            isAllSelected: false,
            selected: []
        };
    },
    getCriteria() {
      if(!this.refs.searchBar){
        return {};
      }
      return this.refs.searchBar.getValue();
    },
    /**
     * Register a listener on the store.
     * @private
     */
    _registerListeners(){
        if(this.store){
            this.store.addSearchChangeListener(this.onSearchChange);
        } else {
            console.warn('Search result has no store to listen to. Please provide one as a "store" property.');
        }
    },
    /**
     * Unregister a listener on the store.
     * @private
     */
    _unRegisterListeners(){
        if(this.store){
            this.store.removeSearchChangeListener(this.onSearchChange);
        }
    },
    /**
     * Handler when store emit a change event.
     */
    onSearchChange() {
        this.setState(assign({isLoadingSearch: false}, this.getScrollState()));
    },
    /**
     * Action on item selection.
     * @param {object} item selected
     */
    _selectItem(item){
        let selected = this.state.selected;
        let index = selected.indexOf(item);
        if(index){
            selected.splice(index, index);
        }else{
            selected.push(item);
        }
        this.setState({selected});
    },
    /**
     * Action on line click.
     * @param {object} item  the item clicked
     */
    _lineClick(item){
        if(this.props.onLineClick){
            this.props.onLineClick(item);
        }
    },
    _prepareSearch(searchValues){
        this.setState(
            assign(
                {isLoadingSearch: true},
                searchValues,
                this.getNoFetchState()
            ),
            this.search
        );
    },
    /**
     * return a SearchBar
     * @returns {XML} the component
     */
    getSearchBarComponent() {
        return (
            <this.props.SearchBar handleChange={this._prepareSearch}
                ref='searchBar'
                scope={this.props.scope}
                scopes={this.props.scopeList}
                loading={this.state.isLoadingSearch}
            />
        );
    }
};

module.exports = builder(QuickSearchMixin, true);
<commit_msg>Add timeout to quickSearch search action<commit_after>// Dependencies

let assign = require('object-assign');
let type = require('focus').component.types;
let builder = require('focus').component.builder;
let React = require('react');

// Components

let SearchBar  = require('../../../search/search-bar').component;

// Mixins

let ScrollInfoMixin = require('../common/scroll-info-mixin').mixin;
let GroupByMixin= require('../common/group-by-mixin').mixin;
let SearchMixin = require('../common/search-mixin').mixin;

/**
 * General search mixin.
 * Contains a search bar, and a results list.
 * @type {Object}
 */
let QuickSearchMixin = {
    mixins: [ScrollInfoMixin, GroupByMixin, SearchMixin],
    /**
     * Tag name.
     */
    displayName: 'quick-search',
    /**
     * Component initialization
     */
    componentDidMount(){
        this._registerListeners();
    },

    /**
     * Actions before component will unmount.
     * @constructor
     */
    componentWillUnmount(){
        this._unRegisterListeners();
    },
    getDefaultProps(){
        return {
            isSelection: false,
            idField: 'id',
            SearchBar: SearchBar,
            groupMaxRows: 3
        };
    },
    /**
     * properties validation
     */
    propTypes: {
        lineMap: type('object'),
        isSelection: type('bool'),
        lineOperationList: type('array'),
        idField: type('string'),
        SearchBar: type('func'),
        groupMaxRows: type('number')
    },
    /**
     * Initial state of the list component.
     * @returns {{list: (*|Array)}} the state
     */
    getInitialState() {
        return {
            isAllSelected: false,
            selected: []
        };
    },
    getCriteria() {
      if(!this.refs.searchBar){
        return {};
      }
      return this.refs.searchBar.getValue();
    },
    /**
     * Register a listener on the store.
     * @private
     */
    _registerListeners(){
        if(this.store){
            this.store.addSearchChangeListener(this.onSearchChange);
        } else {
            console.warn('Search result has no store to listen to. Please provide one as a "store" property.');
        }
    },
    /**
     * Unregister a listener on the store.
     * @private
     */
    _unRegisterListeners(){
        if(this.store){
            this.store.removeSearchChangeListener(this.onSearchChange);
        }
    },
    /**
     * Handler when store emit a change event.
     */
    onSearchChange() {
        this.setState(assign({isLoadingSearch: false}, this.getScrollState()));
    },
    /**
     * Action on item selection.
     * @param {object} item selected
     */
    _selectItem(item){
        let selected = this.state.selected;
        let index = selected.indexOf(item);
        if(index){
            selected.splice(index, index);
        }else{
            selected.push(item);
        }
        this.setState({selected});
    },
    /**
     * Action on line click.
     * @param {object} item  the item clicked
     */
    _lineClick(item){
        if(this.props.onLineClick){
            this.props.onLineClick(item);
        }
    },
    _prepareSearch(searchValues){
        clearTimeout(this._searchTimeout);
        this._searchTimeout = setTimeout(() => {
            this.setState(
                assign(
                    {isLoadingSearch: true},
                    searchValues,
                    this.getNoFetchState()
                ),
                this.search
            );
        }, 500);
    },
    /**
     * return a SearchBar
     * @returns {XML} the component
     */
    getSearchBarComponent() {
        return (
            <this.props.SearchBar handleChange={this._prepareSearch}
                ref='searchBar'
                scope={this.props.scope}
                scopes={this.props.scopeList}
                loading={this.state.isLoadingSearch}
            />
        );
    }
};

module.exports = builder(QuickSearchMixin, true);
<|endoftext|>


<commit_before>import React from 'react';
import cx from 'classnames';
import { pure, skinnable, props, t, contains } from '../../../utils';
import includes from 'lodash/includes';

const { list, maybe, enums } = t;

const propsTypes = {
  className: maybe(t.String),
  selectedRows: maybe(list(t.Integer)),
  onRowsSelect: maybe(t.Function),
  selectionType: enums.of(['multi', 'single', 'none']),
  hoveredRowIndex: maybe(t.Integer),
  onHoveredRowChange: maybe(t.Function)
};

const getLocals = ({
  selectedRows = [],
  onRowsSelect,
  selectionType = 'none',
  className,
  onHoveredRowChange,
  hoveredRowIndex,
  ...gridProps }) => {

  const onRowClick = ({ ctrlKey, metaKey }, index) => {
    if (selectionType === 'none' || !onRowsSelect) {
      return;
    }
    if (selectionType === 'multi' && (ctrlKey || metaKey)) {
      if (includes(selectedRows, index)) {
        onRowsSelect(selectedRows.filter(idx => idx !== index));
      } else {
        onRowsSelect([index, ...selectedRows]);
      }
    } else {
      onRowsSelect([index]);
    }
  };

  const onRowMouseEnter = (_, index) => {
    onHoveredRowChange && onHoveredRowChange(index);
  };

  const onRowMouseLeave = () => {
    onHoveredRowChange && onHoveredRowChange(null);
  };

  const rowClassNameGetter = (index) => cx(
    'tablo-row', {
      selected: includes(selectedRows, index),
      hover: index === hoveredRowIndex
    }
  );

  const scrollToRow = !gridProps.scrollTop ? selectedRows[0] : undefined;

  return {
    className: cx('selectable-tablo', { selectable: selectionType !== 'none' }, className),
    scrollToRow,
    onRowClick,
    rowClassNameGetter,
    onRowMouseEnter,
    onRowMouseLeave,
    ...gridProps
  };
};

export default (Grid) =>

  @skinnable(contains(Grid))
  @pure
  @props(propsTypes, { strict: false })
  class SelectableGrid extends React.Component {

    getLocals = getLocals

  };
<commit_msg>selectionType prop should be optional<commit_after>import React from 'react';
import cx from 'classnames';
import { pure, skinnable, props, t, contains } from '../../../utils';
import includes from 'lodash/includes';

const { list, maybe, enums } = t;

const propsTypes = {
  className: maybe(t.String),
  selectedRows: maybe(list(t.Integer)),
  onRowsSelect: maybe(t.Function),
  selectionType: maybe(enums.of(['multi', 'single', 'none'])),
  hoveredRowIndex: maybe(t.Integer),
  onHoveredRowChange: maybe(t.Function)
};

const getLocals = ({
  selectedRows = [],
  onRowsSelect,
  selectionType = 'none',
  className,
  onHoveredRowChange,
  hoveredRowIndex,
  ...gridProps }) => {

  const onRowClick = ({ ctrlKey, metaKey }, index) => {
    if (selectionType === 'none' || !onRowsSelect) {
      return;
    }
    if (selectionType === 'multi' && (ctrlKey || metaKey)) {
      if (includes(selectedRows, index)) {
        onRowsSelect(selectedRows.filter(idx => idx !== index));
      } else {
        onRowsSelect([index, ...selectedRows]);
      }
    } else {
      onRowsSelect([index]);
    }
  };

  const onRowMouseEnter = (_, index) => {
    onHoveredRowChange && onHoveredRowChange(index);
  };

  const onRowMouseLeave = () => {
    onHoveredRowChange && onHoveredRowChange(null);
  };

  const rowClassNameGetter = (index) => cx(
    'tablo-row', {
      selected: includes(selectedRows, index),
      hover: index === hoveredRowIndex
    }
  );

  const scrollToRow = !gridProps.scrollTop ? selectedRows[0] : undefined;

  return {
    className: cx('selectable-tablo', { selectable: selectionType !== 'none' }, className),
    scrollToRow,
    onRowClick,
    rowClassNameGetter,
    onRowMouseEnter,
    onRowMouseLeave,
    ...gridProps
  };
};

export default (Grid) =>

  @skinnable(contains(Grid))
  @pure
  @props(propsTypes, { strict: false })
  class SelectableGrid extends React.Component {

    getLocals = getLocals

  };
<|endoftext|>


<commit_before>import DS from 'ember-data';

export default DS.Model.extend({
  profile: DS.attr(),
  // no: DS.attr(),
  author: DS.attr(),
  city: DS.attr(),
  favourite_quote: DS.attr(),
  image: DS.attr(),
  content: DS.attr(),
  question: DS.attr(),
  reviews: DS.hasMany('review', {
    async: true
  }),
  likes: DS.attr(),
  dislikes: DS.attr()
});
<commit_msg>commenting on message.js<commit_after>import DS from 'ember-data';

//exporting the attributes of the parent class
export default DS.Model.extend({
  profile: DS.attr(),
  // no: DS.attr(),
  author: DS.attr(),
  city: DS.attr(),
  favourite_quote: DS.attr(),
  image: DS.attr(),
  content: DS.attr(),
  question: DS.attr(),
  reviews: DS.hasMany('review', {
    async: true
  }),
  likes: DS.attr(),
  dislikes: DS.attr()
});
<|endoftext|>


<commit_before>var Substance = require('substance');
var $$ = React.createElement;
var Surface = Substance.Surface;
var _ = require("substance/helpers");
var TextProperty = require("substance/writer").TextProperty;
var TitleEditor = require("./title_editor");

var ENABLED_TOOLS = ["strong", "emphasis", "timecode", "remark", "entity_reference", "subject_reference"];

// Container Node
// ----------------
//
// Represents a flat collection of nodes

// TODO: this is not Substance.Writer but should be in Archivist
// Plan: make this implementation an abstract mixin
// and let the application configure a componentFactory
// that provides a customized version.

var ContentEditor = React.createClass({
  displayName: "ContentEditor",

  contextTypes: {
    componentFactory: React.PropTypes.object.isRequired,
    notifications: React.PropTypes.object.isRequired
  },

  childContextTypes: {
    // provided to editor components so that they know in which context they are
    surface: React.PropTypes.object,
  },

  getChildContext: function() {
    return {
      surface: this.surface
    };
  },

  getInitialState: function() {
    var editor = new Surface.ContainerEditor(this.props.doc.get('content'));
    // HACK: this is also Archivist specific
    editor.defaultTextType = 'text';
    var options = {
      logger: this.context.notifications
    };
    this.surface = new Surface(editor, options);

    return {};
  },

  handleToggleSubjectReference: function(e) {
    e.preventDefault();
    var subjectReferenceId = e.currentTarget.dataset.id;
    var writerCtrl = this.props.writerCtrl;
    var state = writerCtrl.state;

    if (state.contextId === "editSubjectReference" && state.subjectReferenceId === subjectReferenceId) {
      writerCtrl.replaceState({
        contextId: "subjects"
      });
    } else {
      writerCtrl.replaceState({
        contextId: "editSubjectReference",
        subjectReferenceId: subjectReferenceId
      });
    }
  },

  render: function() {
    var containerNode = this.props.node;
    var doc = this.props.doc;
    var writerCtrl = this.props.writerCtrl;

    // Prepare subject reference components
    // ---------

    var subjectReferences = doc.getIndex('type').get('subject_reference');
    var subjectRefComponents = [];
    var activeContainerAnnotations = writerCtrl.getActiveContainerAnnotations();

    _.each(subjectReferences, function(sref) {
      subjectRefComponents.push($$('a', {
        className: "subject-reference"+(_.includes(activeContainerAnnotations, sref.id) ? ' selected' : ''),
        href: "#",
        "data-id": sref.id,
        onClick: this.handleToggleSubjectReference
      }));
    }, this);

    // Prepare container components (aka nodes)
    // ---------

    var componentFactory = this.context.componentFactory;
    var components = [];
    components = components.concat(containerNode.nodes.map(function(nodeId) {
      var node = doc.get(nodeId);
      var ComponentClass = componentFactory.get(node.type);
      if (!ComponentClass) {
        throw new Error('Could not resolve a component for type: ' + node.type);
      }
      return $$(ComponentClass, {
        key: node.id,
        doc: doc,
        node: node,
        // TODO: we should use DI instead of coupling to the writer
        writerCtrl: writerCtrl
      });
    }));

    // Top level structure
    // ---------

    return $$('div', {className: 'content-wrapper'},
      $$(TitleEditor, {writerCtrl: this.props.writerCtrl}),
      // The full fledged interview (ContainerEditor)
      $$("div", {ref: "interviewContent", className: "interview-content", contentEditable: true, "data-id": "content"},
        $$("div", {
            className: "container-node " + this.props.node.id,
            spellCheck: false,
            "data-id": this.props.node.id
          },
          $$('div', {className: "nodes"}, components),
          $$('div', {className: "subject-references", contentEditable: false}, subjectRefComponents)
        )
      )
    );

  },

  updateBrackets: function() {
    var doc = this.props.doc;
    var subjectReferences = doc.getIndex('type').get('subject_reference');

    _.each(subjectReferences, function(subjRef) {
      var anchors = $(this.getDOMNode()).find('.nodes .anchor[data-id='+subjRef.id+']');

      var startAnchorEl, endAnchorEl;
      if ($(anchors[0]).hasClass('start-anchor')) {
        startAnchorEl = anchors[0];
        endAnchorEl = anchors[1];
      } else {
        startAnchorEl = anchors[1];
        endAnchorEl = anchors[0];
      }

      if (!startAnchorEl || !endAnchorEl) {
        console.warn("FIXME: Could not find anchors for subject reference ", subjRef.id);
        return;
      }

      var startTop = $(startAnchorEl).position().top;
      var endTop = $(endAnchorEl).position().top + $(endAnchorEl).height();
      var height = endTop - startTop;

      var subjectRefEl = $(this.getDOMNode()).find('.subject-references .subject-reference[data-id='+subjRef.id+']');

      subjectRefEl.css({
        top: startTop,
        height: height
      });
    }, this);
  },

  componentDidMount: function() {
    var surface = this.surface;

    var doc = this.props.doc;

    doc.connect(this, {
      'document:changed': this.onDocumentChange
    });

    this.props.writerCtrl.registerSurface(surface, "content", {
      enabledTools: ENABLED_TOOLS
    });
    surface.attach(this.refs.interviewContent.getDOMNode());

    doc.connect(this, {
      'container-annotation-update': this.handleContainerAnnotationUpdate
    });

    var self = this;

    // TODO: we need a way so that the brackets get updated properly
    this.forceUpdate(function() {
      self.updateBrackets();
      _.delay(function() {
        self.updateBrackets();
      }, 100);

      self.surface.rerenderDomSelection();
    });

    $(window).resize(this.updateBrackets);
  },

  handleContainerAnnotationUpdate: function() {
    var self = this;
    this.forceUpdate(function() {
      self.updateBrackets();
    });
  },

  componentDidUpdate: function() {
    // HACK: when the state is changed this and particularly TextProperties
    // get rerendered (e.g., as the highlights might have changed)
    // Unfortunately we loose the DOM selection then.
    // Thus, we are resetting it here, but(!) delayed as otherwise the surface itself
    // might not have finished setting the selection to the desired and a proper state.
    if (!this.surface.__prerendering__) {
      var self = this;
      setTimeout(function() {
        self.surface.rerenderDomSelection();
      });
    }
  },

  componentWillUnmount: function() {
    var surface = this.surface;
    var doc = this.props.doc;
    doc.disconnect(this);

    this.props.writerCtrl.unregisterSurface(surface);
    surface.detach();
  },

  onDocumentChange: function(change) {
    var writerCtrl = this.props.writerCtrl;
    // console.log('##### ContainerComponent.onDocumentChange', change);

    var deletedSubjectRefs = _.filter(change.deleted, function(node) {
      return node.type === "subject_reference";
    });

    // HACK: implicitly switch the state when a subject reference is deleted and currently open
    // This implicitly also updates the brackets accordingly
    var subjectRef = deletedSubjectRefs[0];
    if (subjectRef && writerCtrl.state.subjectReferenceId === subjectRef.id) {
      writerCtrl.replaceState({
        contextId: 'subjects'
      });
      return;
    }

    if (change.isAffected([this.props.node.id, 'nodes']) /* || deletedSubjectRefs.length > 0 */) {
      var self = this;
      // console.log('##### calling forceUpdate after document change');
      this.forceUpdate(function() {
        self.updateBrackets();
      });
    }
    // eagerly update brackets on every change
    else {
      this.updateBrackets();
    }
  }

});

module.exports = ContentEditor;<commit_msg>Draw bracks on subject creation.<commit_after>var Substance = require('substance');
var $$ = React.createElement;
var Surface = Substance.Surface;
var _ = require("substance/helpers");
var TextProperty = require("substance/writer").TextProperty;
var TitleEditor = require("./title_editor");

var ENABLED_TOOLS = ["strong", "emphasis", "timecode", "remark", "entity_reference", "subject_reference"];

// Container Node
// ----------------
//
// Represents a flat collection of nodes

// TODO: this is not Substance.Writer but should be in Archivist
// Plan: make this implementation an abstract mixin
// and let the application configure a componentFactory
// that provides a customized version.

var ContentEditor = React.createClass({
  displayName: "ContentEditor",

  contextTypes: {
    componentFactory: React.PropTypes.object.isRequired,
    notifications: React.PropTypes.object.isRequired
  },

  childContextTypes: {
    // provided to editor components so that they know in which context they are
    surface: React.PropTypes.object,
  },

  getChildContext: function() {
    return {
      surface: this.surface
    };
  },

  getInitialState: function() {
    var editor = new Surface.ContainerEditor(this.props.doc.get('content'));
    // HACK: this is also Archivist specific
    editor.defaultTextType = 'text';
    var options = {
      logger: this.context.notifications
    };
    this.surface = new Surface(editor, options);

    return {};
  },

  handleToggleSubjectReference: function(e) {
    e.preventDefault();
    var subjectReferenceId = e.currentTarget.dataset.id;
    var writerCtrl = this.props.writerCtrl;
    var state = writerCtrl.state;

    if (state.contextId === "editSubjectReference" && state.subjectReferenceId === subjectReferenceId) {
      writerCtrl.replaceState({
        contextId: "subjects"
      });
    } else {
      writerCtrl.replaceState({
        contextId: "editSubjectReference",
        subjectReferenceId: subjectReferenceId
      });
    }
  },

  render: function() {
    var containerNode = this.props.node;
    var doc = this.props.doc;
    var writerCtrl = this.props.writerCtrl;

    // Prepare subject reference components
    // ---------

    var subjectReferences = doc.getIndex('type').get('subject_reference');
    var subjectRefComponents = [];
    var activeContainerAnnotations = writerCtrl.getActiveContainerAnnotations();

    _.each(subjectReferences, function(sref) {
      subjectRefComponents.push($$('a', {
        className: "subject-reference"+(_.includes(activeContainerAnnotations, sref.id) ? ' selected' : ''),
        href: "#",
        "data-id": sref.id,
        onClick: this.handleToggleSubjectReference
      }));
    }, this);

    // Prepare container components (aka nodes)
    // ---------

    var componentFactory = this.context.componentFactory;
    var components = [];
    components = components.concat(containerNode.nodes.map(function(nodeId) {
      var node = doc.get(nodeId);
      var ComponentClass = componentFactory.get(node.type);
      if (!ComponentClass) {
        throw new Error('Could not resolve a component for type: ' + node.type);
      }
      return $$(ComponentClass, {
        key: node.id,
        doc: doc,
        node: node,
        // TODO: we should use DI instead of coupling to the writer
        writerCtrl: writerCtrl
      });
    }));

    // Top level structure
    // ---------

    return $$('div', {className: 'content-wrapper'},
      $$(TitleEditor, {writerCtrl: this.props.writerCtrl}),
      // The full fledged interview (ContainerEditor)
      $$("div", {ref: "interviewContent", className: "interview-content", contentEditable: true, "data-id": "content"},
        $$("div", {
            className: "container-node " + this.props.node.id,
            spellCheck: false,
            "data-id": this.props.node.id
          },
          $$('div', {className: "nodes"}, components),
          $$('div', {className: "subject-references", contentEditable: false}, subjectRefComponents)
        )
      )
    );

  },

  updateBrackets: function() {
    var doc = this.props.doc;
    var subjectReferences = doc.getIndex('type').get('subject_reference');

    _.each(subjectReferences, function(subjRef) {
      var anchors = $(this.getDOMNode()).find('.nodes .anchor[data-id='+subjRef.id+']');

      var startAnchorEl, endAnchorEl;
      if ($(anchors[0]).hasClass('start-anchor')) {
        startAnchorEl = anchors[0];
        endAnchorEl = anchors[1];
      } else {
        startAnchorEl = anchors[1];
        endAnchorEl = anchors[0];
      }

      if (!startAnchorEl || !endAnchorEl) {
        console.warn("FIXME: Could not find anchors for subject reference ", subjRef.id);
        return;
      }

      var startTop = $(startAnchorEl).position().top;
      var endTop = $(endAnchorEl).position().top + $(endAnchorEl).height();
      var height = endTop - startTop;

      var subjectRefEl = $(this.getDOMNode()).find('.subject-references .subject-reference[data-id='+subjRef.id+']');

      subjectRefEl.css({
        top: startTop,
        height: height
      });
    }, this);
  },

  componentDidMount: function() {
    var surface = this.surface;

    var doc = this.props.doc;

    doc.connect(this, {
      'document:changed': this.onDocumentChange
    });

    this.props.writerCtrl.registerSurface(surface, "content", {
      enabledTools: ENABLED_TOOLS
    });
    surface.attach(this.refs.interviewContent.getDOMNode());

    doc.connect(this, {
      'container-annotation-update': this.handleContainerAnnotationUpdate
    });

    var self = this;

    // TODO: we need a way so that the brackets get updated properly
    this.forceUpdate(function() {
      self.updateBrackets();
      _.delay(function() {
        self.updateBrackets();
      }, 100);

      self.surface.rerenderDomSelection();
    });

    $(window).resize(this.updateBrackets);
  },

  handleContainerAnnotationUpdate: function() {
    var self = this;
    this.forceUpdate(function() {
      self.updateBrackets();
    });
  },

  componentDidUpdate: function() {
    // HACK: when the state is changed this and particularly TextProperties
    // get rerendered (e.g., as the highlights might have changed)
    // Unfortunately we loose the DOM selection then.
    // Thus, we are resetting it here, but(!) delayed as otherwise the surface itself
    // might not have finished setting the selection to the desired and a proper state.
    if (!this.surface.__prerendering__) {
      var self = this;
      setTimeout(function() {
        self.surface.rerenderDomSelection();
      });
    }
  },

  componentWillUnmount: function() {
    var surface = this.surface;
    var doc = this.props.doc;
    doc.disconnect(this);

    this.props.writerCtrl.unregisterSurface(surface);
    surface.detach();
  },

  onDocumentChange: function(change) {
    var writerCtrl = this.props.writerCtrl;
    // console.log('##### ContainerComponent.onDocumentChange', change);

    var deletedSubjectRefs = _.filter(change.deleted, function(node) {
      return node.type === "subject_reference";
    });

    var createdSubjectRefs = _.filter(change.created, function(node) {
      return node.type === "subject_reference";
    });

    // HACK: implicitly switch the state when a subject reference is deleted and currently open
    // This implicitly also updates the brackets accordingly
    var subjectRef = deletedSubjectRefs[0];
    if (subjectRef && writerCtrl.state.subjectReferenceId === subjectRef.id) {
      writerCtrl.replaceState({
        contextId: 'subjects'
      });
      return;
    }

    if (change.isAffected([this.props.node.id, 'nodes']) || createdSubjectRefs.length > 0 ) {
      var self = this;
      // console.log('##### calling forceUpdate after document change');
      this.forceUpdate(function() {
        self.updateBrackets();
      });
    }
    // eagerly update brackets on every change
    else {
      this.updateBrackets();
    }
  }

});

module.exports = ContentEditor;<|endoftext|>


<commit_before>"use strict";

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

let pokemon = {
    pokemonId: Number,
    name: {type: String},
    icon: {type: String},
    classification: {type: String},
    types: [String],
    resistance: [String],
    weakness: [String],
    fastAttacks: [{name: {type: String}, type: {type: String}, damage: {type: Number}}],
    specialAttacks: [{name: {type: String}, type: {type: String}, damage: {type: Number}}],
    weight: {
        minimum: {type: String},
        maximum: {type: String}
    },
    height: {
        minimum: {type: String},
        maximum: {type: String}
    },
    fleeRate: Number,
    nextEvolutions: [{pokemonId: Number, name: {type: String}}],
    previousEvolutions: [{pokemonId: Number, name: {type: String}}],
    maxCP: Number,
    maxHP: Number,
    gender: {
        abbreviation: {
            type: String, enum: ['m', 'f', 'g', 'h'] //m=male, f=female, g=genderless, h=hermaphrodite
        },
        maleRatio: Number,
        femaleRatio: Number,
        breedable: Boolean
    }
};

var pokemonGoBasicSchema = new Schema(pokemon);

pokemonGoBasicSchema.index({"pokemonId": 1}, {"unique": true});

module.exports = {

    getModel: function () {
        return pokemon;
    },
    getSchema: function () {
        return mongoose.model('pokemon', pokemonGoBasicSchema);
    },
    getMappedModel: function (pokemon) {
        return {
            pokemonId: pokemon.id || pokemon.pokemonId,
            name: pokemon.name,
            icon: pokemon.icon,
            classification: pokemon.classification,
            types: pokemon.type && pokemon.type.toLowerCase(),
            resistance: pokemon.resistance && pokemon.resistance.toLowerCase(),
            weakness: pokemon.weakness && pokemon.weakness.toLowerCase(),
            // fastAttacks: [{name: {type: String}, type: {type: String}, damage: {type: Number}}],
            // specialAttacks: [{name: {type: String}, type: {type: String}, damage: {type: Number}}],
            /*weight: pokemon.weight && {
                minimum: pokemon.weight.min,
                maximum: pokemon.weight.max
            },
            height: pokemon.height && {
                minimum: pokemon.height.min,
                maximum: pokemon.height.max
            },*/
            fleeRate: pokemon.fleeRate,
            // nextEvolutions: pokemon.next && [{pokemonId: pokemon.next.id, name: pokemon.next.name}],
            // previousEvolutions: pokemon.prev && [{pokemonId: pokemon.prev.id, name: pokemon.prev.name}],
            maxCP: pokemon.maxCP,
            maxHP: pokemon.maxHP,
            "gender.abbreviation": pokemon.gender && pokemon.gender.toLowerCase()
        };
    }
};<commit_msg>changes for searching by attack parameters & evolution<commit_after>"use strict";

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

let pokemon = {
    pokemonId: Number,
    name: {type: String},
    icon: {type: String},
    classification: {type: String},
    types: [String],
    resistance: [String],
    weakness: [String],
    fastAttacks: [{name: {type: String}, type: {type: String}, damage: {type: Number}}],
    specialAttacks: [{name: {type: String}, type: {type: String}, damage: {type: Number}}],
    weight: {
        minimum: {type: String},
        maximum: {type: String}
    },
    height: {
        minimum: {type: String},
        maximum: {type: String}
    },
    fleeRate: Number,
    nextEvolutions: [{pokemonId: Number, name: {type: String}}],
    previousEvolutions: [{pokemonId: Number, name: {type: String}}],
    maxCP: Number,
    maxHP: Number,
    gender: {
        abbreviation: {
            type: String, enum: ['m', 'f', 'g', 'h'] //m=male, f=female, g=genderless, h=hermaphrodite
        },
        maleRatio: Number,
        femaleRatio: Number,
        breedable: Boolean
    }
};

var pokemonGoBasicSchema = new Schema(pokemon);

pokemonGoBasicSchema.index({"pokemonId": 1}, {"unique": true});

module.exports = {

    getModel: function () {
        return pokemon;
    },
    getSchema: function () {
        return mongoose.model('pokemon', pokemonGoBasicSchema);
    },
    getMappedModel: function (pokemon) {
        let attack_type_expr, attack_name_expr, attack_damage_expr;
        let search_by = [];

        if (pokemon.attackType) {
            attack_type_expr = new RegExp('^' + pokemon.attackType + '$', 'i');
            search_by.push({$or: [{"fastAttacks.type": attack_type_expr}, {"specialAttacks.type": attack_type_expr}]});
        }
        if (pokemon.attackName) {
            attack_name_expr = new RegExp('^' + pokemon.attackName + '$', 'i');
            search_by.push({$or: [{"fastAttacks.name": attack_name_expr}, {"specialAttacks.name": attack_name_expr}]});
        }

        if (pokemon.minAttackDamage) {
            attack_damage_expr = {};
            attack_damage_expr["$gte"] = pokemon.minAttackDamage;
        }
        if (pokemon.maxAttackDamage) {
            attack_damage_expr = attack_damage_expr || {};
            attack_damage_expr["$lt"] = pokemon.maxAttackDamage;
        }

        if (attack_damage_expr) {
            search_by.push({$or: [{"fastAttacks.damage": attack_damage_expr},
                {"specialAttacks.damage": attack_damage_expr}
            ]});
        }

        if (pokemon.evolution) {
            search_by.push({$or: [{"nextEvolutions.pokemonId": pokemon.evolution},
                {"previousEvolutions.pokemonId": pokemon.evolution}
            ]});
        }

        let mappedModel = {
            "pokemonId": pokemon.id || pokemon.pokemonId,
            "name": pokemon.name,
            "icon": pokemon.icon,
            "classification": pokemon.classification,
            "types": pokemon.type && pokemon.type.toLowerCase(),
            "resistance": pokemon.resistance && pokemon.resistance.toLowerCase(),
            "weakness": pokemon.weakness && pokemon.weakness.toLowerCase(),
            "weight.minimum": pokemon.minWeight,
            "weight.maximum": pokemon.maxWeight,
            "height.minimum": pokemon.minHeight,
            "height.maximum": pokemon.maxHeight,
            "fleeRate": pokemon.fleeRate,
            "maxCP": pokemon.maxCP,
            "maxHP": pokemon.maxHP,
            "gender.abbreviation": pokemon.gender && pokemon.gender.toLowerCase()
        };

        if (search_by.length > 1) {
            mappedModel["$and"] = search_by
        } else if (search_by.length === 1) {
            mappedModel["$or"] = search_by[0]["$or"];
        }

        return mappedModel;
    }
};<|endoftext|>


<commit_before>//functors

function plus1(value) {
    return value + 1;
}

console.log(plus1);<commit_msg>[UPDATE] Functors File<commit_after>//functors

function stringFunctor(value, fn) {
    var chars = value.split("")
    return chars.map(function(char) {
        return String.fromCharCode(fn(char.charCodeAt(0)))
    }).join("")
}

function plus1(value) {
    return value + 1;
}

function minus1(value) {
    return value - 1;
}

console.log("return 1: ", [3, 4].map(plus1)); // returns [4, 5]
console.log("return 2: ", stringFunctor("ABC", plus1)); // returns "BCD"
console.log("return 3: ", stringFunctor("XYZ", minus1)); // returns "RXY"<|endoftext|>


<commit_before>(function() {
	tinymce.PluginManager.requireLangPack("rdface");
	tinymce.create("tinymce.plugins.RdfacePlugin", {
		init : function(a, b) {
			toolbar:"demo",
			$.getJSON(b + '/schema_creator/selection.json', function(data) { 	// get selected schemas
				a.plugins.contextmenu.onContextMenu.add(function(th, menu, event) { // added first level schemas to context menu
					menu.removeAll(); //var add_entity = menu.addMenu({title : 'Add as Entity'}); // show only related entities
					var parent_node = $(event);
					var has_rel = 0;
					var all_datatypes = [];
					$.each(data.types, function(i, v) {
						all_datatypes.push(v.id);
					});

					while (parent_node.length) {
						if (parent_node.hasClass('r_entity')) {
							has_rel = 1;
							var entity_type = getTypeOfEntity(parent_node, getCookie("annotationF"));
							$.each(data.types[entity_type].properties, function(i, v) {
								if (all_datatypes.indexOf(data.properties[v].ranges[0]) != -1) { // only show atomic properties
									//add_entity.add({title : data.properties[v].label, onclick: function(){
									menu.add({
										title : data.properties[v].label,
										onclick : function() {
											insert_entity(a, data.properties[v].ranges[0], b, data.properties[v].id);
										}
									});
								}
							});
							break;
						}
						parent_node = parent_node.parent();
					}
					parent_node = $(event);
					var del_node;
					//todo: enable deleting entities as well
					while (parent_node.length) {
						del_node = parent_node;
						if (parent_node.hasClass('r_prop') || parent_node.hasClass('r_entity')) {
							menu.add({
								title : 'Delete',
								onclick : function() {
									remove_annotation(del_node, getCookie("annotationF"));
									a.setContent(a.getContent());
								}
							});
							break;
						}
						parent_node = parent_node.parent();
					}
					if (!has_rel) {
						var others = {};
						$.each(data.types, function(i, v) {
							//	if(v.level==1){
							menu.add({
								title : v.label,
								onclick : function() {
									insert_entity(a, v.id, b, 0);
								}
							});
							//}else{
							//others[v.id] = v.label;
							//}
						});
						//more_entities = add_entity.addMenu({title : 'More...'});
						//	$.each(others,function(i,v){
						//	more_entities.add({title : v, onclick: function(){
						//		insert_entity(a,i,b,0);
						//	}});
						//	});
					}
					// add related properties based on the
					// selected schema
					var parent_node = $(event);
					while (parent_node.length) {
						if (parent_node.hasClass('r_entity')) {
							// get the type of entity
							var entity_type = getTypeOfEntity(parent_node, getCookie("annotationF"));
							var add_property = menu.addMenu({
								title : 'Add as Property'
							});
							$.each(data.types[entity_type].properties, function(i, v) {
								// only show atomic
								// properties
								if (all_datatypes.indexOf(data.properties[v].ranges[0]) == -1) {
									add_property.add({
										title : data.properties[v].label,
										onclick : function() {
											insert_property(a, data.properties[v].id, b);
										}
									});
								}
							});
							break;
						}
						parent_node = parent_node.parent();
					}
					// show/hide entities
					var browse_schema = menu.addMenu({
						title : 'All Entities'
					});
					browse_schema.add({
						title : "Show all",
						onclick : function() {
							show_entities(a, 'all');
						}
					});
					browse_schema.add({
						title : "Hide all",
						onclick : function() {
							show_entities(a, 'none');
						}
					});
					browse_schema.add({
						title : "Remove all",
						onclick : function() {
							remove_annotations(a, 0);
						}
					});
				});
			});
			a.addButton("Entities",{
				type: 'menubutton',
				title : "Entities",
				label: "Entities",
				name: "Entities",
				icon: false,
				 menu: [
                    {text: 'Show All', onclick: function() {show_entities(a, 'all');}},
                    {text: 'Hide All', onclick: function() {show_entities(a, 'none');}},
                    {text: 'Remove All', onclick: function() {remove_annotations(a, 0);}}
                ]
			});

			a.addButton("rdfaceHelp", {
				title : "RDFa Content Editor",
				cmd : "mceRdfaceHelp",
				image : b + "/img/rdface.png"
			});
			a.addButton("rdfaceRun", {
				title : "Automatic Content Annotation",
				cmd : "mceRdfaEnrich",
				image : b + "/img/connect.png"
			});
			a.addButton("rdfaceFacts", {
				title : "Fact Browser",
				cmd : "mceRdfaFacts",
				image : b + "/img/facts.png"
			});
			a.addButton("rdfaceSetting", {
				title : "Settings",
				cmd : "mceRdfaSetting",
				image : b + "/img/setting.png"
			});
			a.addCommand("mceRdfaEnrich", function() {
				// first we need to remove automatically
				// generated annotations
				remove_annotations(a, 1);
				activateAjaxIndicator(b);
				handleAutomaticAnnotation(a);
			});

			a.addCommand("mceRdfaFacts", function() {
				//show triple browser
				var aF = getCookie("annotationF");
				if (aF == "Microdata") {
					alert('Fact browser only works for RDFa format!');
				} else {
					//create triple browser on the fly
					if ($('#tripleBrowser').length) {
						refreshFacts();
					} else {
						//$('.mceEditor').parent().find('#tripleBrowser').remove();
						$('.mceEditor').parent().prepend('

Fact Browser

 Your browser cannot display IFRAMEs

Statusbar text.

');
						$('#tripleBrowser').drags();
					}
				}

			});
			a.addCommand("mceRdfaSetting", function() {
				a.windowManager.open({
					file : b + "/setting.htm",
					width : 400 + parseInt(a.getLang("rdface.delta_width", 0)),
					height : 260 + parseInt(a.getLang("rdface.delta_height", 0)),
					inline : 1
				}, {
					plugin_url : b
				});
			});
			a.addCommand("mceRdfaceHelp", function() {
				a.windowManager.open({
					file : b + "/help.htm",
					width : 400 + parseInt(a.getLang("rdface.delta_width", 0)),
					height : 260 + parseInt(a.getLang("rdface.delta_height", 0)),
					inline : 1
				}, {
					plugin_url : b
				});
			});
			a.addCommand("editEntity", function(v1) {
				var entity_type, param;
				var aF = getCookie("annotationF");
				if (aF == "RDFa") {
					entity_type = v1.attr('typeof').split(':')[1];
					// send the content as parameter
					param = v1.find('span[property="schema:name"]').text();
				} else {
					entity_type = v1.attr('itemtype').split('http://schema.org/')[1];
					// send the content as parameter
					param = v1.find('span[itemprop="name"]').text();
				}
				var file, height, width;
				file = b + "/schema.htm";
				height = 500;
				width = 700;
				a.windowManager.open({
					file : file,
					width : width + parseInt(a.getLang("rdfa.delta_width", 0)),
					height : height + parseInt(a.getLang("rdfa.delta_height", 0)),
					inline : 1
				}, {
					plugin_url : b,
					entity_type : entity_type,
					selected_txt : param,
					annotationF : aF,
					pointer : v1
				});
			});
			a.addCommand("mceRdfaHighlight", function() {
				showTooltips(a, b);
			});
			a.onSetContent.add(function(ed, o) {
				showTooltips(a, b);
				refreshFacts();
			});
			a.onNodeChange.add(function(d, c, e) {
				showTooltips(a, b);
			});
			a.onLoadContent.add(function(ed, o) {
				//detect existing annotations
				//todo:check if they are in the scope of selected schemas or not
				var aF = getCookie("annotationF");
				adoptPrevAnnotations(ed, aF);
				showTooltips(a, b);
			});
			a.onSubmit.add(function(ed, e) {
				// remove the classes added for visualization in
				// the editor
			});
		},
		createControl : function(b, a) {
			return null;
		},
		getInfo : function() {
			return {
				longname : "RDFaCE Lite",
				author : "Ali Khalili",
				authorurl : "http://aksw.org/AliKhalili",
				infourl : "http://aksw.org/Projects/RDFaCE",
				version : "0.5"
			};
		}
	});
	tinymce.PluginManager.add("rdface", tinymce.plugins.RdfacePlugin);
})();
<commit_msg>simplifying editor's contextual menu<commit_after>(function() {
	tinymce.PluginManager.requireLangPack("rdface");
	tinymce.create("tinymce.plugins.RdfacePlugin", {
		init : function(a, b) {
			toolbar:"demo",
			$.getJSON(b + '/schema_creator/selection.json', function(data) { 	// get selected schemas
				a.plugins.contextmenu.onContextMenu.add(function(th, menu, event) { // added first level schemas to context menu
					menu.removeAll(); //var add_entity = menu.addMenu({title : 'Add as Entity'}); // show only related entities
					var parent_node = $(event);
					var has_rel = 0;
					var all_datatypes = [];
					$.each(data.types, function(i, v) {
						all_datatypes.push(v.id);
					});

					while (parent_node.length) {
						if (parent_node.hasClass('r_entity')) {
							has_rel = 1;
							var entity_type = getTypeOfEntity(parent_node, getCookie("annotationF"));
							$.each(data.types[entity_type].properties, function(i, v) {
								if (all_datatypes.indexOf(data.properties[v].ranges[0]) != -1) { // only show atomic properties
									//add_entity.add({title : data.properties[v].label, onclick: function(){
									// [NB] simplify context menu
									//menu.add({
									//	title : data.properties[v].label,
									//	onclick : function() {
									//		insert_entity(a, data.properties[v].ranges[0], b, data.properties[v].id);
									//	}
									//});
								}
							});
							break;
						}
						parent_node = parent_node.parent();
					}
					parent_node = $(event);
					var del_node;
					//todo: enable deleting entities as well
					while (parent_node.length) {
						del_node = parent_node;
						if (parent_node.hasClass('r_prop') || parent_node.hasClass('r_entity')) {
							menu.add({
								title : 'Delete',
								onclick : function() {
									remove_annotation(del_node, getCookie("annotationF"));
									a.setContent(a.getContent());
								}
							});
							break;
						}
						parent_node = parent_node.parent();
					}
					if (!has_rel) {
						var others = {};
						$.each(data.types, function(i, v) {
							//	if(v.level==1){
							menu.add({
								title : v.label,
								onclick : function() {
									insert_entity(a, v.id, b, 0);
								}
							});
							//}else{
							//others[v.id] = v.label;
							//}
						});
						//more_entities = add_entity.addMenu({title : 'More...'});
						//	$.each(others,function(i,v){
						//	more_entities.add({title : v, onclick: function(){
						//		insert_entity(a,i,b,0);
						//	}});
						//	});
					}
					// add related properties based on the
					// selected schema
					var parent_node = $(event);
					while (parent_node.length) {
						if (parent_node.hasClass('r_entity')) {
							// get the type of entity
							var entity_type = getTypeOfEntity(parent_node, getCookie("annotationF"));
							/*
							var add_property = menu.addMenu({
								title : 'Add as Property'
							});
							$.each(data.types[entity_type].properties, function(i, v) {
								// only show atomic
								// properties
								if (all_datatypes.indexOf(data.properties[v].ranges[0]) == -1) {
									add_property.add({
										title : data.properties[v].label,
										onclick : function() {
											insert_property(a, data.properties[v].id, b);
										}
									});
								}
							});
							*/
							break;
						}
						parent_node = parent_node.parent();
					}
					// show/hide entities
					var browse_schema = menu.addMenu({
						title : 'All Entities'
					});
					browse_schema.add({
						title : "Show all",
						onclick : function() {
							show_entities(a, 'all');
						}
					});
					browse_schema.add({
						title : "Hide all",
						onclick : function() {
							show_entities(a, 'none');
						}
					});
					browse_schema.add({
						title : "Remove all",
						onclick : function() {
							remove_annotations(a, 0);
						}
					});
				});
			});
			a.addButton("Entities",{
				type: 'menubutton',
				title : "Entities",
				label: "Entities",
				name: "Entities",
				icon: false,
				 menu: [
                    {text: 'Show All', onclick: function() {show_entities(a, 'all');}},
                    {text: 'Hide All', onclick: function() {show_entities(a, 'none');}},
                    {text: 'Remove All', onclick: function() {remove_annotations(a, 0);}}
                ]
			});

			a.addButton("rdfaceHelp", {
				title : "RDFa Content Editor",
				cmd : "mceRdfaceHelp",
				image : b + "/img/rdface.png"
			});
			a.addButton("rdfaceRun", {
				title : "Automatic Content Annotation",
				cmd : "mceRdfaEnrich",
				image : b + "/img/connect.png"
			});
			a.addButton("rdfaceFacts", {
				title : "Fact Browser",
				cmd : "mceRdfaFacts",
				image : b + "/img/facts.png"
			});
			a.addButton("rdfaceSetting", {
				title : "Settings",
				cmd : "mceRdfaSetting",
				image : b + "/img/setting.png"
			});
			a.addCommand("mceRdfaEnrich", function() {
				// first we need to remove automatically
				// generated annotations
				remove_annotations(a, 1);
				activateAjaxIndicator(b);
				handleAutomaticAnnotation(a);
			});

			a.addCommand("mceRdfaFacts", function() {
				//show triple browser
				var aF = getCookie("annotationF");
				if (aF == "Microdata") {
					alert('Fact browser only works for RDFa format!');
				} else {
					//create triple browser on the fly
					if ($('#tripleBrowser').length) {
						refreshFacts();
					} else {
						//$('.mceEditor').parent().find('#tripleBrowser').remove();
						$('.mceEditor').parent().prepend('

Fact Browser

 Your browser cannot display IFRAMEs

Statusbar text.

');
						$('#tripleBrowser').drags();
					}
				}

			});
			a.addCommand("mceRdfaSetting", function() {
				a.windowManager.open({
					file : b + "/setting.htm",
					width : 400 + parseInt(a.getLang("rdface.delta_width", 0)),
					height : 260 + parseInt(a.getLang("rdface.delta_height", 0)),
					inline : 1
				}, {
					plugin_url : b
				});
			});
			a.addCommand("mceRdfaceHelp", function() {
				a.windowManager.open({
					file : b + "/help.htm",
					width : 400 + parseInt(a.getLang("rdface.delta_width", 0)),
					height : 260 + parseInt(a.getLang("rdface.delta_height", 0)),
					inline : 1
				}, {
					plugin_url : b
				});
			});
			a.addCommand("editEntity", function(v1) {
				var entity_type, param;
				var aF = getCookie("annotationF");
				if (aF == "RDFa") {
					entity_type = v1.attr('typeof').split(':')[1];
					// send the content as parameter
					param = v1.find('span[property="schema:name"]').text();
				} else {
					entity_type = v1.attr('itemtype').split('http://schema.org/')[1];
					// send the content as parameter
					param = v1.find('span[itemprop="name"]').text();
				}
				var file, height, width;
				file = b + "/schema.htm";
				height = 500;
				width = 700;
				a.windowManager.open({
					file : file,
					width : width + parseInt(a.getLang("rdfa.delta_width", 0)),
					height : height + parseInt(a.getLang("rdfa.delta_height", 0)),
					inline : 1
				}, {
					plugin_url : b,
					entity_type : entity_type,
					selected_txt : param,
					annotationF : aF,
					pointer : v1
				});
			});
			a.addCommand("mceRdfaHighlight", function() {
				showTooltips(a, b);
			});
			a.onSetContent.add(function(ed, o) {
				showTooltips(a, b);
				refreshFacts();
			});
			a.onNodeChange.add(function(d, c, e) {
				showTooltips(a, b);
			});
			a.onLoadContent.add(function(ed, o) {
				//detect existing annotations
				//todo:check if they are in the scope of selected schemas or not
				var aF = getCookie("annotationF");
				adoptPrevAnnotations(ed, aF);
				showTooltips(a, b);
			});
			a.onSubmit.add(function(ed, e) {
				// remove the classes added for visualization in
				// the editor
			});
		},
		createControl : function(b, a) {
			return null;
		},
		getInfo : function() {
			return {
				longname : "RDFaCE Lite",
				author : "Ali Khalili",
				authorurl : "http://aksw.org/AliKhalili",
				infourl : "http://aksw.org/Projects/RDFaCE",
				version : "0.5"
			};
		}
	});
	tinymce.PluginManager.add("rdface", tinymce.plugins.RdfacePlugin);
})();
<|endoftext|>