<commit_before>import React, { Component } from 'react';
import { Text } from 'react-native';

import styles from '../../styles/styles';
import InPageImage from '../inPageImage';
import AnimalText from '../animalText';
import AnimalTemplate from '../animalTemplate';

const IMAGES = [
  require('../../images/animals/husickaVdovka/01.jpg'),
  require('../../images/animals/husickaVdovka/02.jpg'),
  require('../../images/animals/husickaVdovka/03.jpg'),
];

const THUMBNAILS = [
  require('../../images/animals/husickaVdovka/01-thumb.jpg'),
  require('../../images/animals/husickaVdovka/02-thumb.jpg'),
  require('../../images/animals/husickaVdovka/03-thumb.jpg'),
];

var AnimalDetail = React.createClass({
  render() {
    return (
      <AnimalTemplate firstIndex={[1]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator}>
        <AnimalText>
          Dva samečci a jedna samička husičky vdovky se vylíhli v roce 2014 v zoo v Berlíně. V tom samém roce dorazili k nám.
        </AnimalText>
        <AnimalText>
          Husička vdovka (lat. <Text style={styles.italic}>Dendrocygna viduata</Text>) se vyskytuje v tropických oblastech Afriky a Jižní Ameriky. Jak můžete vidět, i tady v zoo je umístěná v Africké vesnici společně s plameňáky.
        </AnimalText>
        <AnimalText>
          Husička, stejně jako všechny její příbuzné druhy, miluje vodu. Zdržuje se tedy především u bažin, jezer či větších řek. Tyto oblasti jí zároveň poskytují dostatek ochrany v podobě vysoké trávy. Dokáže být velmi společenská a v místech, kde je dostatečné množství potravy, se může opakovaně vyskytovat až několik tisíc jedinců.
        </AnimalText>
        <InPageImage indexes={[0]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
          Husička vdovka má hnízdo nejčastěji jako prostý důlek v zemi, který je nedaleko vody a zároveň je skrytý hustou vegetací.
        </AnimalText>
        <AnimalText>
          Vzhledem je husička vdovka velmi odlišná od jiných hus. Má černobílou hlavu. Peří na zádech a křídlech jí přechází od tmavě hnědé do černé barvy. Spodní strana těla je černá stejně jako ocas. Ten je vzhledem k velikosti těla velmi krátký a šedomodré nohy jsou naproti tomu nezvykle dlouhé. Sameček i samička se od sebe vzhledově ani velikostně neliší, avšak mláďata se malinko různí od rodičů svou méně výrazně zbarvenou hlavou.
        </AnimalText>
        <AnimalText>
          Husička vdovka je všežravá a často se potápí, aby si ulovila svoji potravu. Strava se skládá především z vodního hmyzu, vodních měkkýšů, rostlin a semen.
        </AnimalText>
        <InPageImage indexes={[2]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
          Hnízdění může probíhat jak na zemi v ukrytém důlku, tak na stromě. Samička snese 4–13  vajec a skoro měsíc trvá, než se housata vylíhnou. V sezení se střídají oba rodiče. V této době hnízdění je sameček jediný, kdo se k samičce a vejcím může přiblížit, jinak je samička ke svému okolí značně agresivní a odhání i zástupce svého druhu. Po vyhnízdění přichází perioda, kdy dospělí ptáci pelichají, a ztrácí schopnost létat. Jsou tak zranitelnější a musí se více skrývat v husté vegetaci.
        </AnimalText>
        <AnimalText>
          Pozoruhodné je, že se zdá, jako by měla husička kolem hlavy uvázaný černý šátek. Patrně z toho důvodu se jí říká vdovka. Naproti tomu její anglické jméno – <Text style={styles.italic}>White-faced whistling duck</Text> – ji vystihuje ze zcela jiného pohledu. Zmiňuje její typicky bílou tvář, ale také nám říká, že vydává nápadné hvízdavé zvuky. Obě její jména o ní něco napovídají.
        </AnimalText>
      </AnimalTemplate>
    );
  }
});

module.exports = AnimalDetail;
<commit_msg>Update husickaVdovka.adult.js<commit_after>import React, { Component } from 'react';
import { Text } from 'react-native';

import styles from '../../styles/styles';
import InPageImage from '../inPageImage';
import AnimalText from '../animalText';
import AnimalTemplate from '../animalTemplate';

const IMAGES = [
  require('../../images/animals/husickaVdovka/01.jpg'),
  require('../../images/animals/husickaVdovka/02.jpg'),
  require('../../images/animals/husickaVdovka/03.jpg'),
];

const THUMBNAILS = [
  require('../../images/animals/husickaVdovka/01-thumb.jpg'),
  require('../../images/animals/husickaVdovka/02-thumb.jpg'),
  require('../../images/animals/husickaVdovka/03-thumb.jpg'),
];

var AnimalDetail = React.createClass({
  render() {
    return (
      <AnimalTemplate firstIndex={[1]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator}>
        <AnimalText>
          Dva samečci a jedna samička husičky vdovky se vylíhli v roce 2014 v zoo v Berlíně. V tom samém roce dorazili k nám.
        </AnimalText>
        <AnimalText>
          Husička vdovka (lat. <Text style={styles.italic}>Dendrocygna viduata</Text>) se vyskytuje v tropických oblastech Afriky a Jižní Ameriky. Jak můžete vidět, i tady v zoo je umístěná v Africké vesnici společně s plameňáky.
        </AnimalText>
        <AnimalText>
          Husička, stejně jako všechny její příbuzné druhy, miluje vodu. Zdržuje se tedy především u bažin, jezer či větších řek. Tyto oblasti jí zároveň poskytují dostatek ochrany v podobě vysoké trávy. Dokáže být velmi společenská a v místech, kde je dostatečné množství potravy, se může opakovaně vyskytovat až několik tisíc jedinců.
        </AnimalText>
        <InPageImage indexes={[0]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
          Husička vdovka má hnízdo nejčastěji jako prostý důlek v zemi, který je nedaleko vody a zároveň je skrytý hustou vegetací.
        </AnimalText>
        <AnimalText>
          Nejen vzhledem je husička vdovka velmi odlišná od nám dobře známých hus – patří totiž do jiné podčeledi a k husám má stejně daleko jako ke kachnám. Má černobílou hlavu. Peří na zádech a křídlech jí přechází od tmavě hnědé do černé barvy. Spodní strana těla je černá stejně jako ocas. Ten je vzhledem k velikosti těla velmi krátký a šedomodré nohy jsou naproti tomu nezvykle dlouhé. Sameček i samička se od sebe vzhledově ani velikostně neliší, avšak mláďata se malinko různí od rodičů svou méně výrazně zbarvenou hlavou.
        </AnimalText>
        <AnimalText>
          Husička vdovka je všežravá a často se potápí, aby si ulovila svoji potravu. Strava se skládá především z vodního hmyzu, vodních měkkýšů, rostlin a semen.
        </AnimalText>
        <InPageImage indexes={[2]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
          Hnízdění může probíhat jak na zemi v ukrytém důlku, tak na stromě. Samička snese 4–13  vajec a skoro měsíc trvá, než se housata vylíhnou. V sezení se střídají oba rodiče. V této době hnízdění je sameček jediný, kdo se k samičce a vejcím může přiblížit, jinak je samička ke svému okolí značně agresivní a odhání i zástupce svého druhu. Po vyhnízdění přichází perioda, kdy dospělí ptáci pelichají, a ztrácí schopnost létat. Jsou tak zranitelnější a musí se více skrývat v husté vegetaci.
        </AnimalText>
        <AnimalText>
          Pozoruhodné je, že se zdá, jako by měla husička kolem hlavy uvázaný černý šátek. Patrně z toho důvodu se jí říká vdovka. Naproti tomu její anglické jméno – <Text style={styles.italic}>White-faced whistling duck</Text> – ji vystihuje ze zcela jiného pohledu. Zmiňuje její typicky bílou tvář, ale také nám říká, že vydává nápadné hvízdavé zvuky. Obě její jména o ní něco napovídají.
        </AnimalText>
      </AnimalTemplate>
    );
  }
});

module.exports = AnimalDetail;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Text } from 'react-native';

import styles from '../../styles/styles';
import InPageImage from '../inPageImage';
import AnimalText from '../animalText';
import AnimalTemplate from '../animalTemplate';

const IMAGES = [
  require('../../images/animals/pustikBradaty/01.jpg'),
  require('../../images/animals/pustikBradaty/02.jpg'),
  require('../../images/animals/pustikBradaty/03.jpg'),
];

const THUMBNAILS = [
  require('../../images/animals/pustikBradaty/01-thumb.jpg'),
  require('../../images/animals/pustikBradaty/02-thumb.jpg'),
  require('../../images/animals/pustikBradaty/03-thumb.jpg'),
];

var AnimalDetail = React.createClass({
  render() {
    return (
      <AnimalTemplate firstIndex={[1]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator}>
        <AnimalText>
        Ahoj děti!
        </AnimalText>

        <AnimalText>
        Já jsem puštík bradatý a patřím mezi sovy, moudré noční živočichy, jejichž řád čítá přes 200 druhů. Narodil jsem se 13. května 2012 v zemi tulipánů – Nizozemsku. Moje kamarádka, se kterou bydlím ve stejné voliéře, se narodila v sousední Belgii přesně o jeden rok a jeden den dříve, tedy 12. května 2011. Na první pohled nás od sebe nerozeznáte, ale zkušené oko pozorovatele odhalí, že samička je o něco větší. Kromě nás existuje ve světě asi 20 dalších druhů puštíků, ale my jsme ze všech největší. Jsme dokonce větší než výr velký, jen nejsme tak mohutní. Když roztáhneme křídla, od jednoho konce k druhému měříme až 1,5 metru, což je zhruba délka těla vlka obecného.
        </AnimalText>
        <InPageImage indexes={[2]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
        Své druhové jméno – bradatý (nebo také vousatý) – jsme si vysloužili díky tomu, že máme ve spodní části závoje naší kulaté hlavy bílá peříčka, která vypadají úplně jako knírek. Žijeme převážně v jehličnatých lesích severní Evropy, Severní Ameriky a Asie. K jídlu máme nejraději drobné hlodavce, třeba hraboše, veverky a norníky, občas i nějakého toho zajíce nebo kachnu. Umíme létat velice tiše a máme výborný sluch, díky kterému dokážeme vypátrat a zaměřit svoji kořist pod sněhem v hloubce až 60 cm. Ulovíme ji tak, že se vrhneme celou svou vahou proti sněhové krustě, která by mohla unést i 80kg člověka. Díky této schopnosti můžeme přežívat i ve velmi chladném prostředí, kde by si jiná zvířátka potravu obstarat nedokázala.
        </AnimalText>
        <InPageImage indexes={[0]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
        Se svými partnery tvoříme páry na celý život, který trvá až 20 let. Samička snáší 3 až 4 vajíčka, která se líhnou asi po měsíci. Svá mláďátka krmíme a hlídáme ještě dlouho poté, co se vylíhnou. Jsme velmi obětaví rodiče, proto mláďata dokážeme uchránit i před těmi největšími vetřelci.
        </AnimalText>
        <AnimalText>
        V brněnské zoo jsme zatím malé puštíky neměli, ale kdo ví, co přinese budoucnost.
        </AnimalText>
        <AnimalText>
        Puštíka bradatého znáte určitě všichni díky filmům o Harry Potterovi, kde si zahrál sovu Errol.
        </AnimalText>
      </AnimalTemplate>
    );
  }
});

module.exports = AnimalDetail;
<commit_msg>Update pustikBradaty.child.js<commit_after>import React, { Component } from 'react';
import { Text } from 'react-native';

import styles from '../../styles/styles';
import InPageImage from '../inPageImage';
import AnimalText from '../animalText';
import AnimalTemplate from '../animalTemplate';

const IMAGES = [
  require('../../images/animals/pustikBradaty/01.jpg'),
  require('../../images/animals/pustikBradaty/02.jpg'),
  require('../../images/animals/pustikBradaty/03.jpg'),
];

const THUMBNAILS = [
  require('../../images/animals/pustikBradaty/01-thumb.jpg'),
  require('../../images/animals/pustikBradaty/02-thumb.jpg'),
  require('../../images/animals/pustikBradaty/03-thumb.jpg'),
];

var AnimalDetail = React.createClass({
  render() {
    return (
      <AnimalTemplate firstIndex={[1]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator}>
        <AnimalText>
        Ahoj děti!
        </AnimalText>

        <AnimalText>
        Já jsem puštík bradatý a patřím mezi sovy, moudré noční živočichy, jejichž řád čítá přes 200 druhů. Vylíhl jsem se 13. května 2012 v zemi tulipánů – Nizozemsku. Moje kamarádka, se kterou bydlím ve stejné voliéře, se vylíhla v sousední Belgii přesně o jeden rok a jeden den dříve, tedy 12. května 2011. Na první pohled nás od sebe nerozeznáte, ale zkušené oko pozorovatele odhalí, že samička je o něco větší. Kromě nás existuje ve světě asi dvacet dalších druhů puštíků, ale my jsme ze všech největší. Když roztáhneme křídla, od jednoho konce k druhému měříme až 1,5 metru, což je zhruba délka těla vlka obecného.
        </AnimalText>
        <InPageImage indexes={[2]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
        Své druhové jméno – bradatý (nebo také vousatý) – jsme si vysloužili díky tomu, že máme ve spodní části závoje naší kulaté hlavy bílá peříčka, která vypadají úplně jako knírek. Žijeme převážně v jehličnatých lesích severní Evropy, Severní Ameriky a Asie. K jídlu máme nejraději drobné hlodavce, třeba hraboše, veverky a norníky, občas i nějakého toho zajíce nebo kachnu. Umíme létat velice tiše a máme výborný sluch, díky kterému dokážeme vypátrat a zaměřit svoji kořist pod sněhem v hloubce až 60 cm. Ulovíme ji tak, že se vrhneme celou svou vahou proti sněhové krustě, která by mohla unést i 80kg člověka. Díky této schopnosti můžeme přežívat i ve velmi chladném prostředí, kde by si jiná zvířátka potravu obstarat nedokázala.
        </AnimalText>
        <InPageImage indexes={[0]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator} />
        <AnimalText>
        Se svými partnery tvoříme páry na celý život, který trvá až 20 let. Samička snáší 3 až 4 vajíčka, která se líhnou asi po měsíci. Svá mláďátka krmíme a hlídáme ještě dlouho poté, co se vylíhnou. Jsme velmi obětaví rodiče, proto mláďata dokážeme uchránit i před těmi největšími vetřelci.
        </AnimalText>
        <AnimalText>
        V brněnské zoo jsme zatím malé puštíky neměli, ale kdo ví, co přinese budoucnost.
        </AnimalText>
        <AnimalText>
        Puštíka bradatého znáte určitě všichni díky filmům o Harry Potterovi, kde si zahrál sovu Errol.
        </AnimalText>
      </AnimalTemplate>
    );
  }
});

module.exports = AnimalDetail;
<|endoftext|>


<commit_before>const ARROW_OFFSET = 7;
const POPUP_OFFSET = 12;

const getAnchorPositionValues = anchorEl => {
  const { top, left, right, bottom, width, height } = anchorEl.getBoundingClientRect();

  return {
    top,
    left,
    width,
    height,
    right: right || left + width,
    bottom: bottom || top + height,
    middle: top + (bottom - top) / 2,
    center: left + (right - left) / 2,
  };
};

const getPopoverPositionValues = popoverEl => {
  const { width, height } = popoverEl.getBoundingClientRect();

  return {
    width,
    height,
    top: 0,
    left: 0,
    right: width,
    bottom: height,
    middle: width / 2,
    center: height / 2,
  };
};

const getElementHeightValue = element => element.getBoundingClientRect().height;

const getVerticalDirectionPositionValues = ({
  direction,
  position,
  anchorPosition,
  popoverPosition,
  inputOffsetCorrection,
}) => ({
  top: getVerticalDirectionPositionTopValue({
    direction,
    anchorPosition,
    popoverPosition,
  }),
  arrowTop: getVerticalDirectionArrowPositionTopValue({ direction, popoverPosition }),
  left: getVerticalDirectionPositionLeftValue({
    position,
    anchorPosition,
    popoverPosition,
    inputOffsetCorrection,
  }),
  arrowLeft: getVerticalDirectionArrowPositionLeftValue({ position, popoverPosition }),
});

const getHorizontalDirectionPositionValues = ({
  direction,
  position,
  anchorPosition,
  popoverPosition,
  inputOffsetCorrection,
}) => ({
  top: getHorizontalDirectionPositionTopValue({
    position,
    anchorPosition,
    popoverPosition,
    inputOffsetCorrection,
  }),
  arrowTop: getHorizontalDirectionArrowPositionTopValue({ position, popoverPosition }),
  left: getHorizontalDirectionPositionLeftValue({ direction, anchorPosition, popoverPosition }),
  arrowLeft: getHorizontalDirectionArrowPositionLeftValue({
    direction,
    anchorPosition,
    popoverPosition,
  }),
});

const getPositionValues = ({ direction, position, anchorPosition, popoverPosition, inputOffsetCorrection }) =>
  direction === 'north' || direction === 'south'
    ? getVerticalDirectionPositionValues({
        direction,
        position,
        anchorPosition,
        popoverPosition,
        inputOffsetCorrection,
      })
    : getHorizontalDirectionPositionValues({
        direction,
        position,
        anchorPosition,
        popoverPosition,
        inputOffsetCorrection,
      });

// HORIZONTAL
const getHorizontalDirectionPositionTopValue = ({
  position,
  anchorPosition,
  popoverPosition,
  inputOffsetCorrection,
}) => {
  switch (position) {
    case 'middle':
      return anchorPosition.middle - popoverPosition.height / 2;
    case 'top':
      return anchorPosition.top - POPUP_OFFSET * 0.75 - inputOffsetCorrection;
    case 'bottom':
      return anchorPosition.bottom - popoverPosition.height + POPUP_OFFSET * 0.75 + inputOffsetCorrection;
  }
};

const getHorizontalDirectionPositionLeftValue = ({ direction, anchorPosition, popoverPosition }) =>
  direction === 'west'
    ? anchorPosition.left - popoverPosition.width - POPUP_OFFSET
    : anchorPosition.right + POPUP_OFFSET;

const getHorizontalDirectionArrowPositionTopValue = ({ position, popoverPosition }) => {
  switch (position) {
    case 'middle':
      return popoverPosition.height / 2 - ARROW_OFFSET;
    case 'top':
      return ARROW_OFFSET * 2.35;
    case 'bottom':
      return popoverPosition.height - ARROW_OFFSET * 4.5;
  }
};

const getHorizontalDirectionArrowPositionLeftValue = ({ direction, popoverPosition }) =>
  direction === 'west' ? popoverPosition.width - ARROW_OFFSET : -ARROW_OFFSET;

// VERTICAL
const getVerticalDirectionPositionTopValue = ({ direction, anchorPosition, popoverPosition }) =>
  direction === 'north'
    ? anchorPosition.top - popoverPosition.height - POPUP_OFFSET
    : anchorPosition.top + anchorPosition.height + POPUP_OFFSET;

const getVerticalDirectionPositionLeftValue = ({
  position,
  anchorPosition,
  popoverPosition,
  inputOffsetCorrection,
}) => {
  switch (position) {
    case 'center':
      return anchorPosition.center - popoverPosition.width / 2;
    case 'left':
      return anchorPosition.left - inputOffsetCorrection;
    case 'right':
      return anchorPosition.right - popoverPosition.width + inputOffsetCorrection;
  }
};

const getVerticalDirectionArrowPositionTopValue = ({ direction, popoverPosition }) =>
  direction === 'north' ? popoverPosition.height - ARROW_OFFSET : -ARROW_OFFSET;

const getVerticalDirectionArrowPositionLeftValue = ({ position, popoverPosition }) => {
  switch (position) {
    case 'center':
      return popoverPosition.width / 2 - ARROW_OFFSET;
    case 'left':
      return 2 * POPUP_OFFSET;
    case 'right':
      return popoverPosition.width - POPUP_OFFSET * 3;
  }
};

const isInViewport = ({ direction, anchorPosition, popoverPosition }) => {
  switch (direction) {
    case 'north':
      return anchorPosition.top - popoverPosition.height - POPUP_OFFSET > 0;
    case 'south':
      return anchorPosition.bottom + popoverPosition.height + POPUP_OFFSET < window.innerHeight;
    case 'east':
      return anchorPosition.right + popoverPosition.width + POPUP_OFFSET < window.innerWidth;
    case 'west':
      return anchorPosition.left - popoverPosition.width - POPUP_OFFSET > 0;
  }
};

const getOppositeDirection = direction => {
  switch (direction) {
    case 'north':
      return 'south';
    case 'south':
      return 'north';
    case 'east':
      return 'west';
    case 'west':
      return 'east';
  }
};

const getDirection = ({ direction, anchorPosition, popoverPosition }) => {
  const inputDirectionRendersOnScreen = isInViewport({ direction, anchorPosition, popoverPosition });
  const oppositeDirectionRendersOnScreen = isInViewport({
    direction: getOppositeDirection(direction),
    anchorPosition,
    popoverPosition,
  });

  return !inputDirectionRendersOnScreen && oppositeDirectionRendersOnScreen
    ? getOppositeDirection(direction)
    : direction;
};

const isPositionPossible = (position, anchorPosition, popoverPosition) => {
  switch (position) {
    case 'middle':
      return (
        anchorPosition.middle + popoverPosition.height / 2 < window.innerHeight &&
        anchorPosition.middle - popoverPosition.height / 2 > 0
      );
    case 'top':
      return anchorPosition.top + popoverPosition.height < window.innerHeight;
    case 'bottom':
      return anchorPosition.bottom - popoverPosition.height > 0;
    case 'center':
      return (
        anchorPosition.center + popoverPosition.width / 2 < window.innerWidth &&
        anchorPosition.center - popoverPosition.width / 2 > 0
      );
    case 'left':
      return anchorPosition.left + popoverPosition.width < window.innerWidth;
    case 'right':
      return anchorPosition.right - popoverPosition.width > 0;
  }
};

const getOppositePosition = direction => {
  switch (direction) {
    case 'top':
      return 'bottom';
    case 'bottom':
      return 'top';
    case 'left':
      return 'right';
    case 'right':
      return 'left';
  }
};

const getPosition = ({ position, anchorPosition, popoverPosition }) => {
  if (isPositionPossible(position, anchorPosition, popoverPosition)) {
    return position;
  }

  switch (position) {
    case 'middle':
      return isPositionPossible('top', anchorPosition, popoverPosition)
        ? 'top'
        : isPositionPossible('bottom', anchorPosition, popoverPosition)
          ? 'bottom'
          : position;
    case 'center':
      return isPositionPossible('left', anchorPosition, popoverPosition)
        ? 'left'
        : isPositionPossible('right', anchorPosition, popoverPosition)
          ? 'right'
          : position;
    case 'top':
    case 'bottom':
      return isPositionPossible('middle', anchorPosition, popoverPosition) ? 'middle' : getOppositePosition(position);
    case 'left':
    case 'right':
      return isPositionPossible('center', anchorPosition, popoverPosition) ? 'center' : getOppositePosition(position);
  }
};

const getMaxPopoverHeightValue = ({ direction, anchorPosition }) => {
  switch (direction) {
    case 'north':
      return anchorPosition.top - POPUP_OFFSET * 2;
    case 'south':
      return window.innerHeight - anchorPosition.bottom - POPUP_OFFSET * 2;
  }
};

export const calculatePositions = (
  anchorEl,
  popoverEl,
  popoverContentEl,
  inputDirection,
  inputPosition,
  inputOffsetCorrection,
) => {
  const anchorPosition = getAnchorPositionValues(anchorEl);
  const popoverPosition = getPopoverPositionValues(popoverEl);

  const direction = getDirection({ direction: inputDirection, anchorPosition, popoverPosition });
  const position = getPosition({ position: inputPosition, anchorPosition, popoverPosition });

  const inputDirectionContentRendersOnScreen = isInViewport({
    direction: inputDirection,
    anchorPosition,
    popoverPosition: { height: getElementHeightValue(popoverContentEl) },
  });
  const oppositeDirectionContentRendersOnScreen = isInViewport({
    direction: getOppositeDirection(inputDirection),
    anchorPosition,
    popoverPosition: { height: getElementHeightValue(popoverContentEl) },
  });
  let maxPopoverHeight = 'initial';
  if (!inputDirectionContentRendersOnScreen && !oppositeDirectionContentRendersOnScreen) {
    maxPopoverHeight = getMaxPopoverHeightValue({
      direction,
      anchorPosition,
    });
  }

  return {
    maxPopoverHeight,
    ...getPositionValues({
      direction,
      position,
      anchorPosition,
      popoverPosition,
      inputOffsetCorrection,
    }),
  };
};
<commit_msg>Split function for cleaner code<commit_after>const ARROW_OFFSET = 7;
const POPUP_OFFSET = 12;

const getAnchorPositionValues = anchorEl => {
  const { top, left, right, bottom, width, height } = anchorEl.getBoundingClientRect();

  return {
    top,
    left,
    width,
    height,
    right: right || left + width,
    bottom: bottom || top + height,
    middle: top + (bottom - top) / 2,
    center: left + (right - left) / 2,
  };
};

const getPopoverPositionValues = popoverEl => {
  const { width, height } = popoverEl.getBoundingClientRect();

  return {
    width,
    height,
    top: 0,
    left: 0,
    right: width,
    bottom: height,
    middle: width / 2,
    center: height / 2,
  };
};

const getElementHeightValue = element => element.getBoundingClientRect().height;

const getVerticalDirectionPositionValues = ({
  direction,
  position,
  anchorPosition,
  popoverPosition,
  inputOffsetCorrection,
}) => ({
  top: getVerticalDirectionPositionTopValue({
    direction,
    anchorPosition,
    popoverPosition,
  }),
  arrowTop: getVerticalDirectionArrowPositionTopValue({ direction, popoverPosition }),
  left: getVerticalDirectionPositionLeftValue({
    position,
    anchorPosition,
    popoverPosition,
    inputOffsetCorrection,
  }),
  arrowLeft: getVerticalDirectionArrowPositionLeftValue({ position, popoverPosition }),
});

const getHorizontalDirectionPositionValues = ({
  direction,
  position,
  anchorPosition,
  popoverPosition,
  inputOffsetCorrection,
}) => ({
  top: getHorizontalDirectionPositionTopValue({
    position,
    anchorPosition,
    popoverPosition,
    inputOffsetCorrection,
  }),
  arrowTop: getHorizontalDirectionArrowPositionTopValue({ position, popoverPosition }),
  left: getHorizontalDirectionPositionLeftValue({ direction, anchorPosition, popoverPosition }),
  arrowLeft: getHorizontalDirectionArrowPositionLeftValue({
    direction,
    anchorPosition,
    popoverPosition,
  }),
});

const getPositionValues = ({ direction, position, anchorPosition, popoverPosition, inputOffsetCorrection }) =>
  direction === 'north' || direction === 'south'
    ? getVerticalDirectionPositionValues({
        direction,
        position,
        anchorPosition,
        popoverPosition,
        inputOffsetCorrection,
      })
    : getHorizontalDirectionPositionValues({
        direction,
        position,
        anchorPosition,
        popoverPosition,
        inputOffsetCorrection,
      });

// HORIZONTAL
const getHorizontalDirectionPositionTopValue = ({
  position,
  anchorPosition,
  popoverPosition,
  inputOffsetCorrection,
}) => {
  switch (position) {
    case 'middle':
      return anchorPosition.middle - popoverPosition.height / 2;
    case 'top':
      return anchorPosition.top - POPUP_OFFSET * 0.75 - inputOffsetCorrection;
    case 'bottom':
      return anchorPosition.bottom - popoverPosition.height + POPUP_OFFSET * 0.75 + inputOffsetCorrection;
  }
};

const getHorizontalDirectionPositionLeftValue = ({ direction, anchorPosition, popoverPosition }) =>
  direction === 'west'
    ? anchorPosition.left - popoverPosition.width - POPUP_OFFSET
    : anchorPosition.right + POPUP_OFFSET;

const getHorizontalDirectionArrowPositionTopValue = ({ position, popoverPosition }) => {
  switch (position) {
    case 'middle':
      return popoverPosition.height / 2 - ARROW_OFFSET;
    case 'top':
      return ARROW_OFFSET * 2.35;
    case 'bottom':
      return popoverPosition.height - ARROW_OFFSET * 4.5;
  }
};

const getHorizontalDirectionArrowPositionLeftValue = ({ direction, popoverPosition }) =>
  direction === 'west' ? popoverPosition.width - ARROW_OFFSET : -ARROW_OFFSET;

// VERTICAL
const getVerticalDirectionPositionTopValue = ({ direction, anchorPosition, popoverPosition }) =>
  direction === 'north'
    ? anchorPosition.top - popoverPosition.height - POPUP_OFFSET
    : anchorPosition.top + anchorPosition.height + POPUP_OFFSET;

const getVerticalDirectionPositionLeftValue = ({
  position,
  anchorPosition,
  popoverPosition,
  inputOffsetCorrection,
}) => {
  switch (position) {
    case 'center':
      return anchorPosition.center - popoverPosition.width / 2;
    case 'left':
      return anchorPosition.left - inputOffsetCorrection;
    case 'right':
      return anchorPosition.right - popoverPosition.width + inputOffsetCorrection;
  }
};

const getVerticalDirectionArrowPositionTopValue = ({ direction, popoverPosition }) =>
  direction === 'north' ? popoverPosition.height - ARROW_OFFSET : -ARROW_OFFSET;

const getVerticalDirectionArrowPositionLeftValue = ({ position, popoverPosition }) => {
  switch (position) {
    case 'center':
      return popoverPosition.width / 2 - ARROW_OFFSET;
    case 'left':
      return 2 * POPUP_OFFSET;
    case 'right':
      return popoverPosition.width - POPUP_OFFSET * 3;
  }
};

const isInViewport = ({ direction, anchorPosition, popoverPosition }) => {
  switch (direction) {
    case 'north':
      return anchorPosition.top - popoverPosition.height - POPUP_OFFSET > 0;
    case 'south':
      return anchorPosition.bottom + popoverPosition.height + POPUP_OFFSET < window.innerHeight;
    case 'east':
      return anchorPosition.right + popoverPosition.width + POPUP_OFFSET < window.innerWidth;
    case 'west':
      return anchorPosition.left - popoverPosition.width - POPUP_OFFSET > 0;
  }
};

const getOppositeDirection = direction => {
  switch (direction) {
    case 'north':
      return 'south';
    case 'south':
      return 'north';
    case 'east':
      return 'west';
    case 'west':
      return 'east';
  }
};

const getDirection = ({ direction, anchorPosition, popoverPosition }) => {
  const inputDirectionRendersOnScreen = isInViewport({ direction, anchorPosition, popoverPosition });
  const oppositeDirectionRendersOnScreen = isInViewport({
    direction: getOppositeDirection(direction),
    anchorPosition,
    popoverPosition,
  });

  return !inputDirectionRendersOnScreen && oppositeDirectionRendersOnScreen
    ? getOppositeDirection(direction)
    : direction;
};

const isPositionPossible = (position, anchorPosition, popoverPosition) => {
  switch (position) {
    case 'middle':
      return (
        anchorPosition.middle + popoverPosition.height / 2 < window.innerHeight &&
        anchorPosition.middle - popoverPosition.height / 2 > 0
      );
    case 'top':
      return anchorPosition.top + popoverPosition.height < window.innerHeight;
    case 'bottom':
      return anchorPosition.bottom - popoverPosition.height > 0;
    case 'center':
      return (
        anchorPosition.center + popoverPosition.width / 2 < window.innerWidth &&
        anchorPosition.center - popoverPosition.width / 2 > 0
      );
    case 'left':
      return anchorPosition.left + popoverPosition.width < window.innerWidth;
    case 'right':
      return anchorPosition.right - popoverPosition.width > 0;
  }
};

const getOppositePosition = direction => {
  switch (direction) {
    case 'top':
      return 'bottom';
    case 'bottom':
      return 'top';
    case 'left':
      return 'right';
    case 'right':
      return 'left';
  }
};

const getPosition = ({ position, anchorPosition, popoverPosition }) => {
  if (isPositionPossible(position, anchorPosition, popoverPosition)) {
    return position;
  }

  switch (position) {
    case 'middle':
      return isPositionPossible('top', anchorPosition, popoverPosition)
        ? 'top'
        : isPositionPossible('bottom', anchorPosition, popoverPosition)
          ? 'bottom'
          : position;
    case 'center':
      return isPositionPossible('left', anchorPosition, popoverPosition)
        ? 'left'
        : isPositionPossible('right', anchorPosition, popoverPosition)
          ? 'right'
          : position;
    case 'top':
    case 'bottom':
      return isPositionPossible('middle', anchorPosition, popoverPosition) ? 'middle' : getOppositePosition(position);
    case 'left':
    case 'right':
      return isPositionPossible('center', anchorPosition, popoverPosition) ? 'center' : getOppositePosition(position);
  }
};

const getMaxPopoverHeight = ({ direction, anchorPosition, popoverContentEl }) => {
  const directionContentRendersOnScreen = isInViewport({
    direction,
    anchorPosition,
    popoverPosition: { height: getElementHeightValue(popoverContentEl) },
  });
  const oppositeDirectionContentRendersOnScreen = isInViewport({
    direction: getOppositeDirection(direction),
    anchorPosition,
    popoverPosition: { height: getElementHeightValue(popoverContentEl) },
  });

  if (!directionContentRendersOnScreen && !oppositeDirectionContentRendersOnScreen) {
    return getMaxPopoverHeightValue({
      direction,
      anchorPosition,
    });
  }

  return 'initial';
};

const getMaxPopoverHeightValue = ({ direction, anchorPosition }) => {
  switch (direction) {
    case 'north':
      return anchorPosition.top - POPUP_OFFSET * 2;
    case 'south':
      return window.innerHeight - anchorPosition.bottom - POPUP_OFFSET * 2;
  }
};

export const calculatePositions = (
  anchorEl,
  popoverEl,
  popoverContentEl,
  inputDirection,
  inputPosition,
  inputOffsetCorrection,
) => {
  const anchorPosition = getAnchorPositionValues(anchorEl);
  const popoverPosition = getPopoverPositionValues(popoverEl);

  const direction = getDirection({ direction: inputDirection, anchorPosition, popoverPosition });
  const position = getPosition({ position: inputPosition, anchorPosition, popoverPosition });

  return {
    maxPopoverHeight: getMaxPopoverHeight({
      direction,
      anchorPosition,
      popoverContentEl,
    }),
    ...getPositionValues({
      direction,
      position,
      anchorPosition,
      popoverPosition,
      inputOffsetCorrection,
    }),
  };
};
<|endoftext|>


<commit_before>const sass = require('node-sass');

module.exports = function(grunt) {
  var path = require('path');

  var SOURCE_FILES = [
    'src/ts/**/*.ts',
    '!src/ts/types/**'
  ]

  grunt.initConfig({

    pkg: grunt.file.readJSON('package.json'),

    DIST: '../tessera-server/tessera/static',

    /**
     * 1 - Transpile all TypeScript sources to ES6
     */
    ts: {
      default: {
        src: SOURCE_FILES,
        outDir: '_build/phase1',
        options: {
          target: 'es6',
          comments: true,
          declaration: true,
          sourceMap: true,
          moduleResolution: 'node'
        }
      }
    },

    /**
     * 2 - Compile the app sources to a single bundle using
     * browserify, running babeljs over the sources on the way.
     */
    browserify: {

      dep: {
        files: {
          '_build/dependencies.js' : [
            'src/js/dependencies.js'
          ]
        },
        options: {
          browserifyOptions: {
            // debug: true
          }
        }
      },

      app: {
        files: {
          '_build/phase2.js' : [
            '_build/phase1/**/*.js'
          ]
        },
        options: {
          transform: [
            ['babelify', {
              presets: [
                'es2015', 'stage-0'
              ]
            }]
          ],
          browserifyOptions: {
            // debug: true
          }
        }
      }
    },

    /**
     * 3 - Precompile the handlebars templates
     */
    handlebars: {
      all: {
        options: {
          partialsUseNamespace: true,
          namespace: function(filename) {
            return path.dirname(filename).split('/').join('.').replace('src', 'ts')
          },
          processName: function(filename) {
            var pieces = filename.split('/')
            return pieces[pieces.length - 1].split('.')[0]
          }
        },
        files: {
          '_build/templates.js' : [ 'src/templates/**/*.hbs']
        }
      }
    },

    /**
     * 3b - compile the SCSS source to CSS
     */
    sass: {
      options: {
        implementation: sass,
        sourceMap: true
      },
      dist: {
        files: {
          '_build/css/tessera.css':                'src/css/tessera.scss',
          '_build/css/tessera-typography.css':     'src/css/tessera-typography.scss',
          '_build/css/themes/bootstrap-dark.css':  'src/css/themes/bootstrap-dark.scss',
          '_build/css/themes/tessera-dark.css':    'src/css/themes/tessera-dark.scss',
          '_build/css/themes/bootstrap-light.css': 'src/css/themes/bootstrap-light.scss',
          '_build/css/themes/tessera-light.css':   'src/css/themes/tessera-light.scss',
          '_build/css/themes/bootstrap-snow.css':  'src/css/themes/bootstrap-snow.scss',
          '_build/css/themes/tessera-snow.css':     'src/css/themes/tessera-snow.scss',
          '_build/css/themes/tessera-solarized-light.css': 'src/css/themes/tessera-solarized-light.scss',
          '_build/css/themes/tessera-solarized-dark.css':  'src/css/themes/tessera-solarized-dark.scss'
        }
      }
    },

    /**
     * 4 - Concatenate the transpiled sources, the precompiled
     * templates, and the babel polyfill required for all ES6 support.
     */
    concat: {
      dep_css: {
        src: [
          'src/3rd-Party/css/bootstrap.css',
          'src/3rd-Party/css/bootstrap-callouts.css',
          'src/3rd-Party/css/bootstrap-editable.css',
          'src/3rd-Party/css/bootstrap-datetimepicker.css',
          'src/3rd-Party/css/bootstrapValidator.min.css',
          'src/3rd-Party/css/font-awesome.css',
          'src/3rd-Party/css/select2.css',
          'src/3rd-Party/css/select2-bootstrap.css',
          'src/3rd-Party/css/dataTables.bootstrap.css',
          'src/3rd-Party/css/jquery.flot.valuelabels.css',
          'src/3rd-Party/css/highlight-styles/github.css'
        ],
        dest: '<%= DIST %>/css/bundle.css'
      },
      dep_js: {
        options: {
          separator: ';'
        },
        src: [
          '_build/dependencies.js',
          'node_modules/d3-format/dist/d3-format.js',
          'node_modules/d3-shape/dist/d3-shape.js',
          'node_modules/flot/jquery.flot.js',
          'node_modules/flot/jquery.flot.time.js',
          'node_modules/flot/jquery.flot.resize.js',
          'node_modules/flot/jquery.flot.pie.js',
          'node_modules/flot-d3-stack/jquery.flot.d3.stack.js',
          'node_modules/flot-axislabels/jquery.flot.axislabels.js',
          'src/3rd-Party/js/tagmanager.js',
          'src/3rd-Party/js/bootstrap-editable.min.js',
          'src/3rd-Party/js/bootstrap-datetimepicker.min.js',
          'src/3rd-Party/js/bootstrapValidator.min.js',
          'src/3rd-Party/js/flot/jquery.flot.multihighlight.js',
          'src/3rd-Party/js/flot/jquery.flot.crosshair.js',
          'src/3rd-Party/js/flot/jquery.flot.downsample.js',
          'src/3rd-Party/js/flot/jquery.flot.valuelabels.js',
          'src/3rd-Party/js/flot/jquery.flot.barnumbers.enhanced.js',
          'src/3rd-Party/js/equalize.min.js'
        ],
        dest: '<%= DIST %>/bundle.js'
      },
      app: {
        options: {
          separator: ';'
        },
        src: [
          'node_modules/babel-core/browser-polyfill.js',
          '_build/templates.js',
          '_build/phase2.js'
        ],
        dest: '<%= DIST %>/tessera.js'
      }
    },

    /**
     * 5 - Copy sources to the static resources dir.
     */
    copy: {
      dep: {
        files: [
          { expand: true, cwd: 'src/3rd-Party/fonts/', src: '**', dest: '<%= DIST %>/fonts/' },
          { expand: true, cwd: 'src/3rd-Party/img/', src: '**', dest: '<%= DIST %>/img/' },
          {
            expand: true, cwd: 'src/3rd-Party/css/', src: [
              '*.gif', '*.png', '*.map'
            ],
            dest: '<%= DIST %>/css'
          }
        ]
      },
      app: {
        files: [
          { expand: true, cwd: 'node_modules/bootstrap-solarized/', src: '*.css', dest: '<%= DIST %>/themes/' },
          { expand: true, cwd: '_build/css/', src: '**', dest: '<%= DIST %>/' }
        ]
      }
    },

    clean: {
      build: {
        src: [
          '_build/',
          '<%= DIST %>/*'
        ]
      }
    },

    watch: {
      dep: {
        files: [
          'src/js/dependencies.js',
          'src/3rd-Party/**/*.*',
          'node_modules/**/*.js'
        ],
        tasks: ['dep']
      },
      app_templates: {
        files: [
          'src/templates/**/*.hbs'
        ],
        tasks: ['handlebars', 'concat:app', 'copy:app']
      },
      app_js: {
        files: [
          'src/ts/**/*.ts'
        ],
        tasks: ['app']
      },
      app_css: {
        files: [
          'src/css/**/*.scss'
        ],
        tasks: ['sass', 'copy:app']
      }
    },

    run: {
      screenshots: {
        options: {
          wait: true
        },
        args: [
          'screenshots.js'
        ]
      }
    }

  });

  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-handlebars');
  grunt.loadNpmTasks('grunt-browserify');
  grunt.loadNpmTasks('grunt-sass');
  grunt.loadNpmTasks('grunt-ts');
  grunt.loadNpmTasks('grunt-run');

  /** Compile the tessera source and templates */
  grunt.registerTask('app', [
    'ts', 'browserify:app', 'handlebars', 'sass', 'concat:app', 'copy:app'
  ])

  grunt.registerTask('css', [
    'sass', 'copy:app'
  ])

  /** Compile all third-party dependencies */
  grunt.registerTask('dep', [
    'browserify:dep', 'concat:dep_js', 'concat:dep_css', 'copy:dep'
  ]);

  /** Compile everything */
  grunt.registerTask('all', [
    'app', 'dep'
  ])

  /** By default */
  grunt.registerTask('default', [
    'all'
  ])
}
<commit_msg>Fix flot dependency paths<commit_after>const sass = require('node-sass');

module.exports = function(grunt) {
  var path = require('path');

  var SOURCE_FILES = [
    'src/ts/**/*.ts',
    '!src/ts/types/**'
  ]

  grunt.initConfig({

    pkg: grunt.file.readJSON('package.json'),

    DIST: '../tessera-server/tessera/static',

    /**
     * 1 - Transpile all TypeScript sources to ES6
     */
    ts: {
      default: {
        src: SOURCE_FILES,
        outDir: '_build/phase1',
        options: {
          target: 'es6',
          comments: true,
          declaration: true,
          sourceMap: true,
          moduleResolution: 'node'
        }
      }
    },

    /**
     * 2 - Compile the app sources to a single bundle using
     * browserify, running babeljs over the sources on the way.
     */
    browserify: {

      dep: {
        files: {
          '_build/dependencies.js' : [
            'src/js/dependencies.js'
          ]
        },
        options: {
          browserifyOptions: {
            // debug: true
          }
        }
      },

      app: {
        files: {
          '_build/phase2.js' : [
            '_build/phase1/**/*.js'
          ]
        },
        options: {
          transform: [
            ['babelify', {
              presets: [
                'es2015', 'stage-0'
              ]
            }]
          ],
          browserifyOptions: {
            // debug: true
          }
        }
      }
    },

    /**
     * 3 - Precompile the handlebars templates
     */
    handlebars: {
      all: {
        options: {
          partialsUseNamespace: true,
          namespace: function(filename) {
            return path.dirname(filename).split('/').join('.').replace('src', 'ts')
          },
          processName: function(filename) {
            var pieces = filename.split('/')
            return pieces[pieces.length - 1].split('.')[0]
          }
        },
        files: {
          '_build/templates.js' : [ 'src/templates/**/*.hbs']
        }
      }
    },

    /**
     * 3b - compile the SCSS source to CSS
     */
    sass: {
      options: {
        implementation: sass,
        sourceMap: true
      },
      dist: {
        files: {
          '_build/css/tessera.css':                'src/css/tessera.scss',
          '_build/css/tessera-typography.css':     'src/css/tessera-typography.scss',
          '_build/css/themes/bootstrap-dark.css':  'src/css/themes/bootstrap-dark.scss',
          '_build/css/themes/tessera-dark.css':    'src/css/themes/tessera-dark.scss',
          '_build/css/themes/bootstrap-light.css': 'src/css/themes/bootstrap-light.scss',
          '_build/css/themes/tessera-light.css':   'src/css/themes/tessera-light.scss',
          '_build/css/themes/bootstrap-snow.css':  'src/css/themes/bootstrap-snow.scss',
          '_build/css/themes/tessera-snow.css':     'src/css/themes/tessera-snow.scss',
          '_build/css/themes/tessera-solarized-light.css': 'src/css/themes/tessera-solarized-light.scss',
          '_build/css/themes/tessera-solarized-dark.css':  'src/css/themes/tessera-solarized-dark.scss'
        }
      }
    },

    /**
     * 4 - Concatenate the transpiled sources, the precompiled
     * templates, and the babel polyfill required for all ES6 support.
     */
    concat: {
      dep_css: {
        src: [
          'src/3rd-Party/css/bootstrap.css',
          'src/3rd-Party/css/bootstrap-callouts.css',
          'src/3rd-Party/css/bootstrap-editable.css',
          'src/3rd-Party/css/bootstrap-datetimepicker.css',
          'src/3rd-Party/css/bootstrapValidator.min.css',
          'src/3rd-Party/css/font-awesome.css',
          'src/3rd-Party/css/select2.css',
          'src/3rd-Party/css/select2-bootstrap.css',
          'src/3rd-Party/css/dataTables.bootstrap.css',
          'src/3rd-Party/css/jquery.flot.valuelabels.css',
          'src/3rd-Party/css/highlight-styles/github.css'
        ],
        dest: '<%= DIST %>/css/bundle.css'
      },
      dep_js: {
        options: {
          separator: ';'
        },
        src: [
          '_build/dependencies.js',
          'node_modules/d3-format/dist/d3-format.js',
          'node_modules/d3-shape/dist/d3-shape.js',
          'node_modules/flot/dist/es5/jquery.flot.js',
          'node_modules/flot/source/jquery.flot.pie.js',
          'node_modules/flot-d3-stack/jquery.flot.d3.stack.js',
          'src/3rd-Party/js/tagmanager.js',
          'src/3rd-Party/js/bootstrap-editable.min.js',
          'src/3rd-Party/js/bootstrap-datetimepicker.min.js',
          'src/3rd-Party/js/bootstrapValidator.min.js',
          'src/3rd-Party/js/flot/jquery.flot.multihighlight.js',
          'src/3rd-Party/js/flot/jquery.flot.crosshair.js',
          'src/3rd-Party/js/flot/jquery.flot.downsample.js',
          'src/3rd-Party/js/flot/jquery.flot.valuelabels.js',
          'src/3rd-Party/js/flot/jquery.flot.barnumbers.enhanced.js',
          'src/3rd-Party/js/equalize.min.js'
        ],
        dest: '<%= DIST %>/bundle.js'
      },
      app: {
        options: {
          separator: ';'
        },
        src: [
          'node_modules/babel-core/browser-polyfill.js',
          '_build/templates.js',
          '_build/phase2.js'
        ],
        dest: '<%= DIST %>/tessera.js'
      }
    },

    /**
     * 5 - Copy sources to the static resources dir.
     */
    copy: {
      dep: {
        files: [
          { expand: true, cwd: 'src/3rd-Party/fonts/', src: '**', dest: '<%= DIST %>/fonts/' },
          { expand: true, cwd: 'src/3rd-Party/img/', src: '**', dest: '<%= DIST %>/img/' },
          {
            expand: true, cwd: 'src/3rd-Party/css/', src: [
              '*.gif', '*.png', '*.map'
            ],
            dest: '<%= DIST %>/css'
          }
        ]
      },
      app: {
        files: [
          { expand: true, cwd: 'node_modules/bootstrap-solarized/', src: '*.css', dest: '<%= DIST %>/themes/' },
          { expand: true, cwd: '_build/css/', src: '**', dest: '<%= DIST %>/' }
        ]
      }
    },

    clean: {
      build: {
        src: [
          '_build/',
          '<%= DIST %>/*'
        ]
      }
    },

    watch: {
      dep: {
        files: [
          'src/js/dependencies.js',
          'src/3rd-Party/**/*.*',
          'node_modules/**/*.js',
          'Gruntfiles.js'
        ],
        tasks: ['dep']
      },
      app_templates: {
        files: [
          'src/templates/**/*.hbs'
        ],
        tasks: ['handlebars', 'concat:app', 'copy:app']
      },
      app_js: {
        files: [
          'src/ts/**/*.ts'
        ],
        tasks: ['app']
      },
      app_css: {
        files: [
          'src/css/**/*.scss'
        ],
        tasks: ['sass', 'copy:app']
      }
    },

    run: {
      screenshots: {
        options: {
          wait: true
        },
        args: [
          'screenshots.js'
        ]
      }
    }

  });

  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-handlebars');
  grunt.loadNpmTasks('grunt-browserify');
  grunt.loadNpmTasks('grunt-sass');
  grunt.loadNpmTasks('grunt-ts');
  grunt.loadNpmTasks('grunt-run');

  /** Compile the tessera source and templates */
  grunt.registerTask('app', [
    'ts', 'browserify:app', 'handlebars', 'sass', 'concat:app', 'copy:app'
  ])

  grunt.registerTask('css', [
    'sass', 'copy:app'
  ])

  /** Compile all third-party dependencies */
  grunt.registerTask('dep', [
    'browserify:dep', 'concat:dep_js', 'concat:dep_css', 'copy:dep'
  ]);

  /** Compile everything */
  grunt.registerTask('all', [
    'app', 'dep'
  ])

  /** By default */
  grunt.registerTask('default', [
    'all'
  ])
}
<|endoftext|>


<commit_before>const path = require('path');

console.info('balm@zero');

const projectRoot = path.resolve(__dirname, '..');
const workspace = path.join(projectRoot, 'test-workspace');

const config = {
  workspace,
  // useDefaults: false,
  // paths: {
  //   source: {
  //     html: 'tpl'
  //   }
  // },
  styles: {
    extname: 'scss',
    dartSass: true
    // sprites: ['icons', 'mdi']
  },
  scripts: {
    bundler: 'esbuild',
    lint: true
  },
  // images: {
  //   plugins: {
  //     jpeg: false,
  //     png: false
  //   }
  // },
  assets: {
    cache: true
  },
  logs: {
    level: 2
  }
};

const api = (mix) => {
  // mix.sprite(['icons', 'mdi'], '.output/images');

  if (mix.env.isProd) {
    console.log('prod');
  } else {
    console.log('dev');

    // mix.serve((watcher, reload) => {
    //   watcher.on('change', (file) => {
    //     console.log('changed', file);

    //     let extname = file.split('.')[1];
    //     if (extname === 'css') {
    //       mix.css(file, '.test/css');
    //     }
    //     if (extname === 'js') {
    //       mix.js(`./${file}`, '.test/js');
    //       reload();
    //     }
    //   });
    // });
  }
};

module.exports = () => {
  return {
    config,
    api
  };
};
<commit_msg>test: update<commit_after>const path = require('path');

console.info('balm@zero');

const projectRoot = path.resolve(__dirname, '..');
const workspace = path.join(projectRoot, 'test-workspace');

const config = {
  workspace,
  // useDefaults: false,
  // paths: {
  //   source: {
  //     html: 'tpl'
  //   }
  // },
  styles: {
    extname: 'scss',
    dartSass: true
    // sprites: ['icons', 'mdi']
  },
  scripts: {
    bundler: 'esbuild',
    lint: true
  },
  assets: {
    cache: true
  },
  logs: {
    level: 2
  }
};

const api = (mix) => {
  // mix.sprite(['icons', 'mdi'], '.output/images');

  if (mix.env.isProd) {
    console.log('prod');
  } else {
    console.log('dev');

    // mix.serve((watcher, reload) => {
    //   watcher.on('change', (file) => {
    //     console.log('changed', file);

    //     let extname = file.split('.')[1];
    //     if (extname === 'css') {
    //       mix.css(file, '.test/css');
    //     }
    //     if (extname === 'js') {
    //       mix.js(`./${file}`, '.test/js');
    //       reload();
    //     }
    //   });
    // });
  }
};

module.exports = () => {
  return {
    config,
    api
  };
};
<|endoftext|>


<commit_before>Dashboard.SmoothHelper = Ember.Mixin.create({
  interval: 10,

  properties: function() {
    return {};
  }.property(),

  setSmooth: function(property, value, duration) {
    var p = this.get('properties');
    var d = typeof duration !== 'undefined' ? duration : 1000;
    if (p[property] && p[property].intervalCall) {
      clearInterval(p[property].intervalCall);
    }
    p[property] = {
      initialValue: this.get(property),
      targetValue: value,
      currentX: 0,
      step: Math.PI / (d / this.get('interval') * 2)
    };
    var that = this;
    p[property].intervalCall = setInterval(function() {
      if (p[property].currentX >= Math.PI / 2)
        clearInterval(p[property].intervalCall);
      else {
        that.set(property, p[property].initialValue + (p[property].targetValue - p[property].initialValue) * Math.sin(p[property].currentX));
        p[property].currentX = p[property].currentX + p[property].step;
      }
    }, this.get('interval'));
  }
});
<commit_msg>Rename internal properties of SmoothHelper to avoid collisions with classes that use the mixin.<commit_after>Dashboard.SmoothHelper = Ember.Mixin.create({
  _smoothHelperInterval: 10,

  _smoothHelperProperties: function() {
    return {};
  }.property(),

  setSmooth: function(property, value, duration) {
    var p = this.get('_smoothHelperProperties');
    var d = typeof duration !== 'undefined' ? duration : 1000;
    if (p[property] && p[property].intervalCall) {
      clearInterval(p[property].intervalCall);
    }
    p[property] = {
      initialValue: this.get(property),
      targetValue: value,
      currentX: 0,
      step: Math.PI / (d / this.get('_smoothHelperInterval') * 2)
    };
    var that = this;
    p[property].intervalCall = setInterval(function() {
      if (p[property].currentX >= Math.PI / 2)
        clearInterval(p[property].intervalCall);
      else {
        that.set(property, p[property].initialValue + (p[property].targetValue - p[property].initialValue) * Math.sin(p[property].currentX));
        p[property].currentX = p[property].currentX + p[property].step;
      }
    }, this.get('_smoothHelperInterval'));
  }
});
<|endoftext|>


<commit_before>'use strict';
angular.module('arethusa.core').factory('Auth', [
  '$resource',
  '$cookies',
  '$timeout',
  '$injector',
  'translator',
  function ($resource, $cookies, $timeout, $injector, translator) {
    var lazyNotifier;
    function notifier() {
      if (!lazyNotifier) lazyNotifier = $injector.get('notifier');
      return lazyNotifier;
    }

    function Pinger(url,withCredentials) {
      if (url) {
        var resource = $resource(url, null, { get: { withCredentials: withCredentials } });
        this.checkAuth = function(success, error) {
          resource.get(success, error);
        };
      } else {
        this.checkAuth = function(success, error) {
          success();
        };
      }
    }

    function noop() {}

    var translations = {};
    translator('auth.notLoggedIn', translations, 'notLoggedIn');

    return function(conf, modeFn) {
      var self = this;
      self.conf = conf;
      var skipModes = conf.skipModes || [];

      var authFailure;

      function modeToSkip() {
        return arethusaUtil.isIncluded(skipModes, modeFn());
      }

      function loginWarning() {
        authFailure = true;
        notifier().warning(translations.notLoggedIn);
      }

      function checkForAuthFailure(res) {
        if (res.status === 403) loginWarning();
      }

      this.withCredentials = conf.crossDomain ? true : false;

      var pinger = new Pinger(conf.ping,this.withCredentials);

      this.checkAuthentication = function() {
        if (modeToSkip()) return;
        pinger.checkAuth(noop, checkForAuthFailure);
      };

      this.withAuthentication = function(q, callback) {
        var err = function(res) {
          checkForAuthFailure(res);
          q.reject(res);
        };

        var suc = function(res) {
          authFailure = false;
          q.resolve(res);
        };

        var launch = function() {
          callback().then(suc, err);
        };

        // If we had no authFailure before, avoid the indirection and
        // launch the callback right away.
        if (!authFailure || modeToSkip()) {
          launch();
        } else {
          // Check auth will ideally restore our session cookie - we need to
          // $timeout, otherwise we don't see it updated!
          // Angular is polling every 100ms for new cookies, we therefore
          // have to wait a little.
          var authSuc = function() { $timeout(launch, 150); };
          pinger.checkAuth(authSuc, err);
        }
      };

      this.transformRequest = function(headers) {
        if (self.conf.type == 'CSRF') {
          headers()[self.conf.header] = $cookies[self.conf.cookie];
        }
      };
    };
  }
]);
<commit_msg>Debounce not logged in message in notifier<commit_after>'use strict';
angular.module('arethusa.core').factory('Auth', [
  '$resource',
  '$cookies',
  '$timeout',
  '$injector',
  'translator',
  function ($resource, $cookies, $timeout, $injector, translator) {
    var lazyNotifier;
    function notifier() {
      if (!lazyNotifier) lazyNotifier = $injector.get('notifier');
      return lazyNotifier;
    }

    function Pinger(url,withCredentials) {
      if (url) {
        var resource = $resource(url, null, { get: { withCredentials: withCredentials } });
        this.checkAuth = function(success, error) {
          resource.get(success, error);
        };
      } else {
        this.checkAuth = function(success, error) {
          success();
        };
      }
    }

    function noop() {}

    var translations = {};
    translator('auth.notLoggedIn', translations, 'notLoggedIn');

    return function(conf, modeFn) {
      var self = this;
      self.conf = conf;
      var skipModes = conf.skipModes || [];

      var authFailure;

      function modeToSkip() {
        return arethusaUtil.isIncluded(skipModes, modeFn());
      }

      function loginWarning() {
        authFailure = true;
        notifier().warning(translations.notLoggedIn, null, 500);
      }

      function checkForAuthFailure(res) {
        if (res.status === 403) loginWarning();
      }

      this.withCredentials = conf.crossDomain ? true : false;

      var pinger = new Pinger(conf.ping,this.withCredentials);

      this.checkAuthentication = function() {
        if (modeToSkip()) return;
        pinger.checkAuth(noop, checkForAuthFailure);
      };

      this.withAuthentication = function(q, callback) {
        var err = function(res) {
          checkForAuthFailure(res);
          q.reject(res);
        };

        var suc = function(res) {
          authFailure = false;
          q.resolve(res);
        };

        var launch = function() {
          callback().then(suc, err);
        };

        // If we had no authFailure before, avoid the indirection and
        // launch the callback right away.
        if (!authFailure || modeToSkip()) {
          launch();
        } else {
          // Check auth will ideally restore our session cookie - we need to
          // $timeout, otherwise we don't see it updated!
          // Angular is polling every 100ms for new cookies, we therefore
          // have to wait a little.
          var authSuc = function() { $timeout(launch, 150); };
          pinger.checkAuth(authSuc, err);
        }
      };

      this.transformRequest = function(headers) {
        if (self.conf.type == 'CSRF') {
          headers()[self.conf.header] = $cookies[self.conf.cookie];
        }
      };
    };
  }
]);
<|endoftext|>


<commit_before>define({

	define : {
		allow   : "*",
		require : [
			"morphism",
			"transistor",
			"event_master",
		],
	},

	make : function ( define ) {
		var event_circle, body, option_name,
		default_value = define.option.default_value || define.option.choice[0]
		body          = this.library.transistor.make(this.define_body({
			name   : "main",
			option : {
				default_value : default_value,
				choice        : define.option.choice,
				mark          : define.option.mark
			},
			class_name    : define.class_name
		}))
		event_circle = this.library.event_master.make({
			events : this.define_event({
				body : body.body
			}),
			state  : {
				option : {
					"main" : default_value
				}
			},
		})
		event_circle.add_listener(this.define_listener({
			default_value : default_value,
			choice        : define.option.choice,
			mark          : define.option.mark
		}))
		body.append( define.append_to )
		return {}
	},

	define_event : function ( define ) {
		return [
			{
				called       : "toggle_dropdown",
				that_happens : [
					{
						on : define.body,
						is : [ "click" ]
					}
				],
				only_if      : function ( heard ) {
					return (
						heard.event.target.hasAttribute("data-dropdown") ||
						heard.event.target.parentElement.hasAttribute("data-dropdown")
					)
				}
			},
			{
				called       : "option_select",
				that_happens : [
					{
						on : define.body,
						is : [ "click" ]
					}
				],
				only_if : function ( heard ) {
					return ( heard.event.target.getAttribute("data-dropdown-value") )
				}
			}
		]
	},

	define_listener : function ( define ) {
		return [
			{
				for       : "option_select",
				that_does : function ( heard ) {
					var wrap, name, value
					wrap                                        = heard.event.target.parentElement
					name                                        = heard.event.target.getAttribute("data-dropdown-name")
					value                                       = heard.event.target.getAttribute("data-dropdown-value")
					wrap.style.display                          = "none"
					wrap.previousSibling.firstChild.textContent = value
					wrap.previousSibling.lastChild.textContent  = define.mark.closed
					heard.state.option[name]                    = value
					return heard
				},
			},
			{
				for       : "toggle_dropdown",
				that_does : function ( heard ) {
					var dropdown_body
					dropdown_body  = (
						heard.event.target.getAttribute("data-dropdown") ?
							heard.event.target :
							heard.event.target.parentElement
					)
					if ( dropdown_body.nextSibling.style.display === "none" ) {
						dropdown_body.nextSibling.style.display = "block"
						dropdown_body.lastChild.textContent     = define.mark.open
					} else {
						dropdown_body.nextSibling.style.display = "none"
						dropdown_body.lastChild.textContent     = define.mark.closed
					}

					return heard
				}
			}
		]
	},

	define_body : function ( define ) {
		return {
			"class" : define.class_name.main,
			child   : [
				{
					"class"         : define.class_name.option_selected_wrap,
					"data-dropdown" : "true",
					child           : [
						{
							"class" : define.class_name.option_selected,
							"text"  : define.option.default_value
						},
						{
							"class" : define.class_name.option_selector,
							"text"  : define.option.mark.closed
						},
					]
				},
				{
					"display"             : "none",
					"class"               : define.class_name.option_wrap,
					"child"               : this.library.morphism.index_loop({
						array   : define.option.choice,
						else_do : function ( loop ) {
							return loop.into.concat({
								"class"               : define.class_name.option,
								"data-dropdown-name"  : define.name,
								"data-dropdown-value" : loop.indexed,
								"text"                : loop.indexed
							})
						}
					})
				}
			]
		}
	}

})
// could create a context finder that is fed a definiton and then finds what he needs based upon it
// accepts definition,
// node that is meant to represent it,
// what he needs to find,
// returns the node needing to be found

// should also have a more concrete way of assignign events to certain thigns so that hter eare no conflicts
// in the case of using only if checkers.
// perhaps a context assigner as opsoded to the finder. <commit_msg>Some modification to ze main<commit_after>define({

	define : {
		allow   : "*",
		require : [
			"morphism",
			"transistor",
			"event_master",
		],
	},

	make : function ( define ) {
		var event_circle, body, option_name,
		default_value = define.option.default_value || define.option.choice[0]
		body          = this.library.transistor.make(this.define_body({
			name   : "main",
			option : {
				default_value : default_value,
				choice        : define.option.choice,
				mark          : define.option.mark
			},
			class_name    : define.class_name
		}))
		event_circle = this.library.event_master.make({
			events : this.define_event({
				body : body.body
			}),
			state  : {
				option : {
					"main" : default_value
				}
			},
		})
		event_circle.add_listener(this.define_listener({
			default_value : default_value,
			choice        : define.option.choice,
			mark          : define.option.mark
		}))
		body.append( define.append_to )
		return {}
	},

	define_state : function ( define ) {
		console.log( define )
		return {
			value : define.with.option.value || define.with.option.choice[0]
		}
	},

	define_event : function ( define ) {
		return [
			{
				called       : "toggle dropdown",
				that_happens : [
					{
						on : define.with.body,
						is : [ "click" ]
					}
				],
				only_if      : function ( heard ) {
					return (
						heard.event.target.hasAttribute("data-dropdown") ||
						heard.event.target.parentElement.hasAttribute("data-dropdown")
					)
				}
			},
			{
				called       : "option select",
				that_happens : [
					{
						on : define.with.body,
						is : [ "click" ]
					}
				],
				only_if : function ( heard ) {
					return ( heard.event.target.getAttribute("data-dropdown-value") )
				}
			}
		]
	},

	define_listener : function ( define ) {
		return [
			{
				for       : "toggle dropdown",
				that_does : function ( heard ) {
					var dropdown_body
					dropdown_body  = (
						heard.event.target.getAttribute("data-dropdown") ?
							heard.event.target :
							heard.event.target.parentElement
					)

					if ( dropdown_body.nextSibling.style.display === "none" ) {
						dropdown_body.nextSibling.style.display = "block"
						dropdown_body.lastChild.textContent     = dropdown_body.getAttribute("data-mark-open")
					} else {
						dropdown_body.nextSibling.style.display = "none"
						dropdown_body.lastChild.textContent     = dropdown_body.getAttribute("data-mark-closed")
					}

					return heard
				}
			},
			{
				for       : "option select",
				that_does : function ( heard ) {
					var wrap, name, value, text, notation, option, option_state
					option               = heard.event.target
					wrap                 = option.parentElement
					text                 = wrap.previousSibling.firstChild
					notation             = wrap.previousSibling.lastChild
					name                 = option.getAttribute("data-dropdown-name")
					value                = option.getAttribute("data-dropdown-value")
					option_state         = heard.state.option[name]
					wrap.style.display   = "none"
					notation.textContent = wrap.previousSibling.getAttribute("data-mark-closed")
					text.textContent     = value
					option_state.value   = value
					return heard
				},
			}
		]
	},

	define_body : function ( define ) {
		console.log( define.class_name )
		return {
			"class" : define.class_name.main,
			child   : [
				{
					"class"            : define.class_name.option_selected_wrap,
					"data-dropdown"    : "true",
					"data-mark-closed" : define.with.option.mark.closed,
					"data-mark-open"   : define.with.option.mark.open,
					child              : [
						{
							"class" : define.class_name.option_selected,
							"text"  : define.with.option.default_value
						},
						{
							"class"            : define.class_name.option_selector,
							"text"             : define.with.option.mark.closed
						},
					]
				},
				{
					"display"             : "none",
					"class"               : define.class_name.option_wrap,
					"child"               : this.library.morphism.index_loop({
						array   : define.with.option.choice,
						else_do : function ( loop ) {
							return loop.into.concat({
								"class"               : define.class_name.option,
								"data-dropdown-name"  : define.name,
								"data-dropdown-value" : loop.indexed,
								"text"                : loop.indexed
							})
						}
					})
				}
			]
		}
	}

})
// could create a context finder that is fed a definiton and then finds what he needs based upon it
// accepts definition,
// node that is meant to represent it,
// what he needs to find,
// returns the node needing to be found

// should also have a more concrete way of assignign events to certain thigns so that hter eare no conflicts
// in the case of using only if checkers.
// perhaps a context assigner as opsoded to the finder. <|endoftext|>


<commit_before>/*global sinon, todo, chai, describe, it, calledOnce*/
//integration tests - nodeAvailView.js

describe('nodeAvailView.js spec', function() {
    beforeEach(function() {
        $('body').html('

' +
            '
 ' +
            '
' +
            '
' +
            '<form class="global-refresh-selector" role="form">' +
            '
' +
            '
' +
            '
' +
            '<select class="form-control" id="global-refresh-range">' +
            '<option value="15">refresh 15s</option>' +
            '<option value="30" selected>refresh 30s</option>' +
            '<option value="60">refresh 1m</option>' +
            '<option value="300">refresh 5m</option>' +
            '<option value="-1">refresh off</option>' +
            '</select>' +
            '
' +
            '
' +
            '
' +
            '</form>' +
            '
' +
            '
' +
            '<form class="global-lookback-selector" role="form">' +
            '
' +
            '
' +
            '
' +
            '<select class="form-control" id="global-lookback-range">' +
            '<option value="15">lookback 15m</option>' +
            '<option value="60" selected>lookback 1h</option>' +
            '<option value="360">lookback 6h</option>' +
            '<option value="1440">lookback 1d</option>' +
            '</select>' +
            '
' +
            '
' +
            '
' +
            '</form>' +
            '
');

        // to answer GET requests
        this.server = sinon.fakeServer.create();
        this.server.respondWith("GET", "/*", [200, {
            "Content-Type": "application/json"
        }, '{absolutely: "nothing"}']);

        // confirm that dom is clear of view elements before each test:
        expect($('svg').length).to.equal(0);
        expect($('#spinner').length).to.equal(0);

        this.testCollection = new NodeAvailCollection({
            url: '/something/fancy',
        });
        this.testCollection.reset();
        this.testCollection.add([{
            "uuid": "46b24373-eedc-43d5-9543-19dea317d88f",
            "name": "compute-01",
            "created": "2014-10-27T19:26:17Z",
            "updated": "2014-10-28T18:32:18Z",
            "last_seen_method": "LOGS",
            "admin_disabled": false,
            "error_count": 10,
            "warning_count": 4,
            "info_count": 33,
            "audit_count": 551,
            "debug_count": 4,
            "polymorphic_ctype": 12
        }, {
            "uuid": "d0656d75-1c26-48c5-875b-9130dd8892f4",
            "name": "compute-02",
            "created": "2014-10-27T19:27:17Z",
            "updated": "2014-10-28T18:33:17Z",
            "last_seen_method": "LOGS",
            "admin_disabled": false,
            "error_count": 1,
            "warning_count": 2,
            "info_count": 3,
            "audit_count": 448,
            "debug_count": 5,
            "polymorphic_ctype": 12
        }, {
            "uuid": "46b24373-eedc-43d5-9543-19dea317d88f",
            "name": "controller-01",
            "created": "2014-10-27T19:29:17Z",
            "updated": "2014-10-28T18:38:18Z",
            "last_seen_method": "LOGS",
            "admin_disabled": false,
            "error_count": 10,
            "warning_count": 4,
            "info_count": 33,
            "audit_count": 551,
            "debug_count": 0,
            "polymorphic_ctype": 12
        }]);

        blueSpinnerGif = "goldstone/static/images/ajax-loader-solinea-blue.gif";

        this.testView = new NodeAvailView({
            collection: this.testCollection,
            h: {
                "main": 450,
                "swim": 50
            },
            el: '.testContainer',
            chartTitle: "Test Chart Title",
            width: 500
        });
    });
    afterEach(function() {
        $('body').html('');
        this.server.restore();
    });
    describe('collection is constructed', function() {
        it('should exist', function() {
            assert.isDefined(this.testCollection, 'this.testCollection has been defined');
            expect(this.testCollection.parse).to.be.a('function');
            expect(this.testCollection.length).to.equal(2);
            this.testCollection.add({
                test1: 'test1'
            });
            expect(this.testCollection.length).to.equal(3);
            this.testCollection.pop();
            expect(this.testCollection.length).to.equal(2);
            this.testCollection.setXhr();
        });
        it('should parse appropriate', function() {
            var testData = {
                a: "blah",
                b: "wah",
                results: [1, 2, 3]
            };
            var test1 = this.testCollection.parse(testData);
            expect(test1).to.deep.equal([1, 2, 3]);
            testData = {
                a: "blah",
                b: "wah",
                results: [1, 2, 3],
                next: null
            };
            var test2 = this.testCollection.parse(testData);
            expect(test2).to.deep.equal([1, 2, 3]);
            testData = {
                a: "blah",
                b: "wah",
                results: [1, 2, 3],
                next: 'fantastic/loggin/urls/forever'
            };
            var test3 = this.testCollection.parse(testData);
            expect(test3).to.deep.equal([1, 2, 3]);
        });
    });

    describe('view is constructed', function() {
        it('should exist', function() {
            assert.isDefined(this.testView, 'this.testView has been defined');
            expect(this.testView).to.be.an('object');
            expect(this.testView.el).to.equal('.testContainer');
        });
        it('view update appends svg and border elements', function() {
            expect(this.testView.update).to.be.a('function');
            expect($('svg').length).to.equal(1);
            expect($('g').find('.axis').text()).to.equal('DisabledLogsPing Only');
            expect($('.panel-title').text().trim()).to.equal('Test Chart Title');
            expect($('svg').text()).to.not.include('Response was empty');
        });
        it('can handle a null server payload and append appropriate response', function() {
            this.update_spy = sinon.spy(this.testView, "update");
            expect($('#noDataReturned').length).to.equal(0);
            expect($('#noDataReturned').text()).to.equal('');
            this.testCollection.reset();
            this.testView.update();
            expect($('.testContainer').find('#noDataReturned').length).to.equal(1);
            expect($('#noDataReturned').text()).to.equal('No Data Returned');
            // it doesn't RE-apply 'No Data Returned' if it's already there:
            this.testView.update();
            expect($('.testContainer').find('#noDataReturned').length).to.equal(1);
            expect($('#noDataReturned').text()).to.equal('No Data Returned');
            // it REMOVES 'No Data Returned' if data starts flowing again:
            this.testCollection.add({
                "uuid": "46b24373-eedc-43d5-9543-19dea317d88f",
                "name": "compute-01",
                "created": "2014-10-27T19:27:17Z",
                "updated": "2014-10-28T18:33:18Z",
                "last_seen_method": "LOGS",
                "admin_disabled": true,
                "error_count": 10,
                "warning_count": 4,
                "info_count": 33,
                "audit_count": 551,
                "debug_count": 0,
                "polymorphic_ctype": 12
            });
            this.testView.update();
            expect($('.testContainer').find('#noDataReturned').length).to.equal(0);
            expect($('#noDataReturned').text()).to.equal('');
            expect(this.update_spy.callCount).to.equal(3);
            this.update_spy.restore();
        });
        it('populates the event filters', function() {
            this.testView.update();
            expect($('#populateEventFilters').children().length).to.equal(5);
        });
        it('sums appropriately based on filter and count', function() {
            var testData = {
                "info_count": 42
            };
            var test1 = this.testView.sums(testData);
            expect(test1).to.equal(42);

            this.testView.defaults.filter.info_count = false;
            testData = {
                "info_count": 0
            };
            var test2 = this.testView.sums(testData);
            expect(test2).to.equal(0);

            this.testView.defaults.filter.info = false;
            testData = {
                "info_count": 42
            };
            var test3 = this.testView.sums(testData);
            expect(test3).to.equal(0);
        });
        it('redraws successfully', function() {
            expect(this.testView.redraw).is.a('function');

            this.testView.defaults.dataset = this.testCollection.toJSON();

            this.testView.redraw();
        });
        it('appends circles upon update', function() {
            expect($('svg').find('circle').length).to.equal(0);
            this.testView.update();
            expect($('svg').find('circle').length).to.equal(2);
        });
        it('registers changes on the global lookback/refresh selectors', function() {

            this.clearScheduledSpy = sinon.spy(this.testView, "clearScheduledFetch");
            this.updateSettingsSpy = sinon.spy(this.testView, "updateSettings");
            this.scheduleFetchSpy = sinon.spy(this.testView, "scheduleFetch");

            expect(this.clearScheduledSpy.callCount).to.equal(0);
            expect(this.updateSettingsSpy.callCount).to.equal(0);
            expect(this.scheduleFetchSpy.callCount).to.equal(0);

            $('.global-refresh-selector .form-control').trigger('change');
            expect(this.clearScheduledSpy.callCount).to.equal(2);
            expect(this.updateSettingsSpy.callCount).to.equal(1);
            expect(this.scheduleFetchSpy.callCount).to.equal(1);
            this.clearScheduledSpy.restore();
            this.updateSettingsSpy.restore();
            this.scheduleFetchSpy.restore();
        });
        it('scheduleFetch short-circuits if pause is true', function() {
            this.testView.defaults.scheduleTimeout = null;

            this.scheduleFetchSpy = sinon.spy(this.testView, "scheduleFetch");
            this.clearScheduledSpy = sinon.spy(this.testView, "clearScheduledFetch");

            expect(this.clearScheduledSpy.callCount).to.equal(0);
            expect(this.scheduleFetchSpy.callCount).to.equal(0);

            this.testView.defaults.delay = -1;

            this.testView.scheduleFetch();

            expect(this.clearScheduledSpy.callCount).to.equal(1);
            expect(this.scheduleFetchSpy.callCount).to.equal(1);
            expect(this.testView.defaults.scheduleTimeout).to.equal(null);

            this.testView.defaults.delay = 1;
            this.testView.scheduleFetch();

            expect(this.clearScheduledSpy.callCount).to.equal(2);
            expect(this.scheduleFetchSpy.callCount).to.equal(2);
            expect(this.testView.defaults.scheduleTimeout).to.not.equal(null);

            this.scheduleFetchSpy.restore();
            this.clearScheduledSpy.restore();
        });
        it('correctly identifies if refresh is selected', function() {
            var test1 = this.testView.isRefreshSelected();
            expect(test1).to.equal(true);
            $('.global-refresh-selector .form-control').val(-1);
            var test2 = this.testView.isRefreshSelected();
            expect(test2).to.equal(false);
        });
        // pending lookback functionality
        // it('correctly identifies the lookback range', function() {
        //     var test1 = this.testView.lookbackRange();
        //     expect(test1).to.equal(60);
        //     $('.global-lookback-selector .form-control').val(360);
        //     var test2 = this.testView.lookbackRange();
        //     expect(test2).to.equal(360);
        // });
        it('correctly identifies the refresh rate', function() {
            var test1 = this.testView.refreshInterval();
            expect(test1).to.equal(30);
            $('.global-refresh-selector .form-control').val(60);
            var test2 = this.testView.refreshInterval();
            expect(test2).to.equal(60);
        });
    });
});
<commit_msg>Updates tests to reflect change from uuid to id.<commit_after>/*global sinon, todo, chai, describe, it, calledOnce*/
//integration tests - nodeAvailView.js

describe('nodeAvailView.js spec', function() {
    beforeEach(function() {
        $('body').html('

' +
            '
 ' +
            '
' +
            '
' +
            '<form class="global-refresh-selector" role="form">' +
            '
' +
            '
' +
            '
' +
            '<select class="form-control" id="global-refresh-range">' +
            '<option value="15">refresh 15s</option>' +
            '<option value="30" selected>refresh 30s</option>' +
            '<option value="60">refresh 1m</option>' +
            '<option value="300">refresh 5m</option>' +
            '<option value="-1">refresh off</option>' +
            '</select>' +
            '
' +
            '
' +
            '
' +
            '</form>' +
            '
' +
            '
' +
            '<form class="global-lookback-selector" role="form">' +
            '
' +
            '
' +
            '
' +
            '<select class="form-control" id="global-lookback-range">' +
            '<option value="15">lookback 15m</option>' +
            '<option value="60" selected>lookback 1h</option>' +
            '<option value="360">lookback 6h</option>' +
            '<option value="1440">lookback 1d</option>' +
            '</select>' +
            '
' +
            '
' +
            '
' +
            '</form>' +
            '
');

        // to answer GET requests
        this.server = sinon.fakeServer.create();
        this.server.respondWith("GET", "/*", [200, {
            "Content-Type": "application/json"
        }, '{absolutely: "nothing"}']);

        // confirm that dom is clear of view elements before each test:
        expect($('svg').length).to.equal(0);
        expect($('#spinner').length).to.equal(0);

        this.testCollection = new NodeAvailCollection({
            url: '/something/fancy',
        });
        this.testCollection.reset();
        this.testCollection.add([{
            "id": "46b24373-eedc-43d5-9543-19dea317d88f",
            "name": "compute-01",
            "created": "2014-10-27T19:26:17Z",
            "updated": "2014-10-28T18:32:18Z",
            "last_seen_method": "LOGS",
            "admin_disabled": false,
            "error_count": 10,
            "warning_count": 4,
            "info_count": 33,
            "audit_count": 551,
            "debug_count": 4,
            "polymorphic_ctype": 12
        }, {
            "id": "d0656d75-1c26-48c5-875b-9130dd8892f4",
            "name": "compute-02",
            "created": "2014-10-27T19:27:17Z",
            "updated": "2014-10-28T18:33:17Z",
            "last_seen_method": "LOGS",
            "admin_disabled": false,
            "error_count": 1,
            "warning_count": 2,
            "info_count": 3,
            "audit_count": 448,
            "debug_count": 5,
            "polymorphic_ctype": 12
        }, {
            "id": "46b24373-eedc-43d5-9543-19dea317d88f",
            "name": "controller-01",
            "created": "2014-10-27T19:29:17Z",
            "updated": "2014-10-28T18:38:18Z",
            "last_seen_method": "LOGS",
            "admin_disabled": false,
            "error_count": 10,
            "warning_count": 4,
            "info_count": 33,
            "audit_count": 551,
            "debug_count": 0,
            "polymorphic_ctype": 12
        }]);

        blueSpinnerGif = "goldstone/static/images/ajax-loader-solinea-blue.gif";

        this.testView = new NodeAvailView({
            collection: this.testCollection,
            h: {
                "main": 450,
                "swim": 50
            },
            el: '.testContainer',
            chartTitle: "Test Chart Title",
            width: 500
        });
    });
    afterEach(function() {
        $('body').html('');
        this.server.restore();
    });
    describe('collection is constructed', function() {
        it('should exist', function() {
            assert.isDefined(this.testCollection, 'this.testCollection has been defined');
            expect(this.testCollection.parse).to.be.a('function');
            expect(this.testCollection.length).to.equal(2);
            this.testCollection.add({
                test1: 'test1'
            });
            expect(this.testCollection.length).to.equal(3);
            this.testCollection.pop();
            expect(this.testCollection.length).to.equal(2);
            this.testCollection.setXhr();
        });
        it('should parse appropriate', function() {
            var testData = {
                a: "blah",
                b: "wah",
                results: [1, 2, 3]
            };
            var test1 = this.testCollection.parse(testData);
            expect(test1).to.deep.equal([1, 2, 3]);
            testData = {
                a: "blah",
                b: "wah",
                results: [1, 2, 3],
                next: null
            };
            var test2 = this.testCollection.parse(testData);
            expect(test2).to.deep.equal([1, 2, 3]);
            testData = {
                a: "blah",
                b: "wah",
                results: [1, 2, 3],
                next: 'fantastic/loggin/urls/forever'
            };
            var test3 = this.testCollection.parse(testData);
            expect(test3).to.deep.equal([1, 2, 3]);
        });
    });

    describe('view is constructed', function() {
        it('should exist', function() {
            assert.isDefined(this.testView, 'this.testView has been defined');
            expect(this.testView).to.be.an('object');
            expect(this.testView.el).to.equal('.testContainer');
        });
        it('view update appends svg and border elements', function() {
            expect(this.testView.update).to.be.a('function');
            expect($('svg').length).to.equal(1);
            expect($('g').find('.axis').text()).to.equal('DisabledLogsPing Only');
            expect($('.panel-title').text().trim()).to.equal('Test Chart Title');
            expect($('svg').text()).to.not.include('Response was empty');
        });
        it('can handle a null server payload and append appropriate response', function() {
            this.update_spy = sinon.spy(this.testView, "update");
            expect($('#noDataReturned').length).to.equal(0);
            expect($('#noDataReturned').text()).to.equal('');
            this.testCollection.reset();
            this.testView.update();
            expect($('.testContainer').find('#noDataReturned').length).to.equal(1);
            expect($('#noDataReturned').text()).to.equal('No Data Returned');
            // it doesn't RE-apply 'No Data Returned' if it's already there:
            this.testView.update();
            expect($('.testContainer').find('#noDataReturned').length).to.equal(1);
            expect($('#noDataReturned').text()).to.equal('No Data Returned');
            // it REMOVES 'No Data Returned' if data starts flowing again:
            this.testCollection.add({
                "id": "46b24373-eedc-43d5-9543-19dea317d88f",
                "name": "compute-01",
                "created": "2014-10-27T19:27:17Z",
                "updated": "2014-10-28T18:33:18Z",
                "last_seen_method": "LOGS",
                "admin_disabled": true,
                "error_count": 10,
                "warning_count": 4,
                "info_count": 33,
                "audit_count": 551,
                "debug_count": 0,
                "polymorphic_ctype": 12
            });
            this.testView.update();
            expect($('.testContainer').find('#noDataReturned').length).to.equal(0);
            expect($('#noDataReturned').text()).to.equal('');
            expect(this.update_spy.callCount).to.equal(3);
            this.update_spy.restore();
        });
        it('populates the event filters', function() {
            this.testView.update();
            expect($('#populateEventFilters').children().length).to.equal(5);
        });
        it('sums appropriately based on filter and count', function() {
            var testData = {
                "info_count": 42
            };
            var test1 = this.testView.sums(testData);
            expect(test1).to.equal(42);

            this.testView.defaults.filter.info_count = false;
            testData = {
                "info_count": 0
            };
            var test2 = this.testView.sums(testData);
            expect(test2).to.equal(0);

            this.testView.defaults.filter.info = false;
            testData = {
                "info_count": 42
            };
            var test3 = this.testView.sums(testData);
            expect(test3).to.equal(0);
        });
        it('redraws successfully', function() {
            expect(this.testView.redraw).is.a('function');

            this.testView.defaults.dataset = this.testCollection.toJSON();

            this.testView.redraw();
        });
        it('appends circles upon update', function() {
            expect($('svg').find('circle').length).to.equal(0);
            this.testView.update();
            expect($('svg').find('circle').length).to.equal(2);
        });
        it('registers changes on the global lookback/refresh selectors', function() {

            this.clearScheduledSpy = sinon.spy(this.testView, "clearScheduledFetch");
            this.updateSettingsSpy = sinon.spy(this.testView, "updateSettings");
            this.scheduleFetchSpy = sinon.spy(this.testView, "scheduleFetch");

            expect(this.clearScheduledSpy.callCount).to.equal(0);
            expect(this.updateSettingsSpy.callCount).to.equal(0);
            expect(this.scheduleFetchSpy.callCount).to.equal(0);

            $('.global-refresh-selector .form-control').trigger('change');
            expect(this.clearScheduledSpy.callCount).to.equal(2);
            expect(this.updateSettingsSpy.callCount).to.equal(1);
            expect(this.scheduleFetchSpy.callCount).to.equal(1);
            this.clearScheduledSpy.restore();
            this.updateSettingsSpy.restore();
            this.scheduleFetchSpy.restore();
        });
        it('scheduleFetch short-circuits if pause is true', function() {
            this.testView.defaults.scheduleTimeout = null;

            this.scheduleFetchSpy = sinon.spy(this.testView, "scheduleFetch");
            this.clearScheduledSpy = sinon.spy(this.testView, "clearScheduledFetch");

            expect(this.clearScheduledSpy.callCount).to.equal(0);
            expect(this.scheduleFetchSpy.callCount).to.equal(0);

            this.testView.defaults.delay = -1;

            this.testView.scheduleFetch();

            expect(this.clearScheduledSpy.callCount).to.equal(1);
            expect(this.scheduleFetchSpy.callCount).to.equal(1);
            expect(this.testView.defaults.scheduleTimeout).to.equal(null);

            this.testView.defaults.delay = 1;
            this.testView.scheduleFetch();

            expect(this.clearScheduledSpy.callCount).to.equal(2);
            expect(this.scheduleFetchSpy.callCount).to.equal(2);
            expect(this.testView.defaults.scheduleTimeout).to.not.equal(null);

            this.scheduleFetchSpy.restore();
            this.clearScheduledSpy.restore();
        });
        it('correctly identifies if refresh is selected', function() {
            var test1 = this.testView.isRefreshSelected();
            expect(test1).to.equal(true);
            $('.global-refresh-selector .form-control').val(-1);
            var test2 = this.testView.isRefreshSelected();
            expect(test2).to.equal(false);
        });
        // pending lookback functionality
        // it('correctly identifies the lookback range', function() {
        //     var test1 = this.testView.lookbackRange();
        //     expect(test1).to.equal(60);
        //     $('.global-lookback-selector .form-control').val(360);
        //     var test2 = this.testView.lookbackRange();
        //     expect(test2).to.equal(360);
        // });
        it('correctly identifies the refresh rate', function() {
            var test1 = this.testView.refreshInterval();
            expect(test1).to.equal(30);
            $('.global-refresh-selector .form-control').val(60);
            var test2 = this.testView.refreshInterval();
            expect(test2).to.equal(60);
        });
    });
});
<|endoftext|>


<commit_before>'use strict';

angular
.module('app.services')
.factory('userData', function($http, Restangular){
	var user = {
		getInformation: function () {
			return Restangular.one('people/me')
				.get()
				.catch(function(res){
					var status = res.data.errors[0].status;
					if(status === '401') {
						var destinationUrl = 'https://api.tnyu.org/v2/auth/facebook?success=' + window.location;
						window.location = destinationUrl;
					}
				});
		},
		isLoggedIn: function (currentUser) {
			if(Object.keys(currentUser).length !== 0){
				return true;
			} else {
				return false;
			}
		},
		onTeams: function(currentUser, callback){
			$http.get('https://api.tnyu.org/v1.0/teams').success(function(data) {
				var allTeamIds = [], allTeamObjects = [];
				for(var m in data['linked']['team-memberships']){
					if(data['linked']['team-memberships'][m]['links']['member']['id'] === currentUser['id']){
						allTeamIds.push(data['linked']['team-memberships'][m]['id']);
					}
				}
				for(var eachTeam in data['teams']){
					if('links' in data['teams'][eachTeam]){
						for(var eachMemberships in data['teams'][eachTeam]['links']['memberships']){
							for(var eachUserTeam in allTeamIds){
								if(data['teams'][eachTeam]['links']['memberships'][eachMemberships] === allTeamIds[eachUserTeam]){
									allTeamObjects.push(data['teams'][eachTeam]);
								}
							}
						}
					}
				}
				callback(allTeamObjects);
			});
		}
	};
	return user;
});
<commit_msg>Deprecate old user data<commit_after><|endoftext|>


<commit_before>import { NativeModules } from 'react-native'
const { RNBranch } = NativeModules
import { BranchSubscriber } from 'react-native-branch'

test('default initializes with no options', () => {
  const subscriber = new BranchSubscriber(null)
  expect(subscriber.options).toEqual({})
})

test('stores options passed to the constructor', () => {
  const subscriber = new BranchSubscriber({
    checkCachedEvents: false
  })

  expect(subscriber.options).toEqual({ checkCachedEvents: false })
})

test('subscribes to init session start events', () => {
  const subscriber = new BranchSubscriber({
    checkCachedEvents: false,
    onOpenStart: ({uri}) => {},
  })
  subscriber._nativeEventEmitter.addListener = jest.fn((eventType, listener) => {})
  subscriber.subscribe()

  expect(subscriber._nativeEventEmitter.addListener.mock.calls.length).toBe(1)
  expect(subscriber._nativeEventEmitter.addListener.mock.calls[0][0]).toBe(RNBranch.INIT_SESSION_START)
})

test('subscribes to init session success & error events', () => {
  const subscriber = new BranchSubscriber({
    checkCachedEvents: false,
    onOpenComplete: ({params, error, uri}) => {},
  })
  subscriber._nativeEventEmitter.addListener = jest.fn((eventType, listener) => {})
  subscriber.subscribe()

  expect(subscriber._nativeEventEmitter.addListener.mock.calls.length).toBe(2)

  // TODO: This is brittle because it depends on the order.
  expect(subscriber._nativeEventEmitter.addListener.mock.calls[0][0]).toBe(RNBranch.INIT_SESSION_SUCCESS)
  expect(subscriber._nativeEventEmitter.addListener.mock.calls[1][0]).toBe(RNBranch.INIT_SESSION_ERROR)
})
<commit_msg>Ignore call order in test<commit_after>import { NativeModules } from 'react-native'
const { RNBranch } = NativeModules
import { BranchSubscriber } from 'react-native-branch'

test('default initializes with no options', () => {
  const subscriber = new BranchSubscriber(null)
  expect(subscriber.options).toEqual({})
})

test('stores options passed to the constructor', () => {
  const subscriber = new BranchSubscriber({
    checkCachedEvents: false
  })

  expect(subscriber.options).toEqual({ checkCachedEvents: false })
})

test('subscribes to init session start events', () => {
  const subscriber = new BranchSubscriber({
    checkCachedEvents: false,
    onOpenStart: ({uri}) => {},
  })
  subscriber._nativeEventEmitter.addListener = jest.fn((eventType, listener) => {})
  subscriber.subscribe()

  expect(subscriber._nativeEventEmitter.addListener.mock.calls.length).toBe(1)
  expect(subscriber._nativeEventEmitter.addListener.mock.calls[0][0]).toBe(RNBranch.INIT_SESSION_START)
})

test('subscribes to init session success & error events', () => {
  const subscriber = new BranchSubscriber({
    checkCachedEvents: false,
    onOpenComplete: ({params, error, uri}) => {},
  })
  subscriber._nativeEventEmitter.addListener = jest.fn((eventType, listener) => {})
  subscriber.subscribe()

  expect(subscriber._nativeEventEmitter.addListener.mock.calls.length).toBe(2)

  // This comparison ignores the call order.
  const mockArgs = subscriber._nativeEventEmitter.addListener.mock.calls.map(call => call[0]).sort()
  expect(mockArgs).toEqual([
    RNBranch.INIT_SESSION_ERROR,
    RNBranch.INIT_SESSION_SUCCESS,
  ])
})
<|endoftext|>