<commit_before>'use strict';

(function (angular, buildfire) {
  angular.module('contactUsPluginWidget')
    .controller('WidgetHomeCtrl', ['$routeParams', 'Buildfire', 'DataStore', '$scope', 'TAG_NAMES', 'Location', 'LAYOUTS', '$rootScope', '$sce',
      function ($routeParams, Buildfire, DataStore, $scope, TAG_NAMES, Location, LAYOUTS, $rootScope, $sce) {
        var WidgetHome = this;
        var currentListLayout = null;
        WidgetHome.data = {};
        //create new instance of buildfire carousel viewer
        WidgetHome.view = null;
        /*declare the device width heights*/
        $rootScope.deviceHeight = window.innerHeight;
        $rootScope.deviceWidth = window.innerWidth;
        $rootScope.backgroundImage="";
        WidgetHome.device = null;
        /*initialize the device width heights*/
        function initDeviceSize(callback) {
          WidgetHome.deviceHeight = window.innerHeight;
          WidgetHome.deviceWidth = window.innerWidth;
          if (callback) {
            if (WidgetHome.deviceWidth == 0 || WidgetHome.deviceHeight == 0) {
              setTimeout(function () {
                initDeviceSize(callback);
              }, 500);
            } else {
              callback();
              if (!$scope.$$phase && !$scope.$root.$$phase) {
                $scope.$apply();
              }
            }
          }
        }

        /*crop image on the basis of width heights*/
        WidgetHome.cropImage = function (url, settings) {
          var options = {};
          if (!url) {
            return "";
          }
          else {
            if (settings.height) {
              options.height = settings.height;
            }
            if (settings.width) {
              options.width = settings.width;
            }
            return Buildfire.imageLib.cropImage(url, options);
          }
        };

        /*
         * Fetch user's data from datastore
         */
        var init = function () {
          var success = function (result) {
              WidgetHome.data = result.data;
              if (!WidgetHome.data.design)
                WidgetHome.data.design = {};
              if (!WidgetHome.data.design.listLayout) {
                WidgetHome.data.design.listLayout = LAYOUTS.listLayouts[0].name;
              }
              currentListLayout = WidgetHome.data.design.listLayout;
                if(WidgetHome.data.design.backgroundImage){
                  $rootScope.backgroundImage = WidgetHome.data.design.backgroundImage;
                }
                else
                 {
                  $rootScope.backgroundImage = "";
                 }
                var getDevice = function(error, data){
                  if(data)
                    WidgetHome.device  = data.device;
                  else
                    console.log("Error while getting the device context data", error)
                }
                buildfire.getContext(getDevice);
            }
            , error = function (err) {
              console.error('Error while getting data', err);
            };
          DataStore.get(TAG_NAMES.CONTACT_INFO).then(success, error);
        };
        init();
        $rootScope.$on("Carousel:LOADED", function () {
          if (!WidgetHome.view) {
            WidgetHome.view = new Buildfire.components.carousel.view("#carousel", []);
          }
          if (WidgetHome.data.content && WidgetHome.data.content.carouselImages) {
            WidgetHome.view.loadItems(WidgetHome.data.content.carouselImages);
          } else {
            WidgetHome.view.loadItems([]);
          }
        });

        var onUpdateCallback = function (event) {
          setTimeout(function () {
            $scope.imagesUpdated = false;
            $scope.$digest();
            if (event && event.tag === TAG_NAMES.CONTACT_INFO) {
              WidgetHome.data = event.data;
              if (!WidgetHome.data.design)
                WidgetHome.data.design = {};
              if (!WidgetHome.data.content)
                WidgetHome.data.content = {};
            }
            if(WidgetHome.data.design.backgroundImage){
              $rootScope.backgroundImage = WidgetHome.data.design.backgroundImage;
            }else
            {
              $rootScope.backgroundImage = "";
            }
            if (!WidgetHome.data.design.listLayout) {
              WidgetHome.data.design.listLayout = LAYOUTS.listLayouts[0].name;
            }
            if (currentListLayout != WidgetHome.data.design.listLayout && WidgetHome.view && WidgetHome.data.content.carouselImages) {
              WidgetHome.view._destroySlider();
              WidgetHome.view = null;
            }
            else {
              if (WidgetHome.view) {
                WidgetHome.view.loadItems(WidgetHome.data.content.carouselImages);
              }
            }
            currentListLayout = WidgetHome.data.design.listLayout;
            $scope.imagesUpdated = !!event.data.content;
            $scope.$digest();
            $rootScope.$digest();
          }, 0);
        };
        DataStore.onUpdate().then(null, null, onUpdateCallback);

        $scope.$on("$destroy", function () {
          DataStore.clearListener();
        });
        WidgetHome.safeHtml = function (html) {
          if (html)
            return $sce.trustAsHtml(html);
        };

        WidgetHome.openLinks = function (actionItems) {
          if (actionItems && actionItems.length) {
            var options = {};
            var callback = function (error, result) {
              if (error) {
                console.error('Error:', error);
              }
            };
            Buildfire.actionItems.list(actionItems, options, callback);
          }
        };

        WidgetHome.onAddressClick = function (long, lat) {
            if (WidgetHome.device && WidgetHome.device.platform == 'ios')
             buildfire.navigation.openWindow("maps://maps.google.com/maps?daddr=" + lat + "," + long)
          else
             buildfire.navigation.openWindow("http://maps.google.com/maps?daddr=" + lat + "," + long)
         }

      }])
})(window.angular, window.buildfire);
<commit_msg>added option , '_system' for opening maps<commit_after>'use strict';

(function (angular, buildfire) {
  angular.module('contactUsPluginWidget')
    .controller('WidgetHomeCtrl', ['$routeParams', 'Buildfire', 'DataStore', '$scope', 'TAG_NAMES', 'Location', 'LAYOUTS', '$rootScope', '$sce',
      function ($routeParams, Buildfire, DataStore, $scope, TAG_NAMES, Location, LAYOUTS, $rootScope, $sce) {
        var WidgetHome = this;
        var currentListLayout = null;
        WidgetHome.data = {};
        //create new instance of buildfire carousel viewer
        WidgetHome.view = null;
        /*declare the device width heights*/
        $rootScope.deviceHeight = window.innerHeight;
        $rootScope.deviceWidth = window.innerWidth;
        $rootScope.backgroundImage="";
        WidgetHome.device = null;
        /*initialize the device width heights*/
        function initDeviceSize(callback) {
          WidgetHome.deviceHeight = window.innerHeight;
          WidgetHome.deviceWidth = window.innerWidth;
          if (callback) {
            if (WidgetHome.deviceWidth == 0 || WidgetHome.deviceHeight == 0) {
              setTimeout(function () {
                initDeviceSize(callback);
              }, 500);
            } else {
              callback();
              if (!$scope.$$phase && !$scope.$root.$$phase) {
                $scope.$apply();
              }
            }
          }
        }

        /*crop image on the basis of width heights*/
        WidgetHome.cropImage = function (url, settings) {
          var options = {};
          if (!url) {
            return "";
          }
          else {
            if (settings.height) {
              options.height = settings.height;
            }
            if (settings.width) {
              options.width = settings.width;
            }
            return Buildfire.imageLib.cropImage(url, options);
          }
        };

        /*
         * Fetch user's data from datastore
         */
        var init = function () {
          var success = function (result) {
              WidgetHome.data = result.data;
              if (!WidgetHome.data.design)
                WidgetHome.data.design = {};
              if (!WidgetHome.data.design.listLayout) {
                WidgetHome.data.design.listLayout = LAYOUTS.listLayouts[0].name;
              }
              currentListLayout = WidgetHome.data.design.listLayout;
                if(WidgetHome.data.design.backgroundImage){
                  $rootScope.backgroundImage = WidgetHome.data.design.backgroundImage;
                }
                else
                 {
                  $rootScope.backgroundImage = "";
                 }
                var getDevice = function(error, data){
                  if(data)
                    WidgetHome.device  = data.device;
                  else
                    console.log("Error while getting the device context data", error)
                }
                buildfire.getContext(getDevice);
            }
            , error = function (err) {
              console.error('Error while getting data', err);
            };
          DataStore.get(TAG_NAMES.CONTACT_INFO).then(success, error);
        };
        init();
        $rootScope.$on("Carousel:LOADED", function () {
          if (!WidgetHome.view) {
            WidgetHome.view = new Buildfire.components.carousel.view("#carousel", []);
          }
          if (WidgetHome.data.content && WidgetHome.data.content.carouselImages) {
            WidgetHome.view.loadItems(WidgetHome.data.content.carouselImages);
          } else {
            WidgetHome.view.loadItems([]);
          }
        });

        var onUpdateCallback = function (event) {
          setTimeout(function () {
            $scope.imagesUpdated = false;
            $scope.$digest();
            if (event && event.tag === TAG_NAMES.CONTACT_INFO) {
              WidgetHome.data = event.data;
              if (!WidgetHome.data.design)
                WidgetHome.data.design = {};
              if (!WidgetHome.data.content)
                WidgetHome.data.content = {};
            }
            if(WidgetHome.data.design.backgroundImage){
              $rootScope.backgroundImage = WidgetHome.data.design.backgroundImage;
            }else
            {
              $rootScope.backgroundImage = "";
            }
            if (!WidgetHome.data.design.listLayout) {
              WidgetHome.data.design.listLayout = LAYOUTS.listLayouts[0].name;
            }
            if (currentListLayout != WidgetHome.data.design.listLayout && WidgetHome.view && WidgetHome.data.content.carouselImages) {
              WidgetHome.view._destroySlider();
              WidgetHome.view = null;
            }
            else {
              if (WidgetHome.view) {
                WidgetHome.view.loadItems(WidgetHome.data.content.carouselImages);
              }
            }
            currentListLayout = WidgetHome.data.design.listLayout;
            $scope.imagesUpdated = !!event.data.content;
            $scope.$digest();
            $rootScope.$digest();
          }, 0);
        };
        DataStore.onUpdate().then(null, null, onUpdateCallback);

        $scope.$on("$destroy", function () {
          DataStore.clearListener();
        });
        WidgetHome.safeHtml = function (html) {
          if (html)
            return $sce.trustAsHtml(html);
        };

        WidgetHome.openLinks = function (actionItems) {
          if (actionItems && actionItems.length) {
            var options = {};
            var callback = function (error, result) {
              if (error) {
                console.error('Error:', error);
              }
            };
            Buildfire.actionItems.list(actionItems, options, callback);
          }
        };

        WidgetHome.onAddressClick = function (long, lat) {
            if (WidgetHome.device && WidgetHome.device.platform == 'ios')
             buildfire.navigation.openWindow("maps://maps.google.com/maps?daddr=" + lat + "," + long, '_system');
          else
             buildfire.navigation.openWindow("http://maps.google.com/maps?daddr=" + lat + "," + long, '_system');
         }

      }])
})(window.angular, window.buildfire);
<|endoftext|>


<commit_before>import React, { PureComponent, createElement } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import omit from 'lodash.omit';
import {
  IconChevronUpSmallOutline,
  IconChevronDownSmallOutline,
  IconWarningBadgedSmallFilled,
} from '@teamleader/ui-icons';
import InputMetaPropTypes from './InputMetaPropTypes';
import FieldInputPropTypes from './FieldInputPropTypes';
import Box, { omitBoxProps, pickBoxProps } from '../box';
import Button from '../button';
import Counter from '../counter';
import { TextSmall } from '../typography';
import theme from './theme.css';

export default class Input extends PureComponent {
  static getDerivedStateFromProps(nextProps, prevState) {
    const value = nextProps.input ? nextProps.input.value : nextProps.value;
    if (value !== undefined) {
      const newValue = Input.parseValue(Input.getPropsValue(nextProps), nextProps);
      if (newValue !== prevState.value) {
        return {
          value: newValue,
        };
      }
    }

    return null;
  }

  static getPropsValue({ input, value }) {
    const finalValue = input !== undefined ? input.value : value;
    return finalValue || '';
  }

  static parseValue(value, { type, min, max, precision }) {
    return type === 'number' ? Input.toNumber(value, min, max, precision) : value;
  }

  static toNumber(number, min, max, precision) {
    let float = parseFloat(number);

    if (isNaN(float) || !isFinite(float)) {
      float = 0;
    }

    const baseExponent = Math.pow(10, precision === null ? 10 : precision);

    float = Math.min(Math.max(float, min), max);
    float = Math.round(float * baseExponent) / baseExponent;

    return float;
  }

  state = {
    value: '',
  };

  handleChange = event => {
    this.updateValue(event);
  };

  handleIncreaseValue = event => {
    this.updateStep(event, 1);
  };

  handleDecreaseValue = event => {
    this.updateStep(event, -1);
  };

  updateValue(event, rawValue, triggerOnChange = true) {
    const { input, onChange } = this.props;
    const value = Input.parseValue(rawValue || event.target.value, this.props);

    this.setState({
      value,
    });

    if (triggerOnChange) {
      if (input && input.onChange) {
        input.onChange(event, value);
      } else if (onChange) {
        onChange(event, value);
      }
    }
  }

  hasError() {
    const { meta } = this.props;
    return Boolean(meta && meta.error && meta.touched);
  }

  formatNumber(number) {
    const { min, max, precision } = this.props;

    let formattedNumber = Input.toNumber(number, min, max, precision);

    if (precision !== null) {
      formattedNumber = number.toFixed(precision);
    }

    return String(formattedNumber);
  }

  updateStep(event, n) {
    const { step } = this.props;
    const { value = 0 } = this.state;
    this.updateValue(event, value + step * n);
  }

  renderInput() {
    const { bold, max, min, step, type, ...otherProps } = this.props;
    const { value } = this.state;

    const classNames = cx(theme['input'], {
      [theme['is-bold']]: bold,
    });

    const otherPropsWithoutBoxProps = omitBoxProps(otherProps);
    const restProps = omit(otherPropsWithoutBoxProps, [
      'className',
      'connectedLeft',
      'connectedRight',
      'counter',
      'helpText',
      'icon',
      'iconPlacement',
      'input',
      'inverse',
      'meta',
      'onChange',
      'precision',
      'size',
      'spinner',
      'value',
    ]);

    const numberTypeProps = {
      max,
      min,
      step,
      value: value && this.formatNumber(value),
    };

    const props = {
      className: classNames,
      onChange: this.handleChange,
      type,
      value,
      ...restProps,
      ...(type === 'number' && numberTypeProps),
    };

    return <input {...props} />;
  }

  renderCounter() {
    if (this.props.counter) {
      return <Counter className={theme['counter']} count={this.props.counter} color="ruby" size="small" />;
    }
  }

  renderHelpText() {
    const { helpText, inverse } = this.props;

    if (helpText) {
      return (
        <TextSmall color={inverse ? 'white' : 'neutral'} marginTop={1} soft>
          {helpText}
        </TextSmall>
      );
    }
  }

  renderSpinnerControls() {
    const { disabled, readOnly, spinner, type } = this.props;

    const props = {
      disabled: disabled || readOnly,
    };

    if (type === 'number' && spinner) {
      return (

          <Button
            className={theme['spinner-up']}
            icon={<IconChevronUpSmallOutline />}
            onClick={this.handleIncreaseValue}
            {...props}
          />
          <Button
            className={theme['spinner-down']}
            icon={<IconChevronDownSmallOutline />}
            onClick={this.handleDecreaseValue}
            {...props}
          />

      );
    }
  }

  renderValidationMessage() {
    return (
      <TextSmall className={theme['validation-text']} marginTop={2} display="flex">
        <Box element="span" className={theme['validation-icon']}>
          <IconWarningBadgedSmallFilled />
        </Box>
        <Box element="span" marginLeft={1}>
          {this.props.meta.error}
        </Box>
      </TextSmall>
    );
  }

  render() {
    const {
      className,
      connectedLeft,
      connectedRight,
      counter,
      disabled,
      icon,
      iconPlacement,
      inverse,
      size,
      spinner,
      readOnly,
      type,
      ...others
    } = this.props;

    const classNames = cx(
      theme['wrapper'],
      theme[`is-${size}`],
      {
        [theme[`has-icon-${iconPlacement}`]]: icon,
        [theme['has-counter']]: counter,
        [theme['has-error']]: this.hasError(),
        [theme['has-connected-left']]: connectedLeft,
        [theme['has-connected-right']]: connectedRight,
        [theme['has-spinner']]: type === 'number' && spinner,
        [theme['is-inverse']]: inverse,
        [theme['is-disabled']]: disabled,
        [theme['is-read-only']]: readOnly,
      },
      className,
    );

    const inputWrapperClassnames = cx(theme['input-wrapper'], {
      [theme['has-error']]: this.hasError(),
    });

    const rest = pickBoxProps(others);

    return (
      <Box className={classNames} {...rest}>

          {connectedLeft}

            {icon &&
              createElement(icon, {
                className: theme['icon'],
              })}
            {this.renderInput()}
            {this.renderCounter()}
            {this.renderSpinnerControls()}

          {connectedRight}

        {this.hasError() ? this.renderValidationMessage() : this.renderHelpText()}
      </Box>
    );
  }
}

Input.propTypes = {
  autoFocus: PropTypes.bool,
  /** Boolean indicating whether the input text should render in bold. */
  bold: PropTypes.bool,
  /** Sets a class name for the wrapper to give custom styles. */
  className: PropTypes.string,
  connectedLeft: PropTypes.element,
  connectedRight: PropTypes.element,
  /** The number to render as a counter inside the input. */
  counter: PropTypes.number,
  /** Boolean indicating whether the input should render as disabled. */
  disabled: PropTypes.bool,
  /** The text string to use as help text below the input. */
  helpText: PropTypes.string,
  /** The icon displayed inside the input. */
  icon: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
  /** The position of the icon inside the input. */
  iconPlacement: PropTypes.oneOf(['left', 'right']),
  /** Boolean indicating whether the input should render as inverse. */
  inverse: PropTypes.bool,
  max: PropTypes.number,
  min: PropTypes.number,
  /** Object to provide meta information for redux forms. */
  meta: InputMetaPropTypes,
  /** Boolean indicating whether to number type input should render spinner controls */
  spinner: PropTypes.bool,
  /** Object to provide input information for redux forms. */
  input: FieldInputPropTypes,
  /** Callback function that is fired when the component's value changes. */
  onChange: PropTypes.func,
  precision: PropTypes.number,
  /** Boolean indicating whether the input should render as read only. */
  readOnly: PropTypes.bool,
  /** Size of the input element. */
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  /** Limit increment value for numeric inputs. */
  step: PropTypes.number,
  /** Type of the input element. It can be a valid HTML5 input type. */
  type: PropTypes.string,
  /** Current value of the input element. */
  value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};

Input.defaultProps = {
  iconPlacement: 'left',
  inverse: false,
  disabled: false,
  precision: null,
  min: Number.MIN_SAFE_INTEGER,
  max: Number.MAX_SAFE_INTEGER,
  readOnly: false,
  size: 'medium',
  spinner: true,
  step: 1,
};
<commit_msg>Remove the 'autoFocus' prop since it's in 'restProps' now<commit_after>import React, { PureComponent, createElement } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import omit from 'lodash.omit';
import {
  IconChevronUpSmallOutline,
  IconChevronDownSmallOutline,
  IconWarningBadgedSmallFilled,
} from '@teamleader/ui-icons';
import InputMetaPropTypes from './InputMetaPropTypes';
import FieldInputPropTypes from './FieldInputPropTypes';
import Box, { omitBoxProps, pickBoxProps } from '../box';
import Button from '../button';
import Counter from '../counter';
import { TextSmall } from '../typography';
import theme from './theme.css';

export default class Input extends PureComponent {
  static getDerivedStateFromProps(nextProps, prevState) {
    const value = nextProps.input ? nextProps.input.value : nextProps.value;
    if (value !== undefined) {
      const newValue = Input.parseValue(Input.getPropsValue(nextProps), nextProps);
      if (newValue !== prevState.value) {
        return {
          value: newValue,
        };
      }
    }

    return null;
  }

  static getPropsValue({ input, value }) {
    const finalValue = input !== undefined ? input.value : value;
    return finalValue || '';
  }

  static parseValue(value, { type, min, max, precision }) {
    return type === 'number' ? Input.toNumber(value, min, max, precision) : value;
  }

  static toNumber(number, min, max, precision) {
    let float = parseFloat(number);

    if (isNaN(float) || !isFinite(float)) {
      float = 0;
    }

    const baseExponent = Math.pow(10, precision === null ? 10 : precision);

    float = Math.min(Math.max(float, min), max);
    float = Math.round(float * baseExponent) / baseExponent;

    return float;
  }

  state = {
    value: '',
  };

  handleChange = event => {
    this.updateValue(event);
  };

  handleIncreaseValue = event => {
    this.updateStep(event, 1);
  };

  handleDecreaseValue = event => {
    this.updateStep(event, -1);
  };

  updateValue(event, rawValue, triggerOnChange = true) {
    const { input, onChange } = this.props;
    const value = Input.parseValue(rawValue || event.target.value, this.props);

    this.setState({
      value,
    });

    if (triggerOnChange) {
      if (input && input.onChange) {
        input.onChange(event, value);
      } else if (onChange) {
        onChange(event, value);
      }
    }
  }

  hasError() {
    const { meta } = this.props;
    return Boolean(meta && meta.error && meta.touched);
  }

  formatNumber(number) {
    const { min, max, precision } = this.props;

    let formattedNumber = Input.toNumber(number, min, max, precision);

    if (precision !== null) {
      formattedNumber = number.toFixed(precision);
    }

    return String(formattedNumber);
  }

  updateStep(event, n) {
    const { step } = this.props;
    const { value = 0 } = this.state;
    this.updateValue(event, value + step * n);
  }

  renderInput() {
    const { bold, max, min, step, type, ...otherProps } = this.props;
    const { value } = this.state;

    const classNames = cx(theme['input'], {
      [theme['is-bold']]: bold,
    });

    const otherPropsWithoutBoxProps = omitBoxProps(otherProps);
    const restProps = omit(otherPropsWithoutBoxProps, [
      'className',
      'connectedLeft',
      'connectedRight',
      'counter',
      'helpText',
      'icon',
      'iconPlacement',
      'input',
      'inverse',
      'meta',
      'onChange',
      'precision',
      'size',
      'spinner',
      'value',
    ]);

    const numberTypeProps = {
      max,
      min,
      step,
      value: value && this.formatNumber(value),
    };

    const props = {
      className: classNames,
      onChange: this.handleChange,
      type,
      value,
      ...restProps,
      ...(type === 'number' && numberTypeProps),
    };

    return <input {...props} />;
  }

  renderCounter() {
    if (this.props.counter) {
      return <Counter className={theme['counter']} count={this.props.counter} color="ruby" size="small" />;
    }
  }

  renderHelpText() {
    const { helpText, inverse } = this.props;

    if (helpText) {
      return (
        <TextSmall color={inverse ? 'white' : 'neutral'} marginTop={1} soft>
          {helpText}
        </TextSmall>
      );
    }
  }

  renderSpinnerControls() {
    const { disabled, readOnly, spinner, type } = this.props;

    const props = {
      disabled: disabled || readOnly,
    };

    if (type === 'number' && spinner) {
      return (

          <Button
            className={theme['spinner-up']}
            icon={<IconChevronUpSmallOutline />}
            onClick={this.handleIncreaseValue}
            {...props}
          />
          <Button
            className={theme['spinner-down']}
            icon={<IconChevronDownSmallOutline />}
            onClick={this.handleDecreaseValue}
            {...props}
          />

      );
    }
  }

  renderValidationMessage() {
    return (
      <TextSmall className={theme['validation-text']} marginTop={2} display="flex">
        <Box element="span" className={theme['validation-icon']}>
          <IconWarningBadgedSmallFilled />
        </Box>
        <Box element="span" marginLeft={1}>
          {this.props.meta.error}
        </Box>
      </TextSmall>
    );
  }

  render() {
    const {
      className,
      connectedLeft,
      connectedRight,
      counter,
      disabled,
      icon,
      iconPlacement,
      inverse,
      size,
      spinner,
      readOnly,
      type,
      ...others
    } = this.props;

    const classNames = cx(
      theme['wrapper'],
      theme[`is-${size}`],
      {
        [theme[`has-icon-${iconPlacement}`]]: icon,
        [theme['has-counter']]: counter,
        [theme['has-error']]: this.hasError(),
        [theme['has-connected-left']]: connectedLeft,
        [theme['has-connected-right']]: connectedRight,
        [theme['has-spinner']]: type === 'number' && spinner,
        [theme['is-inverse']]: inverse,
        [theme['is-disabled']]: disabled,
        [theme['is-read-only']]: readOnly,
      },
      className,
    );

    const inputWrapperClassnames = cx(theme['input-wrapper'], {
      [theme['has-error']]: this.hasError(),
    });

    const rest = pickBoxProps(others);

    return (
      <Box className={classNames} {...rest}>

          {connectedLeft}

            {icon &&
              createElement(icon, {
                className: theme['icon'],
              })}
            {this.renderInput()}
            {this.renderCounter()}
            {this.renderSpinnerControls()}

          {connectedRight}

        {this.hasError() ? this.renderValidationMessage() : this.renderHelpText()}
      </Box>
    );
  }
}

Input.propTypes = {
  /** Boolean indicating whether the input text should render in bold. */
  bold: PropTypes.bool,
  /** Sets a class name for the wrapper to give custom styles. */
  className: PropTypes.string,
  connectedLeft: PropTypes.element,
  connectedRight: PropTypes.element,
  /** The number to render as a counter inside the input. */
  counter: PropTypes.number,
  /** Boolean indicating whether the input should render as disabled. */
  disabled: PropTypes.bool,
  /** The text string to use as help text below the input. */
  helpText: PropTypes.string,
  /** The icon displayed inside the input. */
  icon: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
  /** The position of the icon inside the input. */
  iconPlacement: PropTypes.oneOf(['left', 'right']),
  /** Boolean indicating whether the input should render as inverse. */
  inverse: PropTypes.bool,
  max: PropTypes.number,
  min: PropTypes.number,
  /** Object to provide meta information for redux forms. */
  meta: InputMetaPropTypes,
  /** Boolean indicating whether to number type input should render spinner controls */
  spinner: PropTypes.bool,
  /** Object to provide input information for redux forms. */
  input: FieldInputPropTypes,
  /** Callback function that is fired when the component's value changes. */
  onChange: PropTypes.func,
  precision: PropTypes.number,
  /** Boolean indicating whether the input should render as read only. */
  readOnly: PropTypes.bool,
  /** Size of the input element. */
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  /** Limit increment value for numeric inputs. */
  step: PropTypes.number,
  /** Type of the input element. It can be a valid HTML5 input type. */
  type: PropTypes.string,
  /** Current value of the input element. */
  value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};

Input.defaultProps = {
  iconPlacement: 'left',
  inverse: false,
  disabled: false,
  precision: null,
  min: Number.MIN_SAFE_INTEGER,
  max: Number.MAX_SAFE_INTEGER,
  readOnly: false,
  size: 'medium',
  spinner: true,
  step: 1,
};
<|endoftext|>


<commit_before>import React, { Fragment, PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box from '../box';
import { TextBody, TextDisplay, TextSmall } from '../typography';
import theme from './theme.css';
import cx from 'classnames';

export default class Label extends PureComponent {
  render() {
    const {
      children,
      connectedLeft,
      connectedRight,
      className,
      inverse,
      helpText,
      required,
      size,
      ...others
    } = this.props;

    const childProps = {
      inverse,
      marginTop: 1,
      size,
    };

    const classNames = cx(
      theme['label'],
      {
        [theme['is-inverse']]: inverse,
      },
      className,
    );

    const Element = size === 'large' ? TextDisplay : TextBody;

    return (
      <Box element="label" marginBottom={3} className={classNames} {...others}>
        {React.Children.map(children, child => {
          if (typeof child !== 'string') {
            return React.cloneElement(child, childProps);
          }

          return (
            <Fragment>
              {connectedLeft && (
                <Box element="span" marginRight={1}>
                  {connectedLeft}
                </Box>
              )}
              <Element color={inverse ? 'white' : 'teal'} element="span">
                {child}
              </Element>
              {!required && (
                <TextSmall
                  color={inverse ? 'teal' : 'neutral'}
                  element="span"
                  marginLeft={1}
                  tint={inverse ? 'light' : 'darkest'}
                >
                  {helpText}
                </TextSmall>
              )}
              {connectedRight && (
                <Box element="span" marginLeft={1}>
                  {connectedRight}
                </Box>
              )}
            </Fragment>
          );
        })}
      </Box>
    );
  }
}

Label.propTypes = {
  className: PropTypes.string,
  children: PropTypes.oneOfType([PropTypes.element, PropTypes.string, PropTypes.array]),
  connectedLeft: PropTypes.element,
  connectedRight: PropTypes.element,
  inverse: PropTypes.bool,
  helpText: PropTypes.string,
  required: PropTypes.bool,
  size: PropTypes.oneOf(['small', 'medium', 'large']),
};

Label.defaultProps = {
  inverse: false,
  helpText: 'Optional',
  required: false,
  size: 'medium',
};
<commit_msg>Label: update label text color<commit_after>import React, { Fragment, PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box from '../box';
import { TextBody, TextDisplay, TextSmall } from '../typography';
import theme from './theme.css';
import cx from 'classnames';

export default class Label extends PureComponent {
  render() {
    const {
      children,
      connectedLeft,
      connectedRight,
      className,
      inverse,
      helpText,
      required,
      size,
      ...others
    } = this.props;

    const childProps = {
      inverse,
      marginTop: 1,
      size,
    };

    const classNames = cx(
      theme['label'],
      {
        [theme['is-inverse']]: inverse,
      },
      className,
    );

    const Element = size === 'large' ? TextDisplay : TextBody;

    return (
      <Box element="label" marginBottom={3} className={classNames} {...others}>
        {React.Children.map(children, child => {
          if (typeof child !== 'string') {
            return React.cloneElement(child, childProps);
          }

          return (
            <Fragment>
              {connectedLeft && (
                <Box element="span" marginRight={1}>
                  {connectedLeft}
                </Box>
              )}
              <Element color={inverse ? 'neutral' : 'teal'} tint={inverse ? 'lightest' : 'darkest'} element="span">
                {child}
              </Element>
              {!required && (
                <TextSmall
                  color={inverse ? 'teal' : 'neutral'}
                  element="span"
                  marginLeft={1}
                  tint={inverse ? 'light' : 'darkest'}
                >
                  {helpText}
                </TextSmall>
              )}
              {connectedRight && (
                <Box element="span" marginLeft={1}>
                  {connectedRight}
                </Box>
              )}
            </Fragment>
          );
        })}
      </Box>
    );
  }
}

Label.propTypes = {
  className: PropTypes.string,
  children: PropTypes.oneOfType([PropTypes.element, PropTypes.string, PropTypes.array]),
  connectedLeft: PropTypes.element,
  connectedRight: PropTypes.element,
  inverse: PropTypes.bool,
  helpText: PropTypes.string,
  required: PropTypes.bool,
  size: PropTypes.oneOf(['small', 'medium', 'large']),
};

Label.defaultProps = {
  inverse: false,
  helpText: 'Optional',
  required: false,
  size: 'medium',
};
<|endoftext|>


<commit_before>import PropTypes from 'prop-types'

const List = ({ selected, members }) => {
  const item = (selectedMember) => {
    const m = members[selectedMember]
    return (

{m.name}

    )
  }

  return (

      {selected.map(item)}

  )
}

List.propTypes = {
  selected: PropTypes.array.isRequired,
  members: PropTypes.object.isRequired
}

export default List
<commit_msg>Fix typo.<commit_after>import PropTypes from 'prop-types'

const List = ({ selected, members }) => {
  const item = (selectedMember) => {
    const m = members[selectedMember]
    return (

{m.name}

    )
  }

  return (

      {selected.map(item)}

  )
}

List.propTypes = {
  selected: PropTypes.array.isRequired,
  members: PropTypes.object.isRequired
}

export default List
<|endoftext|>


<commit_before>/**
 * Created by myth on 2016-08-14.
 */

import React from 'react';

import { API_SLACK_URL } from '../../common/constants';

require('es6-promise').polyfill();
require('isomorphic-fetch');

const Slack = React.createClass({
  getInitialState: function () {
    return {
      triggered: false,
      error: null,
      email: ''
    }
  },

  requestInvitationEmail: function (event) {
    var self = this;

    if (self.state.email.length < 5 || self.state.email.indexOf('@') < 0) {
      this.setState(Object.assign({}, this.state, { error: 'Du må skrive inn en gyldig epostaddresse!' }));
      return false;
    }

    if (self.state.triggered) {
      this.setState(Object.assign({}, this.state, { error: 'Du har allerede forespurt en invitasjon!' }));
      return false;
    }

    fetch(API_SLACK_URL, {
      body: { email: self.state.email },
      headers: {
        Accept: 'application/json'
      },
      method: 'POST',
      mode: 'cors'
    })
    .then((response) => {
      return response.json();
    })
    .then((data) => {
      console.log(data);
      this.setState(Object.assign({}, this.state, { triggered: true }))
    })
    .catch((error) => {
      console.error(error);
      this.setState(Object.assign({}, this.state, { error: error }))
    })
  },

  handleChange: function (event) {
    this.setState(Object.assign({}, this.state, { email: event.target.value }));
  },

  render: function () {
    var self = this;

    return (

Chat med oss på Slack!

Linjeforeningens uformelle chatteplattform er Slack.
          Dersom du ikke har fått stud.ntnu.no-eposten din
        enda kan du be om en invitasjon til din private e-postaddresse.
          Du vil da motta en link for å koble til slack-teamet vårt.

        E-post

          <input type="text"
                 id="slack-email-inputfield"
                 value={self.state.email}
                 placeholder="Skriv inn din E-postaddresse..."
                 onChange={self.handleChange} />
          <button id="slack-submit-button"
                  onClick={self.requestInvitationEmail}
                  disabled={self.state.triggered}>
            Send
          </button>

{self.state.error}

Har du allerede en stud.ntnu.no-epost kan du registrere deg direkte på
           onlinentnu.slack.com

    )
  }
});

export default Slack;<commit_msg>Add key listener for enter key when slack invite email field is active, submitting the request.<commit_after>/**
 * Created by myth on 2016-08-14.
 */

import React from 'react';

import { API_SLACK_URL } from '../../common/constants';

require('es6-promise').polyfill();
require('isomorphic-fetch');

const Slack = React.createClass({
  getInitialState: function () {
    return {
      triggered: false,
      error: null,
      email: ''
    }
  },

  requestInvitationEmail: function () {
    var self = this;

    if (self.state.email.length < 5 || self.state.email.indexOf('@') < 0) {
      this.setState(Object.assign({}, this.state, { error: 'Du må skrive inn en gyldig epostaddresse!' }));
      return false;
    }

    if (self.state.triggered) {
      this.setState(Object.assign({}, this.state, { error: 'Du har allerede forespurt en invitasjon!' }));
      return false;
    }

    fetch(API_SLACK_URL, {
      body: { email: self.state.email },
      headers: {
        Accept: 'application/json'
      },
      method: 'POST',
      mode: 'cors'
    })
    .then((response) => {
      return response.json();
    })
    .then((data) => {
      console.log(data);
      this.setState(Object.assign({}, this.state, { triggered: true }))
    })
    .catch((error) => {
      console.error(error);
      this.setState(Object.assign({}, this.state, { error: error }))
    })
  },

  handleChange: function (event) {
    this.setState(Object.assign({}, this.state, { email: event.target.value }));
  },

  handleKeyPress: function (event) {
    if (event.key === 'Enter') this.requestInvitationEmail();
  },

  render: function () {
    var self = this;

    return (

Chat med oss på Slack!

Linjeforeningens uformelle chatteplattform er Slack.
          Dersom du ikke har fått stud.ntnu.no-eposten din
        enda kan du be om en invitasjon til din private e-postaddresse.
          Du vil da motta en link for å koble til slack-teamet vårt.

        E-post

          <input type="text"
                 id="slack-email-inputfield"
                 value={self.state.email}
                 placeholder="Skriv inn din E-postaddresse..."
                 onChange={self.handleChange}
                 onKeyPress={self.handleKeyPress}/>
          <button id="slack-submit-button"
                  onClick={self.requestInvitationEmail}
                  disabled={self.state.triggered}>
            Send
          </button>

{self.state.error}

Har du allerede en stud.ntnu.no-epost kan du registrere deg direkte på
           onlinentnu.slack.com

    )
  }
});

export default Slack;<|endoftext|>


<commit_before><commit_msg>Added class name to axis<commit_after><|endoftext|>


<commit_before>var option_lists = [
	'antimicrobial',
	'antimicrobial_route',
	'condition',
	'destination',
	'microbiology_organism',
	'patient_category',
	'travel_reason',
];

var microbiology_test_list = [
	'Broncheoalveolar lavage MC&S',
	'Blood Culture',
	'CSF AFB microscopy & TB culture',
	'CSF MC&S',
	'Fluid MC&S',
	'Lymph Node MC&S',
	'Pleural MC&S',
	'Sputum AFB microscopy & TB culture',
	'Sputum MC&S',
	'Stool MC&S',
	'Stool OCP',
	'Throat Swab MC&S',
	'Tissue AFB microscopy & TB culture',
	'Tissue MC&S',
	'Urine AFB microscopy & TB culture',
	'Urine MC&S',
	'Wound swab MC&S',
	'CMV Serology',
	'Dengue Serology',
	'Hepatitis A Serology',
	'Hepatitis E Serology',
	'Measles Serology',
	'Rubella Serology',
	'Toxoplasmosis Serology',
	'VZV Serology',
	'Brucella Serology',
	'EBV Serology',
	'HIV',
	'Hepatitis B Serology',
	'Syphilis Serology',
	'Cryptococcal antigen',
	'Dengue PCR',
	'JC Virus PCR',
	'MRSA PCR',
	'Rickettsia PCR',
	'Scrub Typhus PCR',
	'Borrleia Screening Serology',
	'Brorleia Reference Serology',
	'Viral Haemorrhagic Fever PCR',
	'Amoebic Serology',
	'Cystercicosis Serology',
	'Fasciola Serology',
	'Filaria Serology',
	'Hydatid Serology',
	'Strongyloides Serology',
	'Toxcocara Serology',
	'Trypanosomiasis brucei Serology',
	'Trypanosomiasis cruzi serology',
	'Hepatitis C Serology',
	'Hepatitis D Serology',
	'HHV-6 Serology',
	'HHV-7 Serology',
	'HTLV Serology',
	'CMV Viral Load',
	'EBV Viral Load ',
	'HBV Viral Load',
	'HCV Viral Load',
	'HHV-6 Viral Load',
	'HHV-7 Viral Load',
	'HHV-8 Viral Load',
	'HIV Viral Load',
	'Measles PCR',
	'VZV Viral Load',
	'Babesia Film',
	'Malaria Film',
	'Microfilarial Film',
	'Swab PCR',
	'C. difficile',
	'Leishmaniasis PCR',
	'CSF PCR',
	'Respiratory Virus PCR',
	'Stool PCR',
	'Stool Parasitology PCR',
	'Other',
];

function clone(obj) {
	if (typeof obj == 'object') {
		return $.extend(true, {}, obj);
	} else {
		return obj;
	}
};

function getKeys(obj) {
    var keys = [];
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
                    keys.push(key);
        }
    }
    return keys;
}

var app = angular.module('opalApp', ['$strap.directives']);

// See http://stackoverflow.com/questions/8302928/angularjs-with-django-conflicting-template-tags
app.config(function($interpolateProvider) {
	$interpolateProvider.startSymbol('[[');
	$interpolateProvider.endSymbol(']]');
});

app.controller('TableCtrl', function($scope, $http) {
	var editing = false;
	var deleting = false;

	$scope.rows = [];

	$scope.rix = 0; // row index
	$scope.cix = 0; // column index
	$scope.iix = 0; // item index

	$scope.mouseRix = -1; // index of row mouse is currently over
	$scope.mouseCix = -1; // index of column mouse is currently over

	$http.get('schema/').success(function(columns) {
		$scope.columns = columns;

		$http.get('patient/').success(function(rows) {
			for (var rix = 0; rix < rows.length; rix++) {
				for (var cix = 0; cix < $scope.columns.length; cix++) {
					if (!$scope.columns[cix].single) {
						rows[rix][$scope.columns[cix].name].push({patient: rows[rix].id});
					}
				}
			}
			$scope.rows = rows;
		});
	})

	$scope.getCix = function(name) {
		for (var cix = 0; cix < $scope.columns.length; cix++) {
			if ($scope.columns[cix].name == name) {
				return cix;
			}
		}
		throw 'Unexpected column name: ' + name
	};

	for (var i = 0; i < option_lists.length; i++) {
		(function(option) {
			$http.get('options/' + option + '_list/').success(function(data) {
				$scope[option + '_list'] = [];
				$scope[option + '_synonyms'] = {};
				for (var j = 0; j < data.length; j++) {
					$scope[option + '_list'].push(data[j][0]);
					$scope[option + '_synonyms'][data[j][0]] = data[j][1];
				};
			});
		})(option_lists[i]);
	}

	$scope.getSynonymn = function(option, term) {
		var synonyms = $scope[option + '_synonyms'];
		if (synonyms !== undefined) {
			// The list of synonyms may not have loaded yet.
			// This would be a problem if we serve non-canonical
			// data and try an canonicalise before the synonyms are
			// loaded.  I think we shouldn't serve non-canonical
			// data but there might be a good reason to.
			return synonyms[term] || term;
		} else {
			return term;
		}
	};

	function startEdit() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var columnName = $scope.columns[cix].name;

		editing = true;
		if ($scope.columns[cix]['single']) {
			$scope.editing = clone($scope.rows[rix][columnName]);
		} else {
			$scope.editing = clone($scope.rows[rix][columnName][iix]);
		}
		$('#' + columnName + '-modal').modal();
		$('#' + columnName + '-modal').find('input,textarea').first().focus();
	};

	function startDelete() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var column = $scope.columns[cix];

		if (column.single) {
			return;
		}

		if ($scope.rows[rix][column.name].length == 1) {
			return;
		}

		deleting = true;
		$('#delete-confirmation').modal();
		$('#delete-confirmation').find('.btn-primary').focus();
	};

	function clearModal(columnName) {
		$('#' + columnName + '-modal').modal('hide')

		// See https://github.com/openhealthcare/opal/issues/28
		document.activeElement.blur();
	};

	$scope.addRecord = function() {
		var newRecord = {};
		var column;

		$http.post('patient/').success(function(patient) {
			newRecord.id = patient.id;
			for (var cix = 0; cix < $scope.columns.length; cix++) {
				column = $scope.columns[cix];
				if (column.single) {
					newRecord[column.name] = {patient: patient.id};
				} else {
					newRecord[column.name] = [{patient: patient.id}];
				}
			}

			$scope.rows.push(newRecord);
			$scope.selectItem($scope.rows.length - 1, 0, 0);
			startEdit();
		});
	};

	$scope.saveEdit = function() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var columnName = $scope.columns[cix].name;
		var url;

		clearModal(columnName);
		editing = false;

		if ($scope.columns[cix]['single']) {
			$scope.rows[rix][columnName] = clone($scope.editing);
			url = 'patient/' + $scope.rows[rix].id + '/' + columnName + '/';
			$http.put(url, $scope.editing);
		} else {
			$scope.rows[rix][columnName][iix] = clone($scope.editing);
			if (typeof($scope.editing.id) == 'undefined') {
				url = 'patient/' + $scope.rows[rix].id + '/' + columnName + '/';
				$http.post(url, $scope.editing);
			} else {
				url = 'patient/' + $scope.rows[rix].id + '/' + columnName + '/' + $scope.editing.id + '/';
				$http.put(url, $scope.editing);
			}
			if (iix + 1 == getNumItems(rix, cix)) {
				$scope.rows[rix][columnName].push({patient: $scope.rows[rix].id});
			}
		}
	};

	$scope.cancelEdit = function() {
		var cix = $scope.cix;
		var columnName = $scope.columns[cix].name;

		clearModal(columnName);
		editing = false;
	};

	$scope.doDelete = function() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var column = $scope.columns[cix];

		$scope.rows[rix][column.name].splice(iix, 1);
		deleting = false;
	};

	$scope.cancelDelete = function() {
		deleting = false;
	};

	$scope.selectItem = function(rix, cix, iix) {
		$scope.rix = rix;
		$scope.cix = cix;
		$scope.iix = iix;
	}

	$scope.editItem = function(rix, cix, iix) {
		$scope.selectItem(rix, cix, iix);
		startEdit();
	}

	$scope.mouseEnter = function(rix, columnName) {
		$scope.mouseRix = rix;
		$scope.mouseCix = $scope.getCix(columnName);
	}

	$scope.mouseLeave = function() {
		$scope.mouseRix = -1;
		$scope.mouseCix = -1;
	}

	function getNumItems(rix, cix) {
		var column = $scope.columns[cix];
		if (column.single) {
			return 1;
		} else {
			return $scope.rows[rix][column.name].length;
		}
	};

	$scope.keypress = function(e) {
		if (editing) {
			switch (e.keyCode) {
				case 27: // escape
					$scope.cancelEdit();
					break;
			}
		} else if (deleting) {
			// ignore all keystrokes here
		} else {
			switch (e.keyCode) {
				case 37: // left
				case 72: // h
					goLeft();
					break;
				case 39: // right
				case 76: // l
					goRight();
					break;
				case 38: // up
				case 75: // k
					goUp();
					break;
				case 40: // down
				case 74: // j
					goDown();
					break;
				case 13: // enter
					startEdit();
					break;
				case 46: // delete
					startDelete();
					break;
			}
		}
	}

	function goLeft() {
		if ($scope.cix > 0) {
			$scope.cix--;
			$scope.iix = 0;
		}
	}

	function goRight() {
		if ($scope.cix < $scope.columns.length - 1) {
			$scope.cix++;
			$scope.iix = 0;
		}
	}

	function goUp() {
		if ($scope.iix > 0) {
			$scope.iix--;
		} else {
			if ($scope.rix > 0) {
				$scope.rix--;
				$scope.iix = getNumItems($scope.rix, $scope.cix) - 1;
			}
		}
	}

	function goDown() {
		if ($scope.iix < getNumItems($scope.rix, $scope.cix) - 1) {
			$scope.iix++;
		} else {
			if ($scope.rix < $scope.rows.length - 1) {
				$scope.rix++;
				$scope.iix = 0;
			}
		}
	}
});
<commit_msg>Allow items to be deleted via backspace<commit_after>var option_lists = [
	'antimicrobial',
	'antimicrobial_route',
	'condition',
	'destination',
	'microbiology_organism',
	'patient_category',
	'travel_reason',
];

var microbiology_test_list = [
	'Broncheoalveolar lavage MC&S',
	'Blood Culture',
	'CSF AFB microscopy & TB culture',
	'CSF MC&S',
	'Fluid MC&S',
	'Lymph Node MC&S',
	'Pleural MC&S',
	'Sputum AFB microscopy & TB culture',
	'Sputum MC&S',
	'Stool MC&S',
	'Stool OCP',
	'Throat Swab MC&S',
	'Tissue AFB microscopy & TB culture',
	'Tissue MC&S',
	'Urine AFB microscopy & TB culture',
	'Urine MC&S',
	'Wound swab MC&S',
	'CMV Serology',
	'Dengue Serology',
	'Hepatitis A Serology',
	'Hepatitis E Serology',
	'Measles Serology',
	'Rubella Serology',
	'Toxoplasmosis Serology',
	'VZV Serology',
	'Brucella Serology',
	'EBV Serology',
	'HIV',
	'Hepatitis B Serology',
	'Syphilis Serology',
	'Cryptococcal antigen',
	'Dengue PCR',
	'JC Virus PCR',
	'MRSA PCR',
	'Rickettsia PCR',
	'Scrub Typhus PCR',
	'Borrleia Screening Serology',
	'Brorleia Reference Serology',
	'Viral Haemorrhagic Fever PCR',
	'Amoebic Serology',
	'Cystercicosis Serology',
	'Fasciola Serology',
	'Filaria Serology',
	'Hydatid Serology',
	'Strongyloides Serology',
	'Toxcocara Serology',
	'Trypanosomiasis brucei Serology',
	'Trypanosomiasis cruzi serology',
	'Hepatitis C Serology',
	'Hepatitis D Serology',
	'HHV-6 Serology',
	'HHV-7 Serology',
	'HTLV Serology',
	'CMV Viral Load',
	'EBV Viral Load ',
	'HBV Viral Load',
	'HCV Viral Load',
	'HHV-6 Viral Load',
	'HHV-7 Viral Load',
	'HHV-8 Viral Load',
	'HIV Viral Load',
	'Measles PCR',
	'VZV Viral Load',
	'Babesia Film',
	'Malaria Film',
	'Microfilarial Film',
	'Swab PCR',
	'C. difficile',
	'Leishmaniasis PCR',
	'CSF PCR',
	'Respiratory Virus PCR',
	'Stool PCR',
	'Stool Parasitology PCR',
	'Other',
];

function clone(obj) {
	if (typeof obj == 'object') {
		return $.extend(true, {}, obj);
	} else {
		return obj;
	}
};

function getKeys(obj) {
    var keys = [];
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
                    keys.push(key);
        }
    }
    return keys;
}

var app = angular.module('opalApp', ['$strap.directives']);

// See http://stackoverflow.com/questions/8302928/angularjs-with-django-conflicting-template-tags
app.config(function($interpolateProvider) {
	$interpolateProvider.startSymbol('[[');
	$interpolateProvider.endSymbol(']]');
});

app.controller('TableCtrl', function($scope, $http) {
	var editing = false;
	var deleting = false;

	$scope.rows = [];

	$scope.rix = 0; // row index
	$scope.cix = 0; // column index
	$scope.iix = 0; // item index

	$scope.mouseRix = -1; // index of row mouse is currently over
	$scope.mouseCix = -1; // index of column mouse is currently over

	$http.get('schema/').success(function(columns) {
		$scope.columns = columns;

		$http.get('patient/').success(function(rows) {
			for (var rix = 0; rix < rows.length; rix++) {
				for (var cix = 0; cix < $scope.columns.length; cix++) {
					if (!$scope.columns[cix].single) {
						rows[rix][$scope.columns[cix].name].push({patient: rows[rix].id});
					}
				}
			}
			$scope.rows = rows;
		});
	})

	$scope.getCix = function(name) {
		for (var cix = 0; cix < $scope.columns.length; cix++) {
			if ($scope.columns[cix].name == name) {
				return cix;
			}
		}
		throw 'Unexpected column name: ' + name
	};

	for (var i = 0; i < option_lists.length; i++) {
		(function(option) {
			$http.get('options/' + option + '_list/').success(function(data) {
				$scope[option + '_list'] = [];
				$scope[option + '_synonyms'] = {};
				for (var j = 0; j < data.length; j++) {
					$scope[option + '_list'].push(data[j][0]);
					$scope[option + '_synonyms'][data[j][0]] = data[j][1];
				};
			});
		})(option_lists[i]);
	}

	$scope.getSynonymn = function(option, term) {
		var synonyms = $scope[option + '_synonyms'];
		if (synonyms !== undefined) {
			// The list of synonyms may not have loaded yet.
			// This would be a problem if we serve non-canonical
			// data and try an canonicalise before the synonyms are
			// loaded.  I think we shouldn't serve non-canonical
			// data but there might be a good reason to.
			return synonyms[term] || term;
		} else {
			return term;
		}
	};

	function startEdit() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var columnName = $scope.columns[cix].name;

		editing = true;
		if ($scope.columns[cix]['single']) {
			$scope.editing = clone($scope.rows[rix][columnName]);
		} else {
			$scope.editing = clone($scope.rows[rix][columnName][iix]);
		}
		$('#' + columnName + '-modal').modal();
		$('#' + columnName + '-modal').find('input,textarea').first().focus();
	};

	function startDelete() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var column = $scope.columns[cix];

		if (column.single) {
			return;
		}

		if ($scope.rows[rix][column.name].length == 1) {
			return;
		}

		deleting = true;
		$('#delete-confirmation').modal();
		$('#delete-confirmation').find('.btn-primary').focus();
	};

	function clearModal(columnName) {
		$('#' + columnName + '-modal').modal('hide')

		// See https://github.com/openhealthcare/opal/issues/28
		document.activeElement.blur();
	};

	$scope.addRecord = function() {
		var newRecord = {};
		var column;

		$http.post('patient/').success(function(patient) {
			newRecord.id = patient.id;
			for (var cix = 0; cix < $scope.columns.length; cix++) {
				column = $scope.columns[cix];
				if (column.single) {
					newRecord[column.name] = {patient: patient.id};
				} else {
					newRecord[column.name] = [{patient: patient.id}];
				}
			}

			$scope.rows.push(newRecord);
			$scope.selectItem($scope.rows.length - 1, 0, 0);
			startEdit();
		});
	};

	$scope.saveEdit = function() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var columnName = $scope.columns[cix].name;
		var url;

		clearModal(columnName);
		editing = false;

		if ($scope.columns[cix]['single']) {
			$scope.rows[rix][columnName] = clone($scope.editing);
			url = 'patient/' + $scope.rows[rix].id + '/' + columnName + '/';
			$http.put(url, $scope.editing);
		} else {
			$scope.rows[rix][columnName][iix] = clone($scope.editing);
			if (typeof($scope.editing.id) == 'undefined') {
				url = 'patient/' + $scope.rows[rix].id + '/' + columnName + '/';
				$http.post(url, $scope.editing);
			} else {
				url = 'patient/' + $scope.rows[rix].id + '/' + columnName + '/' + $scope.editing.id + '/';
				$http.put(url, $scope.editing);
			}
			if (iix + 1 == getNumItems(rix, cix)) {
				$scope.rows[rix][columnName].push({patient: $scope.rows[rix].id});
			}
		}
	};

	$scope.cancelEdit = function() {
		var cix = $scope.cix;
		var columnName = $scope.columns[cix].name;

		clearModal(columnName);
		editing = false;
	};

	$scope.doDelete = function() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var column = $scope.columns[cix];

		$scope.rows[rix][column.name].splice(iix, 1);
		deleting = false;
	};

	$scope.cancelDelete = function() {
		deleting = false;
	};

	$scope.selectItem = function(rix, cix, iix) {
		$scope.rix = rix;
		$scope.cix = cix;
		$scope.iix = iix;
	}

	$scope.editItem = function(rix, cix, iix) {
		$scope.selectItem(rix, cix, iix);
		startEdit();
	}

	$scope.mouseEnter = function(rix, columnName) {
		$scope.mouseRix = rix;
		$scope.mouseCix = $scope.getCix(columnName);
	}

	$scope.mouseLeave = function() {
		$scope.mouseRix = -1;
		$scope.mouseCix = -1;
	}

	function getNumItems(rix, cix) {
		var column = $scope.columns[cix];
		if (column.single) {
			return 1;
		} else {
			return $scope.rows[rix][column.name].length;
		}
	};

	$scope.keypress = function(e) {
		if (editing) {
			switch (e.keyCode) {
				case 27: // escape
					$scope.cancelEdit();
					break;
			}
		} else if (deleting) {
			// ignore all keystrokes here
		} else {
			console.log(e.keyCode);
			switch (e.keyCode) {
				case 37: // left
				case 72: // h
					goLeft();
					break;
				case 39: // right
				case 76: // l
					goRight();
					break;
				case 38: // up
				case 75: // k
					goUp();
					break;
				case 40: // down
				case 74: // j
					goDown();
					break;
				case 13: // enter
					startEdit();
					break;
				case 8: // backspace
					e.preventDefault();
				case 46: // delete
					startDelete();
					break;
			}
		}
	}

	function goLeft() {
		if ($scope.cix > 0) {
			$scope.cix--;
			$scope.iix = 0;
		}
	}

	function goRight() {
		if ($scope.cix < $scope.columns.length - 1) {
			$scope.cix++;
			$scope.iix = 0;
		}
	}

	function goUp() {
		if ($scope.iix > 0) {
			$scope.iix--;
		} else {
			if ($scope.rix > 0) {
				$scope.rix--;
				$scope.iix = getNumItems($scope.rix, $scope.cix) - 1;
			}
		}
	}

	function goDown() {
		if ($scope.iix < getNumItems($scope.rix, $scope.cix) - 1) {
			$scope.iix++;
		} else {
			if ($scope.rix < $scope.rows.length - 1) {
				$scope.rix++;
				$scope.iix = 0;
			}
		}
	}
});
<|endoftext|>


<commit_before><commit_msg>finished add ride stuff<commit_after><|endoftext|>


<commit_before>//
// mod-smith
//

'use strict';

module.exports = function (grunt) {
  //
  // Load grunt plugins - just-in-time
  //
  require('jit-grunt')(grunt, {
    'ngtemplates': 'grunt-angular-templates'
  });

  //
  // Display execution time of the tasks
  //
  require('time-grunt')(grunt);

  grunt.initConfig({
    //
    // Package definition
    //
    pkg: grunt.file.readJSON('package.json'),

    //
    // Common module definitions
    //
    self: {
      src: './src',
      dst: './dist',
      tmp: './.tmp'
    },

    //
    // Clean directories
    //
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '<%%= self.tmp %>/*',
            '<%%= self.dst %>/*'
          ]
        }]
      }
    },

    //
    // Inject files
    //
    injector: {
      options: {
        relative: true,
        addRootSlash: false
      },

      stylus: {
        options: {
          transform: function (filePath) {
            return '@import \'' + filePath + '\';';
          },
          starttag: '// injector:stylus:begin',
          endtag: '// injector:stylus:end'
        },
        files: {
          'src/module.styl': [
            '<%%= self.src %>/**/*.styl',
            '!<%%= self.src %>/module.styl'
          ]
        }
      }
    },

    //
    // Compiles Stylus to CSS
    //
    stylus: {
      compile: {
        options: {
          paths: [ '<%%= self.src %>' ],
          'include css': true
        },
        files: {
          '<%%= self.tmp %>/module.css' : '<%%= self.src %>/module.styl'
        }
      }
    },

    //
    // Post-process generated CSS for vendor specific prefixes
    //
    autoprefixer: {
      options: {
        browsers: ['last 1 version']
      },
      dist: {
        files: [{
          expand: true,
          cwd: '<%%= self.tmp %>',
          src: '{,*/}*.css',
          dest: '<%%= self.tmp %>'
        }]
      }
    },

    //
    // Minify and cache HTML templates
    //
    ngtemplates: {
      options: {
        module: '<%= pkg.name.camel %>',
        htmlmin: {
          collapseBooleanAttributes:      true,
          collapseWhitespace:             true,
          keepClosingSlash:               true,
          removeAttributeQuotes:          true,
          removeComments:                 true,
          removeEmptyAttributes:          true,
          removeRedundantAttributes:      true,
          removeScriptTypeAttributes:     true,
          removeStyleLinkTypeAttributes:  true
        }
      },
      main: {
        src:  '<%%= self.src %>/**/*.html',
        dest: '<%%= self.tmp %>/module-templates.js'
      }
    },

    //
    // Concatenate all scripts - including template cache; but excluding test scripts
    //
    concat: {
      main: {
        src: [
          '<%%= self.src %>/**/*.js',
          '!<%%= self.src %>/**/*.spec.js' ,
          '<%%= self.tmp %>/module-templates.js'
        ],
        dest: '<%%= self.tmp %>/module.concat.js'
      }
    },

    //
    // Make scripts minification safe
    //
    ngAnnotate: {
      options: {
        singleQuotes: true
      },
      dist: {
        files:  {
          '<%%= self.tmp %>/module.annotate.js' : '<%%= self.tmp %>/module.concat.js'
        }
      }
    },

    //
    // Uglify the script
    //
    uglify: {
      main: {
        files: [
          {
            src:'<%%= self.tmp %>/module.annotate.js',
            dest:'<%%= self.tmp %>/module.min.js'
          }
        ]
      }
    },

    //
    // Minify styleshets
    //
    cssmin: {
      main: {
        files: {
          '<%%= self.tmp %>/module.min.css': '<%%= self.tmp %>/module.css'
        }
      }
    },

    //
    // Copy files to distribution directory
    //
    copy: {
      main: {
        files: [
          {
            src:'<%%= self.tmp %>/module.css',
            dest:'<%%= self.dst %>/<%= pkg.name.slug %>.css'
          },
          {
            src:'<%%= self.tmp %>/module.min.css',
            dest:'<%%= self.dst %>/<%= pkg.name.slug %>.min.css'
          },
          {
            src:'<%%= self.tmp %>/module.annotate.js',
            dest:'<%%= self.dst %>/<%= pkg.name.slug %>.js'
          },
          {
            src:'<%%= self.tmp %>/module.min.js',
            dest:'<%%= self.dst %>/<%= pkg.name.slug %>.min.js'
          }
        ]
      }
    },

    //
    // Static code checker
    //
    eslint: {
      target: [
        '<%%= self.src %>/**/*.js'
      ]
    }
  });

  //
  // Default task
  //
  grunt.registerTask('default', ['eslint']);
};
<commit_msg>tpl: grunt: Add banner to minified script<commit_after>//
// mod-smith
//

'use strict';

module.exports = function (grunt) {
  //
  // Load grunt plugins - just-in-time
  //
  require('jit-grunt')(grunt, {
    'ngtemplates': 'grunt-angular-templates'
  });

  //
  // Display execution time of the tasks
  //
  require('time-grunt')(grunt);

  grunt.initConfig({
    //
    // Package definition
    //
    pkg: grunt.file.readJSON('package.json'),

    //
    // Common module definitions
    //
    self: {
      src: './src',
      dst: './dist',
      tmp: './.tmp'
    },

    //
    // Banner to be used in minified files
    //
    banner: '/* <%= pkg.name.slug %> v<%%= pkg.version %> | ' +
            '<%%= grunt.template.today("yyyy-mm-dd") %> | ' +
            '<%= author.name %> (<%= author.email %>) | ' +
            '<%= pkg.license %> */\n',

    //
    // Clean directories
    //
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '<%%= self.tmp %>/*',
            '<%%= self.dst %>/*'
          ]
        }]
      }
    },

    //
    // Inject files
    //
    injector: {
      options: {
        relative: true,
        addRootSlash: false
      },

      stylus: {
        options: {
          transform: function (filePath) {
            return '@import \'' + filePath + '\';';
          },
          starttag: '// injector:stylus:begin',
          endtag: '// injector:stylus:end'
        },
        files: {
          'src/module.styl': [
            '<%%= self.src %>/**/*.styl',
            '!<%%= self.src %>/module.styl'
          ]
        }
      }
    },

    //
    // Compiles Stylus to CSS
    //
    stylus: {
      compile: {
        options: {
          paths: [ '<%%= self.src %>' ],
          'include css': true
        },
        files: {
          '<%%= self.tmp %>/module.css' : '<%%= self.src %>/module.styl'
        }
      }
    },

    //
    // Post-process generated CSS for vendor specific prefixes
    //
    autoprefixer: {
      options: {
        browsers: ['last 1 version']
      },
      dist: {
        files: [{
          expand: true,
          cwd: '<%%= self.tmp %>',
          src: '{,*/}*.css',
          dest: '<%%= self.tmp %>'
        }]
      }
    },

    //
    // Minify and cache HTML templates
    //
    ngtemplates: {
      options: {
        module: '<%= pkg.name.camel %>',
        htmlmin: {
          collapseBooleanAttributes:      true,
          collapseWhitespace:             true,
          keepClosingSlash:               true,
          removeAttributeQuotes:          true,
          removeComments:                 true,
          removeEmptyAttributes:          true,
          removeRedundantAttributes:      true,
          removeScriptTypeAttributes:     true,
          removeStyleLinkTypeAttributes:  true
        }
      },
      main: {
        src:  '<%%= self.src %>/**/*.html',
        dest: '<%%= self.tmp %>/module-templates.js'
      }
    },

    //
    // Concatenate all scripts - including template cache; but excluding test scripts
    //
    concat: {
      main: {
        src: [
          '<%%= self.src %>/**/*.js',
          '!<%%= self.src %>/**/*.spec.js' ,
          '<%%= self.tmp %>/module-templates.js'
        ],
        dest: '<%%= self.tmp %>/module.concat.js'
      }
    },

    //
    // Make scripts minification safe
    //
    ngAnnotate: {
      options: {
        singleQuotes: true
      },
      dist: {
        files:  {
          '<%%= self.tmp %>/module.annotate.js' : '<%%= self.tmp %>/module.concat.js'
        }
      }
    },

    //
    // Uglify the script
    //
    uglify: {
      options: {
        preserveComments: 'some',
        banner: '<%%= banner %>'
      },
      main: {
        files: [
          {
            src:'<%%= self.tmp %>/module.annotate.js',
            dest:'<%%= self.tmp %>/module.min.js'
          }
        ]
      }
    },

    //
    // Minify styleshets
    //
    cssmin: {
      main: {
        files: {
          '<%%= self.tmp %>/module.min.css': '<%%= self.tmp %>/module.css'
        }
      }
    },

    //
    // Copy files to distribution directory
    //
    copy: {
      main: {
        files: [
          {
            src:'<%%= self.tmp %>/module.css',
            dest:'<%%= self.dst %>/<%= pkg.name.slug %>.css'
          },
          {
            src:'<%%= self.tmp %>/module.min.css',
            dest:'<%%= self.dst %>/<%= pkg.name.slug %>.min.css'
          },
          {
            src:'<%%= self.tmp %>/module.annotate.js',
            dest:'<%%= self.dst %>/<%= pkg.name.slug %>.js'
          },
          {
            src:'<%%= self.tmp %>/module.min.js',
            dest:'<%%= self.dst %>/<%= pkg.name.slug %>.min.js'
          }
        ]
      }
    },

    //
    // Static code checker
    //
    eslint: {
      target: [
        '<%%= self.src %>/**/*.js'
      ]
    }
  });

  //
  // Default task
  //
  grunt.registerTask('default', ['eslint']);
};
<|endoftext|>


<commit_before>var gulp = require('gulp');
var concat = require('gulp-concat');
var vinyl = require('vinyl-source-stream');
var browserify = require('browserify');
var gulpShell = require('gulp-shell');

gulp.task('perf-assemble', [], assemble);
gulp.task('perf-device', ['perf-assemble'], device);
gulp.task('perf-browser', ['perf-assemble'], browser);
gulp.task('perf-all', ['clean.perf', 'perf-device', 'perf-browser']);
gulp.task('perf-run', ['perf-all'], run());

function run() {
    return gulpShell.task([
        'karma start ./performance/karma.conf.js',
        'node --expose-gc ./performance/node.js'
    ], {
        ignoreErrors:true
    });
}

function assemble() {
    return browserify('./performance/device.js', {
            ignoreMissing: true
        }).
        bundle().
        pipe(vinyl('device-body.js')).
        pipe(gulp.dest('performance/bin'));
}

function browser() {
    return browserify('./performance/browser.js').
        bundle().
        pipe(vinyl('browser.js')).
        pipe(gulp.dest('performance/bin'));
}

function device() {
    return gulp.
        src(['./node_modules/nf-falcor-device-perf/devicePolyfill.js', 'performance/bin/device-body.js']).
        pipe(concat({path: 'device.js'})).
        pipe(gulp.dest('performance/bin'));
}
<commit_msg>Removed temporary 'ignoreErrors' from perf tests<commit_after>var gulp = require('gulp');
var concat = require('gulp-concat');
var vinyl = require('vinyl-source-stream');
var browserify = require('browserify');
var gulpShell = require('gulp-shell');

gulp.task('perf-assemble', [], assemble);
gulp.task('perf-device', ['perf-assemble'], device);
gulp.task('perf-browser', ['perf-assemble'], browser);
gulp.task('perf-all', ['clean.perf', 'perf-device', 'perf-browser']);
gulp.task('perf-run', ['perf-all'], run());

function run() {
    return gulpShell.task([
        'karma start ./performance/karma.conf.js',
        'node --expose-gc ./performance/node.js'
    ]);
}

function assemble() {
    return browserify('./performance/device.js', {
            ignoreMissing: true
        }).
        bundle().
        pipe(vinyl('device-body.js')).
        pipe(gulp.dest('performance/bin'));
}

function browser() {
    return browserify('./performance/browser.js').
        bundle().
        pipe(vinyl('browser.js')).
        pipe(gulp.dest('performance/bin'));
}

function device() {
    return gulp.
        src(['./node_modules/nf-falcor-device-perf/devicePolyfill.js', 'performance/bin/device-body.js']).
        pipe(concat({path: 'device.js'})).
        pipe(gulp.dest('performance/bin'));
}
<|endoftext|>


<commit_before>import { exec } from 'child_process'

export default class AllBranches
{

    execute(cwd = './')
    {
        return new Promise((resolve, reject) => {
            exec('git branch -a', { cwd }, (error, stdout, stderr) => {
                const parsedBranches = this.parseBranches(stdout)
                resolve(parsedBranches)
            })
        })
    }

    parseBranches(output) {
        const lines = output.split("\n")
        const branches = []
        for(let i = 0; i < lines.length; i++) {
            if(lines[i].includes('remotes/origin/HEAD -> origin/master')) {
                continue
            }
            const lineName = this.processBranchName(lines[i])
            if(lineName.substr(0, 2) == '* '){
                branches.push({
                    name: lineName.substr(2),
                    current: true
                })
                continue;
            }
            branches.push({
                name: lineName,
                current: false
            })
        }
        return branches
    }

    processBranchName(name) {
        name =  name.trim()
                    .replace('remotes/', '')
        return name
    }

}
<commit_msg>Small change: remove superfluous spacE<commit_after>import { exec } from 'child_process'

export default class AllBranches
{
    execute(cwd = './')
    {
        return new Promise((resolve, reject) => {
            exec('git branch -a', { cwd }, (error, stdout, stderr) => {
                const parsedBranches = this.parseBranches(stdout)
                resolve(parsedBranches)
            })
        })
    }

    parseBranches(output) {
        const lines = output.split("\n")
        const branches = []
        for(let i = 0; i < lines.length; i++) {
            if(lines[i].includes('remotes/origin/HEAD -> origin/master')) {
                continue
            }
            const lineName = this.processBranchName(lines[i])
            if(lineName.substr(0, 2) == '* '){
                branches.push({
                    name: lineName.substr(2),
                    current: true
                })
                continue;
            }
            branches.push({
                name: lineName,
                current: false
            })
        }
        return branches
    }

    processBranchName(name) {
        name =  name.trim()
                    .replace('remotes/', '')
        return name
    }

}
<|endoftext|>


<commit_before>angular.module('orka.config')

/**
 * @ngdoc object
 * @name orka.config.ConfigServiceProvider
 */
.provider('ConfigService', [function() {
    /**
     * @ngdoc object
     * @name config
     * @propertyOf orka.config.ConfigServiceProvider
     *
     * @description
     * This object contains all configurateble values for orka-app.
     *
     * Most values can be set using {@link orka.config.ConfigServiceProvider#methods_setConfig `setConfig()`}.
     *
     * Below the config structure is documented.
     *
     * - **map** - {Object} - Containing configurations for ol.Map and ol.View
     *   - projection - {Object} - ol.proj.Projection object containing app projection
     *   - extent - {Array.<number>} - View extent
     *   - resolutions - {Array.<number>} - Resolutions used in view
     *   - center - {Array.<number} - Initial center
     *   - zoom - {number} - Initial zoom
     * - **attributions** - {Array.<string>|string} - Attributions added to all background layer
     * - **backgroundLayer** - {Object} - Available background layer configuration. At the moment, only {@link anolApi/anol.map.LayersFactory#methods_newTMS `TMS layer`} supported.
     * - **poi** - {Object} - Configuration of POI map themes.
     *   - layerURL - {string} - URI to poi request backend
     *   - layerName - {string} - Name of layer POIs shown in
     *   - iconBaseURL - {string} - Base URI of used POI-icons
     *   - markerIcon - {string} - URI to used marker icon for highlighting selected POIs
     *   - legendURL - {string} - URI to POI-legend JSON
     *   - symbolAnchor - {Array.<number>} - Placement offset of POI-icons
     *   - markerAnchor - {Array.<number>} - Placement offset of highlight marker icon
     * - **track** - {Object} - Configuration if Track map themes.
     *   - layerURL - {string} - URI to track request backend
     *   - layerName - {string} - Name of layer tracks shown in
     *   - legendURL - {string} - URI to Track-legend json
     * - **print** - {Object} - Configuration of print module
     *   - defaultScale - {number} - Initial scale factor
     *   - createURL - {string} - URI to create endpoint of printqueue
     *   - checkURL - {string} - URI to check endpoint of printqueue to receive current state of requested document
     *   - downloadURL - {string} - URI to download endpoint in printqueue for downloading requested document
     *   - checkDelay - {number} - Time in ms between requests to `checkURL`
     *   - pageSizes - {Array.<Object>} - List of available default print page sizes. See {@link anolApi/anol.print.PrintPageServiceProvider#methods_setPageSizes `PrintPageServiceProvider.setPageSizes`}
     *   - outputFormats - {Array.<Object>} - List of available output formats. See {@link anolApi/anol.print.PrintPageServiceProvider#methods_setOutputFormats `PrintPageServiceProvider.setOutputFormats`}
     *   - style - {Object} - Styling of print area geometry in map
     *     - fillColor {string} - RGBA value for area color
     *     - strokeColor {string} - RGBA value for area outline color
     *     - strokeWidth {number} - Width of area outline
     *     - pointRadius {number} - Radius of draggable points
     *     - pointCursor {string} - Define which cursur apears when mouse over draggeble point
     *     - pointFillColor {string} - RGBA value for point area color
     *     - pointStrokeColor {string} - RGBA value for point outline color
     *     - pointStrokeWidth {number} - Width of point outline
     * - **popup** - {Object} - Configuration of feature popup
     *   - positioning - {string} - Popup placement type. Currently only `center-left` supported. See {@link http://openlayers.org/en/v3.0.0/apidoc/ol.html#OverlayPositioning `ol3 Overlay positioning`} for valid values.
     *   - offset - {Array.<number>} - Popup placement offset.
     *   - buffer - {Array.<number>} - Min distance between popup element and map border for automatical popup movement into view.
     */
    this.config = {};
    var defaults = {
        map: {
            projection: new ol.proj.Projection({
                code: 'EPSG:25833',
                units: 'm'
            }),
            extent: [200000, 5880000, 480000, 6075000],
            resolutions:  [
                529.166666667,
                352.777777778,
                264.583333333,
                176.388888889,
                88.1944444444,
                52.9166666667,
                35.2777777778,
                28.2222222222,
                22.9305555556,
                17.6388888889,
                12.3472222222,
                8.8194444444,
                7.0555555556,
                5.2916666667,
                3.5277777778,
                2.6458333333,
                1.7638888889,
                0.8819444444,
                0.3527777778,
                0.1763888889
            ],
            center: [313282, 6003693],
            zoom: 9
        },
        attributions: [
            '
Kartenbild © Hansestadt Rostock (CC BY 3.0)
',
            '
Kartendaten © OpenStreetMap(ODbL) und uVGB-MV
'
        ],
        backgroundLayer: {
            'ORKA_STADTPLAN': {
                baseURL: 'http://10.1.1.49:8080/tms/1.0.0',
                layer: 'stadtplan_EPSG25833',
                format: 'png',
                title: 'Stadtplan',
                shortcut: 'S',
                printLayer: 'mvp-mapserver-print'
            },
            'ORKA_STADTPLAN_OHNE_TEXT': {
                baseURL: 'http://10.1.1.49:8080/tms/1.0.0',
                layer: 'stadtplan_notext_EPSG25833',
                format: 'png',
                title: 'Stadtplan ohne Text',
                shortcut: 'S',
                printLayer: 'mvp-mapserver-notext-print'
            },
            'ORKA_STADTPLAN_SCHUMMERUNG': {
                baseURL: 'http://10.1.1.49:8080/tms/1.0.0',
                layer: 'stadtplan_hillshade_EPSG25833',
                format: 'png',
                title: 'Stadtplan Schummerung',
                shortcut: 'S',
                printLayer: 'mvp-mapserver-hillshade-print'
            },
            'ORKA_STADTPLAN_SCHUMMERUNG_OHNE_TEXT': {
                baseURL: 'http://10.1.1.49:8080/tms/1.0.0',
                layer: 'stadtplan_hillshade_notext_EPSG25833',
                format: 'png',
                title: 'Stadtplan Schummerung ohne Text',
                shortcut: 'S',
                printLayer: 'mvp-mapserver-hillshade-notext-print'
            },
            'ORKA_STADTPLAN_GRAU': {
                baseURL: 'http://10.1.1.49:8080/tms/1.0.0',
                layer: 'stadtplan_grau_EPSG25833',
                format: 'png',
                title: 'Stadtplan Grau',
                shortcut: 'G',
                printLayer: 'mvp-mapserver-grayscale-print'
            },
            'ORKA_STADTPLAN_GRAU_OHNE_TEXT': {
                baseURL: 'http://10.1.1.49:8080/tms/1.0.0',
                layer: 'stadtplan_grau_notext_EPSG25833',
                format: 'png',
                title: 'Stadtplan Grau ohne Text',
                shortcut: 'S',
                printLayer: 'mvp-mapserver-grayscale-notext-print'
            }
        },
        poi: {
            layerName: 'poi_layer',
            layerURL: 'http://10.1.1.49:8888/proxy/http://10.1.1.49:4000/poi.geojson?',
            iconBaseURL: 'http://www.orka-mv.de/static/icons/',
            markerIcon: '/static/img/highlightMarker.png',
            legendURL: '/static/data/poi_legend_data.json',
            symbolAnchor: [10, 26],
            markerAnchor: [17, 33]
        },
        track: {
            layerURL: 'http://www.orka-mv.de/citymap/tracks',
            layerName: 'tracks',
            legendURL: '/static/data/track_legend_data.json'
        },
        print: {
            defaultScale: 250000,
            createURL: 'http://10.1.1.49:8888/proxy/http://10.1.1.49:5000/print',
            checkURL: 'http://10.1.1.49:8888/proxy/http://10.1.1.49:5000',
            downloadURL: 'http://10.1.1.49:8888/proxy/http://10.1.1.49:5000',
            checkDelay: 2000,
            pageSizes: [{
                'label': 'A4',
                'icon': 'glyphicon-resize-vertical',
                'value': [210, 297]
            }, {
                'label': 'A4',
                'icon': 'glyphicon-resize-horizontal',
                'value': [297, 210]
            }, {
                'label': 'A3',
                'icon': 'glyphicon-resize-vertical',
                'value': [297, 420]
            }, {
                'label': 'A3',
                'icon': 'glyphicon-resize-horizontal',
                'value': [420, 297]
            }],
            outputFormats: [{
                'label': 'PDF',
                'value': 'pdf'
            },
            {
                'label': 'PNG',
                'value': 'png'
            }],
            style: {
                areaFillColor: 'rgba(255, 255, 255, 0.4)',
                strokeColor: 'rgba(0, 0, 0, 1)',
                strokeWidth: 1,
                pointRadius: 5,
                pointCursor: 'pointer',
                pointFillColor: 'rgba(255, 255, 255, 1)',
                pointStrokeColor: 'rgba(0, 0, 0, 1)',
                pointStrokeWidth: 1
            }
        },
        popup: {
            positioning: 'center-left',
            offset: [10, -15],
            buffer: [5, 5, 5, 5]
        }
    };

    /**
     * @ngdoc method
     * @name setConfig
     * @methodOf orka.config.ConfigServiceProvider
     *
     * @param {Object} config
     * - **header** - {string|boolean} - If containing '0px' header is set to false, otherwise it will be true
     * - **map** - {Object} - Containing map related configurations
     *   - **center** - {Array.<number>} - Initial map center
     *   - **zoom** - {number} - Initial map zoom
     *   - **layers** - {Array.<string>} - Background layer names to include in map
     *   - **attributions** - {Array.<string>|string} - Map attributions
     *   - **openLayerswitcher** - {boolean} - Expand layerswitcher at startup
     *   - **openLagend** - {boolean} - Expand legend at startup
     * - **locations** - {string} - Path/url to geojson containing locations
     * - **themes** - {boolean} - Activate themes module
     * - **print** - {boolean} - Activate print module
     */
    this.setConfig = function(config) {
        var self = this;
        if(config.header === undefined) {
            self.config.header = true;
        } else {
            self.config.header = config.header.height === '0px' ? false : true;
        }
        self.config.popup = $.extend({}, defaults.popup);
        self.config.map = $.extend({}, defaults.map);
        self.config.backgroundLayer = [];
        if(config.map !== undefined) {
            if(config.map.center !== undefined) {
                self.config.map.center = config.map.center;
            }
            if(config.map.zoom !== undefined) {
                self.config.map.zoom = config.map.zoom;
            }
            angular.forEach(config.map.layers, function(layerName) {
                var layer = defaults.backgroundLayer[layerName];
                layer.attributions = config.map.attributions || defaults.attributions;
                self.config.backgroundLayer.push(layer);
            });
            if(config.map.openLayerswitcher !== undefined) {
                self.config.map.layerswitcher = config.map.openLayerswitcher === true ? 'open' : 'closed';
            }
            if(config.map.openLegend !== undefined) {
                self.config.map.legend = config.map.openLegend === true ? 'open' : 'closed';
            }
        }
        if(config.locations !== undefined) {
            self.config.locations = config.locations;
        }
        if(config.themes === true) {
            self.config.poi = $.extend({}, defaults.poi);
            if(config.poi !== undefined && config.poi.legendURL !== undefined) {
                self.config.poi.legendURL = config.poi.legendURL;
            }
            self.config.track = $.extend({}, defaults.track);
        }
        if(config.print === true) {
            self.config.print = $.extend({}, defaults.print);
        }
        ol.proj.addProjection(self.config.map.projection);
    };

    this.$get = [function() {
        /**
         * @ngdoc service
         * @name orka.config.ConfigService
         * @description
         * Service to receive config
         */

        /**
         * @ngdoc object
         * @name config
         * @propertyOf orka.config.ConfigService
         * @description
         * `ConfigService.config` is the same object as {@link orkaApi/orka.config.ConfigServiceProvider#properties_config `ConfigServiceProvider.config`}.
         */
        return this;
    }];
}]);
<commit_msg>Fixed typo<commit_after>angular.module('orka.config')

/**
 * @ngdoc object
 * @name orka.config.ConfigServiceProvider
 */
.provider('ConfigService', [function() {
    /**
     * @ngdoc object
     * @name config
     * @propertyOf orka.config.ConfigServiceProvider
     *
     * @description
     * This object contains all configurateble values for orka-app.
     *
     * Most values can be set using {@link orka.config.ConfigServiceProvider#methods_setConfig `setConfig()`}.
     *
     * Below the config structure is documented.
     *
     * - **map** - {Object} - Containing configurations for ol.Map and ol.View
     *   - projection - {Object} - ol.proj.Projection object containing app projection
     *   - extent - {Array.<number>} - View extent
     *   - resolutions - {Array.<number>} - Resolutions used in view
     *   - center - {Array.<number} - Initial center
     *   - zoom - {number} - Initial zoom
     * - **attributions** - {Array.<string>|string} - Attributions added to all background layer
     * - **backgroundLayer** - {Object} - Available background layer configuration. At the moment, only {@link anolApi/anol.map.LayersFactory#methods_newTMS `TMS layer`} supported.
     * - **poi** - {Object} - Configuration of POI map themes.
     *   - layerURL - {string} - URI to poi request backend
     *   - layerName - {string} - Name of layer POIs shown in
     *   - iconBaseURL - {string} - Base URI of used POI-icons
     *   - markerIcon - {string} - URI to used marker icon for highlighting selected POIs
     *   - legendURL - {string} - URI to POI-legend JSON
     *   - symbolAnchor - {Array.<number>} - Placement offset of POI-icons
     *   - markerAnchor - {Array.<number>} - Placement offset of highlight marker icon
     * - **track** - {Object} - Configuration if Track map themes.
     *   - layerURL - {string} - URI to track request backend
     *   - layerName - {string} - Name of layer tracks shown in
     *   - legendURL - {string} - URI to Track-legend json
     * - **print** - {Object} - Configuration of print module
     *   - defaultScale - {number} - Initial scale factor
     *   - createURL - {string} - URI to create endpoint of printqueue
     *   - checkURL - {string} - URI to check endpoint of printqueue to receive current state of requested document
     *   - downloadURL - {string} - URI to download endpoint in printqueue for downloading requested document
     *   - checkDelay - {number} - Time in ms between requests to `checkURL`
     *   - pageSizes - {Array.<Object>} - List of available default print page sizes. See {@link anolApi/anol.print.PrintPageServiceProvider#methods_setPageSizes `PrintPageServiceProvider.setPageSizes`}
     *   - outputFormats - {Array.<Object>} - List of available output formats. See {@link anolApi/anol.print.PrintPageServiceProvider#methods_setOutputFormats `PrintPageServiceProvider.setOutputFormats`}
     *   - style - {Object} - Styling of print area geometry in map
     *     - fillColor {string} - RGBA value for area color
     *     - strokeColor {string} - RGBA value for area outline color
     *     - strokeWidth {number} - Width of area outline
     *     - pointRadius {number} - Radius of draggable points
     *     - pointCursor {string} - Define which cursur apears when mouse over draggeble point
     *     - pointFillColor {string} - RGBA value for point area color
     *     - pointStrokeColor {string} - RGBA value for point outline color
     *     - pointStrokeWidth {number} - Width of point outline
     * - **popup** - {Object} - Configuration of feature popup
     *   - positioning - {string} - Popup placement type. Currently only `center-left` supported. See {@link http://openlayers.org/en/v3.0.0/apidoc/ol.html#OverlayPositioning `ol3 Overlay positioning`} for valid values.
     *   - offset - {Array.<number>} - Popup placement offset.
     *   - buffer - {Array.<number>} - Min distance between popup element and map border for automatical popup movement into view.
     */
    this.config = {};
    var defaults = {
        map: {
            projection: new ol.proj.Projection({
                code: 'EPSG:25833',
                units: 'm'
            }),
            extent: [200000, 5880000, 480000, 6075000],
            resolutions:  [
                529.166666667,
                352.777777778,
                264.583333333,
                176.388888889,
                88.1944444444,
                52.9166666667,
                35.2777777778,
                28.2222222222,
                22.9305555556,
                17.6388888889,
                12.3472222222,
                8.8194444444,
                7.0555555556,
                5.2916666667,
                3.5277777778,
                2.6458333333,
                1.7638888889,
                0.8819444444,
                0.3527777778,
                0.1763888889
            ],
            center: [313282, 6003693],
            zoom: 9
        },
        attributions: [
            '
Kartenbild © Hansestadt Rostock (CC BY 3.0)
',
            '
Kartendaten © OpenStreetMap(ODbL) und uVGB-MV
'
        ],
        backgroundLayer: {
            'ORKA_STADTPLAN': {
                baseURL: 'http://10.1.1.49:8080/tms/1.0.0',
                layer: 'stadtplan_EPSG25833',
                format: 'png',
                title: 'Stadtplan',
                shortcut: 'S',
                printLayer: 'mvp-mapserver-print'
            },
            'ORKA_STADTPLAN_OHNE_TEXT': {
                baseURL: 'http://10.1.1.49:8080/tms/1.0.0',
                layer: 'stadtplan_notext_EPSG25833',
                format: 'png',
                title: 'Stadtplan ohne Text',
                shortcut: 'S',
                printLayer: 'mvp-mapserver-notext-print'
            },
            'ORKA_STADTPLAN_SCHUMMERUNG': {
                baseURL: 'http://10.1.1.49:8080/tms/1.0.0',
                layer: 'stadtplan_hillshade_EPSG25833',
                format: 'png',
                title: 'Stadtplan Schummerung',
                shortcut: 'S',
                printLayer: 'mvp-mapserver-hillshade-print'
            },
            'ORKA_STADTPLAN_SCHUMMERUNG_OHNE_TEXT': {
                baseURL: 'http://10.1.1.49:8080/tms/1.0.0',
                layer: 'stadtplan_hillshade_notext_EPSG25833',
                format: 'png',
                title: 'Stadtplan Schummerung ohne Text',
                shortcut: 'S',
                printLayer: 'mvp-mapserver-hillshade-notext-print'
            },
            'ORKA_STADTPLAN_GRAU': {
                baseURL: 'http://10.1.1.49:8080/tms/1.0.0',
                layer: 'stadtplan_grau_EPSG25833',
                format: 'png',
                title: 'Stadtplan Grau',
                shortcut: 'G',
                printLayer: 'mvp-mapserver-grayscale-print'
            },
            'ORKA_STADTPLAN_GRAU_OHNE_TEXT': {
                baseURL: 'http://10.1.1.49:8080/tms/1.0.0',
                layer: 'stadtplan_grau_notext_EPSG25833',
                format: 'png',
                title: 'Stadtplan Grau ohne Text',
                shortcut: 'S',
                printLayer: 'mvp-mapserver-grayscale-notext-print'
            }
        },
        poi: {
            layerName: 'poi_layer',
            layerURL: 'http://10.1.1.49:8888/proxy/http://10.1.1.49:4000/poi.geojson?',
            iconBaseURL: 'http://www.orka-mv.de/static/icons/',
            markerIcon: '/static/img/highlightMarker.png',
            legendURL: '/static/data/poi_legend_data.json',
            symbolAnchor: [10, 26],
            markerAnchor: [17, 33]
        },
        track: {
            layerURL: 'http://www.orka-mv.de/citymap/tracks',
            layerName: 'tracks',
            legendURL: '/static/data/track_legend_data.json'
        },
        print: {
            defaultScale: 250000,
            createURL: 'http://10.1.1.49:8888/proxy/http://10.1.1.49:5000/print',
            checkURL: 'http://10.1.1.49:8888/proxy/http://10.1.1.49:5000',
            downloadURL: 'http://10.1.1.49:8888/proxy/http://10.1.1.49:5000',
            checkDelay: 2000,
            pageSizes: [{
                'label': 'A4',
                'icon': 'glyphicon-resize-vertical',
                'value': [210, 297]
            }, {
                'label': 'A4',
                'icon': 'glyphicon-resize-horizontal',
                'value': [297, 210]
            }, {
                'label': 'A3',
                'icon': 'glyphicon-resize-vertical',
                'value': [297, 420]
            }, {
                'label': 'A3',
                'icon': 'glyphicon-resize-horizontal',
                'value': [420, 297]
            }],
            outputFormats: [{
                'label': 'PDF',
                'value': 'pdf'
            },
            {
                'label': 'PNG',
                'value': 'png'
            }],
            style: {
                areaFillColor: 'rgba(255, 255, 255, 0.4)',
                strokeColor: 'rgba(0, 0, 0, 1)',
                strokeWidth: 1,
                pointRadius: 5,
                pointCursor: 'pointer',
                pointFillColor: 'rgba(255, 255, 255, 1)',
                pointStrokeColor: 'rgba(0, 0, 0, 1)',
                pointStrokeWidth: 1
            }
        },
        popup: {
            positioning: 'center-left',
            offset: [10, -15],
            buffer: [5, 5, 5, 5]
        }
    };

    /**
     * @ngdoc method
     * @name setConfig
     * @methodOf orka.config.ConfigServiceProvider
     *
     * @param {Object} config
     * - **header** - {string|boolean} - If containing '0px' header is set to false, otherwise it will be true
     * - **map** - {Object} - Containing map related configurations
     *   - **center** - {Array.<number>} - Initial map center
     *   - **zoom** - {number} - Initial map zoom
     *   - **layers** - {Array.<string>} - Background layer names to include in map
     *   - **attributions** - {Array.<string>|string} - Map attributions
     *   - **openLayerswitcher** - {boolean} - Expand layerswitcher at startup
     *   - **openLegend** - {boolean} - Expand legend at startup
     * - **locations** - {string} - Path/url to geojson containing locations
     * - **themes** - {boolean} - Activate themes module
     * - **print** - {boolean} - Activate print module
     */
    this.setConfig = function(config) {
        var self = this;
        if(config.header === undefined) {
            self.config.header = true;
        } else {
            self.config.header = config.header.height === '0px' ? false : true;
        }
        self.config.popup = $.extend({}, defaults.popup);
        self.config.map = $.extend({}, defaults.map);
        self.config.backgroundLayer = [];
        if(config.map !== undefined) {
            if(config.map.center !== undefined) {
                self.config.map.center = config.map.center;
            }
            if(config.map.zoom !== undefined) {
                self.config.map.zoom = config.map.zoom;
            }
            angular.forEach(config.map.layers, function(layerName) {
                var layer = defaults.backgroundLayer[layerName];
                layer.attributions = config.map.attributions || defaults.attributions;
                self.config.backgroundLayer.push(layer);
            });
            if(config.map.openLayerswitcher !== undefined) {
                self.config.map.layerswitcher = config.map.openLayerswitcher === true ? 'open' : 'closed';
            }
            if(config.map.openLegend !== undefined) {
                self.config.map.legend = config.map.openLegend === true ? 'open' : 'closed';
            }
        }
        if(config.locations !== undefined) {
            self.config.locations = config.locations;
        }
        if(config.themes === true) {
            self.config.poi = $.extend({}, defaults.poi);
            if(config.poi !== undefined && config.poi.legendURL !== undefined) {
                self.config.poi.legendURL = config.poi.legendURL;
            }
            self.config.track = $.extend({}, defaults.track);
        }
        if(config.print === true) {
            self.config.print = $.extend({}, defaults.print);
        }
        ol.proj.addProjection(self.config.map.projection);
    };

    this.$get = [function() {
        /**
         * @ngdoc service
         * @name orka.config.ConfigService
         * @description
         * Service to receive config
         */

        /**
         * @ngdoc object
         * @name config
         * @propertyOf orka.config.ConfigService
         * @description
         * `ConfigService.config` is the same object as {@link orkaApi/orka.config.ConfigServiceProvider#properties_config `ConfigServiceProvider.config`}.
         */
        return this;
    }];
}]);
<|endoftext|>