<commit_before>import React from 'react';
import Tabs from 'react-bootstrap/lib/Tabs';
import BsTab from 'react-bootstrap/lib/Tab';
import Accordion from 'react-bootstrap/lib/Accordion';
import Panel from 'react-bootstrap/lib/Panel';
import uniqueid from 'lodash.uniqueid';
import classnames from 'classnames';

const BaseTabs = React.createClass({
  propTypes: {
    defaultActiveKey: React.PropTypes.any,
    tabType: React.PropTypes.oneOf(['tab-simple', 'tab-simple-alt', 'tab-left']),
    responsiveBreakpoint: React.PropTypes.oneOf(['xs', 'sm', 'md', 'lg']),
    largeScreenClassName: React.PropTypes.string,
    smallScreenClassName: React.PropTypes.string,
    onSelect: React.PropTypes.func,
    position: React.PropTypes.oneOf(['top', 'left']),
    tabWidth: React.PropTypes.number,
    paneWidth: React.PropTypes.number
  },

  getDefaultProps() {
    return {
      responsiveBreakpoint: 'xs'
    };
  },

  getInitialState() {
    return {activeKey: this.props.defaultActiveKey};
  },

  setActiveKey(key) {
    this.setState({activeKey: key});
  },

  componentWillReceiveProps(nextProps) {
    if (nextProps.defaultActiveKey !== this.props.defaultActiveKey) {
      this.setActiveKey(nextProps.defaultActiveKey);
    }
  },

  handleSelect(key) {
    if (!this.props.onSelect) {
      this.setActiveKey(key);
    } else {
      this.props.onSelect(key);
    }
  },

  render() {
    const {defaultActiveKey, children, responsiveBreakpoint, tabType, largeScreenClassName,
      smallScreenClassName, onSelect, position, tabWidth, paneWidth, ...props} = this.props;
    const largeScreenClasses = classnames([`hidden-${responsiveBreakpoint}`, tabType, largeScreenClassName]);
    const smallScreenClasses = classnames([`visible-${responsiveBreakpoint}-block`, `${tabType}-small-screen`, smallScreenClassName]);
    return (

          <Tabs id={uniqueid('pui-react-tabs-')} position={position} tabWidth={tabWidth} paneWidth={paneWidth} activeKey={this.state.activeKey} onSelect={this.handleSelect}>
            {children}
          </Tabs>

        <Accordion className={smallScreenClasses} activeKey={this.state.activeKey} onSelect={this.handleSelect}>
          {React.Children.map(children, (child) => {
            const {title, ...childProps} = child.props;
            return <Panel header={title} {...childProps}/>;
          })}
        </Accordion>

    );
  }
});

/**
 * @component SimpleTabs
 * @description Tab-based content toggling
 *

 * @example ```js
 * var SimpleTabs = require('pui-react-tabs').SimpleTabs;
 * var Tab = require('pui-react-tabs').Tab;
 * var MyComponent = React.createClass({
 *   render() {
 *     return (
 *       <SimpleTabs defaultActiveKey={2}>
 *         <Tab eventKey={1}>Content for tab 1</Tab>
 *         <Tab eventKey={2}>Content for tab 2</Tab>
 *         <Tab eventKey={3}>Content for tab 3</Tab>
 *       </SimpleTabs>
 *     );
 *   }
 * });
 * ```
 *
 * @property responsiveBreakpoint {one of: `"xs"`, `"sm"`, `"md"`, `lg`} The
 * size at which the small-screen tabs (accordion-style) should switch to
 * large-screen tabs (folder-style)
 *
 * @property defaultActiveKey {should equal one of your tab's event keys} The
 * tab which will start out open
 *
 * @property smallScreenClassName {css class} Will be applied to small screen
 * tabs only
 *
 * @property largeScreenClassName {css class} Will be applied to large screen
 * tabs only
 *
 * @property onSelect {function} Will override default behavior when clicking
 * on a tab. If you want to retain the default behavior as well as add new
 * functionality, change default active key in the function you provide
 *
 * @see [Pivotal UI React](http://styleguide.pivotal.io/react.html#tabs_react)
 * @see [Pivotal UI CSS](http://styleguide.pivotal.io/objects.html#tab)
 */
const SimpleTabs = React.createClass({
  render() {
    return (
      <BaseTabs {...this.props} tabType="tab-simple"/>
    );
  }
});

/**
 * @component SimpleAltTabs
 * @description `<SimpleTabs>` with different styling
 *
 * @example ```js
 * var SimpleAltTabs = require('pui-react-tabs').SimpleAltTabs;
 * var Tab = require('pui-react-tabs').Tab;
 * var MyComponent = React.createClass({
 *   render() {
 *     return (
 *       <SimpleAltTabs defaultActiveKey={2}>
 *         <Tab eventKey={1}>Content for tab 1</Tab>
 *         <Tab eventKey={2}>Content for tab 2</Tab>
 *         <Tab eventKey={3}>Content for tab 3</Tab>
 *       </SimpleAltTabs>
 *     );
 *   }
 * });
 * ```
 *
 * @property responsiveBreakpoint {one of: `"xs"`, `"sm"`, `"md"`, `lg`} The
 * size at which the small-screen tabs (accordion-style) should switch to
 * large-screen tabs (folder-style)
 *
 * @property defaultActiveKey {should equal one of your tab's event keys} The
 * tab which will start out open
 *
 * @property smallScreenClassName {css class} Will be applied to small screen
 * tabs only
 *
 * @property largeScreenClassName {css class} Will be applied to large screen
 * tabs only
 *
 * @property onSelect {function} Will override default behavior when clicking
 * on a tab. If you want to retain the default behavior as well as add new
 * functionality, change default active key in the function you provide
 *
 * @see [Pivotal UI React](http://styleguide.pivotal.io/react.html#tabs_react)
 * @see [Pivotal UI CSS](http://styleguide.pivotal.io/objects.html#tab)
 */
const SimpleAltTabs = React.createClass({
  render() {
    return (
      <BaseTabs {...this.props} tabType="tab-simple-alt"/>
    );
  }
});

/**
 * @component LeftTabs
 * @description Tabs with the nav stacked on the left
 *
 * @example ```js
 * var LeftTabs = require('pui-react-tabs').LeftTabs;
 * var Tab = require('pui-react-tabs').Tab;
 * var MyComponent = React.createClass({
 *   render() {
 *     return (
 *       <LeftTabs defaultActiveKey={1} tabWidth={3} paneWidth={9}>
 *         <Tab eventKey={1} title="Tab 1">Wow!</Tab>
 *         <Tab eventKey={2} title="Tab 2">
 *           <h2>Neat!</h2>
 *           <span>So much content.</span>
 *         </Tab>
 *       </LeftTabs>
 *     );
 *   }
 * });
 * ```
 *
 * @property responsiveBreakpoint {one of: `"xs"`, `"sm"`, `"md"`, `lg`} The
 * size at which the small-screen tabs (accordion-style) should switch to
 * large-screen tabs (folder-style)
 *
 * @property defaultActiveKey {should equal one of your tab's event keys} The
 * tab which will start out open
 *
 * @property smallScreenClassName {css class} Will be applied to small screen
 * tabs only
 *
 * @property largeScreenClassName {css class} Will be applied to large screen
 * tabs only
 *
 * @property onSelect {function} Will override default behavior when clicking
 * on a tab. If you want to retain the default behavior as well as add new
 * functionality, change default active key in the function you provide
 *
 * @property tabWidth {number} Takes the number of bs Columns. Optional: the default is 6.
 *
 * @property paneWidth {number} Takes the number of bs Columns. Optional: the default is 24 - tabWidth.
 *
 * @see [Pivotal UI React](http://styleguide.pivotal.io/react.html#tabs_react)
 * @see [Pivotal UI CSS](http://styleguide.pivotal.io/objects.html#tab)
 */
const LeftTabs = React.createClass({
  propTypes: {
    position: React.PropTypes.oneOf(['top', 'left']),
    tabWidth: React.PropTypes.number,
    paneWidth: React.PropTypes.number
  },
  getDefaultProps() {
    return {
      position: 'left',
      tabWidth: 6
    };
  },
  render() {
    let {tabWidth, paneWidth, ...props} = this.props;
    if (!paneWidth) {
      paneWidth = 24 - tabWidth;
    }
    return (
      <BaseTabs {...props} tabWidth={tabWidth} paneWidth={paneWidth} tabType="tab-left"/>
    );
  }
});

/**
 * @component Tab
 * @description A container for content in a `<SimpleTabs>` or `<SimpleAltTabs>`
 *
 * @property eventKey {Number} An identifier for the tab
 *
 * @see [Pivotal UI React](http://styleguide.pivotal.io/react.html#tabs_react)
 * @see [Pivotal UI CSS](http://styleguide.pivotal.io/objects.html#tab)
 */
let Tab = BsTab;

module.exports = {
  BaseTabs,
  SimpleTabs,
  SimpleAltTabs,
  Tab,
  LeftTabs
};

/*doc
---
title: Tabs
name: tabs_react
categories:
- React
---

npm install pui-react-tabs --save

Require the subcomponent:

```
var SimpleTabs = require('pui-react-tabs').SimpleTabs;
var Tab = require('pui-react-tabs').Tab;
```

Using Tab components in React consists of a parent element for the desired Tab type (for example,
`SimpleTabs` or `SimpleAltTabs`). Each `Tab` is a child of this and has a `tab` property for the
string value a Tab should display. Additionally, each `Tab` must define an `eventKey` property
for uniquely identifying this tab to its parent component.

Tabs are responsive, and will display accordion-style on small screens and folder-style on large
screens. They can also take a few optional special props.

Property   | Required? | Type             | Description
-----------| ----------|------------------| --------------------------------------------------------------------------
`responsiveBreakpoint` | no        | one of: `"xs"`, `"sm"`, `"md"`, `lg`,          | The size at which the small-screen tabs (accordion-style) should switch to large-screen tabs (folder-style)
`defaultActiveKey` | no            | should equal one of your tab's event keys | The tab which will start out open
`smallScreenClassName` | no  | css class | Will be applied to small screen tabs only
`largeScreenClassName` | no  | css class | Will be applied to large screen tabs only
`onSelect` | no | function | Will override default behavior when clicking on a tab. If you want to retain the default behavior as well as add new functionality, change default active key in the function you provide

*/

/*doc
---
title: Simple
name: 01_simple_tabs_react
parent: tabs_react
---

```react_example
<SimpleTabs defaultActiveKey={1}>
  <Tab eventKey={1} title="Tab 1">Wow!</Tab>
  <Tab eventKey={2} title="Tab 2">
    <h2>Neat!</h2>
    <span>So much content.</span>
  </Tab>
</SimpleTabs>
```
*/

/*doc
---
title: Alt
name: 02_alt_tabs_react
parent: tabs_react
---

```react_example
<SimpleAltTabs defaultActiveKey={2}>
  <Tab eventKey={1} title="Tab 1">Wow!</Tab>
  <Tab eventKey={2} title="Tab 2">
    <h2>Neat!</h2>
    <span>So much content.</span>
  </Tab>
</SimpleAltTabs>
```
*/

/*doc
 ---
 title: Left
 name: 03_left_tabs_react
 parent: tabs_react
 ---

 `LeftTabs` can be used to create tabs where the nav is stacked on the left. They
 take a few optional special properties in addition to the same properties as SimpleTabs and SimpleAltTabs.

 Property   | Required? | Type             | Description                                  | Default
 -----------| ----------|------------------| ---------------------------------------------|------------------------
 `tabWidth` | no        |  `number`        | The number of bs columns for the tabs        | 6
 `paneWidth` | no       | `number`         | The number of bs columns for the tab content | 24 - `tabWidth`

```react_example
<LeftTabs defaultActiveKey={1} tabWidth={3} paneWidth={9}>
  <Tab eventKey={1} title="Tab 1">Wow!</Tab>
  <Tab eventKey={2} title="Tab 2">
    Neat!
    <span>So much content.</span>
  </Tab>
</LeftTabs>
```

 */
<commit_msg>chore(tabs): Fixes active tab selection in xs screens<commit_after>import React from 'react';
import Tabs from 'react-bootstrap/lib/Tabs';
import BsTab from 'react-bootstrap/lib/Tab';
import Accordion from 'react-bootstrap/lib/Accordion';
import Panel from 'react-bootstrap/lib/Panel';
import uniqueid from 'lodash.uniqueid';
import classnames from 'classnames';

const BaseTabs = React.createClass({
  propTypes: {
    defaultActiveKey: React.PropTypes.any,
    tabType: React.PropTypes.oneOf(['tab-simple', 'tab-simple-alt', 'tab-left']),
    responsiveBreakpoint: React.PropTypes.oneOf(['xs', 'sm', 'md', 'lg']),
    largeScreenClassName: React.PropTypes.string,
    smallScreenClassName: React.PropTypes.string,
    onSelect: React.PropTypes.func,
    position: React.PropTypes.oneOf(['top', 'left']),
    tabWidth: React.PropTypes.number,
    paneWidth: React.PropTypes.number
  },

  getDefaultProps() {
    return {
      responsiveBreakpoint: 'xs'
    };
  },

  getInitialState() {
    return {activeKey: this.props.defaultActiveKey};
  },

  setActiveKey(key) {
    const previousActiveKey = this.state.activeKey;
    this.setState({
      activeKey: key,
      previousActiveKey
    });
  },

  componentWillReceiveProps(nextProps) {
    if (nextProps.defaultActiveKey !== this.props.defaultActiveKey) {
      this.setActiveKey(nextProps.defaultActiveKey);
    }
  },

  handleSelect(key) {
    if (!this.props.onSelect) {
      this.setActiveKey(key);
    } else {
      this.props.onSelect(key);
    }
  },

  render() {
    const {defaultActiveKey, children, responsiveBreakpoint, tabType, largeScreenClassName,
      smallScreenClassName, onSelect, position, tabWidth, paneWidth, ...props} = this.props;
    const largeScreenClasses = classnames([`hidden-${responsiveBreakpoint}`, tabType, largeScreenClassName]);
    const smallScreenClasses = classnames([`visible-${responsiveBreakpoint}-block`, `${tabType}-small-screen`, smallScreenClassName]);
    return (

          <Tabs id={uniqueid('pui-react-tabs-')} position={position} tabWidth={tabWidth}
                paneWidth={paneWidth} activeKey={this.state.activeKey}
                onSelect={this.handleSelect}>
            {children}
          </Tabs>

        <Accordion className={smallScreenClasses} activeKey={this.state.activeKey} onSelect={this.handleSelect}>
          {React.Children.map(children, (child) => {
            const {title, ...childProps} = child.props;
            return <Panel header={title} {...childProps}/>;
          })}
        </Accordion>

    );
  }
});

/**
 * @component SimpleTabs
 * @description Tab-based content toggling
 *

 * @example ```js
 * var SimpleTabs = require('pui-react-tabs').SimpleTabs;
 * var Tab = require('pui-react-tabs').Tab;
 * var MyComponent = React.createClass({
 *   render() {
 *     return (
 *       <SimpleTabs defaultActiveKey={2}>
 *         <Tab eventKey={1}>Content for tab 1</Tab>
 *         <Tab eventKey={2}>Content for tab 2</Tab>
 *         <Tab eventKey={3}>Content for tab 3</Tab>
 *       </SimpleTabs>
 *     );
 *   }
 * });
 * ```
 *
 * @property responsiveBreakpoint {one of: `"xs"`, `"sm"`, `"md"`, `lg`} The
 * size at which the small-screen tabs (accordion-style) should switch to
 * large-screen tabs (folder-style)
 *
 * @property defaultActiveKey {should equal one of your tab's event keys} The
 * tab which will start out open
 *
 * @property smallScreenClassName {css class} Will be applied to small screen
 * tabs only
 *
 * @property largeScreenClassName {css class} Will be applied to large screen
 * tabs only
 *
 * @property onSelect {function} Will override default behavior when clicking
 * on a tab. If you want to retain the default behavior as well as add new
 * functionality, change default active key in the function you provide
 *
 * @see [Pivotal UI React](http://styleguide.pivotal.io/react.html#tabs_react)
 * @see [Pivotal UI CSS](http://styleguide.pivotal.io/objects.html#tab)
 */
const SimpleTabs = React.createClass({
  render() {
    return (
      <BaseTabs {...this.props} tabType="tab-simple"/>
    );
  }
});

/**
 * @component SimpleAltTabs
 * @description `<SimpleTabs>` with different styling
 *
 * @example ```js
 * var SimpleAltTabs = require('pui-react-tabs').SimpleAltTabs;
 * var Tab = require('pui-react-tabs').Tab;
 * var MyComponent = React.createClass({
 *   render() {
 *     return (
 *       <SimpleAltTabs defaultActiveKey={2}>
 *         <Tab eventKey={1}>Content for tab 1</Tab>
 *         <Tab eventKey={2}>Content for tab 2</Tab>
 *         <Tab eventKey={3}>Content for tab 3</Tab>
 *       </SimpleAltTabs>
 *     );
 *   }
 * });
 * ```
 *
 * @property responsiveBreakpoint {one of: `"xs"`, `"sm"`, `"md"`, `lg`} The
 * size at which the small-screen tabs (accordion-style) should switch to
 * large-screen tabs (folder-style)
 *
 * @property defaultActiveKey {should equal one of your tab's event keys} The
 * tab which will start out open
 *
 * @property smallScreenClassName {css class} Will be applied to small screen
 * tabs only
 *
 * @property largeScreenClassName {css class} Will be applied to large screen
 * tabs only
 *
 * @property onSelect {function} Will override default behavior when clicking
 * on a tab. If you want to retain the default behavior as well as add new
 * functionality, change default active key in the function you provide
 *
 * @see [Pivotal UI React](http://styleguide.pivotal.io/react.html#tabs_react)
 * @see [Pivotal UI CSS](http://styleguide.pivotal.io/objects.html#tab)
 */
const SimpleAltTabs = React.createClass({
  render() {
    return (
      <BaseTabs {...this.props} tabType="tab-simple-alt"/>
    );
  }
});

/**
 * @component LeftTabs
 * @description Tabs with the nav stacked on the left
 *
 * @example ```js
 * var LeftTabs = require('pui-react-tabs').LeftTabs;
 * var Tab = require('pui-react-tabs').Tab;
 * var MyComponent = React.createClass({
 *   render() {
 *     return (
 *       <LeftTabs defaultActiveKey={1} tabWidth={3} paneWidth={9}>
 *         <Tab eventKey={1} title="Tab 1">Wow!</Tab>
 *         <Tab eventKey={2} title="Tab 2">
 *           <h2>Neat!</h2>
 *           <span>So much content.</span>
 *         </Tab>
 *       </LeftTabs>
 *     );
 *   }
 * });
 * ```
 *
 * @property responsiveBreakpoint {one of: `"xs"`, `"sm"`, `"md"`, `lg`} The
 * size at which the small-screen tabs (accordion-style) should switch to
 * large-screen tabs (folder-style)
 *
 * @property defaultActiveKey {should equal one of your tab's event keys} The
 * tab which will start out open
 *
 * @property smallScreenClassName {css class} Will be applied to small screen
 * tabs only
 *
 * @property largeScreenClassName {css class} Will be applied to large screen
 * tabs only
 *
 * @property onSelect {function} Will override default behavior when clicking
 * on a tab. If you want to retain the default behavior as well as add new
 * functionality, change default active key in the function you provide
 *
 * @property tabWidth {number} Takes the number of bs Columns. Optional: the default is 6.
 *
 * @property paneWidth {number} Takes the number of bs Columns. Optional: the default is 24 - tabWidth.
 *
 * @see [Pivotal UI React](http://styleguide.pivotal.io/react.html#tabs_react)
 * @see [Pivotal UI CSS](http://styleguide.pivotal.io/objects.html#tab)
 */
const LeftTabs = React.createClass({
  propTypes: {
    position: React.PropTypes.oneOf(['top', 'left']),
    tabWidth: React.PropTypes.number,
    paneWidth: React.PropTypes.number
  },
  getDefaultProps() {
    return {
      position: 'left',
      tabWidth: 6
    };
  },
  render() {
    let {tabWidth, paneWidth, ...props} = this.props;
    if (!paneWidth) {
      paneWidth = 24 - tabWidth;
    }
    return (
      <BaseTabs {...props} tabWidth={tabWidth} paneWidth={paneWidth} tabType="tab-left"/>
    );
  }
});

/**
 * @component Tab
 * @description A container for content in a `<SimpleTabs>` or `<SimpleAltTabs>`
 *
 * @property eventKey {Number} An identifier for the tab
 *
 * @see [Pivotal UI React](http://styleguide.pivotal.io/react.html#tabs_react)
 * @see [Pivotal UI CSS](http://styleguide.pivotal.io/objects.html#tab)
 */
let Tab = BsTab;

module.exports = {
  BaseTabs,
  SimpleTabs,
  SimpleAltTabs,
  Tab,
  LeftTabs
};

/*doc
---
title: Tabs
name: tabs_react
categories:
- React
---

npm install pui-react-tabs --save

Require the subcomponent:

```
var SimpleTabs = require('pui-react-tabs').SimpleTabs;
var Tab = require('pui-react-tabs').Tab;
```

Using Tab components in React consists of a parent element for the desired Tab type (for example,
`SimpleTabs` or `SimpleAltTabs`). Each `Tab` is a child of this and has a `tab` property for the
string value a Tab should display. Additionally, each `Tab` must define an `eventKey` property
for uniquely identifying this tab to its parent component.

Tabs are responsive, and will display accordion-style on small screens and folder-style on large
screens. They can also take a few optional special props.

Property   | Required? | Type             | Description
-----------| ----------|------------------| --------------------------------------------------------------------------
`responsiveBreakpoint` | no        | one of: `"xs"`, `"sm"`, `"md"`, `lg`,          | The size at which the small-screen tabs (accordion-style) should switch to large-screen tabs (folder-style)
`defaultActiveKey` | no            | should equal one of your tab's event keys | The tab which will start out open
`smallScreenClassName` | no  | css class | Will be applied to small screen tabs only
`largeScreenClassName` | no  | css class | Will be applied to large screen tabs only
`onSelect` | no | function | Will override default behavior when clicking on a tab. If you want to retain the default behavior as well as add new functionality, change default active key in the function you provide

*/

/*doc
---
title: Simple
name: 01_simple_tabs_react
parent: tabs_react
---

```react_example
<SimpleTabs defaultActiveKey={1}>
  <Tab eventKey={1} title="Tab 1">Wow!</Tab>
  <Tab eventKey={2} title="Tab 2">
    <h2>Neat!</h2>
    <span>So much content.</span>
  </Tab>
</SimpleTabs>
```
*/

/*doc
---
title: Alt
name: 02_alt_tabs_react
parent: tabs_react
---

```react_example
<SimpleAltTabs defaultActiveKey={2}>
  <Tab eventKey={1} title="Tab 1">Wow!</Tab>
  <Tab eventKey={2} title="Tab 2">
    <h2>Neat!</h2>
    <span>So much content.</span>
  </Tab>
</SimpleAltTabs>
```
*/

/*doc
 ---
 title: Left
 name: 03_left_tabs_react
 parent: tabs_react
 ---

 `LeftTabs` can be used to create tabs where the nav is stacked on the left. They
 take a few optional special properties in addition to the same properties as SimpleTabs and SimpleAltTabs.

 Property   | Required? | Type             | Description                                  | Default
 -----------| ----------|------------------| ---------------------------------------------|------------------------
 `tabWidth` | no        |  `number`        | The number of bs columns for the tabs        | 6
 `paneWidth` | no       | `number`         | The number of bs columns for the tab content | 24 - `tabWidth`

```react_example
<LeftTabs defaultActiveKey={1} tabWidth={3} paneWidth={9}>
  <Tab eventKey={1} title="Tab 1">Wow!</Tab>
  <Tab eventKey={2} title="Tab 2">
    Neat!
    <span>So much content.</span>
  </Tab>
</LeftTabs>
```

 */
<|endoftext|>


<commit_before>/*global FB*/
Template.Challenge.events ({
	'click .button__challenge': function() {
		var currentUrl = Router.current().url;
		if (currentUrl.indexOf('http') === -1) {
			currentUrl = Meteor.absoluteUrl(currentUrl.substring(1)); //substring to remove the initial /
		}

		console.log('FB URL to share:', currentUrl);

		FB.ui({
			method: 'feed',
			//href: currentUrl, //share from current URL of the app
			link: currentUrl,
			caption: 'Reference Documentation',
			description: 'Lorem ipsum dolor sit amet, consectetur arum aliquam reprehenderit laudantium disti. Dicta.'
		}, function(response) {
			if (response && response.post_id) {
				console.log('Post was published.');
			} else {
				console.log('Post was not published.');
			}
		});
	},

});

Template.Challenge.helpers ({
	'inMapMaster': function() {
		var isHidden = '';
		if (Session.get('showGame')) {
			isHidden= 'hidden-smartphone';
		}
		return isHidden;
	}
});<commit_msg>fix method changllen friends<commit_after>/*global FB*/
Template.Challenge.events ({
	'click .button__challenge': function() {
		var currentUrl = Router.current().url;
		if (currentUrl.indexOf('http') === -1) {
			currentUrl = Meteor.absoluteUrl(currentUrl.substring(1)); //substring to remove the initial /
		}

		console.log('FB URL to share:', currentUrl);
		var description = [
			'Bạn khâm phục thành tích chơi của mình? Vậy hãy thử thách bạn bè của mình để quyên được nhiều tiền hơn cho các em nhỏ.',
			'Bạn nghĩ chẳng ai có thể chơi giỏi hơn mình? Hãy thách bạn bè cùng chơi để chứng tỏ nào!',
			'Đây có phải thành tích tốt nhất chưa? Mời bạn bè cùng chơi để xem nhé.',
			'Không ai có thể giải nhanh hơn bạn? Thách bạn bè nào!'
		];

		var index = Math.floor((Math.random() * 4));

		var mapId = Router.current().params.mapId;
		var caption ='Thử thách '+mapId+' - Bánh Chưng Xanh';

		FB.ui({
			method: 'feed',
			//href: currentUrl, //share from current URL of the app
			link: currentUrl,
			caption: caption,
			description: description[index]
		}, function(response) {
			if (response && response.post_id) {
				console.log('Post was published.');
			} else {
				console.log('Post was not published.');
			}
		});
	},

});

Template.Challenge.helpers ({
	'inMapMaster': function() {
		var isHidden = '';
		if (Session.get('showGame')) {
			isHidden= 'hidden-smartphone';
		}
		return isHidden;
	}
});<|endoftext|>


<commit_before>'use strict';

import { Number, Angle } from '@entrylabs/tool';

Entry.FieldTextInput = class FieldTextInput extends Entry.Field {
    constructor(content, blockView, index) {
        super(content, blockView, index);
        const { data = {} } = blockView;
        const { type = 'text' } = data;
        this.type = type;
        this.TEXT_Y_PADDING = 3;

        this._blockView = blockView;
        this.board = this._blockView.getBoard();
        this._block = blockView.block;

        this.box = new Entry.BoxModel();

        this.svgGroup = null;
        this.optionWidget = null;
        this.optionInput = null;

        this.position = content.position;
        this._contents = content;
        this._isClearBG = content.clearBG || false;
        this._index = index;
        this._CONTENT_HEIGHT = this.getContentHeight();
        this._font_size = content.fontSize || 10;
        this._neighborFields = null;

        this.renderStart();
    }

    // 기본 모드의 keyEvent(tab) 용
    _focusNeighbor(direction) {
        const fields = this.getNeighborFields();

        let idx = fields.indexOf(this);
        if (direction === 'prev') {
            idx--;
        } else {
            idx++;
        }
        const field = fields[idx];

        //no field to focus
        if (!field) {
            return;
        }

        this.destroyOption(undefined, true);
        field.renderOptions(fields);
    }

    renderStart() {
        const blockView = this._blockView;

        if (!this.svgGroup) {
            this.svgGroup = blockView.contentSvgGroup.elem('g');
        }

        if (!this.textElement) {
            this.textElement = this.svgGroup.elem('text', {
                x: 0,
                y: this.TEXT_Y_PADDING,
                fill: this._contents.color || 'black',
                'font-size': `${this._font_size}px`,
                'font-weight': 'bold',
                'font-family': EntryStatic.fontFamily || 'NanumGothic',
            });
        }

        this.svgGroup.attr({ class: 'entry-input-field' });

        this._setConvertedValue();

        const width = this.getTextWidth();
        let y = this.position && this.position.y ? this.position.y : 0;
        const CONTENT_HEIGHT = this._CONTENT_HEIGHT;
        y -= CONTENT_HEIGHT / 2;
        if (!this._header) {
            this._header = this.svgGroup.elem('rect', {
                width,
                x: 0,
                y,
                height: CONTENT_HEIGHT,
                rx: 0,
                ry: 3,
                fill: '#fff',
                'fill-opacity': 0,
            });
        } else {
            this._header.setAttribute('width', width);
        }

        if (this._isClearBG) {
            $(this._header).css({ stroke: 'none' });
        }

        this.svgGroup.appendChild(this.textElement);

        this._bindRenderOptions();

        this.box.set({
            x: 0,
            y: 0,
            width,
            height: CONTENT_HEIGHT,
        });
    }

    renderOptions(neighborFields) {
        const { _block = {} } = this;
        const { defaultType = 'text' } = _block;
        if (neighborFields) {
            this._neighborFields = neighborFields;
        }

        this.optionGroup = Entry.Dom('div', {
            class: 'entry-widget-parent',
            parent: $('body'),
        });

        if (Entry.isMobile()) {
            if (defaultType === 'number') {
                this.optionWidget = this._getNumberOptionWidget();
            } else if (defaultType === 'angle') {
                this.optionWidget = this._getAngleOptionWidget();
            } else {
                this.optionInput = this._getInputFieldOption();
                this._attachDisposeEvent();
            }
        } else {
            if (defaultType === 'angle') {
                this.optionInput = this._getInputFieldOption();
                this.optionWidget = this._getAngleOptionWidget(this.optionInput[0]);
            } else {
                this.optionInput = this._getInputFieldOption();
                this._attachDisposeEvent();
            }
        }

        this._setTextValue();
        this.optionDomCreated();
    }

    _getNumberOptionWidget() {
        return new Number({
            type: 'numberWidget',
            data: {
                eventTypes: ['mousedown', 'touchstart', 'wheel'],
                positionDom: this.svgGroup,
                onOutsideClick: () => {
                    this.destroyOption(undefined, true);
                },
            },
            container: this.optionGroup[0],
        }).on('click', (eventName, value) => {
            let prevValue = String(this.getValue());
            switch (eventName) {
                case 'buttonPressed':
                    if (prevValue === '0' && _.includes(['0', '.'], value) === false) {
                        prevValue = '';
                    }
                    this.applyValue(prevValue + value);
                    break;
                case 'backButtonPressed': {
                    const nextValue = prevValue.substring(0, prevValue.length - 1);
                    this.applyValue(_.isEmpty(nextValue) ? 0 : nextValue);
                    break;
                }
            }
        });
    }

    /**
     *
     * @param {Array} excludeDom outside 로 판단하지 않을 dom target list
     * @returns {EntryTool} Angle Widget
     * @private
     */
    _getAngleOptionWidget(...excludeDom) {
        return new Angle({
            type: 'angleWidget',
            data: {
                eventTypes: ['mousedown', 'touchstart', 'wheel'],
                angle: this.getValue(),
                outsideExcludeDom: excludeDom,
                positionDom: this.svgGroup,
                onOutsideClick: (angle) => {
                    this.applyValue(FieldTextInput._refineDegree(angle));
                    this.destroyOption();
                },
            },
            container: this.optionGroup[0],
        })
            .on('click', (eventName, value) => {
                let nextValue = 0;
                switch (eventName) {
                    case 'buttonPressed': {
                        nextValue = this._getNextValue(value);
                        break;
                    }
                    case 'backButtonPressed': {
                        nextValue = this._getSubstringValue();
                        break;
                    }
                }
                this.applyValue(nextValue);
            })
            .on('change', (value) => {
                this.applyValue(String(value));
            });
    }

    _getInputFieldOption() {
        const inputField = Entry.Dom('input', {
            class: 'entry-widget-input-field',
            parent: $('body'),
        });

        inputField.val(this.getValue());

        inputField.on('mousedown', (e) => {
            e.stopPropagation();
        });

        inputField.on('keyup', (e) => {
            this.applyValue(inputField[0].value, true);
            if (_.includes([13, 27], e.keyCode || e.which)) {
                this.destroyOption(undefined, true);
            }
        });

        inputField.on('keydown', (e) => {
            const keyCode = e.keyCode || e.which;

            if (keyCode === 9) {
                e.preventDefault();
                this._focusNeighbor(e.shiftKey ? 'prev' : 'next');
            }
        });
        const { scale = 1 } = this.board;
        this._font_size = 10 * scale;
        const { x, y } = this.getAbsolutePosFromDocument();
        const height = (this._CONTENT_HEIGHT - 4) * scale;
        inputField.css({
            height,
            left: x + 1,
            top: y + (scale - 1) * 4 + 2 * scale - 1 * (scale / 2) - this.box.height / 2,
            width: this.box.width * scale,
            'font-size': `${this._font_size}px`,
            'background-color': EntryStatic.colorSet.block.lighten.CALC,
        });

        inputField.focus && inputField.focus();

        inputField[0].setSelectionRange(0, inputField[0].value.length, 'backward');
        return inputField;
    }

    applyValue(value, isNotUpdate) {
        let result = value;
        if (this.optionWidget) {
            switch (this.optionWidget.type) {
                case 'angleWidget':
                    this.optionWidget.data = {
                        angle: FieldTextInput._refineDegree(value),
                    };
                    if (
                        Entry.Utils.isNumber(value) &&
                        value.lastIndexOf('.') !== value.length - 1
                    ) {
                        result = String(result % 360);
                    }
                    break;
            }
        }
        if (this.optionInput && !isNotUpdate) {
            this.optionInput.val(result);
        }

        this.setValue(result);
        this._setTextValue();
        this.resize();
    }

    resize() {
        const { scale = 1 } = this.board;
        const size = { width: this.getTextWidth() };
        const scaleSize = { width: this.getTextWidth() / scale };
        this._header.attr(scaleSize);
        this.box.set(scaleSize);
        this.optionInput && this.optionInput.css(size);
        this._blockView.dAlignContent();
    }

    destroyOption(skipCommand, forceCommand) {
        this._setConvertedValue();

        if (this.optionWidget) {
            this.optionWidget.isShow && this.optionWidget.hide();
            this.optionWidget.remove();
            delete this.optionWidget;
        }

        if (this.optionInput) {
            this.optionInput.remove();
            delete this.optionInput;
        }

        super.destroyOption(skipCommand, forceCommand);
    }

    getTextWidth() {
        return Math.max(this.getTextBBox().width, 7);
    }

    _setTextValue() {
        const value = this.getValue();
        if (this.textElement.textContent !== value) {
            this.textElement.textContent = value;
        }
    }

    _setConvertedValue() {
        const { _block = {} } = this;
        const { defaultType = 'text' } = _block;
        let value = this._convert(this.getValue(), this.getValue());

        if (defaultType === 'angle') {
            value += '°';
        }

        if (this.textElement.textContent !== value) {
            this.textElement.textContent = value;
        }
    }

    getNeighborFields() {
        if (!this._neighborFields) {
            const FIELD_TEXT_INPUT = Entry.FieldTextInput;
            this._neighborFields = this._block
                .getRootBlock()
                .getThread()
                .view.getFields()
                .filter((f) => f instanceof FIELD_TEXT_INPUT);
        }

        return this._neighborFields;
    }

    /**
     * 기존 값의 뒤에 새 값을 추가한다. 내부에서 모든 숫자는 문자열이다.
     * 규칙은 아래와 같다.
     *
     * - 마이너스 입력은 현재 값이 0 인 경우만 가능
     * - . 은 값에서 유일하게 하나만 허용한다.
     * - 현재 값이 0 혹은 -0 인 경우 0은 입력할 수 없다. 다른 숫자는 입력할 수 있다.
     *
     * @param value 이번에 입력된 값
     * @return {string} 규칙에 맞추어 정제된 값
     * @private
     */
    _getNextValue(value) {
        let returnValue = String(this.getValue());
        returnValue = returnValue.replace('°', '');

        if (!FieldTextInput._isValidInputValue(value)) {
            return returnValue;
        }

        switch (value) {
            case '-':
                if (returnValue === '0') {
                    return '-';
                }
                return returnValue;
            case '.':
                if (/\./.test(returnValue) || returnValue === '-') {
                    return returnValue;
                }
                break;
            case '0':
                if (returnValue.startsWith('0') || returnValue.startsWith('-0')) {
                    return returnValue;
                }
                break;
            default:
                if (returnValue === '0') {
                    return value;
                }
                break;
        }

        returnValue += value;
        return returnValue;
    }

    /**
     * 현재 값 블록에서 마지막 숫자를 삭제한 값을 반환한다.
     * 0 인 경우는 0 을 반환, - 인 경우는 0 을 반환한다.
     * @returns {string} 마지막 위치가 삭제된 블록 값
     * @private
     */
    _getSubstringValue() {
        const returnValue = String(this.getValue());
        if (returnValue.length === 1) {
            return '0';
        } else {
            return returnValue.slice(0, returnValue.length - 1);
        }
    }

    static _refineDegree(value) {
        const reg = /&value/gm;
        if (reg.test(value)) {
            return value;
        }

        const numberOnlyValue = String(value).match(/[\d|\-|.|\+]+/g);
        let refinedDegree = (numberOnlyValue && numberOnlyValue[0]) || '0';
        if (refinedDegree > 360) {
            refinedDegree %= 360;
        } else if (refinedDegree < 0) {
            refinedDegree = refinedDegree % 360;
        }
        refinedDegree = String(refinedDegree);

        if (refinedDegree.lastIndexOf('.') === refinedDegree.length - 1) {
            return refinedDegree.slice(0, refinedDegree.length - 1);
        }

        return refinedDegree;
    }

    static _isValidInputValue(value) {
        return Entry.Utils.isNumber(value) || value === '-' || value === '.';
    }
};
<commit_msg>[#364] append blur event.<commit_after>'use strict';

import { Number, Angle } from '@entrylabs/tool';

Entry.FieldTextInput = class FieldTextInput extends Entry.Field {
    constructor(content, blockView, index) {
        super(content, blockView, index);
        const { data = {} } = blockView;
        const { type = 'text' } = data;
        this.type = type;
        this.TEXT_Y_PADDING = 3;

        this._blockView = blockView;
        this.board = this._blockView.getBoard();
        this._block = blockView.block;

        this.box = new Entry.BoxModel();

        this.svgGroup = null;
        this.optionWidget = null;
        this.optionInput = null;

        this.position = content.position;
        this._contents = content;
        this._isClearBG = content.clearBG || false;
        this._index = index;
        this._CONTENT_HEIGHT = this.getContentHeight();
        this._font_size = content.fontSize || 10;
        this._neighborFields = null;

        this.renderStart();
    }

    // 기본 모드의 keyEvent(tab) 용
    _focusNeighbor(direction) {
        const fields = this.getNeighborFields();

        let idx = fields.indexOf(this);
        if (direction === 'prev') {
            idx--;
        } else {
            idx++;
        }
        const field = fields[idx];

        //no field to focus
        if (!field) {
            return;
        }

        this.destroyOption(undefined, true);
        field.renderOptions(fields);
    }

    renderStart() {
        const blockView = this._blockView;

        if (!this.svgGroup) {
            this.svgGroup = blockView.contentSvgGroup.elem('g');
        }

        if (!this.textElement) {
            this.textElement = this.svgGroup.elem('text', {
                x: 0,
                y: this.TEXT_Y_PADDING,
                fill: this._contents.color || 'black',
                'font-size': `${this._font_size}px`,
                'font-weight': 'bold',
                'font-family': EntryStatic.fontFamily || 'NanumGothic',
            });
        }

        this.svgGroup.attr({ class: 'entry-input-field' });

        this._setConvertedValue();

        const width = this.getTextWidth();
        let y = this.position && this.position.y ? this.position.y : 0;
        const CONTENT_HEIGHT = this._CONTENT_HEIGHT;
        y -= CONTENT_HEIGHT / 2;
        if (!this._header) {
            this._header = this.svgGroup.elem('rect', {
                width,
                x: 0,
                y,
                height: CONTENT_HEIGHT,
                rx: 0,
                ry: 3,
                fill: '#fff',
                'fill-opacity': 0,
            });
        } else {
            this._header.setAttribute('width', width);
        }

        if (this._isClearBG) {
            $(this._header).css({ stroke: 'none' });
        }

        this.svgGroup.appendChild(this.textElement);

        this._bindRenderOptions();

        this.box.set({
            x: 0,
            y: 0,
            width,
            height: CONTENT_HEIGHT,
        });
    }

    renderOptions(neighborFields) {
        const { _block = {} } = this;
        const { defaultType = 'text' } = _block;
        if (neighborFields) {
            this._neighborFields = neighborFields;
        }

        this.optionGroup = Entry.Dom('div', {
            class: 'entry-widget-parent',
            parent: $('body'),
        });

        if (Entry.isMobile()) {
            if (defaultType === 'number') {
                this.optionWidget = this._getNumberOptionWidget();
            } else if (defaultType === 'angle') {
                this.optionWidget = this._getAngleOptionWidget();
            } else {
                this.optionInput = this._getInputFieldOption();
                this._attachDisposeEvent();
            }
        } else {
            if (defaultType === 'angle') {
                this.optionInput = this._getInputFieldOption();
                this.optionWidget = this._getAngleOptionWidget(this.optionInput[0]);
            } else {
                this.optionInput = this._getInputFieldOption();
                this._attachDisposeEvent();
            }
        }

        this._setTextValue();
        this.optionDomCreated();
    }

    _getNumberOptionWidget() {
        return new Number({
            type: 'numberWidget',
            data: {
                eventTypes: ['mousedown', 'touchstart', 'wheel'],
                positionDom: this.svgGroup,
                onOutsideClick: () => {
                    this.destroyOption(undefined, true);
                },
            },
            container: this.optionGroup[0],
        }).on('click', (eventName, value) => {
            let prevValue = String(this.getValue());
            switch (eventName) {
                case 'buttonPressed':
                    if (prevValue === '0' && _.includes(['0', '.'], value) === false) {
                        prevValue = '';
                    }
                    this.applyValue(prevValue + value);
                    break;
                case 'backButtonPressed': {
                    const nextValue = prevValue.substring(0, prevValue.length - 1);
                    this.applyValue(_.isEmpty(nextValue) ? 0 : nextValue);
                    break;
                }
            }
        });
    }

    /**
     *
     * @param {Array} excludeDom outside 로 판단하지 않을 dom target list
     * @returns {EntryTool} Angle Widget
     * @private
     */
    _getAngleOptionWidget(...excludeDom) {
        return new Angle({
            type: 'angleWidget',
            data: {
                eventTypes: ['mousedown', 'touchstart', 'wheel'],
                angle: this.getValue(),
                outsideExcludeDom: excludeDom,
                positionDom: this.svgGroup,
                onOutsideClick: (angle) => {
                    this.applyValue(FieldTextInput._refineDegree(angle));
                    this.destroyOption();
                },
            },
            container: this.optionGroup[0],
        })
            .on('click', (eventName, value) => {
                let nextValue = 0;
                switch (eventName) {
                    case 'buttonPressed': {
                        nextValue = this._getNextValue(value);
                        break;
                    }
                    case 'backButtonPressed': {
                        nextValue = this._getSubstringValue();
                        break;
                    }
                }
                this.applyValue(nextValue);
            })
            .on('change', (value) => {
                this.applyValue(String(value));
            });
    }

    _getInputFieldOption() {
        const inputField = Entry.Dom('input', {
            class: 'entry-widget-input-field',
            parent: $('body'),
        });

        inputField.val(this.getValue());

        inputField.on('mousedown', (e) => {
            e.stopPropagation();
        });

        inputField.on('keyup', (e) => {
            this.applyValue(inputField[0].value, true);
            if (_.includes([13, 27], e.keyCode || e.which)) {
                this.destroyOption(undefined, true);
            }
        });

        inputField.on('keydown', (e) => {
            const keyCode = e.keyCode || e.which;

            if (keyCode === 9) {
                e.preventDefault();
                this._focusNeighbor(e.shiftKey ? 'prev' : 'next');
            }
        });

        inputField.on('blur', (e) => {
            console.log('blur');
            this.destroyOption(undefined, true);
        });

        const { scale = 1 } = this.board;
        this._font_size = 10 * scale;
        const { x, y } = this.getAbsolutePosFromDocument();
        const height = (this._CONTENT_HEIGHT - 4) * scale;
        inputField.css({
            height,
            left: x + 1,
            top: y + (scale - 1) * 4 + 2 * scale - 1 * (scale / 2) - this.box.height / 2,
            width: this.box.width * scale,
            'font-size': `${this._font_size}px`,
            'background-color': EntryStatic.colorSet.block.lighten.CALC,
        });

        inputField.focus && inputField.focus();

        inputField[0].setSelectionRange(0, inputField[0].value.length, 'backward');
        return inputField;
    }

    applyValue(value, isNotUpdate) {
        let result = value;
        if (this.optionWidget) {
            switch (this.optionWidget.type) {
                case 'angleWidget':
                    this.optionWidget.data = {
                        angle: FieldTextInput._refineDegree(value),
                    };
                    if (
                        Entry.Utils.isNumber(value) &&
                        value.lastIndexOf('.') !== value.length - 1
                    ) {
                        result = String(result % 360);
                    }
                    break;
            }
        }
        if (this.optionInput && !isNotUpdate) {
            this.optionInput.val(result);
        }

        this.setValue(result);
        this._setTextValue();
        this.resize();
    }

    resize() {
        const { scale = 1 } = this.board;
        const size = { width: this.getTextWidth() };
        const scaleSize = { width: this.getTextWidth() / scale };
        this._header.attr(scaleSize);
        this.box.set(scaleSize);
        this.optionInput && this.optionInput.css(size);
        this._blockView.dAlignContent();
    }

    destroyOption(skipCommand, forceCommand) {
        this._setConvertedValue();

        if (this.optionWidget) {
            this.optionWidget.isShow && this.optionWidget.hide();
            this.optionWidget.remove();
            delete this.optionWidget;
        }

        if (this.optionInput) {
            this.optionInput.remove();
            delete this.optionInput;
        }

        super.destroyOption(skipCommand, forceCommand);
    }

    getTextWidth() {
        return Math.max(this.getTextBBox().width, 7);
    }

    _setTextValue() {
        const value = this.getValue();
        if (this.textElement.textContent !== value) {
            this.textElement.textContent = value;
        }
    }

    _setConvertedValue() {
        const { _block = {} } = this;
        const { defaultType = 'text' } = _block;
        let value = this._convert(this.getValue(), this.getValue());

        if (defaultType === 'angle') {
            value += '°';
        }

        if (this.textElement.textContent !== value) {
            this.textElement.textContent = value;
        }
    }

    getNeighborFields() {
        if (!this._neighborFields) {
            const FIELD_TEXT_INPUT = Entry.FieldTextInput;
            this._neighborFields = this._block
                .getRootBlock()
                .getThread()
                .view.getFields()
                .filter((f) => f instanceof FIELD_TEXT_INPUT);
        }

        return this._neighborFields;
    }

    /**
     * 기존 값의 뒤에 새 값을 추가한다. 내부에서 모든 숫자는 문자열이다.
     * 규칙은 아래와 같다.
     *
     * - 마이너스 입력은 현재 값이 0 인 경우만 가능
     * - . 은 값에서 유일하게 하나만 허용한다.
     * - 현재 값이 0 혹은 -0 인 경우 0은 입력할 수 없다. 다른 숫자는 입력할 수 있다.
     *
     * @param value 이번에 입력된 값
     * @return {string} 규칙에 맞추어 정제된 값
     * @private
     */
    _getNextValue(value) {
        let returnValue = String(this.getValue());
        returnValue = returnValue.replace('°', '');

        if (!FieldTextInput._isValidInputValue(value)) {
            return returnValue;
        }

        switch (value) {
            case '-':
                if (returnValue === '0') {
                    return '-';
                }
                return returnValue;
            case '.':
                if (/\./.test(returnValue) || returnValue === '-') {
                    return returnValue;
                }
                break;
            case '0':
                if (returnValue.startsWith('0') || returnValue.startsWith('-0')) {
                    return returnValue;
                }
                break;
            default:
                if (returnValue === '0') {
                    return value;
                }
                break;
        }

        returnValue += value;
        return returnValue;
    }

    /**
     * 현재 값 블록에서 마지막 숫자를 삭제한 값을 반환한다.
     * 0 인 경우는 0 을 반환, - 인 경우는 0 을 반환한다.
     * @returns {string} 마지막 위치가 삭제된 블록 값
     * @private
     */
    _getSubstringValue() {
        const returnValue = String(this.getValue());
        if (returnValue.length === 1) {
            return '0';
        } else {
            return returnValue.slice(0, returnValue.length - 1);
        }
    }

    static _refineDegree(value) {
        const reg = /&value/gm;
        if (reg.test(value)) {
            return value;
        }

        const numberOnlyValue = String(value).match(/[\d|\-|.|\+]+/g);
        let refinedDegree = (numberOnlyValue && numberOnlyValue[0]) || '0';
        if (refinedDegree > 360) {
            refinedDegree %= 360;
        } else if (refinedDegree < 0) {
            refinedDegree = refinedDegree % 360;
        }
        refinedDegree = String(refinedDegree);

        if (refinedDegree.lastIndexOf('.') === refinedDegree.length - 1) {
            return refinedDegree.slice(0, refinedDegree.length - 1);
        }

        return refinedDegree;
    }

    static _isValidInputValue(value) {
        return Entry.Utils.isNumber(value) || value === '-' || value === '.';
    }
};
<|endoftext|>


<commit_before>/***
|''Name''|TiddlySpaceToolbar|
|''Description''|augments tiddler toolbar commands with SVG icons|
|''Author''|Osmosoft|
|''Version''|0.6.1|
|''Status''|@@beta@@|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceToolbar.js|
|''CodeRepository''|http://github.com/TiddlySpace/tiddlyspace|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5.0|
|''Requires''|ImageMacroPlugin|
|''Keywords''|toolbar icons SVG|
!Description
replaces tiddler toolbar commands with SVG icons if available
!Notes
requires [[ImageMacroPlugin|http://svn.tiddlywiki.org/Trunk/contributors/JonRobson/plugins/ImageMacroPlugin/plugins/ImageMacroPlugin.tid]]

SVG icons are drawn from tiddlers titled {{{<command>.svg}}}
!TODO
* rename (IconToolbarPlugin?)
!Code
***/
//{{{
(function($) {

if(!config.macros.image) {
	throw "Missing dependency: ImageMacroPlugin";
}

var macro = config.macros.toolbar;

macro.icons = {
	cloneTiddler: "editTiddler"
};

var _handler = macro.handler;
macro.handler = function(place, macroName, params, wikifier,
		paramString, tiddler) {
	var toolbar = $(place);
	toolbar.attr({
		refresh: "macro",
		macroName: macroName
	}).data("args", arguments);
	var status = _handler.apply(this, arguments);
	if(tiddler.isReadOnly()) {
		toolbar.addClass("toolbarReadOnly");
	} else {
		toolbar.removeClass("toolbarReadOnly");
	}
	var parsedParams = paramString.parseParams("name")[0];
	if(parsedParams.icons && parsedParams.icons == "yes") {
		this.augmentCommandButtons(place);
	}
	if(parsedParams.more && parsedParams.more == "popup") {
		// note we must override the onclick event like in createTiddlyButton
		// otherwise the click event is the popup AND the slider
		$(".moreCommand", place)[0].onclick = macro.onClickMorePopUp;
	}
	else if (	parsedParams.icons && parsedParams.icons == "yes" &&
				parsedParams.more && parsedParams.more == "slider") {
		// initialize the slider with icons.
		$(".moreCommand", place)[0].onclick = macro.onClickMoreSlider;
	}
	return status;
};

macro.refresh = function(place, params) {
	var args = $(place).empty().data("args");
	this.handler.apply(this, args);
};

var imageMacro = config.macros.image;
macro.augmentCommandButtons = function(toolbar) {
	$(toolbar).children(".button").each(function(i, el) {
		var cmd = el.className.match(/\bcommand_([^ ]+?)\b/); // XXX: gratuitous RegEx?
		cmd = cmd ? cmd[1] : "moreCommand"; // XXX: special-casing of moreCommand due to ticket #1234
		var icon = store.tiddlerExists(cmd) ? cmd : macro.icons[cmd];
		var text = $(el).text();
		if(store.tiddlerExists(icon)) {
			$(el).empty();
			imageMacro.renderImage(el, icon, { alt: text });
		}
	});
};

// OnClickMore slider
macro.onClickMoreSlider = function(ev) {
    var e = this.nextSibling;
    e.style.display = "inline";
    this.style.display = "none";
    macro.augmentCommandButtons(e);
    return false;
};

// provide onClickMore to provide extra commands in a popup
macro.onClickMorePopUp = function(ev) {
	ev = ev || window.event;
	var sibling = this.nextSibling;
	var commands = sibling.childNodes;
	var popup = Popup.create(this);
	addClass(popup ,"taggedTiddlerList");
	for(var i = 0; i < commands.length; i++) {
		var li = createTiddlyElement(popup, "li", null);
		var oldCommand = commands[i];
		var command = oldCommand.cloneNode(true);
		command.onclick = oldCommand.onclick;
		li.appendChild(command);
	}
	Popup.show();
	ev.cancelBubble = true;
	if(ev.stopPropagation) {
		ev.stopPropagation();
	}
	return false;
};

})(jQuery);
//}}}
<commit_msg>Added onClickMoreSlider which is activated by ViewTemplate icons:yes more:slider<commit_after>/***
|''Name''|TiddlySpaceToolbar|
|''Description''|augments tiddler toolbar commands with SVG icons|
|''Author''|Osmosoft|
|''Version''|0.6.1|
|''Status''|@@beta@@|
|''Source''|http://github.com/TiddlySpace/tiddlyspace/raw/master/src/plugins/TiddlySpaceToolbar.js|
|''CodeRepository''|http://github.com/TiddlySpace/tiddlyspace|
|''License''|[[BSD|http://www.opensource.org/licenses/bsd-license.php]]|
|''CoreVersion''|2.5.0|
|''Requires''|ImageMacroPlugin|
|''Keywords''|toolbar icons SVG|
!Description
replaces tiddler toolbar commands with SVG icons if available
!Notes
requires [[ImageMacroPlugin|http://svn.tiddlywiki.org/Trunk/contributors/JonRobson/plugins/ImageMacroPlugin/plugins/ImageMacroPlugin.tid]]

SVG icons are drawn from tiddlers titled {{{<command>.svg}}}
!TODO
* rename (IconToolbarPlugin?)
!Code
***/
//{{{
(function($) {

if(!config.macros.image) {
	throw "Missing dependency: ImageMacroPlugin";
}

var macro = config.macros.toolbar;

macro.icons = {
	cloneTiddler: "editTiddler"
};

var _handler = macro.handler;
macro.handler = function(place, macroName, params, wikifier,
		paramString, tiddler) {
	var toolbar = $(place);
	toolbar.attr({
		refresh: "macro",
		macroName: macroName
	}).data("args", arguments);
	var status = _handler.apply(this, arguments);
	if(tiddler.isReadOnly()) {
		toolbar.addClass("toolbarReadOnly");
	} else {
		toolbar.removeClass("toolbarReadOnly");
	}
	var parsedParams = paramString.parseParams("name")[0];
	if(parsedParams.icons && parsedParams.icons == "yes") {
		this.augmentCommandButtons(place);
	}
	if(parsedParams.more && parsedParams.more == "popup") {
		// note we must override the onclick event like in createTiddlyButton
		// otherwise the click event is the popup AND the slider
		$(".moreCommand", place)[0].onclick = macro.onClickMorePopUp;
	}
	else if ( parsedParams.icons && parsedParams.icons == "yes" &&
			parsedParams.more && parsedParams.more == "slider") {
		// initialize the slider with icons.
		$(".moreCommand", place)[0].onclick = macro.onClickMoreSlider;
	}
	return status;
};

macro.refresh = function(place, params) {
	var args = $(place).empty().data("args");
	this.handler.apply(this, args);
};

var imageMacro = config.macros.image;
macro.augmentCommandButtons = function(toolbar) {
	$(toolbar).children(".button").each(function(i, el) {
		var cmd = el.className.match(/\bcommand_([^ ]+?)\b/); // XXX: gratuitous RegEx?
		cmd = cmd ? cmd[1] : "moreCommand"; // XXX: special-casing of moreCommand due to ticket #1234
		var icon = store.tiddlerExists(cmd) ? cmd : macro.icons[cmd];
		var text = $(el).text();
		if(store.tiddlerExists(icon)) {
			$(el).empty();
			imageMacro.renderImage(el, icon, { alt: text });
		}
	});
};

// OnClickMore slider
macro.onClickMoreSlider = function(ev) {
    var e = this.nextSibling;
    e.style.display = "inline";
    this.style.display = "none";
    macro.augmentCommandButtons(e);
    return false;
};

// provide onClickMore to provide extra commands in a popup
macro.onClickMorePopUp = function(ev) {
	ev = ev || window.event;
	var sibling = this.nextSibling;
	var commands = sibling.childNodes;
	var popup = Popup.create(this);
	addClass(popup ,"taggedTiddlerList");
	for(var i = 0; i < commands.length; i++) {
		var li = createTiddlyElement(popup, "li", null);
		var oldCommand = commands[i];
		var command = oldCommand.cloneNode(true);
		command.onclick = oldCommand.onclick;
		li.appendChild(command);
	}
	Popup.show();
	ev.cancelBubble = true;
	if(ev.stopPropagation) {
		ev.stopPropagation();
	}
	return false;
};

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


<commit_before>/* global Scientilla */

(function () {
        "use strict";

        angular
            .module('users')
            .component('scientillaDocumentVerificationForm', {
                templateUrl: 'partials/scientilla-document-verification-form.html',
                controller: DocumentVerificationController,
                controllerAs: 'vm',
                bindings: {
                    document: "<",
                    document2: "<",
                    verificationFn: "&",
                    onFailure: "&",
                    onSubmit: "&"
                }
            });

        DocumentVerificationController.$inject = [
            '$scope',
            'Restangular',
            'context',
            'UsersService',
            'ModalService'
        ];

        function DocumentVerificationController($scope, Restangular, context, UsersService, ModalService) {
            const vm = this;
            vm.instituteToId = instituteToId;
            vm.getInstitutesFilter = getInstitutesFilter;
            vm.getInstitutesQuery = getInstitutesQuery;
            vm.submit = submit;
            vm.copyToDraft = copyToDraft;
            vm.cancel = cancel;
            vm.viewSynchFields = viewSynchFields;
            vm.viewSynchMessage = viewSynchMessage;
            vm.viewAuthorshipFields = viewAuthorshipFields;
            vm.viewCopyToDraft = viewCopyToDraft;
            vm.viewLastCoauthor = viewLastCoauthor;
            vm.viewFirstCoauthor = viewFirstCoauthor;
            vm.viewOralPresentation = viewOralPresentation;
            vm.verificationData = {};
            vm.canBeSubmitted = canBeSubmitted;
            if (vm.document2)
                vm.document2id = vm.document2.id;

            const user = context.getResearchEntity();
            const DocumentService = context.getDocumentService();
            const deregisteres = [];
            const coauthorsDeregisteres = [];

            vm.$onInit = function () {
                if (user.getType() === 'group')
                    return vm.onFailure()();

                vm.verificationData.position = vm.document.getUserIndex(user);
                vm.verificationData.synchronize = vm.document.synchronized;
                vm.verificationData.public = true;

                deregisteres.push($scope.$watch('vm.verificationData.position', userSelectedChanged));
            };
            vm.$onDestroy = () => {
                for (const deregisterer of deregisteres)
                    deregisterer();

                for (const deregisterer of coauthorsDeregisteres)
                    deregisterer();
            };

            function getInstitutesQuery(searchText) {
                var qs = {where: {name: {contains: searchText}, parentId: null}};
                var model = 'institutes';
                return {model: model, qs: qs};
            }

            function instituteToId(institute) {
                return institute.id;
            }

            function copyToDraft() {
                DocumentService.copyDocument(vm.document);
                executeOnSubmit({buttonIndex: 0});
            }

            function canBeSubmitted() {
                return vm.verificationData.affiliations &&
                    vm.verificationData.affiliations.length &&
                    vm.verificationData.position >= 0;
            }

            /* jshint ignore:start */

            async function submit() {
                const data = {
                    affiliations: _.map(vm.verificationData.affiliations, 'id'),
                    position: vm.verificationData.position,
                    corresponding: vm.verificationData.corresponding,
                    synchronize: vm.verificationData.synchronize,
                    'public': vm.verificationData.public,
                    first_coauthor: vm.verificationData.first_coauthor,
                    last_coauthor: vm.verificationData.last_coauthor,
                    oral_presentation: vm.verificationData.oral_presentation,
                };

                const authorsArr = vm.document.authorsStr.split(', ');
                if (data.position < authorsArr.length) {
                    const authorStr = authorsArr[data.position];
                    const alias = user.aliases.find(a => a.str === authorStr);

                    if (!alias) {
                        const aliases = user.aliases.map(a => a.str).join(', ');
                        const result = await ModalService.multipleChoiceConfirm('New alias!',
                            'The author string you have selected "' + authorStr + '" is not among your aliases (' + aliases + ')' +
                            ' by proceeding it will be automatically added to them.' +
                            ' You can manage your aliases from your profile settings.',
                            ['Proceed']);

                        if (result === -1)
                            return;
                    }

                }
                else return;

                try {
                    const res = await verify(user, vm.document.id, data, vm.document2id);
                    const newUser = await UsersService.getProfile(user.id);
                    await context.setResearchEntity(newUser);
                    executeOnSubmit({buttonIndex: 1, data: res});
                } catch (e) {
                    executeOnFailure();
                }
            }

            /* jshint ignore:end */

            function userSelectedChanged() {
                const authorship = vm.document.authorships.find(a => a.position === vm.verificationData.position);
                if (authorship) {
                    vm.verificationData.corresponding = authorship.corresponding;
                    vm.verificationData.first_coauthor = authorship.first_coauthor;
                    vm.verificationData.last_coauthor = authorship.last_coauthor;
                    vm.verificationData.oral_presentation = authorship.oral_presentation;
                }

                getInstitutes().then(function (institutes) {
                    vm.verificationData.affiliations = institutes;
                });

                if (coauthorsDeregisteres.length) {
                    coauthorsDeregisteres.pop()();
                    coauthorsDeregisteres.pop()();
                }
                coauthorsDeregisteres.push($scope.$watch('vm.verificationData.first_coauthor', getCoauthorChangedCB(0)));
                coauthorsDeregisteres.push($scope.$watch('vm.verificationData.last_coauthor', getCoauthorChangedCB(1)));
            }

            function getCoauthorChangedCB(field) {
                const fields = ['first_coauthor', 'last_coauthor'];
                return () => {
                    const index = (field - 1 + fields.length) % fields.length;
                    if (vm.verificationData.first_coauthor && vm.verificationData.last_coauthor)
                        vm.verificationData[fields[index]] = false;
                };
            }

            function getInstitutes() {
                if (_.isNil(vm.verificationData.position) || vm.verificationData.position < 0)
                    return Promise.resolve([]);
                var qs = {
                    where: {document: vm.document.id, position: vm.verificationData.position},
                    populate: 'affiliations'
                };
                return Restangular.all('authorships').getList(qs).then(function (authorships) {
                    if (_.isEmpty(authorships))
                        return [];
                    var authorship = authorships[0];
                    return authorship.affiliations;
                });
            }

            function getInstitutesFilter() {
                return vm.verificationData.affiliations;
            }

            function cancel() {
                executeOnSubmit({buttonIndex: 0});
            }

            function viewSynchFields() {
                return vm.document.kind === 'v' && vm.document.origin && vm.document.synchronized;
            }

            function viewAuthorshipFields() {
                return true;
            }

            function viewSynchMessage() {
                return vm.document.kind === 'v' && !vm.document.synchronized;
            }

            function viewCopyToDraft() {
                return vm.document.kind === 'v';
            }

            function viewFirstCoauthor() {
                return vm.verificationData.position > 0 && vm.verificationData.position < vm.document.getAuthors().length - 1 && vm.document.sourceTypeObj.type !== 'invited_talk';
            }

            function viewLastCoauthor() {
                return vm.verificationData.position > 0 && vm.verificationData.position < vm.document.getAuthors().length - 1 && vm.document.sourceTypeObj.type !== 'invited_talk';
            }

            function viewOralPresentation() {
                return vm.verificationData.position >= 0 && vm.document.sourceTypeObj.type !== 'invited_talk';
            }

            function verify(user, documentId, verificationData, document2id) {
                if (_.isFunction(vm.verificationFn()))
                    return vm.verificationFn()(user, documentId, verificationData, document2id);
                return Promise.reject('no verification function');
            }

            function executeOnSubmit(res) {
                if (_.isFunction(vm.onSubmit()))
                    vm.onSubmit()(res);
            }

            function executeOnFailure() {
                if (_.isFunction(vm.onFailure()))
                    vm.onFailure()();
            }

        }
    }

)
();
<commit_msg>Changed message text<commit_after>/* global Scientilla */

(function () {
        "use strict";

        angular
            .module('users')
            .component('scientillaDocumentVerificationForm', {
                templateUrl: 'partials/scientilla-document-verification-form.html',
                controller: DocumentVerificationController,
                controllerAs: 'vm',
                bindings: {
                    document: "<",
                    document2: "<",
                    verificationFn: "&",
                    onFailure: "&",
                    onSubmit: "&"
                }
            });

        DocumentVerificationController.$inject = [
            '$scope',
            'Restangular',
            'context',
            'UsersService',
            'ModalService'
        ];

        function DocumentVerificationController($scope, Restangular, context, UsersService, ModalService) {
            const vm = this;
            vm.instituteToId = instituteToId;
            vm.getInstitutesFilter = getInstitutesFilter;
            vm.getInstitutesQuery = getInstitutesQuery;
            vm.submit = submit;
            vm.copyToDraft = copyToDraft;
            vm.cancel = cancel;
            vm.viewSynchFields = viewSynchFields;
            vm.viewSynchMessage = viewSynchMessage;
            vm.viewAuthorshipFields = viewAuthorshipFields;
            vm.viewCopyToDraft = viewCopyToDraft;
            vm.viewLastCoauthor = viewLastCoauthor;
            vm.viewFirstCoauthor = viewFirstCoauthor;
            vm.viewOralPresentation = viewOralPresentation;
            vm.verificationData = {};
            vm.canBeSubmitted = canBeSubmitted;
            if (vm.document2)
                vm.document2id = vm.document2.id;

            const user = context.getResearchEntity();
            const DocumentService = context.getDocumentService();
            const deregisteres = [];
            const coauthorsDeregisteres = [];

            vm.$onInit = function () {
                if (user.getType() === 'group')
                    return vm.onFailure()();

                vm.verificationData.position = vm.document.getUserIndex(user);
                vm.verificationData.synchronize = vm.document.synchronized;
                vm.verificationData.public = true;

                deregisteres.push($scope.$watch('vm.verificationData.position', userSelectedChanged));
            };
            vm.$onDestroy = () => {
                for (const deregisterer of deregisteres)
                    deregisterer();

                for (const deregisterer of coauthorsDeregisteres)
                    deregisterer();
            };

            function getInstitutesQuery(searchText) {
                var qs = {where: {name: {contains: searchText}, parentId: null}};
                var model = 'institutes';
                return {model: model, qs: qs};
            }

            function instituteToId(institute) {
                return institute.id;
            }

            function copyToDraft() {
                DocumentService.copyDocument(vm.document);
                executeOnSubmit({buttonIndex: 0});
            }

            function canBeSubmitted() {
                return vm.verificationData.affiliations &&
                    vm.verificationData.affiliations.length &&
                    vm.verificationData.position >= 0;
            }

            /* jshint ignore:start */

            async function submit() {
                const data = {
                    affiliations: _.map(vm.verificationData.affiliations, 'id'),
                    position: vm.verificationData.position,
                    corresponding: vm.verificationData.corresponding,
                    synchronize: vm.verificationData.synchronize,
                    'public': vm.verificationData.public,
                    first_coauthor: vm.verificationData.first_coauthor,
                    last_coauthor: vm.verificationData.last_coauthor,
                    oral_presentation: vm.verificationData.oral_presentation,
                };

                const authorsArr = vm.document.authorsStr.split(', ');
                if (data.position < authorsArr.length) {
                    const authorStr = authorsArr[data.position];
                    const alias = user.aliases.find(a => a.str === authorStr);

                    if (!alias) {
                        const aliases = user.aliases.map(a => a.str).join(', ');
                        const result = await ModalService.multipleChoiceConfirm('New alias!',
                            'You are verifying the document as "' + authorStr + '".\n' +
                            'By clicking on Proceed "' + authorStr + '" will be automatically added to your aliases (' + aliases + ').\n' +
                            'You can always manage them from your profile settings.\n',
                            ['Proceed']);

                        if (result === -1)
                            return;
                    }

                }
                else return;

                try {
                    const res = await verify(user, vm.document.id, data, vm.document2id);
                    const newUser = await UsersService.getProfile(user.id);
                    await context.setResearchEntity(newUser);
                    executeOnSubmit({buttonIndex: 1, data: res});
                } catch (e) {
                    executeOnFailure();
                }
            }

            /* jshint ignore:end */

            function userSelectedChanged() {
                const authorship = vm.document.authorships.find(a => a.position === vm.verificationData.position);
                if (authorship) {
                    vm.verificationData.corresponding = authorship.corresponding;
                    vm.verificationData.first_coauthor = authorship.first_coauthor;
                    vm.verificationData.last_coauthor = authorship.last_coauthor;
                    vm.verificationData.oral_presentation = authorship.oral_presentation;
                }

                getInstitutes().then(function (institutes) {
                    vm.verificationData.affiliations = institutes;
                });

                if (coauthorsDeregisteres.length) {
                    coauthorsDeregisteres.pop()();
                    coauthorsDeregisteres.pop()();
                }
                coauthorsDeregisteres.push($scope.$watch('vm.verificationData.first_coauthor', getCoauthorChangedCB(0)));
                coauthorsDeregisteres.push($scope.$watch('vm.verificationData.last_coauthor', getCoauthorChangedCB(1)));
            }

            function getCoauthorChangedCB(field) {
                const fields = ['first_coauthor', 'last_coauthor'];
                return () => {
                    const index = (field - 1 + fields.length) % fields.length;
                    if (vm.verificationData.first_coauthor && vm.verificationData.last_coauthor)
                        vm.verificationData[fields[index]] = false;
                };
            }

            function getInstitutes() {
                if (_.isNil(vm.verificationData.position) || vm.verificationData.position < 0)
                    return Promise.resolve([]);
                var qs = {
                    where: {document: vm.document.id, position: vm.verificationData.position},
                    populate: 'affiliations'
                };
                return Restangular.all('authorships').getList(qs).then(function (authorships) {
                    if (_.isEmpty(authorships))
                        return [];
                    var authorship = authorships[0];
                    return authorship.affiliations;
                });
            }

            function getInstitutesFilter() {
                return vm.verificationData.affiliations;
            }

            function cancel() {
                executeOnSubmit({buttonIndex: 0});
            }

            function viewSynchFields() {
                return vm.document.kind === 'v' && vm.document.origin && vm.document.synchronized;
            }

            function viewAuthorshipFields() {
                return true;
            }

            function viewSynchMessage() {
                return vm.document.kind === 'v' && !vm.document.synchronized;
            }

            function viewCopyToDraft() {
                return vm.document.kind === 'v';
            }

            function viewFirstCoauthor() {
                return vm.verificationData.position > 0 && vm.verificationData.position < vm.document.getAuthors().length - 1 && vm.document.sourceTypeObj.type !== 'invited_talk';
            }

            function viewLastCoauthor() {
                return vm.verificationData.position > 0 && vm.verificationData.position < vm.document.getAuthors().length - 1 && vm.document.sourceTypeObj.type !== 'invited_talk';
            }

            function viewOralPresentation() {
                return vm.verificationData.position >= 0 && vm.document.sourceTypeObj.type !== 'invited_talk';
            }

            function verify(user, documentId, verificationData, document2id) {
                if (_.isFunction(vm.verificationFn()))
                    return vm.verificationFn()(user, documentId, verificationData, document2id);
                return Promise.reject('no verification function');
            }

            function executeOnSubmit(res) {
                if (_.isFunction(vm.onSubmit()))
                    vm.onSubmit()(res);
            }

            function executeOnFailure() {
                if (_.isFunction(vm.onFailure()))
                    vm.onFailure()();
            }

        }
    }

)
();
<|endoftext|>


<commit_before>(function () {

    angular.module("app")
        .factory("ResearchItemSearchFormStructureService", ResearchItemSearchFormStructureService);

    ResearchItemSearchFormStructureService.$inject = [
        'ResearchItemTypesService',
        'documentSearchForm',
        'groupTypes',
        'groupTypeLabels',
        'AuthService',
        'ExternalConnectorService'
    ];

    function ResearchItemSearchFormStructureService(ResearchItemTypesService, documentSearchForm, groupTypes, groupTypeLabels, AuthService, ExternalConnectorService) {

        const service = {
            getStructure
        };

        const formStructures = {
            accomplishment: {
                title: {
                    inputType: 'text',
                    label: 'Title',
                    matchColumn: 'title',
                    matchRule: 'contains',
                    type: 'field'
                },
                author: {
                    inputType: 'text',
                    label: 'Author',
                    matchColumn: 'authorsStr',
                    matchRule: 'contains',
                    type: 'field'
                },
                maxYear: {
                    inputType: 'year',
                    label: 'Year from',
                    matchColumn: 'year',
                    matchRule: '>=',
                    type: 'field'
                },
                minYear: {
                    inputType: 'year',
                    label: 'Year to',
                    matchColumn: 'year',
                    matchRule: '<=',
                    type: 'field'
                },
                accomplishmentType: {
                    inputType: 'select',
                    label: 'Accomplishment Type',
                    values: [],
                    matchColumn: 'type',
                    type: 'field'
                }
            },
            group: {
                name: {
                    inputType: 'text',
                    label: 'Name',
                    matchColumn: 'name',
                    matchRule: 'contains',
                    type: 'field'
                },
                type: {
                    inputType: 'select',
                    label: 'Type',
                    matchColumn: 'type',
                    values: [],
                    type: 'field'
                },
                code: {
                    inputType: 'text',
                    label: 'CDR/CODE',
                    matchColumn: 'code',
                    matchRule: 'contains',
                    ngIf: false,
                    type: 'field'
                },
                active: {
                    inputType: 'checkbox',
                    label: 'Active',
                    matchColumn: 'active',
                    defaultValue: true,
                    type: 'action'
                }
            },
            user: {
                name: {
                    inputType: 'text',
                    label: 'Name',
                    matchColumn: 'name',
                    matchRule: 'contains',
                    type: 'field'
                },
                surname: {
                    inputType: 'text',
                    label: 'Surname',
                    matchColumn: 'surname',
                    matchRule: 'contains',
                    type: 'field'
                }
            }
        };

        return service;

        /* jshint ignore:start */
        async function getStructure(constant) {

            let structure;

            switch(constant) {
                case 'accomplishment':
                    const types = await ResearchItemTypesService.getTypes('accomplishment');

                    formStructures[constant].accomplishmentType.values = _.concat(
                        [{value: "?", label: 'Select'}],
                        types.map(s => ({value: s.key, label: s.label}))
                    );

                    structure = formStructures[constant];
                    break;
                case 'document':
                    structure = documentSearchForm;
                    break;
                case 'external':
                    structure = Object.assign({},
                        {
                            connector: await getConnectorField()
                        },
                        documentSearchForm
                    );
                    break;
                case 'suggested':
                    structure = Object.assign({},
                        documentSearchForm,
                        {
                            rejected: {
                                inputType: 'checkbox',
                                label: 'Show discarded documents',
                                defaultValue: false,
                                matchColumn: 'discarded',
                                type: 'action'
                            }
                        }
                    );
                    break;
                case 'group':
                    const user = AuthService.user;
                    formStructures[constant].type.values = [{
                        value: '?',
                        label: 'All'
                    }].concat(
                        Object.keys(groupTypes)
                            .map(k => ({label: groupTypeLabels[k], value: groupTypes[k]}))
                    );

                    formStructures[constant].code.ngIf = user.isAdmin();

                    structure = formStructures[constant];
                    break;
                case 'user':
                    structure = formStructures[constant];
                    break;
                default:
                    break;
            }

            return structure;
        }

        async function getConnectorField() {
            let externalConnectors = [],
                defaultValue = '';

            await ExternalConnectorService.getConnectors().then((connectors) => {
                if (connectors && connectors.publications && connectors.publications.active) {
                    externalConnectors.push({value: 'publications', label: 'Publications'});
                }

                if (connectors && connectors.elsevier && connectors.elsevier.active) {
                    externalConnectors.push({value: 'scopus', label: 'Scopus'});
                    defaultValue = 'scopus';
                } else {
                    if (externalConnectors.length > 0) {
                        defaultValue = externalConnectors[0].value;
                    }
                }
            });

            return {
                inputType: 'select',
                label: 'Connector',
                values: externalConnectors,
                matchColumn: 'origin',
                defaultValue: defaultValue,
                type: 'connector'
            };

            //const values = connectors.map(c => ({value: c.value, label: c.label}));

        }
        /* jshint ignore:end */
    }
})();<commit_msg>Remove commented code<commit_after>(function () {

    angular.module("app")
        .factory("ResearchItemSearchFormStructureService", ResearchItemSearchFormStructureService);

    ResearchItemSearchFormStructureService.$inject = [
        'ResearchItemTypesService',
        'documentSearchForm',
        'groupTypes',
        'groupTypeLabels',
        'AuthService',
        'ExternalConnectorService'
    ];

    function ResearchItemSearchFormStructureService(ResearchItemTypesService, documentSearchForm, groupTypes, groupTypeLabels, AuthService, ExternalConnectorService) {

        const service = {
            getStructure
        };

        const formStructures = {
            accomplishment: {
                title: {
                    inputType: 'text',
                    label: 'Title',
                    matchColumn: 'title',
                    matchRule: 'contains',
                    type: 'field'
                },
                author: {
                    inputType: 'text',
                    label: 'Author',
                    matchColumn: 'authorsStr',
                    matchRule: 'contains',
                    type: 'field'
                },
                maxYear: {
                    inputType: 'year',
                    label: 'Year from',
                    matchColumn: 'year',
                    matchRule: '>=',
                    type: 'field'
                },
                minYear: {
                    inputType: 'year',
                    label: 'Year to',
                    matchColumn: 'year',
                    matchRule: '<=',
                    type: 'field'
                },
                accomplishmentType: {
                    inputType: 'select',
                    label: 'Accomplishment Type',
                    values: [],
                    matchColumn: 'type',
                    type: 'field'
                }
            },
            group: {
                name: {
                    inputType: 'text',
                    label: 'Name',
                    matchColumn: 'name',
                    matchRule: 'contains',
                    type: 'field'
                },
                type: {
                    inputType: 'select',
                    label: 'Type',
                    matchColumn: 'type',
                    values: [],
                    type: 'field'
                },
                code: {
                    inputType: 'text',
                    label: 'CDR/CODE',
                    matchColumn: 'code',
                    matchRule: 'contains',
                    ngIf: false,
                    type: 'field'
                },
                active: {
                    inputType: 'checkbox',
                    label: 'Active',
                    matchColumn: 'active',
                    defaultValue: true,
                    type: 'action'
                }
            },
            user: {
                name: {
                    inputType: 'text',
                    label: 'Name',
                    matchColumn: 'name',
                    matchRule: 'contains',
                    type: 'field'
                },
                surname: {
                    inputType: 'text',
                    label: 'Surname',
                    matchColumn: 'surname',
                    matchRule: 'contains',
                    type: 'field'
                }
            }
        };

        return service;

        /* jshint ignore:start */
        async function getStructure(constant) {

            let structure;

            switch(constant) {
                case 'accomplishment':
                    const types = await ResearchItemTypesService.getTypes('accomplishment');

                    formStructures[constant].accomplishmentType.values = _.concat(
                        [{value: "?", label: 'Select'}],
                        types.map(s => ({value: s.key, label: s.label}))
                    );

                    structure = formStructures[constant];
                    break;
                case 'document':
                    structure = documentSearchForm;
                    break;
                case 'external':
                    structure = Object.assign({},
                        {
                            connector: await getConnectorField()
                        },
                        documentSearchForm
                    );
                    break;
                case 'suggested':
                    structure = Object.assign({},
                        documentSearchForm,
                        {
                            rejected: {
                                inputType: 'checkbox',
                                label: 'Show discarded documents',
                                defaultValue: false,
                                matchColumn: 'discarded',
                                type: 'action'
                            }
                        }
                    );
                    break;
                case 'group':
                    const user = AuthService.user;
                    formStructures[constant].type.values = [{
                        value: '?',
                        label: 'All'
                    }].concat(
                        Object.keys(groupTypes)
                            .map(k => ({label: groupTypeLabels[k], value: groupTypes[k]}))
                    );

                    formStructures[constant].code.ngIf = user.isAdmin();

                    structure = formStructures[constant];
                    break;
                case 'user':
                    structure = formStructures[constant];
                    break;
                default:
                    break;
            }

            return structure;
        }

        async function getConnectorField() {
            let externalConnectors = [],
                defaultValue = '';

            await ExternalConnectorService.getConnectors().then((connectors) => {
                if (connectors && connectors.publications && connectors.publications.active) {
                    externalConnectors.push({value: 'publications', label: 'Publications'});
                }

                if (connectors && connectors.elsevier && connectors.elsevier.active) {
                    externalConnectors.push({value: 'scopus', label: 'Scopus'});
                    defaultValue = 'scopus';
                } else {
                    if (externalConnectors.length > 0) {
                        defaultValue = externalConnectors[0].value;
                    }
                }
            });

            return {
                inputType: 'select',
                label: 'Connector',
                values: externalConnectors,
                matchColumn: 'origin',
                defaultValue: defaultValue,
                type: 'connector'
            };
        }
        /* jshint ignore:end */
    }
})();<|endoftext|>


<commit_before>
module.exports = {
  entry: './example/build/index.js',
  output: {
    filename: './example/build/bundle.js'
  },
  node: {
    fs: "empty"
  },
  bail: true,
  module: {
    loaders: [
      { test: /\.css$/, loader: 'style-loader!css-loader' },
    ]
  },
  resolve: {
    alias: {
      'requirejs': 'requirejs/require'
    }
  }
}
<commit_msg>Remove unused webpack config<commit_after>
module.exports = {
  entry: './example/build/index.js',
  output: {
    filename: './example/build/bundle.js'
  },
  node: {
    fs: "empty"
  },
  bail: true,
  module: {
    loaders: [
      { test: /\.css$/, loader: 'style-loader!css-loader' },
    ]
  }
}
<|endoftext|>


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

    angular.module('sideNavDirective', ['brandHeaderDirective'])
        .directive('sideNav', function() {
            return {
                restrict: 'E',
                replace: true,
                templateUrl: 'components/UI/side-nav.html',
                controller: 'NavCtrl'
            };
        })
        .controller('NavCtrl', ['$scope', '$location',
            function($scope, $location) {
                // Items to show in the side navigation.
                // Object with a title and route property. If no route
                // is provided the lowercase'd title will be used
                $scope.navItems = [{
                    title: 'Dashboard',
                    route: 'dashboard',
                    icon: 'dashboard',
                }, {
                    title: 'Users',
                    icon: 'users',
                    route: 'users',
                    subitems: [{
                        title: 'All',
                        route: ''
                    }, {
                        title: 'New',
                        route: '/new'
                    }]
                }, {
                    title: 'Accounts',
                    icon: 'money',
                    route: 'accounts',
                    subitems: [{
                        title: 'All',
                        route: ''
                    }]
                }, {
                    title: 'Transactions',
                    icon: 'exchange',
                    route: 'transactions',
                    subitems: [{
                        title: 'All',
                        route: ''
                    }]
                }];
                // Used to set the active class on the nav li elements
                $scope.isActive = function(route) {
                    return route === $location.path();
                };
            }
        ]);

})();<commit_msg>remove account and transaction sub items<commit_after>(function() {
    'use strict';

    angular.module('sideNavDirective', ['brandHeaderDirective'])
        .directive('sideNav', function() {
            return {
                restrict: 'E',
                replace: true,
                templateUrl: 'components/UI/side-nav.html',
                controller: 'NavCtrl'
            };
        })
        .controller('NavCtrl', ['$scope', '$location',
            function($scope, $location) {
                // Items to show in the side navigation.
                // Object with a title and route property. If no route
                // is provided the lowercase'd title will be used
                $scope.navItems = [{
                    title: 'Dashboard',
                    route: 'dashboard',
                    icon: 'dashboard',
                }, {
                    title: 'Users',
                    icon: 'users',
                    route: 'users',
                    subitems: [{
                        title: 'All',
                        route: ''
                    }, {
                        title: 'New',
                        route: '/new'
                    }]
                }, {
                    title: 'Accounts',
                    icon: 'money',
                    route: 'accounts'
                }, {
                    title: 'Transactions',
                    icon: 'exchange',
                    route: 'transactions'
                }];
                // Used to set the active class on the nav li elements
                $scope.isActive = function(route) {
                    return route === $location.path();
                };
            }
        ]);

})();<|endoftext|>