<commit_before>import React from 'react';
import { Text, StyleSheet, View, Button, ScrollView } from 'react-native';
import { connect } from 'react-redux';

import moment from 'moment';
import Icon from 'react-native-vector-icons/FontAwesome';
import style from '../../common/style.js'

const styles = StyleSheet.create({
  sessionHeader: {
    flex: 1,
    padding: 5,
    backgroundColor: style.colors.background,
  },
  heading1: {
    color: style.colors.color1,
    fontSize: style.fontSizes.heading1,
    fontFamily: style.fonts.juraBold,
  },
  heading2: {
    fontSize: style.fontSizes.heading2,
    fontFamily: style.fonts.juraBold,
    padding: 5,
  },
  headingSpeakerName: {
    color: style.colors.color2,
    fontWeight: "500",
    padding: 5,
  },
  textStyleHeder: {
    color: style.colors.color1,
  },
  textStyle: {
    color: style.colors.primary,
    padding: 5,
  },
  container: {
    backgroundColor: style.colors.backgroundSecondary,
  },
  keywordContainer: {
    fontFamily: style.fonts.juraLight,
    padding: 3,
    margin: 5,
  }
});

export default class SessionDetail extends React.Component {

  render() {
    const { params } = this.props.navigation.state;
    let fromTime = moment(new Date(params.sessionData.startTime)).format('dddd, MMMM DD HH:mm');
    let toTime = moment (new Date(params.sessionData.endTime)).format('HH:mm');
    return (
      <ScrollView>
        <View style={ styles.sessionHeader }>
          <View style={{ flex: 1, flexDirection: 'row' }}>
            <Icon name="arrow-left" style={{padding: 15}} size={40} color={style.colors.color4}
              onPress={() => this.props.navigation.navigate('SessionList')}/>
            <Icon name="star-o" style={{padding: 15}}size={40} color={style.colors.color4}/>
          </View>
          <Text style={ styles.heading1 }>{ (params.sessionData.title).toUpperCase() }</Text>
          <View style={{flex: 1, flexDirection: 'row'}}>
            <View>
              <Text style={ styles.textStyleHeder }>{ params.sessionData.room } { params.sessionData.format }</Text>
              <Text style={{color: style.colors.color1}}>{ fromTime } - { toTime }</Text>
            </View>
          </View>
        </View>
        <View style={ styles.container }>
          <Text style={ styles.textStyle }>{ params.sessionData.abstract }</Text>
          <Text style={ styles.textStyle }>{ params.sessionData.intendedAudience }</Text>
          <Text style={ styles.heading2 }>SPEAKER:</Text>
          {
            params.sessionData.speakers.map( (speaker, index) => {
              return (
                <View key={index}>
                  <Text style={ styles.headingSpeakerName }>{ speaker.name }</Text>
                  <Text style={ styles.textStyle }>{ speaker.bio }</Text>
                </View>);
            })
          }
          <Text style={ styles.heading2 }>KEYWORDS:</Text>
          <View>
          {
            params.sessionData.keywords.map( (keyword, index) => {
              return <Text style={ styles.keywordContainer } key={index}>{keyword}</Text>
            })
          }
          </View>
        </View>
      </ScrollView>
    )
  }
}
<commit_msg>adjusted session detail view for better readability<commit_after>import React from 'react';
import { Text, StyleSheet, View, Button, ScrollView } from 'react-native';
import { connect } from 'react-redux';

import moment from 'moment';
import Icon from 'react-native-vector-icons/FontAwesome';
import style from '../../common/style.js'

const styles = StyleSheet.create({
  sessionHeaderWrapper: {
    flex: 1,
    padding: 5,
    backgroundColor: style.colors.background,
    paddingBottom: 10,
    borderBottomWidth: 2,
    borderBottomColor: style.colors.color2,
  },
  heading1: {
    color: style.colors.color1,
    fontSize: style.fontSizes.heading1,
    fontFamily: style.fonts.juraBold,
  },
  heading2: {
    color: style.colors.color4,
    fontSize: style.fontSizes.heading2,
    fontFamily: style.fonts.juraBold,
    padding: 5,
  },
  headingSpeakerName: {
    color: style.colors.primary,
    fontWeight: "500",
    padding: 5,
  },
  textStyleHeder: {
    color: style.colors.color1,
  },
  textStyle: {
    color: style.colors.primary,
    padding: 5,
  },
  container: {
    backgroundColor: style.colors.backgroundSecondary,
  },
  keywordContainer: {
    borderWidth: 1,
    borderColor: style.colors.color3,
    borderRadius: 4,
    color: style.colors.primary,
    fontFamily: style.fonts.juraLight,
    padding: 3,
    margin: 5,
  }
});

export default class SessionDetail extends React.Component {

  render() {
    const { params } = this.props.navigation.state;
    let fromTime = moment(new Date(params.sessionData.startTime)).format('dddd, MMMM DD HH:mm');
    let toTime = moment (new Date(params.sessionData.endTime)).format('HH:mm');
    return (
      <ScrollView>
        <View style={ styles.sessionHeaderWrapper }>
          <View style={{ flex: 1, flexDirection: 'row' }}>
            <Icon name="arrow-left" style={{padding: 15}} size={40} color={style.colors.color4}
              onPress={() => this.props.navigation.navigate('SessionList')}/>
            <Icon name="star-o" style={{padding: 15}}size={40} color={style.colors.color4}/>
          </View>
          <Text style={ styles.heading1 }>{ (params.sessionData.title).toUpperCase() }</Text>
          <View style={{flex: 1, flexDirection: 'row'}}>
            <View>
              <Text style={ styles.textStyleHeder }>{ params.sessionData.room } { params.sessionData.format }</Text>
              <Text style={{color: style.colors.color1}}>{ fromTime } - { toTime }</Text>
            </View>
          </View>
        </View>
        <View style={ styles.container }>
          <Text style={ styles.textStyle }>{ params.sessionData.abstract }</Text>
          <Text style={ styles.heading2 }>INTENDED AUDIENCE:</Text>
          <Text style={ styles.textStyle }>{ params.sessionData.intendedAudience }</Text>
          <Text style={ styles.heading2 }>{params.sessionData.speakers.length === 1 ? "SPEAKER:" : "SPEAKERS:"}</Text>
          {
            params.sessionData.speakers.map( (speaker, index) => {
              return (
                <View key={index}>
                  <Text style={ styles.headingSpeakerName }>{ speaker.name }</Text>
                  <Text style={ styles.textStyle }>{ speaker.bio }</Text>
                </View>);
            })
          }
          <Text style={ styles.heading2 }>KEYWORDS:</Text>
            <View style={{flex: 1, flexDirection: 'row'}}>
              {
                params.sessionData.keywords.map( (keyword, index) => {
                  return <Text style={ styles.keywordContainer } key={index}>{keyword}</Text>
                })
              }
            </View>
        </View>
      </ScrollView>
    )
  }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Modal, Alert, Glyphicon, Button } from 'react-bootstrap'
import { withRouter } from 'react-router-dom'
import './PaymentModal.css'
import {coupons} from 'APP/src/coupons'

class PaymentModal extends Component {

  constructor (props) {
    super(props)
    this.state = {
      coupon: null,
      amount:0,
      title:'',
      body:'',
      footer:'',
      style:'',
      error:null,
    }
  }

  // componentWillMount(){
  //   console.log('WILLL', this.props.jobs)
  // }

  componentDidMount(){
    const {jobs} = this.props
    if(jobs.length === 0){
      this.setState({title:"Error",
        body:'You must submit at least one job before checking out',
      })
    } else {
      const amount = this.calculatePrice(jobs, null)
      this.setState({amount, modal_title:"Checkout",
        body:"You're total price will be $",
        style:'success'
      })
    }
  }

  onHide = () => {
    const {next, history, dismissAlert} = this.props
    dismissAlert()
    if (next) history.push(next)
  }

  handleClick = type => event => {
    const {history, dismissAlert} = this.props
    dismissAlert()
    history.push(`/${type}`)
  }

  handleChange = type => event => {
    const {value} = event.target
    this.setState({[type]: value})
  }

  validateCoupon = () => {
    const state = this.state
    const coupon = coupons[this.state.coupon]
    const {jobs} = this.props
    if(coupon){
      const amount = this.calculatePrice(jobs, coupon)
      this.setState({amount})
    } else{
      this.setState({error:'Invalid coupon code'})
    }
  }

  calculatePrice(jobs, coupon){
    let {amount} = this.state
    if (jobs.length >= 5) {
      amount = jobs.length * 225
    } else if (jobs.length >= 2 && jobs.length <= 4) {
      amount = jobs.length * 270
    } else if (jobs.length === 1) {
      amount = 300
    }
    if(coupon){
      if(coupon.title === 'wemustlikeyou'){
        amount = 0
      } else if(coupon.type === "amount"){
        amount = (amount - coupon.amount) > 0 ? amount - coupon.amount : 0;
      } else {
        amount = (amount * coupon.percent) > 0 ? amount * coupon.percent : 0;
      }
    }
    return amount
  }

  render () {
    const {show, style, jobs} = this.props
    const {amount, title, body, footer} = this.state
    const glyph = style === 'success' ? 'check' : 'exclamation-sign'
    return (
      <Modal
        className={`PaymentModal`}
        show={show}
        onHide={this.onHide}
      >
        <Modal.Header closeButton className={`modal-${style}`}>
          <Modal.Title className='PaymentModal__title'>
            <Glyphicon glyph={glyph} /> {title}
          </Modal.Title>
        </Modal.Header>
        <Alert className='PaymentModal__alert' bsStyle={style}>

{body + amount}

          {jobs && jobs.map((job, i) => {
            return (

                {job.title}

            )
          })}
          <input onChange={this.handleChange("coupon")} type='text' placeholder="Coupon Code" name="coupon"/>
          <Button
            bsSize='large'
            onClick={this.validateCoupon}
            className={`btn-modal btn-modal-${style}`}
          >
            Apply
          </Button>
        </Alert>
        { // if users try to access private routes, an alert is dispatched
          // with 'footer: true' so user can
          footer &&
          <Modal.Footer className={`modal-${style}`}>
            <Button
              bsSize='large'
              onClick={this.props.handleSubmit}
              className={`btn-modal btn-modal-${style}`}
            >
              Submit
            </Button>
          </Modal.Footer>
        }
      </Modal>
    )
  }
}

const mapDispatchToProps = dispatch => ({
  // dismissAlert: () => dispatch(dismissAlert())
})

PaymentModal.propTypes = {
  title: PropTypes.string,
  body: PropTypes.string,
  footer: PropTypes.bool,
  next: PropTypes.string,
  style: PropTypes.string, // success, warning, danger etc (Bootstrap)
  show: PropTypes.bool,
  history: PropTypes.object,
  dismissAlert: PropTypes.func
}

export default withRouter(connect(null, mapDispatchToProps)(PaymentModal))
<commit_msg>fixed payment madal<commit_after>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Modal, Alert, Glyphicon, Button } from 'react-bootstrap'
import { withRouter } from 'react-router-dom'
import './PaymentModal.css'
import {coupons} from 'APP/src/coupons'

class PaymentModal extends Component {

  constructor (props) {
    super(props)
    this.state = {
      coupon: null,
      amount:0,
      title:'',
      body:'',
      footer:'',
      style:'',
      error:null,
    }
  }

  // componentWillMount(){
  //   console.log('WILLL', this.props.jobs)
  // }

  componentDidMount(){
    const {jobs} = this.props
    if(jobs.length === 0){
      this.setState({title:"Error",
        body:'You must submit at least one job before checking out',
      })
    } else {
      const amount = this.calculatePrice(jobs, null)
      this.setState({amount, modal_title:"Checkout",
        body:"You're total price will be $",
        style:'success'
      })
    }
  }

  onHide = () => {
    const {next, history, dismissAlert} = this.props
    dismissAlert()
    if (next) history.push(next)
  }

  handleClick = type => event => {
    const {history, dismissAlert} = this.props
    dismissAlert()
    history.push(`/${type}`)
  }

  handleChange = type => event => {
    const {value} = event.target
    this.setState({[type]: value})
  }

  validateCoupon = () => {
    const state = this.state
    const coupon = coupons[this.state.coupon]
    const {jobs} = this.props
    if(coupon){
      const amount = this.calculatePrice(jobs, coupon)
      this.setState({amount})
    } else{
      this.setState({error:'Invalid coupon code'})
    }
  }

  calculatePrice(jobs, coupon){
    let {amount} = this.state
    if (jobs.length >= 5) {
      amount = jobs.length * 225
    } else if (jobs.length >= 2 && jobs.length <= 4) {
      amount = jobs.length * 270
    } else if (jobs.length === 1) {
      amount = 300
    }
    if(coupon){
      if(coupon.title === 'wemustlikeyou'){
        amount = 0
      } else if(coupon.type === "amount"){
        amount = (amount - coupon.amount) > 0 ? amount - coupon.amount : 0;
      } else {
        amount = (amount * coupon.percent) > 0 ? amount * coupon.percent : 0;
      }
    }
    return amount
  }

  render () {
    const {show, style, jobs, title, body, footer} = this.props
    const {amount} = this.state
    const glyph = style === 'success' ? 'check' : 'exclamation-sign'
    return (
      <Modal
        className={`PaymentModal`}
        show={show}
        onHide={this.onHide}
      >
        <Modal.Header closeButton className={`modal-${style}`}>
          <Modal.Title className='PaymentModal__title'>
            <Glyphicon glyph={glyph} /> {title}
          </Modal.Title>
        </Modal.Header>
        <Alert className='PaymentModal__alert' bsStyle={style}>

{body + amount}

          {jobs && jobs.map((job, i) => {
            return (

                {job.title}

            )
          })}
          <input onChange={this.handleChange("coupon")} type='text' placeholder="Coupon Code" name="coupon"/>
          <Button
            bsSize='large'
            onClick={this.validateCoupon}
            className={`btn-modal btn-modal-${style}`}
          >
            Apply
          </Button>
        </Alert>
        { // if users try to access private routes, an alert is dispatched
          // with 'footer: true' so user can
          footer &&
          <Modal.Footer className={`modal-${style}`}>
            <Button
              bsSize='large'
              onClick={this.props.handleSubmit}
              className={`btn-modal btn-modal-${style}`}
            >
              Submit
            </Button>
          </Modal.Footer>
        }
      </Modal>
    )
  }
}

const mapDispatchToProps = dispatch => ({
  // dismissAlert: () => dispatch(dismissAlert())
})

PaymentModal.propTypes = {
  title: PropTypes.string,
  body: PropTypes.string,
  footer: PropTypes.bool,
  next: PropTypes.string,
  style: PropTypes.string, // success, warning, danger etc (Bootstrap)
  show: PropTypes.bool,
  history: PropTypes.object,
  dismissAlert: PropTypes.func
}

export default withRouter(connect(null, mapDispatchToProps)(PaymentModal))
<|endoftext|>


<commit_before>/*
Copyright 2017 New Vector Ltd.
Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2019 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import classNames from 'classnames';
import * as sdk from '../../../index';
import dis from '../../../dispatcher';
import { isOnlyCtrlOrCmdIgnoreShiftKeyEvent } from '../../../Keyboard';
import * as FormattingUtils from '../../../utils/FormattingUtils';

import FlairStore from '../../../stores/FlairStore';
import GroupStore from '../../../stores/GroupStore';
import TagOrderStore from '../../../stores/TagOrderStore';
import MatrixClientContext from "../../../contexts/MatrixClientContext";

// A class for a child of TagPanel (possibly wrapped in a DNDTagTile) that represents
// a thing to click on for the user to filter the visible rooms in the RoomList to:
//  - Rooms that are part of the group
//  - Direct messages with members of the group
// with the intention that this could be expanded to arbitrary tags in future.
export default createReactClass({
    displayName: 'TagTile',

    propTypes: {
        // A string tag such as "m.favourite" or a group ID such as "+groupid:domain.bla"
        // For now, only group IDs are handled.
        tag: PropTypes.string,
        contextMenuButtonRef: PropTypes.object,
        openMenu: PropTypes.func,
        menuDisplayed: PropTypes.bool,
    },

    statics: {
        contextType: MatrixClientContext,
    },

    getInitialState() {
        return {
            // Whether the mouse is over the tile
            hover: false,
            // The profile data of the group if this.props.tag is a group ID
            profile: null,
        };
    },

    componentDidMount() {
        this.unmounted = false;
        if (this.props.tag[0] === '+') {
            FlairStore.addListener('updateGroupProfile', this._onFlairStoreUpdated);
            this._onFlairStoreUpdated();
            // New rooms or members may have been added to the group, fetch async
            this._refreshGroup(this.props.tag);
        }
    },

    componentWillUnmount() {
        this.unmounted = true;
        if (this.props.tag[0] === '+') {
            FlairStore.removeListener('updateGroupProfile', this._onFlairStoreUpdated);
        }
    },

    _onFlairStoreUpdated() {
        if (this.unmounted) return;
        FlairStore.getGroupProfileCached(
            this.context,
            this.props.tag,
        ).then((profile) => {
            if (this.unmounted) return;
            this.setState({profile});
        }).catch((err) => {
            console.warn('Could not fetch group profile for ' + this.props.tag, err);
        });
    },

    _refreshGroup(groupId) {
        GroupStore.refreshGroupRooms(groupId);
        GroupStore.refreshGroupMembers(groupId);
    },

    onClick: function(e) {
        e.preventDefault();
        e.stopPropagation();
        dis.dispatch({
            action: 'select_tag',
            tag: this.props.tag,
            ctrlOrCmdKey: isOnlyCtrlOrCmdIgnoreShiftKeyEvent(e),
            shiftKey: e.shiftKey,
        });
        if (this.props.tag[0] === '+') {
            // New rooms or members may have been added to the group, fetch async
            this._refreshGroup(this.props.tag);
        }
    },

    onMouseOver: function() {
        this.setState({hover: true});
    },

    onMouseOut: function() {
        this.setState({hover: false});
    },

    openMenu: function(e) {
        // Prevent the TagTile onClick event firing as well
        e.stopPropagation();
        e.preventDefault();
        this.setState({hover: false});
        this.props.openMenu();
    },

    render: function() {
        const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
        const profile = this.state.profile || {};
        const name = profile.name || this.props.tag;
        const avatarHeight = 40;

        const httpUrl = profile.avatarUrl ? this.context.mxcUrlToHttp(
            profile.avatarUrl, avatarHeight, avatarHeight, "crop",
        ) : null;

        const className = classNames({
            mx_TagTile: true,
            mx_TagTile_selected: this.props.selected,
        });

        const badge = TagOrderStore.getGroupBadge(this.props.tag);
        let badgeElement;
        if (badge && !this.state.hover) {
            const badgeClasses = classNames({
                "mx_TagTile_badge": true,
                "mx_TagTile_badgeHighlight": badge.highlight,
            });
            badgeElement = (
{FormattingUtils.formatCount(badge.count)}
);
        }

        // FIXME: this ought to use AccessibleButton for a11y but that causes onMouseOut/onMouseOver to fire too much
        const contextButton = this.state.hover || this.props.menuDisplayed ?

                { "\u00B7\u00B7\u00B7" }

 :
;

        const AccessibleTooltipButton = sdk.getComponent("elements.AccessibleTooltipButton");

        return <AccessibleTooltipButton
                className={className}
                onClick={this.onClick}
                onContextMenu={this.openMenu}
                title={name}
            >

                    <BaseAvatar
                        name={name}
                        idName={this.props.tag}
                        url={httpUrl}
                        width={avatarHeight}
                        height={avatarHeight}
                    />
                    { contextButton }
                    { badgeElement }

            </AccessibleTooltipButton>;
    },
});
<commit_msg>hide badge when context menu is open<commit_after>/*
Copyright 2017 New Vector Ltd.
Copyright 2018 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2019 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import classNames from 'classnames';
import * as sdk from '../../../index';
import dis from '../../../dispatcher';
import { isOnlyCtrlOrCmdIgnoreShiftKeyEvent } from '../../../Keyboard';
import * as FormattingUtils from '../../../utils/FormattingUtils';

import FlairStore from '../../../stores/FlairStore';
import GroupStore from '../../../stores/GroupStore';
import TagOrderStore from '../../../stores/TagOrderStore';
import MatrixClientContext from "../../../contexts/MatrixClientContext";

// A class for a child of TagPanel (possibly wrapped in a DNDTagTile) that represents
// a thing to click on for the user to filter the visible rooms in the RoomList to:
//  - Rooms that are part of the group
//  - Direct messages with members of the group
// with the intention that this could be expanded to arbitrary tags in future.
export default createReactClass({
    displayName: 'TagTile',

    propTypes: {
        // A string tag such as "m.favourite" or a group ID such as "+groupid:domain.bla"
        // For now, only group IDs are handled.
        tag: PropTypes.string,
        contextMenuButtonRef: PropTypes.object,
        openMenu: PropTypes.func,
        menuDisplayed: PropTypes.bool,
    },

    statics: {
        contextType: MatrixClientContext,
    },

    getInitialState() {
        return {
            // Whether the mouse is over the tile
            hover: false,
            // The profile data of the group if this.props.tag is a group ID
            profile: null,
        };
    },

    componentDidMount() {
        this.unmounted = false;
        if (this.props.tag[0] === '+') {
            FlairStore.addListener('updateGroupProfile', this._onFlairStoreUpdated);
            this._onFlairStoreUpdated();
            // New rooms or members may have been added to the group, fetch async
            this._refreshGroup(this.props.tag);
        }
    },

    componentWillUnmount() {
        this.unmounted = true;
        if (this.props.tag[0] === '+') {
            FlairStore.removeListener('updateGroupProfile', this._onFlairStoreUpdated);
        }
    },

    _onFlairStoreUpdated() {
        if (this.unmounted) return;
        FlairStore.getGroupProfileCached(
            this.context,
            this.props.tag,
        ).then((profile) => {
            if (this.unmounted) return;
            this.setState({profile});
        }).catch((err) => {
            console.warn('Could not fetch group profile for ' + this.props.tag, err);
        });
    },

    _refreshGroup(groupId) {
        GroupStore.refreshGroupRooms(groupId);
        GroupStore.refreshGroupMembers(groupId);
    },

    onClick: function(e) {
        e.preventDefault();
        e.stopPropagation();
        dis.dispatch({
            action: 'select_tag',
            tag: this.props.tag,
            ctrlOrCmdKey: isOnlyCtrlOrCmdIgnoreShiftKeyEvent(e),
            shiftKey: e.shiftKey,
        });
        if (this.props.tag[0] === '+') {
            // New rooms or members may have been added to the group, fetch async
            this._refreshGroup(this.props.tag);
        }
    },

    onMouseOver: function() {
        this.setState({hover: true});
    },

    onMouseOut: function() {
        this.setState({hover: false});
    },

    openMenu: function(e) {
        // Prevent the TagTile onClick event firing as well
        e.stopPropagation();
        e.preventDefault();
        this.setState({hover: false});
        this.props.openMenu();
    },

    render: function() {
        const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
        const profile = this.state.profile || {};
        const name = profile.name || this.props.tag;
        const avatarHeight = 40;

        const httpUrl = profile.avatarUrl ? this.context.mxcUrlToHttp(
            profile.avatarUrl, avatarHeight, avatarHeight, "crop",
        ) : null;

        const className = classNames({
            mx_TagTile: true,
            mx_TagTile_selected: this.props.selected,
        });

        const badge = TagOrderStore.getGroupBadge(this.props.tag);
        let badgeElement;
        if (badge && !this.state.hover && !this.props.menuDisplayed) {
            const badgeClasses = classNames({
                "mx_TagTile_badge": true,
                "mx_TagTile_badgeHighlight": badge.highlight,
            });
            badgeElement = (
{FormattingUtils.formatCount(badge.count)}
);
        }

        // FIXME: this ought to use AccessibleButton for a11y but that causes onMouseOut/onMouseOver to fire too much
        const contextButton = this.state.hover || this.props.menuDisplayed ?

                { "\u00B7\u00B7\u00B7" }

 :
;

        const AccessibleTooltipButton = sdk.getComponent("elements.AccessibleTooltipButton");

        return <AccessibleTooltipButton
                className={className}
                onClick={this.onClick}
                onContextMenu={this.openMenu}
                title={name}
            >

                    <BaseAvatar
                        name={name}
                        idName={this.props.tag}
                        url={httpUrl}
                        width={avatarHeight}
                        height={avatarHeight}
                    />
                    { contextButton }
                    { badgeElement }

            </AccessibleTooltipButton>;
    },
});
<|endoftext|>


<commit_before>describe('concentratesPurchased  module', function() {

  // instantiate service
  var $log;
  var concentratesPurchased, pelletsCalf, pelletsCalfName = 'Pellets Calf',
    pelletsDairy,pelletsDairyName = 'Pellets Dairy',
    averageConcentrate, averageConcentrateName = 'Average concentrate',
    fruit,fruitName='Fruit'
  ;

  beforeEach(module('farmbuild.nutrientCalculator', function($provide) {
    $provide.value('$log', console);
  }));

  beforeEach(inject(function (_$log_, _concentratesPurchased_) {
    $log = _$log_;
    concentratesPurchased  = _concentratesPurchased_;
    pelletsCalf =  concentratesPurchased.types.byName(pelletsCalfName);
    expect(pelletsCalf.name).toEqual(pelletsCalfName);
    pelletsDairy =  concentratesPurchased.types.byName(pelletsDairyName);
    expect(pelletsDairy.name).toEqual(pelletsDairyName);
    averageConcentrate =  concentratesPurchased.types.byName(averageConcentrateName);
    fruit =  concentratesPurchased.types.byName(fruitName);
    expect(fruit.name).toEqual(fruitName);
  }));

  describe('Given concentratesPurchased  factory', function(){
    it('concentratesPurchased  should be defined', inject(function() {
      expect(concentratesPurchased).toBeDefined();
    }));
  });

  function createdConcentrate(type, weight, isDry) {
    return {type: type, weight:weight, isDry:isDry};
  }

  function addConcentrate(type, weight, isDry) {
    return [createdConcentrate(type, weight, isDry)];
  }

  function between(val, min, max) {
    return val >= min && val <= max;
  }

  describe('Given the default value, calculate the nutrient of concentrate purchased', function(){
    it(pelletsCalfName + ' type with undefined amount should fail', inject(function() {
      var result = concentratesPurchased.calculate(addConcentrate(pelletsCalf, true))
      expect(result).toBeUndefined()
    }));

    it(pelletsCalfName + ' type and the weight of 4000kg should calculate', inject(function() {
      var weight = 1850,
        concentrate = addConcentrate(pelletsCalf, weight, true);
      $log.info('concentrate: %j', concentrate);
      var result = concentratesPurchased.calculate(concentrate)

      $log.info('result generated: %j', result);

      expect(result.weight).toEqual(1850)
      expect(result.dryMatterWeight).toEqual(1850)
      expect(result.nitrogenPercentage).toEqual(3.1400000000000006)
      expect(result.nitrogenInKg).toEqual(58.09)
      expect(result.phosphorusInKg).toEqual(12.395)
      expect(between(result.phosphorusPercentage, 0.669, 0.67)).toBeTruthy()
      expect(result.potassiumInKg).toEqual(15.54)
      expect(result.potassiumPercentage).toEqual(0.84)
      expect(result.sulphurInKg).toEqual(5.18)
      expect(result.sulphurPercentage).toEqual(0.27999999999999997)
      expect(result.metabolisableEnergyInMJ).toEqual(23532)
      expect(result.metabolisableEnergyInMJPerKg).toEqual(12.72)
    }));

  });

  describe('Given the default value, calculate the nutrient of concentrate purchased', function(){

    it('DAP, Super and Urea type and the weight of 4000kg, 13000kg, 11000kg', inject(function() {
      var weightPelletsCalf1=1850,weightPelletsDairy1 =8150,
        weightPelletsDairy2 = 2050,weightAverageConcentrate1=7815,weightPelletsCalf2=1012,
        weightPelletsDairy3=9658,weightPelletsDairy4=8571,weightFruit=328;
        concentrates = concentratesPurchased
          .add(pelletsCalf, weightPelletsCalf1, true)
          .add(pelletsDairy, weightPelletsDairy1, true)
          .add(pelletsDairy, weightPelletsDairy2, true)
          .add(averageConcentrate, weightAverageConcentrate1, true)
          .add(pelletsCalf, weightPelletsCalf2, true)
          .add(pelletsDairy, weightPelletsDairy3, true)
          .add(pelletsDairy, weightPelletsDairy4, true)
          .add(fruit, weightFruit, true)
          .concentrates()
      expect(angular.isArray(concentrates)).toBeTruthy()

      var result = concentratesPurchased.calculate(concentrates)

      $log.info('result generated: %j', result);

      expect(result.weight).toEqual(39434)
      expect(result.dryMatterWeight).toEqual(39434)
      expect(result.nitrogenInKg).toEqual(1075.8433)
      expect(result.nitrogenPercentage).toEqual(2.728212456256023)
      expect(result.phosphorusInKg).toEqual(275.5202)
      expect(result.phosphorusPercentage).toBe(0.6986869199168231)
      expect(result.potassiumInKg).toEqual(292.8796)
      expect(result.potassiumPercentage).toEqual(0.7427083227671551)
      expect(result.sulphurInKg).toEqual(101.94000000000001)
      expect(result.sulphurPercentage).toEqual(0.25850788659532387)
      expect(result.metabolisableEnergyInMJ).toEqual(495334.39999999997)
      expect(result.metabolisableEnergyInMJPerKg).toEqual(11.6)
    }));

  });

});

<commit_msg>test fix<commit_after>describe('concentratesPurchased  module', function() {

  // instantiate service
  var $log;
  var concentratesPurchased, pelletsCalf, pelletsCalfName = 'Pellets Calf',
    pelletsDairy,pelletsDairyName = 'Pellets Dairy',
    averageConcentrate, averageConcentrateName = 'Average concentrate',
    fruit,fruitName='Fruit'
  ;

  beforeEach(module('farmbuild.nutrientCalculator', function($provide) {
    $provide.value('$log', console);
  }));

  beforeEach(inject(function (_$log_, _concentratesPurchased_) {
    $log = _$log_;
    concentratesPurchased  = _concentratesPurchased_;
    pelletsCalf =  concentratesPurchased.types.byName(pelletsCalfName);
    expect(pelletsCalf.name).toEqual(pelletsCalfName);
    pelletsDairy =  concentratesPurchased.types.byName(pelletsDairyName);
    expect(pelletsDairy.name).toEqual(pelletsDairyName);
    averageConcentrate =  concentratesPurchased.types.byName(averageConcentrateName);
    fruit =  concentratesPurchased.types.byName(fruitName);
    expect(fruit.name).toEqual(fruitName);
  }));

  describe('Given concentratesPurchased  factory', function(){
    it('concentratesPurchased  should be defined', inject(function() {
      expect(concentratesPurchased).toBeDefined();
    }));
  });

  function createdConcentrate(type, weight, isDry) {
    return {type: type, weight:weight, isDry:isDry};
  }

  function addConcentrate(type, weight, isDry) {
    return [createdConcentrate(type, weight, isDry)];
  }

  function between(val, min, max) {
    return val >= min && val <= max;
  }

  describe('Given the default value, calculate the nutrient of concentrate purchased', function(){
    it(pelletsCalfName + ' type with undefined amount should fail', inject(function() {
      var result = concentratesPurchased.calculate(addConcentrate(pelletsCalf, true))
      expect(result).toBeUndefined()
    }));

    it(pelletsCalfName + ' type and the weight of 4000kg should calculate', inject(function() {
      var weight = 1850,
        concentrate = addConcentrate(pelletsCalf, weight, true);
      $log.info('concentrate: %j', concentrate);
      var result = concentratesPurchased.calculate(concentrate)

      $log.info('result generated: %j', result);

      expect(result.weight).toEqual(1850)
      expect(result.dryMatterWeight).toEqual(1850)
      expect(result.nitrogenPercentage).toEqual(3.1400000000000006)
      expect(result.nitrogenInKg).toEqual(58.09)
      expect(result.phosphorusInKg).toEqual(12.395)
      expect(between(result.phosphorusPercentage, 0.669, 0.67)).toBeTruthy()
      expect(result.potassiumInKg).toEqual(15.54)
      expect(result.potassiumPercentage).toEqual(0.84)
      expect(result.sulphurInKg).toEqual(5.18)
      expect(result.sulphurPercentage).toEqual(0.27999999999999997)
      expect(result.metabolisableEnergyInMJ).toEqual(23532)
      expect(result.metabolisableEnergyInMJPerKg).toEqual(12.72)
    }));

  });

  describe('Given the default value, calculate the nutrient of concentrate purchased', function(){

    it('DAP, Super and Urea type and the weight of 4000kg, 13000kg, 11000kg', inject(function() {
      var weightPelletsCalf1=18500,weightPelletsDairy1 =81500,
        weightPelletsDairy2 = 20500,weightAverageConcentrate1=78150,weightPelletsCalf2=10120,
        weightPelletsDairy3=96580,weightPelletsDairy4=85710,weightFruit=3280;
        concentrates = concentratesPurchased
          .add(pelletsCalf, weightPelletsCalf1, true)
          .add(pelletsDairy, weightPelletsDairy1, true)
          .add(pelletsDairy, weightPelletsDairy2, true)
          .add(averageConcentrate, weightAverageConcentrate1, true)
          .add(pelletsCalf, weightPelletsCalf2, true)
          .add(pelletsDairy, weightPelletsDairy3, true)
          .add(pelletsDairy, weightPelletsDairy4, true)
          .add(fruit, weightFruit, true)
          .concentrates()
      expect(angular.isArray(concentrates)).toBeTruthy()

      var result = concentratesPurchased.calculate(concentrates)

      $log.info('result generated: %j', result);

      expect(result.weight).toEqual(394340)
      expect(result.dryMatterWeight).toEqual(394340)
      expect(result.nitrogenInKg).toEqual(10758.433)
      expect(result.nitrogenPercentage).toEqual(2.728212456256023)
      expect(result.phosphorusInKg).toEqual(2755.202)
      expect(result.phosphorusPercentage).toBe(0.6986869199168231)
      expect(result.potassiumInKg).toEqual(2928.7960000000003)
      expect(result.potassiumPercentage).toEqual(0.7427083227671553)
      expect(result.sulphurInKg).toEqual(1019.4000000000001)
      expect(result.sulphurPercentage).toEqual(0.25850788659532387)
      expect(result.metabolisableEnergyInMJ).toEqual(4953343.9999999997)
      expect(result.metabolisableEnergyInMJPerKg).toEqual(11.6)
    }));

  });

});

<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ConnectedStudyBrowser from './ConnectedStudyBrowser.js';
import ConnectedViewerMain from './ConnectedViewerMain.js';
import ConnectedMeasurementTable from './ConnectedMeasurementTable';
import './FlexboxLayout.css';

class FlexboxLayout extends Component {
  static propTypes = {
    studies: PropTypes.array.isRequired,
    leftSidebarOpen: PropTypes.bool.isRequired,
    rightSidebarOpen: PropTypes.bool.isRequired,
  };

  state = {
    studiesForBrowser: [],
  };

  componentDidMount() {
    const studiesForBrowser = this.getStudiesForBrowser();

    this.setState({
      studiesForBrowser,
    });
  }

  getStudiesForBrowser = () => {
    const { studies } = this.props;

    // TODO[react]:
    // - Add sorting of display sets
    // - Add useMiddleSeriesInstanceAsThumbnail
    // - Add showStackLoadingProgressBar option
    return studies.map(study => {
      const { studyInstanceUid } = study;

      const thumbnails = study.displaySets.map(displaySet => {
        const {
          displaySetInstanceUid,
          seriesDescription,
          seriesNumber,
          instanceNumber,
          numImageFrames,
        } = displaySet;

        let imageId;

        if (displaySet.images && displaySet.images.length) {
          imageId = displaySet.images[0].getImageId();
        }

        return {
          imageId,
          displaySetInstanceUid,
          seriesDescription,
          seriesNumber,
          instanceNumber,
          numImageFrames,
        };
      });

      return {
        studyInstanceUid,
        thumbnails,
      };
    });
  };

  render() {
    let mainContentClassName = 'main-content';
    if (this.props.leftSidebarOpen) {
      mainContentClassName += ' sidebar-left-open';
    }

    if (this.props.rightSidebarOpen) {
      mainContentClassName += ' sidebar-right-open';
    }

    // TODO[react]: Make ConnectedMeasurementTable extension with state.timepointManager
    return (

          <ConnectedStudyBrowser studies={this.state.studiesForBrowser} />

          <ConnectedViewerMain studies={this.props.studies} />

          <ConnectedMeasurementTable />

    );
  }
}

export default FlexboxLayout;
<commit_msg>@swederik's prop to show prettier SR thumbnails<commit_after>import './FlexboxLayout.css';

import React, { Component } from 'react';

import ConnectedMeasurementTable from './ConnectedMeasurementTable';
import ConnectedStudyBrowser from './ConnectedStudyBrowser.js';
import ConnectedViewerMain from './ConnectedViewerMain.js';
import PropTypes from 'prop-types';

class FlexboxLayout extends Component {
  static propTypes = {
    studies: PropTypes.array.isRequired,
    leftSidebarOpen: PropTypes.bool.isRequired,
    rightSidebarOpen: PropTypes.bool.isRequired,
  };

  state = {
    studiesForBrowser: [],
  };

  componentDidMount() {
    const studiesForBrowser = this.getStudiesForBrowser();

    this.setState({
      studiesForBrowser,
    });
  }

  getStudiesForBrowser = () => {
    const { studies } = this.props;

    // TODO[react]:
    // - Add sorting of display sets
    // - Add useMiddleSeriesInstanceAsThumbnail
    // - Add showStackLoadingProgressBar option
    return studies.map(study => {
      const { studyInstanceUid } = study;

      const thumbnails = study.displaySets.map(displaySet => {
        const {
          displaySetInstanceUid,
          seriesDescription,
          seriesNumber,
          instanceNumber,
          numImageFrames,
          modality,
        } = displaySet;

        let imageId;

        if (displaySet.images && displaySet.images.length) {
          imageId = displaySet.images[0].getImageId();
        }

        return {
          imageId,
          altImageText: modality,
          displaySetInstanceUid,
          seriesDescription,
          seriesNumber,
          instanceNumber,
          numImageFrames,
        };
      });

      return {
        studyInstanceUid,
        thumbnails,
      };
    });
  };

  render() {
    let mainContentClassName = 'main-content';
    if (this.props.leftSidebarOpen) {
      mainContentClassName += ' sidebar-left-open';
    }

    if (this.props.rightSidebarOpen) {
      mainContentClassName += ' sidebar-right-open';
    }

    // TODO[react]: Make ConnectedMeasurementTable extension with state.timepointManager
    return (

          <ConnectedStudyBrowser studies={this.state.studiesForBrowser} />

          <ConnectedViewerMain studies={this.props.studies} />

          <ConnectedMeasurementTable />

    );
  }
}

export default FlexboxLayout;
<|endoftext|>


<commit_before>'use strict';

define((require) => {
	const Inject = require('browser/inject');
	const BrowserAction = require('browser/browser-action');

	const Options = require('storage/options');

	const Controller = require('object/controller');
	const { isActiveMode, isInactiveMode } = require('object/controller-mode');

	const { INJECTED, MATCHED, NO_MATCH } = require('object/inject-result');
	const { getCurrentTab } = require('util/util-browser');
	const { getConnectorByUrl } = require('util/util-connector');
	const {
		contextMenus, i18n, runtime, tabs,
	} = require('webextension-polyfill');

	class TabWorker {
		constructor() {
			this.initialize();
		}

		/** Listeners. */

		/**
		 * Called if a new event is dispatched.
		 *
		 * @param {Object} ctrl Controller instance
		 * @param {Object} event Event generated by the controller.
		 */
		onControllerEvent(ctrl, event) { // eslint-disable-line no-unused-vars
			throw new Error('This function must be overridden!');
		}

		/** Public methods. */

		/**
		 * Called when a command is executed.
		 *
		 * @param  {String} command Command ID
		 */
		async processCommand(command) {
			const ctrl = this.tabControllers[this.activeTabId] ||
				this.tabControllers[this.currentTabId];
			if (!ctrl) {
				return;
			}

			switch (command) {
				case 'toggle-connector':
					this.setControllerState(ctrl, !ctrl.isEnabled);
					break;

				case 'love-song':
				case 'unlove-song': {
					const isLoved = command === 'love-song';

					await ctrl.toggleLove(isLoved);
					this.browserAction.setSongLoved(isLoved, ctrl.getCurrentSong());
					break;
				}
			}
		}

		/**
		 * Called when something sent message to the background script
		 * via `browser.runtime.sendMessage` function.
		 *
		 * @param  {Number} tabId ID of a tab to which the message is addressed
		 * @param  {String} type Message type
		 * @param  {Object} data Object contains data sent in the message
		 */
		async processMessage(tabId, type, data) {
			switch (type) {
				case 'REQUEST_ACTIVE_TABID':
					return this.activeTabId;
			}

			const ctrl = this.tabControllers[tabId];

			if (!ctrl) {
				console.warn(
					`Attempted to send ${type} event to controller for tab ${tabId}`);
				return;
			}

			switch (type) {
				case 'REQUEST_GET_SONG':
					return ctrl.getCurrentSong().getCloneableData();

				case 'REQUEST_CORRECT_SONG':
					ctrl.setUserSongData(data);
					break;

				case 'REQUEST_TOGGLE_LOVE':
					await ctrl.toggleLove(data.isLoved);
					return data.isLoved;

				case 'REQUEST_SKIP_SONG':
					ctrl.skipCurrentSong();
					break;

				case 'REQUEST_RESET_SONG':
					ctrl.resetSongData();
					break;
			}
		}

		/**
		 * Called when something sent message to the background script via port.
		 *
		 * @param  {Number} tabId ID of a tab to which the message is addressed
		 * @param  {String} type Message type
		 * @param  {Object} data Object contains data sent in the message
		 */
		processPortMessage(tabId, type, data) {
			switch (type) {
				case 'EVENT_STATE_CHANGED': {
					const ctrl = this.tabControllers[tabId];
					if (ctrl) {
						ctrl.onStateChanged(data);
					}
					break;
				}
			}
		}

		/**
		 * Called when a tab is updated.
		 *
		 * @param  {Number} tabId Tab ID
		 * @param  {String} url Object contains changes of updated tab
		 */
		async processTabUpdate(tabId, url) {
			const connector = await getConnectorByUrl(url);
			this.tryToInjectConnector(tabId, connector);
		}

		/**
		 * Called when a current tab is changed.
		 *
		 * @param  {Number} tabId Tab ID
		 */
		processTabChange(tabId) {
			this.currentTabId = tabId;

			if (this.shouldUpdateBrowserAction(tabId)) {
				this.updateBrowserAction(tabId);
				this.activeTabId = tabId;
			}

			this.updateContextMenu(tabId);
		}

		/**
		 * Called when a tab is removed.
		 *
		 * @param  {Number} removedTabId Tab ID
		 */
		async processTabRemove(removedTabId) {
			this.unloadController(removedTabId);

			if (removedTabId === this.activeTabId) {
				this.activeTabId = tabs.TAB_ID_NONE;
				this.updateLastActiveTab();
			}
		}

		/** Private methods. */

		async initialize() {
			const currentTab = await getCurrentTab();
			// We cannot get a current tab in some cases on startup
			if (currentTab) {
				this.currentTabId = currentTab.id;
			} else {
				this.currentTabId = tabs.TAB_ID_NONE;
			}
			this.activeTabId = tabs.TAB_ID_NONE;
			this.tabControllers = [];

			this.browserAction = new BrowserAction();
			/*
			 * Prevent restoring the browser action icon
			 * from the previous session.
			 */
			this.browserAction.reset();
		}

		/**
		 * Update the browser action in context of a given tab ID.
		 *
		 * @param  {Number} tabId Tab ID
		 */
		updateBrowserAction(tabId) {
			const ctrl = this.tabControllers[tabId];
			if (ctrl) {
				this.browserAction.update(ctrl);
			} else {
				this.browserAction.reset();
			}
		}

		/**
		 * Check if the browser action should be updated
		 * in context of a given tab ID.
		 *
		 * @param  {Number} tabId Tab ID
		 *
		 * @return {Boolean} Check result
		 */
		shouldUpdateBrowserAction(tabId) {
			const activeCtrl = this.tabControllers[this.activeTabId];
			if (activeCtrl && isActiveMode(activeCtrl.mode)) {
				return false;
			}

			const ctrl = this.tabControllers[tabId];
			if (ctrl) {
				if (tabId !== this.currentTabId && isInactiveMode(ctrl.mode)) {
					return false;
				}
			}

			return true;
		}

		/**
		 * Get ID of a tab with recent active controller.
		 *
		 * @return {Number} Tab ID
		 */
		findActiveTabId() {
			const ctrl = this.tabControllers[this.currentTabId];
			if (ctrl && isActiveMode(ctrl.mode)) {
				return this.currentTabId;
			}

			for (const tabId in this.tabControllers) {
				const ctrl = this.tabControllers[tabId];
				const mode = ctrl.getMode();
				if (isActiveMode(mode)) {
					// NOTE: Don't use `tabId` directly, it's a string.
					return ctrl.tabId;
				}
			}

			if (ctrl) {
				return this.currentTabId;
			}

			return tabs.TAB_ID_NONE;
		}

		/**
		 * Update the browser action and the context menu in context of a last
		 * active tab. If no active tab is found, reset the browser action icon
		 * and the context menu.
		 */
		updateLastActiveTab() {
			const lastActiveTabId = this.findActiveTabId();
			if (lastActiveTabId !== tabs.TAB_ID_NONE) {
				this.activeTabId = lastActiveTabId;

				this.updateBrowserAction(this.activeTabId);
				this.updateContextMenu(this.activeTabId);
			} else {
				this.browserAction.reset();
				this.resetContextMenu();
			}
		}

		/**
 		 * Setup context menu of the browser action for a tab with given tab ID.
		 *
		 * @param  {Number} tabId Tab ID
		 */
		updateContextMenu(tabId) {
			this.resetContextMenu();

			const ctrl = this.tabControllers[tabId];

			// Always display context menu for current tab
			if (ctrl) {
				this.addToggleConnectorMenu(tabId, ctrl);
				if (ctrl.isEnabled) {
					this.addDisableUntilTabClosedItem(tabId, ctrl);
				}
			}

			// Add additional menu items for active tab (if it's not current)...
			if (this.activeTabId !== tabId) {
				const activeCtrl = this.tabControllers[this.activeTabId];

				if (activeCtrl) {
					if (ctrl && activeCtrl.getConnector().id === ctrl.getConnector().id) {
						return;
					}

					// ...but only if it has a different connector injected.
					this.addToggleConnectorMenu(tabId, activeCtrl);
				}
			}
		}

		/**
		 * Remove all items from the context menu.
		 */
		resetContextMenu() {
			contextMenus.removeAll();
		}

		/**
		 * Add a "Enable/Disable X" menu item for a given controller.
		 *
		 * @param  {Number} tabId Tab ID
		 * @param  {Object} ctrl Controller instance
		 */
		addToggleConnectorMenu(tabId, ctrl) {
			const { label } = ctrl.getConnector();
			const titleId = ctrl.isEnabled ? 'menuDisableConnector' : 'menuEnableConnector';
			const itemTitle = i18n.getMessage(titleId, label);
			const newState = !ctrl.isEnabled;

			this.addContextMenuItem(tabId, itemTitle, () => {
				this.setConnectorState(ctrl, newState);
			});
		}

		/**
		 * Add a "Disable X until tab is closed" menu item for a given controller.
		 *
		 * @param  {Number} tabId Tab ID
		 * @param  {Object} ctrl Controller instance
		 */
		addDisableUntilTabClosedItem(tabId, ctrl) {
			const { label } = ctrl.getConnector();
			const itemTitle2 = i18n.getMessage(
				'menuDisableUntilTabClosed', label);
			this.addContextMenuItem(tabId, itemTitle2, () => {
				ctrl.setEnabled(false);
			});
		}

		/**
		 * Helper function to add item to page action context menu.
		 *
		 * @param  {Number} tabId Tab ID
		 * @param {String} title Item title
		 * @param {Function} onClicked Function that will be called on item click
		 */
		addContextMenuItem(tabId, title, onClicked) {
			const onclick = () => {
				onClicked();

				this.updateContextMenu(tabId);
				if (this.shouldUpdateBrowserAction(tabId)) {
					this.updateBrowserAction(tabId);
				}
			};

			const type = 'normal';
			contextMenus.create({
				title, type, onclick, contexts: ['browser_action'],
			});
		}

		/**
		 * Called when a controller changes its mode.
		 *
		 * @param  {Object} ctrl  Controller instance
		 * @param  {Number} tabId ID of a tab attached to the controller
		 */
		processControlleModeChange(ctrl, tabId) {
			const mode = ctrl.getMode();
			const isCtrlModeInactive = isInactiveMode(mode);
			let isActiveCtrlChanged = false;

			if (this.activeTabId !== tabId) {
				if (isCtrlModeInactive) {
					return;
				}

				this.activeTabId = tabId;
				isActiveCtrlChanged = true;
			}

			if (isActiveCtrlChanged) {
				this.updateContextMenu(this.currentTabId);
			}

			if (isCtrlModeInactive) {
				// Use the current tab as a context
				this.updateBrowserAction(this.currentTabId);
			} else {
				// Use a tab to which the given controller attached as a context
				this.updateBrowserAction(tabId);
			}
		}

		/**
		 * Notify other modules if a controller updated the song.
		 *
		 * @param  {Object} ctrl  Controller instance
		 * @param  {Number} tabId ID of a tab attached to the controller
		 */
		async notifySongIsUpdated(ctrl, tabId) {
			const data = ctrl.getCurrentSong().getCloneableData();
			const type = 'EVENT_SONG_UPDATED';

			try {
				await runtime.sendMessage({ type, data, tabId });
			} catch (e) {
				// Suppress errors
			}
		}

		/**
		 * Make an attempt to inject a connector into a page.
		 *
		 * @param  {Number} tabId An ID of a tab where the connector will be injected
		 * @param  {String} connector Connector match object
		 *
		 * @return {Object} InjectResult value
		*/
		async tryToInjectConnector(tabId, connector) {
			const result = await Inject.injectConnector(tabId, connector);

			switch (result) {
				case INJECTED: {
					return;
				}

				case NO_MATCH: {
					if (this.tabControllers[tabId]) {
						this.unloadController(tabId);
						this.updateLastActiveTab();
					}
					break;
				}

				case MATCHED: {
					this.unloadController(tabId);
					await this.createController(tabId, connector);

					if (this.shouldUpdateBrowserAction(tabId)) {
						this.updateBrowserAction(tabId);
					}
					this.updateContextMenu(tabId);

					tabs.sendMessage(tabId, { type: 'EVENT_READY' });

					this.onConnectorActivated(connector);
					break;
				}
			}
		}

		/**
		 * Create a controller for a tab.
		 *
		 * @param  {Number} tabId An ID of a tab bound to the controller
		 * @param  {Object} connector A connector match object
		 */
		async createController(tabId, connector) {
			const isEnabled = await Options.isConnectorEnabled(connector);
			const ctrl = new Controller(tabId, connector, isEnabled);
			ctrl.onSongUpdated = async () => {
				this.notifySongIsUpdated(ctrl, tabId);
			};
			ctrl.onModeChanged = () => {
				this.processControlleModeChange(ctrl, tabId);
			};
			ctrl.onControllerEvent = (event) => {
				this.onControllerEvent(ctrl, event);
			};

			this.tabControllers[tabId] = ctrl;
		}

		/**
		 * Stop and remove controller for a tab with a given tab ID.
		 *
		 * @param  {Number} tabId Tab ID
		 */
		async unloadController(tabId) {
			const controller = this.tabControllers[tabId];
			if (!controller) {
				return;
			}

			controller.finish();
			delete this.tabControllers[tabId];
		}

		/**
		 * Enable or disable a connector attached to a given controller.
		 *
		 * @param  {Object} ctrl Controller instance
		 * @param  {Boolean} isEnabled Flag value
		 */
		setConnectorState(ctrl, isEnabled) {
			const connector = ctrl.getConnector();

			ctrl.setEnabled(isEnabled);
			Options.setConnectorEnabled(connector, isEnabled);
		}
	}

	return TabWorker;
});
<commit_msg>Remove calling non-existing method<commit_after>'use strict';

define((require) => {
	const Inject = require('browser/inject');
	const BrowserAction = require('browser/browser-action');

	const Options = require('storage/options');

	const Controller = require('object/controller');
	const { isActiveMode, isInactiveMode } = require('object/controller-mode');

	const { INJECTED, MATCHED, NO_MATCH } = require('object/inject-result');
	const { getCurrentTab } = require('util/util-browser');
	const { getConnectorByUrl } = require('util/util-connector');
	const {
		contextMenus, i18n, runtime, tabs,
	} = require('webextension-polyfill');

	class TabWorker {
		constructor() {
			this.initialize();
		}

		/** Listeners. */

		/**
		 * Called if a new event is dispatched.
		 *
		 * @param {Object} ctrl Controller instance
		 * @param {Object} event Event generated by the controller.
		 */
		onControllerEvent(ctrl, event) { // eslint-disable-line no-unused-vars
			throw new Error('This function must be overridden!');
		}

		/** Public methods. */

		/**
		 * Called when a command is executed.
		 *
		 * @param  {String} command Command ID
		 */
		async processCommand(command) {
			const ctrl = this.tabControllers[this.activeTabId] ||
				this.tabControllers[this.currentTabId];
			if (!ctrl) {
				return;
			}

			switch (command) {
				case 'toggle-connector':
					this.setControllerState(ctrl, !ctrl.isEnabled);
					break;

				case 'love-song':
				case 'unlove-song': {
					const isLoved = command === 'love-song';

					await ctrl.toggleLove(isLoved);
					this.browserAction.setSongLoved(isLoved, ctrl.getCurrentSong());
					break;
				}
			}
		}

		/**
		 * Called when something sent message to the background script
		 * via `browser.runtime.sendMessage` function.
		 *
		 * @param  {Number} tabId ID of a tab to which the message is addressed
		 * @param  {String} type Message type
		 * @param  {Object} data Object contains data sent in the message
		 */
		async processMessage(tabId, type, data) {
			switch (type) {
				case 'REQUEST_ACTIVE_TABID':
					return this.activeTabId;
			}

			const ctrl = this.tabControllers[tabId];

			if (!ctrl) {
				console.warn(
					`Attempted to send ${type} event to controller for tab ${tabId}`);
				return;
			}

			switch (type) {
				case 'REQUEST_GET_SONG':
					return ctrl.getCurrentSong().getCloneableData();

				case 'REQUEST_CORRECT_SONG':
					ctrl.setUserSongData(data);
					break;

				case 'REQUEST_TOGGLE_LOVE':
					await ctrl.toggleLove(data.isLoved);
					return data.isLoved;

				case 'REQUEST_SKIP_SONG':
					ctrl.skipCurrentSong();
					break;

				case 'REQUEST_RESET_SONG':
					ctrl.resetSongData();
					break;
			}
		}

		/**
		 * Called when something sent message to the background script via port.
		 *
		 * @param  {Number} tabId ID of a tab to which the message is addressed
		 * @param  {String} type Message type
		 * @param  {Object} data Object contains data sent in the message
		 */
		processPortMessage(tabId, type, data) {
			switch (type) {
				case 'EVENT_STATE_CHANGED': {
					const ctrl = this.tabControllers[tabId];
					if (ctrl) {
						ctrl.onStateChanged(data);
					}
					break;
				}
			}
		}

		/**
		 * Called when a tab is updated.
		 *
		 * @param  {Number} tabId Tab ID
		 * @param  {String} url Object contains changes of updated tab
		 */
		async processTabUpdate(tabId, url) {
			const connector = await getConnectorByUrl(url);
			this.tryToInjectConnector(tabId, connector);
		}

		/**
		 * Called when a current tab is changed.
		 *
		 * @param  {Number} tabId Tab ID
		 */
		processTabChange(tabId) {
			this.currentTabId = tabId;

			if (this.shouldUpdateBrowserAction(tabId)) {
				this.updateBrowserAction(tabId);
				this.activeTabId = tabId;
			}

			this.updateContextMenu(tabId);
		}

		/**
		 * Called when a tab is removed.
		 *
		 * @param  {Number} removedTabId Tab ID
		 */
		async processTabRemove(removedTabId) {
			this.unloadController(removedTabId);

			if (removedTabId === this.activeTabId) {
				this.activeTabId = tabs.TAB_ID_NONE;
				this.updateLastActiveTab();
			}
		}

		/** Private methods. */

		async initialize() {
			const currentTab = await getCurrentTab();
			// We cannot get a current tab in some cases on startup
			if (currentTab) {
				this.currentTabId = currentTab.id;
			} else {
				this.currentTabId = tabs.TAB_ID_NONE;
			}
			this.activeTabId = tabs.TAB_ID_NONE;
			this.tabControllers = [];

			this.browserAction = new BrowserAction();
			/*
			 * Prevent restoring the browser action icon
			 * from the previous session.
			 */
			this.browserAction.reset();
		}

		/**
		 * Update the browser action in context of a given tab ID.
		 *
		 * @param  {Number} tabId Tab ID
		 */
		updateBrowserAction(tabId) {
			const ctrl = this.tabControllers[tabId];
			if (ctrl) {
				this.browserAction.update(ctrl);
			} else {
				this.browserAction.reset();
			}
		}

		/**
		 * Check if the browser action should be updated
		 * in context of a given tab ID.
		 *
		 * @param  {Number} tabId Tab ID
		 *
		 * @return {Boolean} Check result
		 */
		shouldUpdateBrowserAction(tabId) {
			const activeCtrl = this.tabControllers[this.activeTabId];
			if (activeCtrl && isActiveMode(activeCtrl.mode)) {
				return false;
			}

			const ctrl = this.tabControllers[tabId];
			if (ctrl) {
				if (tabId !== this.currentTabId && isInactiveMode(ctrl.mode)) {
					return false;
				}
			}

			return true;
		}

		/**
		 * Get ID of a tab with recent active controller.
		 *
		 * @return {Number} Tab ID
		 */
		findActiveTabId() {
			const ctrl = this.tabControllers[this.currentTabId];
			if (ctrl && isActiveMode(ctrl.mode)) {
				return this.currentTabId;
			}

			for (const tabId in this.tabControllers) {
				const ctrl = this.tabControllers[tabId];
				const mode = ctrl.getMode();
				if (isActiveMode(mode)) {
					// NOTE: Don't use `tabId` directly, it's a string.
					return ctrl.tabId;
				}
			}

			if (ctrl) {
				return this.currentTabId;
			}

			return tabs.TAB_ID_NONE;
		}

		/**
		 * Update the browser action and the context menu in context of a last
		 * active tab. If no active tab is found, reset the browser action icon
		 * and the context menu.
		 */
		updateLastActiveTab() {
			const lastActiveTabId = this.findActiveTabId();
			if (lastActiveTabId !== tabs.TAB_ID_NONE) {
				this.activeTabId = lastActiveTabId;

				this.updateBrowserAction(this.activeTabId);
				this.updateContextMenu(this.activeTabId);
			} else {
				this.browserAction.reset();
				this.resetContextMenu();
			}
		}

		/**
 		 * Setup context menu of the browser action for a tab with given tab ID.
		 *
		 * @param  {Number} tabId Tab ID
		 */
		updateContextMenu(tabId) {
			this.resetContextMenu();

			const ctrl = this.tabControllers[tabId];

			// Always display context menu for current tab
			if (ctrl) {
				this.addToggleConnectorMenu(tabId, ctrl);
				if (ctrl.isEnabled) {
					this.addDisableUntilTabClosedItem(tabId, ctrl);
				}
			}

			// Add additional menu items for active tab (if it's not current)...
			if (this.activeTabId !== tabId) {
				const activeCtrl = this.tabControllers[this.activeTabId];

				if (activeCtrl) {
					if (ctrl && activeCtrl.getConnector().id === ctrl.getConnector().id) {
						return;
					}

					// ...but only if it has a different connector injected.
					this.addToggleConnectorMenu(tabId, activeCtrl);
				}
			}
		}

		/**
		 * Remove all items from the context menu.
		 */
		resetContextMenu() {
			contextMenus.removeAll();
		}

		/**
		 * Add a "Enable/Disable X" menu item for a given controller.
		 *
		 * @param  {Number} tabId Tab ID
		 * @param  {Object} ctrl Controller instance
		 */
		addToggleConnectorMenu(tabId, ctrl) {
			const { label } = ctrl.getConnector();
			const titleId = ctrl.isEnabled ? 'menuDisableConnector' : 'menuEnableConnector';
			const itemTitle = i18n.getMessage(titleId, label);
			const newState = !ctrl.isEnabled;

			this.addContextMenuItem(tabId, itemTitle, () => {
				this.setConnectorState(ctrl, newState);
			});
		}

		/**
		 * Add a "Disable X until tab is closed" menu item for a given controller.
		 *
		 * @param  {Number} tabId Tab ID
		 * @param  {Object} ctrl Controller instance
		 */
		addDisableUntilTabClosedItem(tabId, ctrl) {
			const { label } = ctrl.getConnector();
			const itemTitle2 = i18n.getMessage(
				'menuDisableUntilTabClosed', label);
			this.addContextMenuItem(tabId, itemTitle2, () => {
				ctrl.setEnabled(false);
			});
		}

		/**
		 * Helper function to add item to page action context menu.
		 *
		 * @param  {Number} tabId Tab ID
		 * @param {String} title Item title
		 * @param {Function} onClicked Function that will be called on item click
		 */
		addContextMenuItem(tabId, title, onClicked) {
			const onclick = () => {
				onClicked();

				this.updateContextMenu(tabId);
				if (this.shouldUpdateBrowserAction(tabId)) {
					this.updateBrowserAction(tabId);
				}
			};

			const type = 'normal';
			contextMenus.create({
				title, type, onclick, contexts: ['browser_action'],
			});
		}

		/**
		 * Called when a controller changes its mode.
		 *
		 * @param  {Object} ctrl  Controller instance
		 * @param  {Number} tabId ID of a tab attached to the controller
		 */
		processControlleModeChange(ctrl, tabId) {
			const mode = ctrl.getMode();
			const isCtrlModeInactive = isInactiveMode(mode);
			let isActiveCtrlChanged = false;

			if (this.activeTabId !== tabId) {
				if (isCtrlModeInactive) {
					return;
				}

				this.activeTabId = tabId;
				isActiveCtrlChanged = true;
			}

			if (isActiveCtrlChanged) {
				this.updateContextMenu(this.currentTabId);
			}

			if (isCtrlModeInactive) {
				// Use the current tab as a context
				this.updateBrowserAction(this.currentTabId);
			} else {
				// Use a tab to which the given controller attached as a context
				this.updateBrowserAction(tabId);
			}
		}

		/**
		 * Notify other modules if a controller updated the song.
		 *
		 * @param  {Object} ctrl  Controller instance
		 * @param  {Number} tabId ID of a tab attached to the controller
		 */
		async notifySongIsUpdated(ctrl, tabId) {
			const data = ctrl.getCurrentSong().getCloneableData();
			const type = 'EVENT_SONG_UPDATED';

			try {
				await runtime.sendMessage({ type, data, tabId });
			} catch (e) {
				// Suppress errors
			}
		}

		/**
		 * Make an attempt to inject a connector into a page.
		 *
		 * @param  {Number} tabId An ID of a tab where the connector will be injected
		 * @param  {String} connector Connector match object
		 *
		 * @return {Object} InjectResult value
		*/
		async tryToInjectConnector(tabId, connector) {
			const result = await Inject.injectConnector(tabId, connector);

			switch (result) {
				case INJECTED: {
					return;
				}

				case NO_MATCH: {
					if (this.tabControllers[tabId]) {
						this.unloadController(tabId);
						this.updateLastActiveTab();
					}
					break;
				}

				case MATCHED: {
					this.unloadController(tabId);
					await this.createController(tabId, connector);

					if (this.shouldUpdateBrowserAction(tabId)) {
						this.updateBrowserAction(tabId);
					}
					this.updateContextMenu(tabId);

					tabs.sendMessage(tabId, { type: 'EVENT_READY' });
					break;
				}
			}
		}

		/**
		 * Create a controller for a tab.
		 *
		 * @param  {Number} tabId An ID of a tab bound to the controller
		 * @param  {Object} connector A connector match object
		 */
		async createController(tabId, connector) {
			const isEnabled = await Options.isConnectorEnabled(connector);
			const ctrl = new Controller(tabId, connector, isEnabled);
			ctrl.onSongUpdated = async () => {
				this.notifySongIsUpdated(ctrl, tabId);
			};
			ctrl.onModeChanged = () => {
				this.processControlleModeChange(ctrl, tabId);
			};
			ctrl.onControllerEvent = (event) => {
				this.onControllerEvent(ctrl, event);
			};

			this.tabControllers[tabId] = ctrl;
		}

		/**
		 * Stop and remove controller for a tab with a given tab ID.
		 *
		 * @param  {Number} tabId Tab ID
		 */
		async unloadController(tabId) {
			const controller = this.tabControllers[tabId];
			if (!controller) {
				return;
			}

			controller.finish();
			delete this.tabControllers[tabId];
		}

		/**
		 * Enable or disable a connector attached to a given controller.
		 *
		 * @param  {Object} ctrl Controller instance
		 * @param  {Boolean} isEnabled Flag value
		 */
		setConnectorState(ctrl, isEnabled) {
			const connector = ctrl.getConnector();

			ctrl.setEnabled(isEnabled);
			Options.setConnectorEnabled(connector, isEnabled);
		}
	}

	return TabWorker;
});
<|endoftext|>


<commit_before>if(!(/Android|iPhone|iPad|iPod|BlackBerry|Windows Phone/i).test(navigator.userAgent || navigator.vendor || window.opera)){
    skrollr.init({
        forceHeight: false
    });
}

$(document).ready(function() {
    if ($(document.body).attr('id') == 'apply') {
        $('form#application-form').submit(function(evt) {
            var data = $(this).serialize();
            $('.spinner').show(100);

            $.ajax({
                type: 'POST',
                url: $(this).attr('action'),
                data: data,
                encode: true,
                dataType: 'json',
                accepts: {
                    json: 'application/json'
                }
            }).done(function(resp) {
                $('.spinner').hide(100);
                $('.status').hide(700, function() {
                                $(this).removeClass('error')
                                       .html(resp.response)
                                       .show(700);
                            });

                $('#applicant-submit-button').hide(700);
                $('.g-recaptcha').hide(700);
            }).fail(function(obj) {
                $('.spinner').hide(100);
                resp = obj.responseJSON;
                if (typeof resp == 'undefined' && obj.status == 419) {
                    resp = {
                        response: '
Фајлови су превелики. Максимална величина једног фајла је 15MiB.
'
                    }
                }
                if (typeof resp == 'undefined') {
                    resp = {
                        response: '
Неочекивана грешка. Молимо вас контактирајте нас на kontakt@csnedelja.mg.edu.rs
',
                    };
                }
                if (window['grecaptcha']) {
                    grecaptcha.reset();
                }
                if (typeof resp.errors == 'undefined' || typeof resp.errors[0] == 'undefined')
                    resp.errors = [];

                    $('.status').hide(700, function() {
                        $(this).addClass('error')
                               .html(resp.response + '
' + resp.errors.reduce(function(prev, c) {
                                   return prev + '
' + c + '
';
                                }, ''))
                                .show(700)
                    });

            });

            evt.preventDefault();
        });

        function updateFilename(elem) {
            $(elem).parent().parent().children('.filename').html($(elem).val());
        }

        $('a.upload input').change(function() {
            updateFilename(this);
        });

        $('a.upload input').each(function() {
            updateFilename($(this));
        });
    }

    $('#hamburger-icon').click(function() {
        if ($('header nav ul.active').length > 0) {
            $('header nav ul').removeClass('active')
                              .slideUp();
        } else {
            $('header nav ul').addClass('active')
                              .slideDown();
        }

    })
});
<commit_msg>Update email<commit_after>if(!(/Android|iPhone|iPad|iPod|BlackBerry|Windows Phone/i).test(navigator.userAgent || navigator.vendor || window.opera)){
    skrollr.init({
        forceHeight: false
    });
}

$(document).ready(function() {
    if ($(document.body).attr('id') == 'apply') {
        $('form#application-form').submit(function(evt) {
            var data = $(this).serialize();
            $('.spinner').show(100);

            $.ajax({
                type: 'POST',
                url: $(this).attr('action'),
                data: data,
                encode: true,
                dataType: 'json',
                accepts: {
                    json: 'application/json'
                }
            }).done(function(resp) {
                $('.spinner').hide(100);
                $('.status').hide(700, function() {
                                $(this).removeClass('error')
                                       .html(resp.response)
                                       .show(700);
                            });

                $('#applicant-submit-button').hide(700);
                $('.g-recaptcha').hide(700);
            }).fail(function(obj) {
                $('.spinner').hide(100);
                resp = obj.responseJSON;
                if (typeof resp == 'undefined' && obj.status == 419) {
                    resp = {
                        response: '
Фајлови су превелики. Максимална величина једног фајла је 15MiB.
'
                    }
                }
                if (typeof resp == 'undefined') {
                    resp = {
                        response: '
Неочекивана грешка. Молимо вас контактирајте нас на ni@ni.mg.edu.rs
',
                    };
                }
                if (window['grecaptcha']) {
                    grecaptcha.reset();
                }
                if (typeof resp.errors == 'undefined' || typeof resp.errors[0] == 'undefined')
                    resp.errors = [];

                    $('.status').hide(700, function() {
                        $(this).addClass('error')
                               .html(resp.response + '
' + resp.errors.reduce(function(prev, c) {
                                   return prev + '
' + c + '
';
                                }, ''))
                                .show(700)
                    });

            });

            evt.preventDefault();
        });

        function updateFilename(elem) {
            $(elem).parent().parent().children('.filename').html($(elem).val());
        }

        $('a.upload input').change(function() {
            updateFilename(this);
        });

        $('a.upload input').each(function() {
            updateFilename($(this));
        });
    }

    $('#hamburger-icon').click(function() {
        if ($('header nav ul.active').length > 0) {
            $('header nav ul').removeClass('active')
                              .slideUp();
        } else {
            $('header nav ul').addClass('active')
                              .slideDown();
        }

    })
});
<|endoftext|>


<commit_before>'use strict';

/*eslint no-process-env: 0*/

var config = {
	specs: [
		'../src/**/*.spec.js'
	],
	directConnect: true,
	framework: 'jasmine',
	multiCapabilities: [{
		browserName: 'chrome'
	}],
	baseUrl: 'http://localhost:8000/demo',
	beforeLaunch: function() {
		var exec = require('child_process').exec;

		exec('gulp serve');
		return new Promise((resolve) => {
			setTimeout(resolve, process.env.TRAVIS ? 5000 : 0);
		});
	}
};

if (process.env.TRAVIS) {
	config.allScriptsTimeout = 110000;
	config.jasmineNodeOpts = {
		defaultTimeoutInterval: 100000
	};
	config.multiCapabilities = [{
		browserName: 'firefox'
	}];
}

exports.config = config;
<commit_msg>chore(test): change timeout for e2e tests<commit_after>'use strict';

/*eslint no-process-env: 0*/

var config = {
	specs: [
		'../src/**/*.spec.js'
	],
	directConnect: true,
	framework: 'jasmine',
	multiCapabilities: [{
		browserName: 'chrome'
	}],
	baseUrl: 'http://localhost:8000/demo',
	beforeLaunch: function() {
		var exec = require('child_process').exec;

		exec('gulp serve');
		return new Promise((resolve) => {
			setTimeout(resolve, 5000);
		});
	}
};

if (process.env.TRAVIS) {
	config.allScriptsTimeout = 110000;
	config.jasmineNodeOpts = {
		defaultTimeoutInterval: 100000
	};
	config.multiCapabilities = [{
		browserName: 'firefox'
	}];
}

exports.config = config;
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief tests for query language, variables
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var errors = require("internal").errors;
var jsunity = require("jsunity");
var helper = require("org/arangodb/aql-helper");
var getQueryResults = helper.getQueryResults2;
var assertQueryError = helper.assertQueryError2;

////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////

function ahuacatlVariablesTestSuite () {

  return {

////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////

    setUp : function () {
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////

    tearDown : function () {
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test valid declaration
////////////////////////////////////////////////////////////////////////////////

    testValid1 : function () {
      var result = getQueryResults("LET a = 1 RETURN a");

      assertEqual([ 1 ], result);
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test valid declaration
////////////////////////////////////////////////////////////////////////////////

    testValid2 : function () {
      var result = getQueryResults("LET a = 1 LET b = 2 RETURN [ a, b ]");

      assertEqual([ [ 1, 2 ] ], result);
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test valid declaration
////////////////////////////////////////////////////////////////////////////////

    testValid3 : function () {
      var result = getQueryResults("LET `a b c` = 1 RETURN `a b c`");

      assertEqual([ 1 ], result);
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test loop variable
////////////////////////////////////////////////////////////////////////////////

    testCounter1 : function () {
      var actual = getQueryResults("LET sum = 42, iter = 7 FOR i IN 0..99 LET iter = iter + 2, sum = sum + i RETURN [ iter, sum ]");
      assertEqual(100, actual.length);

      var sum = 42, iter = 7, i;
      for (i = 0; i < 99; ++i) {
        sum += i;
        iter += 2;
        assertEqual(iter, actual[i][0]);
        assertEqual(sum, actual[i][1]);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test loop variable
////////////////////////////////////////////////////////////////////////////////

    testCounter2 : function () {
      assertEqual([ 5050 ], getQueryResults("LET sum = 0 LET s = (FOR i IN 1..100 LET sum = sum + i RETURN sum) RETURN sum"));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test undeclared
////////////////////////////////////////////////////////////////////////////////

    testUndeclared : function () {
      assertQueryError(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, "LET a = nonexisting + 1 RETURN 0");
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test redeclaration
////////////////////////////////////////////////////////////////////////////////

    testRedeclare1 : function () {
      assertEqual([ 1 ], getQueryResults("LET a = 1 LET a = 1 RETURN a"));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test redeclaration
////////////////////////////////////////////////////////////////////////////////

    testRedeclare2 : function () {
      assertEqual([ 2 ], getQueryResults("LET a = 1 LET a = 2 RETURN a"));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test redeclaration
////////////////////////////////////////////////////////////////////////////////

    testRedeclare3 : function () {
      assertEqual([ [ 1, 1, 3 ] ], getQueryResults("LET a = 1 LET b = 2 LET c = 3 LET b = a RETURN [ a, b, c ]"));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test redeclaration
////////////////////////////////////////////////////////////////////////////////

    testRedeclare4 : function () {
      assertQueryError(errors.ERROR_QUERY_VARIABLE_REDECLARED.code, "LET a = 1 FOR a IN [ 1 ] RETURN 0");
    }

  };
}

////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////

jsunity.run(ahuacatlVariablesTestSuite);

return jsunity.done();

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:
<commit_msg>removed tests for now-unsupported functionality<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief tests for query language, variables
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var errors = require("internal").errors;
var jsunity = require("jsunity");
var helper = require("org/arangodb/aql-helper");
var getQueryResults = helper.getQueryResults2;
var assertQueryError = helper.assertQueryError2;

////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////

function ahuacatlVariablesTestSuite () {

  return {

////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////

    setUp : function () {
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////

    tearDown : function () {
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test valid declaration
////////////////////////////////////////////////////////////////////////////////

    testValid1 : function () {
      var result = getQueryResults("LET a = 1 RETURN a");

      assertEqual([ 1 ], result);
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test valid declaration
////////////////////////////////////////////////////////////////////////////////

    testValid2 : function () {
      var result = getQueryResults("LET a = 1 LET b = 2 RETURN [ a, b ]");

      assertEqual([ [ 1, 2 ] ], result);
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test valid declaration
////////////////////////////////////////////////////////////////////////////////

    testValid3 : function () {
      var result = getQueryResults("LET `a b c` = 1 RETURN `a b c`");

      assertEqual([ 1 ], result);
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test undeclared
////////////////////////////////////////////////////////////////////////////////

    testUndeclared : function () {
      assertQueryError(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, "LET a = nonexisting + 1 RETURN 0");
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test redeclaration
////////////////////////////////////////////////////////////////////////////////

    testRedeclare : function () {
      assertQueryError(errors.ERROR_QUERY_VARIABLE_REDECLARED.code, "LET a = 1 FOR a IN [ 1 ] RETURN 0");
    }

  };
}

////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////

jsunity.run(ahuacatlVariablesTestSuite);

return jsunity.done();

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:
<|endoftext|>


<commit_before>angular
	.module('toggleInstitutions', [])
	.component('prmAlmaMoreInstAfter', {
		template: `
			<md-button class="md-raised" ng-click="$ctrl.toggleLibs()">
				{{ showLibs ? 'Hide Libraries «' : 'Show Libraries »' }}
			</md-button>`,
		controller: ['$scope', function ($scope) {
			$scope.showLibs = false
			this.toggleLibs = function () {
				$scope.showLibs = !$scope.showLibs
				this.tabs.hasClass('hide') ? this.tabs.removeClass('hide') : this.tabs.addClass('hide')
			}
			this.$onInit = function () {
				this.button = angular.element(document.querySelector('prm-alma-more-inst-after'))
				this.tabs = angular.element(document.querySelector('prm-alma-more-inst md-tabs'))
				if (!$scope.showLibs) this.tabs.addClass('hide')
			}
		}]
	})
<commit_msg>make button stay on top of list<commit_after>angular
	.module('toggleInstitutions', [])
	.component('prmAlmaMoreInstAfter', {
		template: `
			<md-button class="md-raised" ng-click="$ctrl.toggleLibs()">
				{{ showLibs ? 'Hide Libraries «' : 'Show Libraries »' }}
			</md-button>`,
		controller: ['$scope', function ($scope) {
			$scope.showLibs = false
			this.toggleLibs = function () {
				$scope.showLibs = !$scope.showLibs
				this.tabs.hasClass('hide') ? this.tabs.removeClass('hide') : this.tabs.addClass('hide')
			}
			this.$onInit = function () {
				this.button = angular.element(document.querySelector('prm-alma-more-inst-after'))
				this.tabs = angular.element(document.querySelector('prm-alma-more-inst md-tabs'))
				this.button.after(this.tabs)
				if (!$scope.showLibs) this.tabs.addClass('hide')
			}
		}]
	})
<|endoftext|>


<commit_before>// @flow
import React, {PropTypes as t} from 'react';

type LookupInputPropsType = {
  img: string,
  onChange?: () => any,
  onSubmit: () => any
};

type EventType = {
  target: {
    name: string,
    value: string
  }
};

const styles = {
  container: {
    display: 'flex',
    alignItems: 'center',
  },
  icon: {
    position: 'relative',
    flex: '1 1 0px',
    left: '-20px',
  },
  input: {
    width: '90%',
    flex: '9 9 0px',
    paddingRight: '32px',
  },
};

const LookupInput = ({img, onChange, onSubmit}: LookupInputPropsType) => (

    <input
      className="form-control lookup-input-input"
      onChange={onChange}
      onKeyPress={(event: EventType) => event.which === 13 ? onSubmit() : null}
      type="text"
      style={styles.input}
    />
    <i
      className={`lookup-input-icon fa fa-${img}`}
      onClick={onSubmit}
      style={styles.icon}
    />

);

LookupInput.displayName = 'LookupInput';

LookupInput.propTypes = t.shape({
  img: t.string.isRequired,
  onChange: t.func,
  onClick: t.func,
}).isRequired;

export default LookupInput;
<commit_msg>shorten name of propstype<commit_after>// @flow
import React, {PropTypes as t} from 'react';

type PropsType = {
  img: string,
  onChange?: () => any,
  onSubmit: () => any
};

type EventType = {
  target: {
    name: string,
    value: string
  }
};

const styles = {
  container: {
    display: 'flex',
    alignItems: 'center',
  },
  icon: {
    position: 'relative',
    flex: '1 1 0px',
    left: '-20px',
  },
  input: {
    width: '90%',
    flex: '9 9 0px',
    paddingRight: '32px',
  },
};

const LookupInput = ({img, onChange, onSubmit}: PropsType) => (

    <input
      className="form-control lookup-input-input"
      onChange={onChange}
      onKeyPress={(event: EventType) => event.which === 13 ? onSubmit() : null}
      type="text"
      style={styles.input}
    />
    <i
      className={`lookup-input-icon fa fa-${img}`}
      onClick={onSubmit}
      style={styles.icon}
    />

);

LookupInput.displayName = 'LookupInput';

LookupInput.propTypes = t.shape({
  img: t.string.isRequired,
  onChange: t.func,
  onClick: t.func,
}).isRequired;

export default LookupInput;
<|endoftext|>


<commit_before>Ext.namespace('ui','ui.component','ui.component._LocalMailGrid');

//------------------------------------------------------------------------------
// LocalMailGrid internals

// Store : Mailing with Informations about phpdoc-LANG mailing
ui.component._LocalMailGrid.store = new Ext.data.Store({
    proxy : new Ext.data.HttpProxy({
        url : './do/getLastNews'
    }),
    reader : new Ext.data.JsonReader(
        {
            root          : 'Items',
            totalProperty : 'nbItems',
            id            : 'id'
        }, Ext.data.Record.create([
            {
                name    : 'id',
                mapping : 'id'
            }, {
                name    : 'title',
                mapping : 'title'
            }, {
                name    : 'link',
                mapping : 'link'
            }, {
                name    : 'description',
                mapping : 'description'
            }, {
                name       : 'pubDate',
                mapping    : 'pubDate',
                type       : 'date',
                dateFormat : 'Y/m/d H:i:s'
            }
        ])
    )
});
ui.component._LocalMailGrid.store.setDefaultSort('pubDate', 'desc');

// LocalMailGrid columns definition
ui.component._LocalMailGrid.columns = [
    new Ext.grid.RowNumberer(), {
        id        : 'GridMailingTitle',
        header    : _('Title'),
        sortable  : true,
        dataIndex : 'title'
    }, {
        header    : _('By'),
        width     : 110,
        sortable  : true,
        dataIndex : 'description'
    }, {
        header    : _('Date'),
        width     : 140,
        sortable  : true,
        dataIndex : 'pubDate',
        renderer  : Ext.util.Format.dateRenderer(_('Y-m-d, H:i'))
    }
];

//------------------------------------------------------------------------------
// LocalMailGrid
ui.component.LocalMailGrid = Ext.extend(Ext.grid.GridPanel,
{
    iconCls          : 'home-mailing-title',
    height           : 400,
    width            : 800,
    loadMask         : true,
    autoScroll       : true,
    autoExpandColumn : 'GridMailingTitle',
    store            : ui.component._LocalMailGrid.store,
    columns          : ui.component._LocalMailGrid.columns,
    sm               : new Ext.grid.RowSelectionModel({ singleSelect: true }),

    listeners : {
        render : function(grid)
        {
            grid.store.load.defer(20, grid.store);
        },
        rowcontextmenu : function(grid, rowIndex, e)
        {
            grid.getSelectionModel().selectRow(rowIndex);

            new Ext.menu.Menu({
                id    : 'submenu',
                items : [{
                    text    : ''+_('Open in a new Tab')+'',
                    iconCls : 'openInTab',
                    handler : function()
                    {
                        grid.fireEvent('rowdblclick', grid, rowIndex, e);
                    }
                }, '-', {
                    text    : _('Refresh this grid'),
                    iconCls : 'refresh',
                    handler : function()
                    {
                        grid.store.reload();
                    }
                }]
            }).showAt(e.getXY());
        },
        rowdblclick : function(grid, rowIndex, e)
        {
            var MailId    = grid.store.getAt(rowIndex).data.pubDate,
                MailUrl   = grid.store.getAt(rowIndex).data.link,
                MailTitle = grid.store.getAt(rowIndex).data.title;

            Ext.getCmp('main-panel').add({
                xtype      : 'iframepanel',
                id         : 'mifp_' + MailId,
                title      : _('Loading...'),
                tabTip     : MailTitle,
                iconCls    : 'home-mailing-title',
                loadMask   : true,
                defaultSrc : MailUrl,
                listeners : {
                    documentloaded : function(frame)
                    {
                        frame.ownerCt.setTitle(
                            Ext.util.Format.substr(MailTitle, 0, 20) + '...'
                        );
                    }
                }
            });
            Ext.getCmp('main-panel').setActiveTab('mifp_' + MailId);
        }
    },

    initComponent : function()
    {
        Ext.apply(this,
        {
            title : String.format(_('Mails from {0}'), 'doc-' + phpDoc.userLang),
            tbar : [{
                tooltip : _('Refresh this grid'),
                iconCls : 'refresh',
                handler : function()
                {
                    ui.component.LocalMailGrid.reload();
                }
            }]
        });
        ui.component.LocalMailGrid.superclass.initComponent.call(this);
    }
});

// singleton
ui.component._LocalMailGrid.instance = null;
ui.component.LocalMailGrid.getInstance = function(config)
{
    if (!ui.component._LocalMailGrid.instance) {
        if (!config) config = {};
        ui.component._LocalMailGrid.instance = new ui.component.LocalMailGrid(config);
    }
    return ui.component._LocalMailGrid.instance;
}
<commit_msg>fix reload task<commit_after>Ext.namespace('ui','ui.component','ui.component._LocalMailGrid');

//------------------------------------------------------------------------------
// LocalMailGrid internals

// Store : Mailing with Informations about phpdoc-LANG mailing
ui.component._LocalMailGrid.store = new Ext.data.Store({
    proxy : new Ext.data.HttpProxy({
        url : './do/getLastNews'
    }),
    reader : new Ext.data.JsonReader(
        {
            root          : 'Items',
            totalProperty : 'nbItems',
            id            : 'id'
        }, Ext.data.Record.create([
            {
                name    : 'id',
                mapping : 'id'
            }, {
                name    : 'title',
                mapping : 'title'
            }, {
                name    : 'link',
                mapping : 'link'
            }, {
                name    : 'description',
                mapping : 'description'
            }, {
                name       : 'pubDate',
                mapping    : 'pubDate',
                type       : 'date',
                dateFormat : 'Y/m/d H:i:s'
            }
        ])
    )
});
ui.component._LocalMailGrid.store.setDefaultSort('pubDate', 'desc');

// LocalMailGrid columns definition
ui.component._LocalMailGrid.columns = [
    new Ext.grid.RowNumberer(), {
        id        : 'GridMailingTitle',
        header    : _('Title'),
        sortable  : true,
        dataIndex : 'title'
    }, {
        header    : _('By'),
        width     : 110,
        sortable  : true,
        dataIndex : 'description'
    }, {
        header    : _('Date'),
        width     : 140,
        sortable  : true,
        dataIndex : 'pubDate',
        renderer  : Ext.util.Format.dateRenderer(_('Y-m-d, H:i'))
    }
];

//------------------------------------------------------------------------------
// LocalMailGrid
ui.component.LocalMailGrid = Ext.extend(Ext.grid.GridPanel,
{
    iconCls          : 'home-mailing-title',
    height           : 400,
    width            : 800,
    loadMask         : true,
    autoScroll       : true,
    autoExpandColumn : 'GridMailingTitle',
    store            : ui.component._LocalMailGrid.store,
    columns          : ui.component._LocalMailGrid.columns,
    sm               : new Ext.grid.RowSelectionModel({ singleSelect: true }),

    listeners : {
        render : function(grid)
        {
            grid.store.load.defer(20, grid.store);
        },
        rowcontextmenu : function(grid, rowIndex, e)
        {
            grid.getSelectionModel().selectRow(rowIndex);

            new Ext.menu.Menu({
                id    : 'submenu',
                items : [{
                    text    : ''+_('Open in a new Tab')+'',
                    iconCls : 'openInTab',
                    handler : function()
                    {
                        grid.fireEvent('rowdblclick', grid, rowIndex, e);
                    }
                }, '-', {
                    text    : _('Refresh this grid'),
                    iconCls : 'refresh',
                    handler : function()
                    {
                        grid.store.reload();
                    }
                }]
            }).showAt(e.getXY());
        },
        rowdblclick : function(grid, rowIndex, e)
        {
            var MailId    = grid.store.getAt(rowIndex).data.pubDate,
                MailUrl   = grid.store.getAt(rowIndex).data.link,
                MailTitle = grid.store.getAt(rowIndex).data.title;

            Ext.getCmp('main-panel').add({
                xtype      : 'iframepanel',
                id         : 'mifp_' + MailId,
                title      : _('Loading...'),
                tabTip     : MailTitle,
                iconCls    : 'home-mailing-title',
                loadMask   : true,
                defaultSrc : MailUrl,
                listeners : {
                    documentloaded : function(frame)
                    {
                        frame.ownerCt.setTitle(
                            Ext.util.Format.substr(MailTitle, 0, 20) + '...'
                        );
                    }
                }
            });
            Ext.getCmp('main-panel').setActiveTab('mifp_' + MailId);
        }
    },

    initComponent : function()
    {
        Ext.apply(this,
        {
            title : String.format(_('Mails from {0}'), 'doc-' + phpDoc.userLang),
            tbar : [{
				scope: this,
                tooltip : _('Refresh this grid'),
                iconCls : 'refresh',
                handler : function()
                {
					console.log(this); this.store.reload();
                }
            }]
        });
        ui.component.LocalMailGrid.superclass.initComponent.call(this);
    }
});

// singleton
ui.component._LocalMailGrid.instance = null;
ui.component.LocalMailGrid.getInstance = function(config)
{
    if (!ui.component._LocalMailGrid.instance) {
        if (!config) config = {};
        ui.component._LocalMailGrid.instance = new ui.component.LocalMailGrid(config);
    }
    return ui.component._LocalMailGrid.instance;
}
<|endoftext|>