<commit_before>// @flow
// @jsx glam
import React, { Component, type ElementRef } from 'react';
import { findDOMNode } from 'react-dom';
import glam from 'glam';
import rafScheduler from 'raf-schd';
import { ViewPager, Frame, Track, View as PageView } from 'react-view-pager';

const viewPagerStyles = {
  flex: '1 1 auto',
  position: 'relative',
  width: '100vw',
};
const frameStyles = { outline: 0 };

import {
  defaultCarouselComponents,
  type CarouselComponents,
} from './defaultComponents';
import { defaultCarouselStyles, type CarouselStylesConfig } from '../styles';
import { type ModalProps } from './Modal/Modal';
import { className, isTouch } from '../utils';
import formatters from '../formatters';
import { type ViewsType } from '../types';
import componentBaseClassNames from './componentBaseClassNames';

type SpringConfig = { [key: string]: number };
export type fn = (any) => void;
export type IndicesType = Array<number>;
export type CarouselProps = {
  /* Replace any of the carousel components */
  components?: CarouselComponents,
  /* Take control of the component's view index state */
  currentIndex: number,
  // See https://github.com/souporserious/react-view-pager#frame-props
  frameProps: {
    accessibility: boolean,
    autoSize: true | false | 'width' | 'height',
    springConfig: SpringConfig,
    tag: any,
  },
  /* Formatters get called when language is used, defaults use english. */
  formatters: typeof formatters,
  /* Duration, in milliseconds, to wait before hiding controls when the user is idle */
  hideControlsWhenIdle?: number | false,
  /* Force hide or show controls on touch devices */
  showNavigationOnTouchDevice?: boolean,
  /* When envoked within a modal, props are cloned from the modal */
  modalProps?: ModalProps,
  /* Style modifier methods */
  styles: CarouselStylesConfig,
  // See https://github.com/souporserious/react-view-pager#track-props
  trackProps: {
    align: number,
    animations: Array<{ props: string, stops: Array<[number, number]> }>,
    axis: 'x' | 'y',
    contain: boolean,
    currentView: any,
    flickTimeout: number,
    infinite: boolean,
    instant: boolean,
    onRest: fn,
    onScroll: fn,
    onSwipeEnd: fn,
    onSwipeMove: fn,
    onSwipeStart: fn,
    onViewChange: (number) => void,
    springConfig: SpringConfig,
    swipe: true | false | 'mouse' | 'touch',
    swipeThreshold: number,
    tag: any,
    viewsToMove: number,
    viewsToShow: number | 'auto',
  },
  /* The items to render in the carousel */
  views: ViewsType,
};

export type CarouselState = {
  currentIndex: number,
  interactionIsIdle: boolean,
};
const defaultProps = {
  currentIndex: 0,
  formatters,
  hideControlsWhenIdle: 3000,
  showNavigationOnTouchDevice: false,
  styles: {},
  trackProps: {
    instant: !isTouch(),
    swipe: 'touch',
  },
};

const trackBaseClassName = componentBaseClassNames.Track;

class Carousel extends Component<CarouselProps, CarouselState> {
  commonProps: any; // TODO
  components: CarouselComponents;
  container: HTMLElement;
  footer: HTMLElement;
  frame: ElementRef<Frame>;
  header: HTMLElement;
  mounted: boolean = false;
  track: ElementRef<Track>;
  timer: number;

  static defaultProps = defaultProps;

  constructor(props: CarouselProps) {
    super(props);

    this.cacheComponents(props.components);

    this.state = {
      currentIndex: props.currentIndex,
      interactionIsIdle: isTouch(),
    };
  }

  componentDidMount() {
    const { hideControlsWhenIdle, modalProps } = this.props;
    const isModal = Boolean(modalProps);

    this.mounted = true;

    if (hideControlsWhenIdle && this.container) {
      this.container.addEventListener('mousedown', this.handleMouseActivity);
      this.container.addEventListener('mousemove', this.handleMouseActivity);
      this.container.addEventListener('touchmove', this.handleMouseActivity);
    }
    if (isModal) {
      this.focusViewFrame();
    }
  }
  componentDidUpdate(prevProps: CarouselProps) {
    if (prevProps.components !== this.props.components) {
      this.cacheComponents(prevProps.components);
    }

    if (this.props.currentIndex !== prevProps.currentIndex) {
      this.setState({ currentIndex: this.props.currentIndex });
    }
  }
  componentWillUnmount() {
    this.mounted = false;

    if (this.props.hideControlsWhenIdle && this.container) {
      this.container.removeEventListener('mousedown', this.handleMouseActivity);
      this.container.removeEventListener('mousemove', this.handleMouseActivity);
      this.container.removeEventListener('touchmove', this.handleMouseActivity);
      this.handleMouseActivity.cancel();
    }
  }
  cacheComponents = (comps?: CarouselComponents) => {
    this.components = defaultCarouselComponents(comps);
  };

  // ==============================
  // Refs
  // ==============================

  getContainer = (ref: HTMLElement) => {
    this.container = ref;
  };
  getFooter = (ref: HTMLElement) => {
    this.footer = ref;
  };
  getFrame = (ref: Frame) => {
    this.frame = findDOMNode(ref);
  };
  getHeader = (ref: HTMLElement) => {
    this.header = ref;
  };
  getTrack = (ref: Track) => {
    this.track = ref;
  };

  // ==============================
  // Utilities
  // ==============================

  hasPreviousView = (): boolean => {
    const { trackProps } = this.props;
    const { currentIndex } = this.state;

    return trackProps.infinite || currentIndex !== 0;
  };
  hasNextView = (): boolean => {
    const { trackProps, views } = this.props;
    const { currentIndex } = this.state;

    return trackProps.infinite || currentIndex !== views.length - 1;
  };

  getStyles = (key: string, props: {}): {} => {
    const base = defaultCarouselStyles[key](props);
    base.boxSizing = 'border-box';
    const custom = this.props.styles[key];
    return custom ? custom(base, props) : base;
  };
  // combine defaultProps with consumer props to maintain expected behaviour
  getTrackProps = (props: CarouselProps) => {
    return { ...defaultProps.trackProps, ...props.trackProps };
  };
  // combine defaultProps with consumer props to maintain expected behaviour
  getFormatters = () => {
    return { ...defaultProps.formatters, ...this.props.formatters };
  };
  getViewData = () => {
    const { views } = this.props;
    const { currentIndex } = this.state;

    return views[currentIndex];
  };
  focusViewFrame = () => {
    if (this.frame && document.activeElement !== this.frame) {
      this.frame.focus();
    }
  };

  prev = (event) => {
    event.stopPropagation();
    this.track.prev();
    this.focusViewFrame();
  };
  next = (event) => {
    event.stopPropagation();
    this.track.next();
    this.focusViewFrame();
  };

  // ==============================
  // Handlers
  // ==============================

  handleMouseActivity = rafScheduler(() => {
    clearTimeout(this.timer);

    if (this.state.interactionIsIdle) {
      this.setState({ interactionIsIdle: false });
    }

    this.timer = setTimeout(() => {
      if (this.mounted) {
        this.setState({ interactionIsIdle: true });
      }
    }, this.props.hideControlsWhenIdle);
  });
  handleViewChange = (indicies: IndicesType) => {
    const { trackProps } = this.props;

    // simplify by enforcing number
    const currentIndex = indicies[0];

    this.setState({ currentIndex });

    // call the consumer's onViewChange fn
    if (trackProps && trackProps.onViewChange) {
      trackProps.onViewChange(currentIndex);
    }
  };

  // ==============================
  // Renderers
  // ==============================

  renderNavigation = () => {
    const {
      getNextLabel,
      getPrevLabel,
      getNextTitle,
      getPrevTitle,
    } = this.getFormatters();
    const { Navigation, NavigationPrev, NavigationNext } = this.components;
    const { commonProps } = this;

    const showPrev = this.hasPreviousView();
    const showNext = this.hasNextView();
    const showNav = (showPrev || showNext) && Navigation;

    return showNav ? (
      <Navigation {...commonProps}>
        {showPrev && (
          <NavigationPrev
            {...commonProps}
            align="left"
            innerProps={{
              'aria-label': getPrevLabel(commonProps),
              onClick: this.prev,
              title: getPrevTitle(commonProps),
            }}
          />
        )}
        {showNext && (
          <NavigationNext
            {...commonProps}
            align="right"
            innerProps={{
              'aria-label': getNextLabel(commonProps),
              onClick: this.next,
              title: getNextTitle(commonProps),
            }}
          />
        )}
      </Navigation>
    ) : null;
  };
  renderFooter = () => {
    const { Footer, FooterCaption, FooterCount } = this.components;
    const { commonProps } = this;

    return Footer ? (
      <Footer
        {...commonProps}
        components={{
          Caption: FooterCaption,
          Count: FooterCount,
        }}
        innerProps={{ innerRef: this.getFooter }}
      />
    ) : null;
  };
  renderHeader = () => {
    const { Header, HeaderClose, HeaderFullscreen } = this.components;
    const { getCloseLabel, getFullscreenLabel } = this.getFormatters();
    const { commonProps } = this;

    return Header ? (
      <Header
        {...commonProps}
        getCloseLabel={getCloseLabel}
        getFullscreenLabel={getFullscreenLabel}
        components={{
          CloseButton: HeaderClose,
          FullscreenButton: HeaderFullscreen,
        }}
        data={this.getViewData()}
        innerProps={{ innerRef: this.getHeader }}
      />
    ) : null;
  };

  getCommonProps() {
    const {
      frameProps,
      trackProps,
      modalProps,
      views,
      showNavigationOnTouchDevice,
    } = this.props;
    const isModal = Boolean(modalProps);
    const isFullscreen = Boolean(modalProps && modalProps.isFullscreen);
    const { currentIndex, interactionIsIdle } = this.state;
    const currentView = this.getViewData();

    return {
      carouselProps: this.props,
      currentIndex,
      currentView,
      formatters: this.props.formatters,
      frameProps,
      getStyles: this.getStyles,
      showNavigationOnTouchDevice,
      isFullscreen,
      isModal,
      modalProps,
      interactionIsIdle,
      trackProps,
      views,
    };
  }
  render() {
    const { Container, View } = this.components;
    const { currentIndex } = this.state;
    const { frameProps, views } = this.props;
    const commonProps = (this.commonProps = this.getCommonProps());

    return (
      <Container {...commonProps} innerProps={{ innerRef: this.getContainer }}>
        {this.renderHeader()}
        <ViewPager
          tag="main"
          style={viewPagerStyles}
          className={className('pager')}
        >
          <Frame
            {...frameProps}
            ref={this.getFrame}
            className={className('frame')}
            style={frameStyles}
            tabIndex="-1"
          >
            <Track
              {...this.getTrackProps(this.props)}
              style={{ display: 'flex', alignItems: 'center' }}
              currentView={currentIndex}
              className={className(trackBaseClassName)}
              onViewChange={this.handleViewChange}
              ref={this.getTrack}
            >
              {views &&
                views.map((data, index) => {
                  return (
                    <PageView className={className('view-wrapper')} key={index}>
                      <View {...commonProps} data={data} index={index} />
                    </PageView>
                  );
                })}
            </Track>
          </Frame>
          {this.renderNavigation()}
        </ViewPager>
        {this.renderFooter()}
      </Container>
    );
  }
}
export default Carousel;
export type CarouselType = typeof Carousel;
<commit_msg>:bug: Fix broken carousel when not in modal<commit_after>// @flow
// @jsx glam
import React, { Component, type ElementRef } from 'react';
import { findDOMNode } from 'react-dom';
import glam from 'glam';
import rafScheduler from 'raf-schd';
import { ViewPager, Frame, Track, View as PageView } from 'react-view-pager';

const viewPagerStyles = {
  flex: '1 1 auto',
  position: 'relative',
};
const frameStyles = { outline: 0 };

import {
  defaultCarouselComponents,
  type CarouselComponents,
} from './defaultComponents';
import { defaultCarouselStyles, type CarouselStylesConfig } from '../styles';
import { type ModalProps } from './Modal/Modal';
import { className, isTouch } from '../utils';
import formatters from '../formatters';
import { type ViewsType } from '../types';
import componentBaseClassNames from './componentBaseClassNames';

type SpringConfig = { [key: string]: number };
export type fn = (any) => void;
export type IndicesType = Array<number>;
export type CarouselProps = {
  /* Replace any of the carousel components */
  components?: CarouselComponents,
  /* Take control of the component's view index state */
  currentIndex: number,
  // See https://github.com/souporserious/react-view-pager#frame-props
  frameProps: {
    accessibility: boolean,
    autoSize: true | false | 'width' | 'height',
    springConfig: SpringConfig,
    tag: any,
  },
  /* Formatters get called when language is used, defaults use english. */
  formatters: typeof formatters,
  /* Duration, in milliseconds, to wait before hiding controls when the user is idle */
  hideControlsWhenIdle?: number | false,
  /* Force hide or show controls on touch devices */
  showNavigationOnTouchDevice?: boolean,
  /* When envoked within a modal, props are cloned from the modal */
  modalProps?: ModalProps,
  /* Style modifier methods */
  styles: CarouselStylesConfig,
  // See https://github.com/souporserious/react-view-pager#track-props
  trackProps: {
    align: number,
    animations: Array<{ props: string, stops: Array<[number, number]> }>,
    axis: 'x' | 'y',
    contain: boolean,
    currentView: any,
    flickTimeout: number,
    infinite: boolean,
    instant: boolean,
    onRest: fn,
    onScroll: fn,
    onSwipeEnd: fn,
    onSwipeMove: fn,
    onSwipeStart: fn,
    onViewChange: (number) => void,
    springConfig: SpringConfig,
    swipe: true | false | 'mouse' | 'touch',
    swipeThreshold: number,
    tag: any,
    viewsToMove: number,
    viewsToShow: number | 'auto',
  },
  /* The items to render in the carousel */
  views: ViewsType,
};

export type CarouselState = {
  currentIndex: number,
  interactionIsIdle: boolean,
};
const defaultProps = {
  currentIndex: 0,
  formatters,
  hideControlsWhenIdle: 3000,
  showNavigationOnTouchDevice: false,
  styles: {},
  trackProps: {
    instant: !isTouch(),
    swipe: 'touch',
  },
};

const trackBaseClassName = componentBaseClassNames.Track;

class Carousel extends Component<CarouselProps, CarouselState> {
  commonProps: any; // TODO
  components: CarouselComponents;
  container: HTMLElement;
  footer: HTMLElement;
  frame: ElementRef<Frame>;
  header: HTMLElement;
  mounted: boolean = false;
  track: ElementRef<Track>;
  timer: number;

  static defaultProps = defaultProps;

  constructor(props: CarouselProps) {
    super(props);

    this.cacheComponents(props.components);

    this.state = {
      currentIndex: props.currentIndex,
      interactionIsIdle: isTouch(),
    };
  }

  componentDidMount() {
    const { hideControlsWhenIdle, modalProps } = this.props;
    const isModal = Boolean(modalProps);

    this.mounted = true;

    if (hideControlsWhenIdle && this.container) {
      this.container.addEventListener('mousedown', this.handleMouseActivity);
      this.container.addEventListener('mousemove', this.handleMouseActivity);
      this.container.addEventListener('touchmove', this.handleMouseActivity);
    }
    if (isModal) {
      this.focusViewFrame();
    }
  }
  componentDidUpdate(prevProps: CarouselProps) {
    if (prevProps.components !== this.props.components) {
      this.cacheComponents(prevProps.components);
    }

    if (this.props.currentIndex !== prevProps.currentIndex) {
      this.setState({ currentIndex: this.props.currentIndex });
    }
  }
  componentWillUnmount() {
    this.mounted = false;

    if (this.props.hideControlsWhenIdle && this.container) {
      this.container.removeEventListener('mousedown', this.handleMouseActivity);
      this.container.removeEventListener('mousemove', this.handleMouseActivity);
      this.container.removeEventListener('touchmove', this.handleMouseActivity);
      this.handleMouseActivity.cancel();
    }
  }
  cacheComponents = (comps?: CarouselComponents) => {
    this.components = defaultCarouselComponents(comps);
  };

  // ==============================
  // Refs
  // ==============================

  getContainer = (ref: HTMLElement) => {
    this.container = ref;
  };
  getFooter = (ref: HTMLElement) => {
    this.footer = ref;
  };
  getFrame = (ref: Frame) => {
    this.frame = findDOMNode(ref);
  };
  getHeader = (ref: HTMLElement) => {
    this.header = ref;
  };
  getTrack = (ref: Track) => {
    this.track = ref;
  };

  // ==============================
  // Utilities
  // ==============================

  hasPreviousView = (): boolean => {
    const { trackProps } = this.props;
    const { currentIndex } = this.state;

    return trackProps.infinite || currentIndex !== 0;
  };
  hasNextView = (): boolean => {
    const { trackProps, views } = this.props;
    const { currentIndex } = this.state;

    return trackProps.infinite || currentIndex !== views.length - 1;
  };

  getStyles = (key: string, props: {}): {} => {
    const base = defaultCarouselStyles[key](props);
    base.boxSizing = 'border-box';
    const custom = this.props.styles[key];
    return custom ? custom(base, props) : base;
  };
  // combine defaultProps with consumer props to maintain expected behaviour
  getTrackProps = (props: CarouselProps) => {
    return { ...defaultProps.trackProps, ...props.trackProps };
  };
  // combine defaultProps with consumer props to maintain expected behaviour
  getFormatters = () => {
    return { ...defaultProps.formatters, ...this.props.formatters };
  };
  getViewData = () => {
    const { views } = this.props;
    const { currentIndex } = this.state;

    return views[currentIndex];
  };
  focusViewFrame = () => {
    if (this.frame && document.activeElement !== this.frame) {
      this.frame.focus();
    }
  };

  prev = (event) => {
    event.stopPropagation();
    this.track.prev();
    this.focusViewFrame();
  };
  next = (event) => {
    event.stopPropagation();
    this.track.next();
    this.focusViewFrame();
  };

  // ==============================
  // Handlers
  // ==============================

  handleMouseActivity = rafScheduler(() => {
    clearTimeout(this.timer);

    if (this.state.interactionIsIdle) {
      this.setState({ interactionIsIdle: false });
    }

    this.timer = setTimeout(() => {
      if (this.mounted) {
        this.setState({ interactionIsIdle: true });
      }
    }, this.props.hideControlsWhenIdle);
  });
  handleViewChange = (indicies: IndicesType) => {
    const { trackProps } = this.props;

    // simplify by enforcing number
    const currentIndex = indicies[0];

    this.setState({ currentIndex });

    // call the consumer's onViewChange fn
    if (trackProps && trackProps.onViewChange) {
      trackProps.onViewChange(currentIndex);
    }
  };

  // ==============================
  // Renderers
  // ==============================

  renderNavigation = () => {
    const {
      getNextLabel,
      getPrevLabel,
      getNextTitle,
      getPrevTitle,
    } = this.getFormatters();
    const { Navigation, NavigationPrev, NavigationNext } = this.components;
    const { commonProps } = this;

    const showPrev = this.hasPreviousView();
    const showNext = this.hasNextView();
    const showNav = (showPrev || showNext) && Navigation;

    return showNav ? (
      <Navigation {...commonProps}>
        {showPrev && (
          <NavigationPrev
            {...commonProps}
            align="left"
            innerProps={{
              'aria-label': getPrevLabel(commonProps),
              onClick: this.prev,
              title: getPrevTitle(commonProps),
            }}
          />
        )}
        {showNext && (
          <NavigationNext
            {...commonProps}
            align="right"
            innerProps={{
              'aria-label': getNextLabel(commonProps),
              onClick: this.next,
              title: getNextTitle(commonProps),
            }}
          />
        )}
      </Navigation>
    ) : null;
  };
  renderFooter = () => {
    const { Footer, FooterCaption, FooterCount } = this.components;
    const { commonProps } = this;

    return Footer ? (
      <Footer
        {...commonProps}
        components={{
          Caption: FooterCaption,
          Count: FooterCount,
        }}
        innerProps={{ innerRef: this.getFooter }}
      />
    ) : null;
  };
  renderHeader = () => {
    const { Header, HeaderClose, HeaderFullscreen } = this.components;
    const { getCloseLabel, getFullscreenLabel } = this.getFormatters();
    const { commonProps } = this;

    return Header ? (
      <Header
        {...commonProps}
        getCloseLabel={getCloseLabel}
        getFullscreenLabel={getFullscreenLabel}
        components={{
          CloseButton: HeaderClose,
          FullscreenButton: HeaderFullscreen,
        }}
        data={this.getViewData()}
        innerProps={{ innerRef: this.getHeader }}
      />
    ) : null;
  };

  getCommonProps() {
    const {
      frameProps,
      trackProps,
      modalProps,
      views,
      showNavigationOnTouchDevice,
    } = this.props;
    const isModal = Boolean(modalProps);
    const isFullscreen = Boolean(modalProps && modalProps.isFullscreen);
    const { currentIndex, interactionIsIdle } = this.state;
    const currentView = this.getViewData();

    return {
      carouselProps: this.props,
      currentIndex,
      currentView,
      formatters: this.props.formatters,
      frameProps,
      getStyles: this.getStyles,
      showNavigationOnTouchDevice,
      isFullscreen,
      isModal,
      modalProps,
      interactionIsIdle,
      trackProps,
      views,
    };
  }
  render() {
    const { Container, View } = this.components;
    const { currentIndex } = this.state;
    const { frameProps, views } = this.props;
    const commonProps = (this.commonProps = this.getCommonProps());

    return (
      <Container {...commonProps} innerProps={{ innerRef: this.getContainer }}>
        {this.renderHeader()}
        <ViewPager
          tag="main"
          style={viewPagerStyles}
          className={className('pager')}
        >
          <Frame
            {...frameProps}
            ref={this.getFrame}
            className={className('frame')}
            style={frameStyles}
            tabIndex="-1"
          >
            <Track
              {...this.getTrackProps(this.props)}
              style={{ display: 'flex', alignItems: 'center' }}
              currentView={currentIndex}
              className={className(trackBaseClassName)}
              onViewChange={this.handleViewChange}
              ref={this.getTrack}
            >
              {views &&
                views.map((data, index) => {
                  return (
                    <PageView className={className('view-wrapper')} key={index}>
                      <View {...commonProps} data={data} index={index} />
                    </PageView>
                  );
                })}
            </Track>
          </Frame>
          {this.renderNavigation()}
        </ViewPager>
        {this.renderFooter()}
      </Container>
    );
  }
}
export default Carousel;
export type CarouselType = typeof Carousel;
<|endoftext|>


<commit_before>/*
 *
 *  Web Starter Kit
 *  Copyright 2015 Google Inc. All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *    https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License
 *
 */

(function(window, document) {
  'use strict';

  // Check to make sure service workers are supported in the current browser,
  // and that the current page is accessed from a secure origin. Using a
  // service worker from an insecure origin will trigger JS console errors. See
  // http://www.chromium.org/Home/chromium-security/prefer-secure-origins-for-powerful-new-features
  let isLocalhost = Boolean(window.location.hostname === 'localhost' ||
    // [::1] is the IPv6 localhost address.
    window.location.hostname === '[::1]' ||
    // 127.0.0.1/8 is considered localhost for IPv4.
    window.location.hostname.match(
      /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
    )
);

  if ('serviceWorker' in window.navigator &&
    (window.location.protocol === 'https:' || isLocalhost)) {
      window.navigator.serviceWorker.register('service-worker.js')
        .then(function(registration) {
          // updatefound is fired if service-worker.js changes.
          registration.onupdatefound = function() {
            // updatefound is also fired the very first time the SW is
            // installed,
            // and there's no need to prompt for a reload at that point.
            // So check here to see if the page is already controlled,
            // i.e. whether there's an existing service worker.
            if (window.navigator.serviceWorker.controller) {
              // The updatefound event implies that registration.installing is
              // set:
              // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-container-updatefound-event
              let installingWorker = registration.installing;

              installingWorker.onstatechange = function() {
                switch (installingWorker.state) {
                  case 'installed':
                    // At this point, the old content will have been purged and
                    // the
                    // fresh content will have been added to the cache.
                    // It's the perfect time to display a "New content is
                    // available; please refresh." message in the page's
                    // interface.
                    break;

                  case 'redundant':
                    throw new Error('The installing ' +
                      'service worker became redundant.');

                  default:
                    // Ignore
                }
              };
            }
          };
        }).catch(function(e) {
          console.error('Error during service worker registration:', e);
        });
    }

  // Your custom JavaScript goes here

  let app = window.app || {};

  // hold strictMode boolean (change on event switch1.change)
  app.strictMode = document.getElementById('switch1').checked;
  // hold sequence of values 0-3
  app.sequence = [];
  // index list of buttons 0-3
  app.buttons = [
    'button-green',
    'button-red',
    'button-yellow',
    'button-blue',
  ];
  app.gameOn = false;
  app.playersTurn = true;
  // keep track of players sequence
  app.counter = 0;

  document.getElementById('switch1').addEventListener('change', function(e) {
    app.strictMode = e.target.checked;
    console.log('strictMode: ' + app.strictMode);
  });

  document.getElementById('reset-button').addEventListener('click', function() {
    app.resetGame();
  }, false);

  app.resetGame = function(event) {
    console.log('reset');
    app.gameOn = false;
    app.sequence = [];
    document.getElementById('step-counter').innerHTML = 'Steps: 00';
  };

  document.getElementById('start-button').addEventListener('click', function() {
    app.nextPlay();
  }, false);

  app.nextPlay = function(e) {
    console.log('nextPlay');
    app.clearWin();
    app.gameOn = true;
    app.playersTurn = false;
    app.createSequence();
    app.playSequence(0);
    console.log(`current sequence: ${app.sequence}`);
  };

  app.clearWin = function() {
    let t = document.getElementById('title');
    if (t.innerHTML.endsWith('!!')) {
      t.innerHTML = 'Simon';
    }
  };

  app.setupSquareEventListeners = function() {
    let sqrCollection = document.getElementsByClassName('squares');
    for (let i = 0; i < sqrCollection.length; i++) {
      sqrCollection.item(i).addEventListener('click', app.squareClickEvent);
      console.log('event handler added for: ' + sqrCollection.item(i).id);
    }
  };

  app.squareClickEvent = function(e) {
    if (app.gameOn && app.playersTurn) {
      app.play(e.target.id);
      app.isCorrect(e.target.id);
    } else {
      if (!app.gameOn) {
        app.updateTitle('Game not Started');
      } else if (!app.playersTurn) {
        app.updateTitle('Not your turn');
      }
    }
  };

  app.updateTitle = function(message) {
      let t = document.getElementById('title');
      t.innerHTML = 'Simon - ' + message;
  };

  app.isCorrect = function(id) {
    let index = app.buttons.indexOf(id);
    if (index === app.sequence[app.counter]) {
      console.log(
        `correct: app.counter:${app.counter} sequence: ${app.sequence.length}`);

      app.updateTitle(`Correct for ${app.counter+1} steps`);

      if ( app.counter === app.sequence.length - 1 ) {
        console.log('end of sequence');

        if (app.sequence.length < 20 ) {
          window.setTimeout( function() {
            app.nextPlay();
          }, 2000);
        } else {
          app.updateTitle(
            `Correct for ${app.sequence.length} steps!! You Win!!`
          );
          app.resetGame();
        }
      }
    } else {
      app.updateTitle(`Wrong on step # ${app.counter}`);
      console.log('wrong');
      let el = document.getElementById(id);
      el.className += ' wrong-square';
      document.getElementById('sound-wrong').play();
      window.setTimeout( function() {
        el.className = el.className.replace(' wrong-square', '');
      }, 1000);

      if (app.strictMode) {
        window.setTimeout( function() {
          app.resetGame();
        }, 2000);
      } else {
        window.setTimeout( function() {
          app.playSequence(0);
        }, 2000);
      }
    }
    app.counter++;
    console.log(`count: ${app.counter}`);
  };

  app.play = function(id) {
    // get square by id
    let el = document.getElementById(id);
    // get color of square from preset id name
    let color = id.substr(7);
    console.log(`id: ${id}, sound: ${color}`);

    // add css class to lighten color (white background + opacity)
    el.className += ' shift-color';

    // play sound preset id contains specified format
    document.getElementById('sound-' + color).play();

    // create a timer to return color to normal 300ms is enough to notice
    // setTimeout executes the function after the specified time
    window.setTimeout(function() {
      el.className = el.className.replace(' shift-color', '');
    }, 500);
  };

  app.playSequence = function(i) {
    if (i < app.sequence.length) {
      app.play(app.buttons[app.sequence[i]]);
      window.setTimeout( function() {
        console.log('i: ' + i);
        app.playSequence(i+1);
      }, 1000);
    } else {
      app.playersTurn = true;
      app.counter = 0;
      console.log(`game: ${app.gameOn} player: ${app.playersTurn}`);
    }
  };

  app.createSequence = function() {
    let n = getRandomIntInclusive(3);
    app.sequence.push(n);
    document.getElementById('step-counter').innerHTML =
      'Steps: ' + app.sequence.length;
  };

  /**
  *  Using Math.round() will give you a non-uniform distribution!
  *  @param {integer} max
  *  @param {integer} min
  *  @return {number} - Returns a random integer between 0 and max (inclusive)
  */
  function getRandomIntInclusive(max, min) {
    min = min || 0; // Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }

  window.onload = function() {
    console.log('loaded javascript');
    app.setupSquareEventListeners();
  };
})(window, document);
<commit_msg>clean per wsk eslint rules<commit_after>/*
 *
 *  Web Starter Kit
 *  Copyright 2015 Google Inc. All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *    https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License
 *
 */

(function(window, document) {
  'use strict';

  // Check to make sure service workers are supported in the current browser,
  // and that the current page is accessed from a secure origin. Using a
  // service worker from an insecure origin will trigger JS console errors. See
  // http://www.chromium.org/Home/chromium-security/prefer-secure-origins-for-powerful-new-features
  let isLocalhost = Boolean(window.location.hostname === 'localhost' ||
    // [::1] is the IPv6 localhost address.
    window.location.hostname === '[::1]' ||
    // 127.0.0.1/8 is considered localhost for IPv4.
    window.location.hostname.match(
      /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
    )
);

  if ('serviceWorker' in window.navigator &&
    (window.location.protocol === 'https:' || isLocalhost)) {
    window.navigator.serviceWorker.register('service-worker.js')
        .then(function(registration) {
          // updatefound is fired if service-worker.js changes.
          registration.onupdatefound = function() {
            // updatefound is also fired the very first time the SW is
            // installed,
            // and there's no need to prompt for a reload at that point.
            // So check here to see if the page is already controlled,
            // i.e. whether there's an existing service worker.
            if (window.navigator.serviceWorker.controller) {
              // The updatefound event implies that registration.installing is
              // set:
              // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-container-updatefound-event
              let installingWorker = registration.installing;

              installingWorker.onstatechange = function() {
                switch (installingWorker.state) {
                  case 'installed':
                    // At this point, the old content will have been purged and
                    // the
                    // fresh content will have been added to the cache.
                    // It's the perfect time to display a "New content is
                    // available; please refresh." message in the page's
                    // interface.
                    break;

                  case 'redundant':
                    throw new Error('The installing ' +
                      'service worker became redundant.');

                  default:
                    // Ignore
                }
              };
            }
          };
        }).catch(function(e) {
          console.error('Error during service worker registration:', e);
        });
  }

  // Your custom JavaScript goes here

  let app = window.app || {};

  // hold strictMode boolean (change on event switch1.change)
  app.strictMode = document.getElementById('switch1').checked;
  // hold sequence of values 0-3
  app.sequence = [];
  // index list of buttons 0-3
  app.buttons = [
    'button-green',
    'button-red',
    'button-yellow',
    'button-blue'
  ];
  app.gameOn = false;
  app.playersTurn = true;
  // keep track of players sequence
  app.counter = 0;

  document.getElementById('switch1').addEventListener('change', function(e) {
    app.strictMode = e.target.checked;
    console.log('strictMode: ' + app.strictMode);
  });

  document.getElementById('reset-button').addEventListener('click', function() {
    app.resetGame();
  }, false);

  app.resetGame = function() {
    console.log('reset');
    app.gameOn = false;
    app.sequence = [];
    document.getElementById('step-counter').innerHTML = 'Steps: 00';
  };

  document.getElementById('start-button').addEventListener('click', function() {
    app.nextPlay();
  }, false);

  app.nextPlay = function() {
    console.log('nextPlay');
    app.clearWin();
    app.gameOn = true;
    app.playersTurn = false;
    app.createSequence();
    app.playSequence(0);
    console.log(`current sequence: ${app.sequence}`);
  };

  app.clearWin = function() {
    let t = document.getElementById('title');
    if (t.innerHTML.endsWith('!!')) {
      t.innerHTML = 'Simon';
    }
  };

  app.setupSquareEventListeners = function() {
    let sqrCollection = document.getElementsByClassName('squares');
    for (let i = 0; i < sqrCollection.length; i++) {
      sqrCollection.item(i).addEventListener('click', app.squareClickEvent);
      console.log('event handler added for: ' + sqrCollection.item(i).id);
    }
  };

  app.squareClickEvent = function(e) {
    if (app.gameOn && app.playersTurn) {
      app.play(e.target.id);
      app.isCorrect(e.target.id);
    } else if (!app.gameOn) {
      app.updateTitle('Game not Started');
    } else if (!app.playersTurn) {
      app.updateTitle('Not your turn');
    }
  };

  app.updateTitle = function(message) {
    let t = document.getElementById('title');
    t.innerHTML = 'Simon - ' + message;
  };

  app.isCorrect = function(id) {
    let index = app.buttons.indexOf(id);
    if (index === app.sequence[app.counter]) {
      console.log(
        `correct: app.counter:${app.counter} sequence: ${app.sequence.length}`);

      app.updateTitle(`Correct for ${app.counter + 1} steps`);

      if (app.counter === app.sequence.length - 1) {
        console.log('end of sequence');

        if (app.sequence.length < 20) {
          window.setTimeout(function() {
            app.nextPlay();
          }, 2000);
        } else {
          app.updateTitle(
            `Correct for ${app.sequence.length} steps!! You Win!!`
          );
          app.resetGame();
        }
      }
    } else {
      app.updateTitle(`Wrong on step # ${app.counter}`);
      console.log('wrong');
      let el = document.getElementById(id);
      el.className += ' wrong-square';
      document.getElementById('sound-wrong').play();
      window.setTimeout(function() {
        el.className = el.className.replace(' wrong-square', '');
      }, 1000);

      if (app.strictMode) {
        window.setTimeout(function() {
          app.resetGame();
        }, 2000);
      } else {
        window.setTimeout(function() {
          app.playSequence(0);
        }, 2000);
      }
    }
    app.counter++;
    console.log(`count: ${app.counter}`);
  };

  app.play = function(id) {
    // get square by id
    let el = document.getElementById(id);
    // get color of square from preset id name
    let color = id.substr(7);
    console.log(`id: ${id}, sound: ${color}`);

    // add css class to lighten color (white background + opacity)
    el.className += ' shift-color';

    // play sound preset id contains specified format
    document.getElementById('sound-' + color).play();

    // create a timer to return color to normal 300ms is enough to notice
    // setTimeout executes the function after the specified time
    window.setTimeout(function() {
      el.className = el.className.replace(' shift-color', '');
    }, 500);
  };

  app.playSequence = function(i) {
    if (i < app.sequence.length) {
      app.play(app.buttons[app.sequence[i]]);
      window.setTimeout(function() {
        console.log('i: ' + i);
        app.playSequence(i + 1);
      }, 1000);
    } else {
      app.playersTurn = true;
      app.counter = 0;
      console.log(`game: ${app.gameOn} player: ${app.playersTurn}`);
    }
  };

  app.createSequence = function() {
    let n = getRandomIntInclusive(3);
    app.sequence.push(n);
    document.getElementById('step-counter').innerHTML =
      'Steps: ' + app.sequence.length;
  };

  /**
  *  Using Math.round() will give you a non-uniform distribution!
  *  @param {integer} max maximum value
  *  @param {integer} min minimum value
  *  @return {number} - Returns a random integer between 0 and max (inclusive)
  */
  function getRandomIntInclusive(max, min) {
    min = min || 0;
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }

  window.onload = function() {
    console.log('loaded javascript');
    app.setupSquareEventListeners();
  };
})();
<|endoftext|>


<commit_before>// dependencies
//
import React from 'react';
import uniqueId from 'lodash/uniqueId';
import Label from './Label';

class Dropdown extends React.Component {
    constructor(props) {
        super(props);

        this.permittedValues = props.options.map((opt) => opt.value);

        this.id = uniqueId('Dropdown-');

        this.validationMessage = `${props.description || 'This value'} is required`;

        this.state = this.validate(props.value);

        this.state.hasValidated = false;

        this.onChange = this.onChange.bind(this);
    }

    componentWillMount() {
        if (this.props.onValidation) {
            this.props.onValidation(this.state.hasValidated, this.state.isValid, this.state.validationMessage);
        }
    }

    onChange(event) {
        const newState = this.validate(event.target.value);

        this.setState((state) => newState);

        if (this.props.onValidation) {
            this.props.onValidation(newState.hasValidated, newState.isValid, newState.validationMessage);
        }
    }

    validate(option) {
        let value = `${option || ''}`;

        const inValues = this.permittedValues.find((val) => val === value);

        if (!inValues) {
            value = null;
        }

        const isValid = !this.props.required || !!value;

        return {
            value,
            hasValidated:      true,
            isValid,
            validationMessage: isValid ? null : this.validationMessage,
        };
    }

    render() {
        return (

                {this.props.label
                    ?
                    : ''
                }
                <select id={this.id} className="form-control" onChange={this.onChange} onBlur={this.onChange}>
                    {this.props.includeNull
                        ? <option key={uniqueId('Dropdown-')} value="">
                            {this.props.nullName || 'Please select one'}
                        </option>
                        : ''
                    }
                    {this.props.options.map((opt) =>
                        <option key={uniqueId('Dropdown-')} value={opt.value}>{opt.name}</option>)
                    }
                </select>

        );
    }
}

// set the property types for the Dropdown component
//
Dropdown.propTypes = {
    label:        React.PropTypes.string,
    includeNull:  React.PropTypes.bool,
    nullName:     React.PropTypes.string,
    required:     React.PropTypes.bool,
    options:      React.PropTypes.array,
    onValidation: React.PropTypes.func,
};

export default Dropdown;
<commit_msg>code cleanup<commit_after>// dependencies
//
import React from 'react';
import uniqueId from 'lodash/uniqueId';
import Label from './Label';

class Dropdown extends React.Component {
    constructor(props) {
        super(props);

        this.permittedValues = props.options.map((opt) => opt.value);

        this.id = uniqueId('Dropdown-');

        this.validationMessage = `${props.description || 'This value'} is required`;

        this.state = this.validate(props.value);

        this.state.hasValidated = false;

        this.onChange = this.onChange.bind(this);
    }

    componentWillMount() {
        if (this.props.onValidation) {
            this.props.onValidation(
                this.state.hasValidated,
                this.state.isValid,
                this.state.validationMessage
            );
        }
    }

    onChange(event) {
        const newState = this.validate(event.target.value);

        this.setState(() => newState);

        if (this.props.onValidation) {
            this.props.onValidation(
                newState.hasValidated,
                newState.isValid,
                newState.validationMessage
            );
        }
    }

    validate(option) {
        let value = `${option || ''}`;

        const inValues = this.permittedValues.find((val) => val === value);

        if (!inValues) {
            value = null;
        }

        const isValid = !this.props.required || !!value;

        return {
            value,
            hasValidated:      true,
            isValid,
            validationMessage: isValid ? null : this.validationMessage,
        };
    }

    render() {
        return (

                {this.props.label
                    ?
                    : ''
                }
                <select id={this.id} className="form-control" onChange={this.onChange} onBlur={this.onChange}>
                    {this.props.includeNull
                        ? <option key={uniqueId('Dropdown-')} value="">
                            {this.props.nullName || 'Please select one'}
                        </option>
                        : ''
                    }
                    {this.props.options.map((opt) =>
                        <option key={uniqueId('Dropdown-')} value={opt.value}>{opt.name}</option>)
                    }
                </select>

        );
    }
}

// set the property types for the Dropdown component
//
Dropdown.propTypes = {
    label:        React.PropTypes.string,
    includeNull:  React.PropTypes.bool,
    nullName:     React.PropTypes.string,
    required:     React.PropTypes.bool,
    options:      React.PropTypes.array,
    onValidation: React.PropTypes.func,
};

export default Dropdown;
<|endoftext|>


<commit_before>/*
 Copyright 2008-present Shaiksphere, Inc.

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

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

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

/**
 * A collection of useful static methods to deal with JavaScript URLs.
 *
 * @since 3.5.0
 *
 */
mindsmine.URL = class {
    /**
     * Returns true if the passed string is a valid URL, false otherwise.
     *
     * Example Usage:
     *
     *      mindsmine.URL.isValidURL("http://userid@example.com")       //  true
     *      mindsmine.URL.isValidURL("www.example.com/main.html")       //  false
     *
     * @see {@link @MDN_API_URI@/URL|URL}
     *
     * @param {String} url to check
     *
     * @returns {Boolean} if the string is a valid URL
     *
     * @since 3.5.0
     *
     */
    static isValidURL(url) {
        if (mindsmine.String.isEmpty(url)) {
            return false;
        }

        try {
            let _url = new URL(url);
        } catch (e) {
            return false;
        }

        return true;
    }

    /**
     * Appends content to the query string of a URL, handling logic for whether to place a question mark or ampersand.
     *
     * @see {@link @MDN_API_URI@/URL|URL}
     * @see {@link @MDN_API_URI@/URLSearchParams|URLSearchParams}
     *
     * @param {String} url The URL to append to.
     * @param {String} param The parameter key to append to the URL.
     * @param {Object} value The parameter value to append to the URL.
     *
     * @returns {String} The resulting URL
     *
     * @since 3.5.0
     *
     */
    static appendQuery(url, param, value) {
        if (!this.isValidURL(url)) {
            throw new TypeError("Fatal Error. 'url'. Invalid URL.");
        }

        if (mindsmine.String.isEmpty(param)) {
            throw new TypeError("Fatal Error. 'param'. @ERROR_PERMITTED_STRING@");
        }

        let _url = new URL(url);

        _url.searchParams.append(param, value);

        return _url.href;
    }
};
<commit_msg>Updating the linter rule and applying the same<commit_after>/*
 Copyright 2008-present Shaiksphere, Inc.

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

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

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

/**
 * A collection of useful static methods to deal with JavaScript URLs.
 *
 * @since 3.5.0
 *
 */
mindsmine.URL = class {
    /**
     * Returns true if the passed string is a valid URL, false otherwise.
     *
     * Example Usage:
     *
     *      mindsmine.URL.isValidURL("http://userid@example.com")       //  true
     *      mindsmine.URL.isValidURL("www.example.com/main.html")       //  false
     *
     * @see {@link @MDN_API_URI@/URL|URL}
     *
     * @param {String} url to check
     *
     * @returns {Boolean} if the string is a valid URL
     *
     * @since 3.5.0
     *
     */
    static isValidURL(url) {
        if (mindsmine.String.isEmpty(url)) {
            return false;
        }

        try {
            new URL(url);
        } catch (e) {
            return false;
        }

        return true;
    }

    /**
     * Appends content to the query string of a URL, handling logic for whether to place a question mark or ampersand.
     *
     * @see {@link @MDN_API_URI@/URL|URL}
     * @see {@link @MDN_API_URI@/URLSearchParams|URLSearchParams}
     *
     * @param {String} url The URL to append to.
     * @param {String} param The parameter key to append to the URL.
     * @param {Object} value The parameter value to append to the URL.
     *
     * @returns {String} The resulting URL
     *
     * @since 3.5.0
     *
     */
    static appendQuery(url, param, value) {
        if (!this.isValidURL(url)) {
            throw new TypeError("Fatal Error. 'url'. Invalid URL.");
        }

        if (mindsmine.String.isEmpty(param)) {
            throw new TypeError("Fatal Error. 'param'. @ERROR_PERMITTED_STRING@");
        }

        let _url = new URL(url);

        _url.searchParams.append(param, value);

        return _url.href;
    }
};
<|endoftext|>


<commit_before>let React = require('react');

// import { Link } from 'react-router';
import Section from './Section.js';
import CursiveHeader from './CursiveHeader.js';
import CenteredContainer from './CenteredContainer.js';
import CircularProgess from'./CircularProgress.js';
import SweetAlert from 'sweetalert-react';

let PollForm = React.createClass({
  getInitialState: function(){
    return {notifyUsersAlert: false};
  },
  render: function() {
    let currentPoll = this.props.currentPoll;
    let currentEvent = this.props.currentEvent;

    console.log("currentEvent", currentEvent.usersPresent);
    let numUsers = currentEvent.usersPresent.length;

    let userNotVoted = currentEvent.usersPresent.filter(function(obj){
      let userVoted = false;
      currentPoll.usersVoted.forEach(function(obj2){
        if(obj._id == obj2._id){
          userVoted = true;
        }
      })

      let userNotVoted = !userVoted;

      return userNotVoted;
    });

    let bottomMessage = "";

    if(userNotVoted.length == 0){
      bottomMessage =
Everyone Has Voted!
;
    }else{
      bottomMessage =
User Who Haven't Voted
;
    }

    let that = this;

    return (

        <SweetAlert
          show={that.state.notifyUsersAlert}
          type="success"
          title="Success!"
          text="Notified users"
          onConfirm={() => this.setState({notifyUsersAlert: false})}
        />

        <CursiveHeader>Poll: {currentPoll.name}</CursiveHeader>

 {
            this.props.notify_users(currentEvent._id, currentPoll._id);
            this.setState({notifyUsersAlert: true});
          }}
          >Notify Users

          {currentPoll.options.map(function(obj){
            let progressWidth = ((obj.votes/numUsers) * 100) + "%";
            return (

              //

                // <CenteredContainer>

{obj.name + " - " + obj.votes + " votes"}

                    <svg className="progress-div" width={progressWidth} />

                  /* <CircularProgess radius="50" percentage="50" strokeWidth="10"/> */

                // </CenteredContainer>
              //

            );
          })}

          {

          }

          {bottomMessage}

            {userNotVoted.map(function(obj){
              return (

{obj.name}

              );
            })}

    );
  }

});

export default PollForm;
<commit_msg>changed class on header on poll page<commit_after>let React = require('react');

// import { Link } from 'react-router';
import Section from './Section.js';
import CursiveHeader from './CursiveHeader.js';
import CenteredContainer from './CenteredContainer.js';
import CircularProgess from'./CircularProgress.js';
import SweetAlert from 'sweetalert-react';

let PollForm = React.createClass({
  getInitialState: function(){
    return {notifyUsersAlert: false};
  },
  render: function() {
    let currentPoll = this.props.currentPoll;
    let currentEvent = this.props.currentEvent;

    console.log("currentEvent", currentEvent.usersPresent);
    let numUsers = currentEvent.usersPresent.length;

    let userNotVoted = currentEvent.usersPresent.filter(function(obj){
      let userVoted = false;
      currentPoll.usersVoted.forEach(function(obj2){
        if(obj._id == obj2._id){
          userVoted = true;
        }
      })

      let userNotVoted = !userVoted;

      return userNotVoted;
    });

    let bottomMessage = "";

    if(userNotVoted.length == 0){
      bottomMessage =
Everyone Has Voted!
;
    }else{
      bottomMessage =
User Who Haven't Voted
;
    }

    let that = this;

    return (

        <SweetAlert
          show={that.state.notifyUsersAlert}
          type="success"
          title="Success!"
          text="Notified users"
          onConfirm={() => this.setState({notifyUsersAlert: false})}
        />

        <CursiveHeader>Poll: {currentPoll.name}</CursiveHeader>

 {
            this.props.notify_users(currentEvent._id, currentPoll._id);
            this.setState({notifyUsersAlert: true});
          }}
          >Notify Users

          {currentPoll.options.map(function(obj){
            let progressWidth = ((obj.votes/numUsers) * 100) + "%";
            return (

              //

                // <CenteredContainer>

{obj.name + " - " + obj.votes + " votes"}

                    <svg className="progress-div" width={progressWidth} />

                  /* <CircularProgess radius="50" percentage="50" strokeWidth="10"/> */

                // </CenteredContainer>
              //

            );
          })}

          {

          }

          {bottomMessage}

            {userNotVoted.map(function(obj){
              return (

{obj.name}

              );
            })}

    );
  }

});

export default PollForm;
<|endoftext|>


<commit_before>import React        from 'react';
import connectField from 'uniforms/connectField';
import {Component}  from 'react';

import styles from '../lib/styles';
import themes from '../lib/themes';

import ApplicationField from './ApplicationField';

class ApplicationPreview extends Component {
    constructor () {
        super(...arguments);

        this.state = {model: undefined};

        this.onModel = this.onModel.bind(this);
    }

    componentWillReceiveProps (props) {
        if (this.props.value.schema !== props.value.schema) {
            this.onModel({});
        }
    }

    onModel (model) {
        this.setState({model: JSON.stringify(model, null, 4)});
    }

    render () {
        const Form = themes[this.props.theme].AutoForm;
        const link = styles[this.props.theme];

        const props = {...this.props.value};
        props.schema = eval(`(${props.schema})`);

        return (

                {link}

                {this.props.errorMessage ? (

                ) : (
                    <Form key={this.props.value.schema} onChangeModel={this.onModel} {...props} />
                )}

                {this.state.model !== undefined &&
}
                {this.state.model !== undefined &&
}

        );
    }
}

export default connectField(ApplicationPreview, {baseField: ApplicationField});
<commit_msg>Optimized demo rendering.<commit_after>import React        from 'react';
import connectField from 'uniforms/connectField';
import {Component}  from 'react';

import styles from '../lib/styles';
import themes from '../lib/themes';

import ApplicationField from './ApplicationField';

class ApplicationPreview extends Component {
    constructor () {
        super(...arguments);

        this.state = {model: undefined};

        this.onModel = this.onModel.bind(this);
        this._schema = eval(`(${this.props.value.schema})`);
    }

    componentWillReceiveProps (props) {
        if (this.props.value.schema !== props.value.schema) {
            this.onModel({});
            this._schema = eval(`(${props.value.schema})`);
        }
    }

    onModel (model) {
        this.setState({model: JSON.stringify(model, null, 4)});
    }

    render () {
        const Form = themes[this.props.theme].AutoForm;
        const link = styles[this.props.theme];

        const props = {...this.props.value};
        props.schema = this._schema;

        return (

                {link}

                {this.props.errorMessage ? (

                ) : (
                    <Form key={this.props.value.schema} onChangeModel={this.onModel} {...props} />
                )}

                {this.state.model !== undefined &&
}
                {this.state.model !== undefined &&
}

        );
    }
}

export default connectField(ApplicationPreview, {baseField: ApplicationField});
<|endoftext|>


<commit_before>//= require leaflet/draw
//= require leaflet/map

//= require leaflet/draw.translations

const $building_geo_data = {
  element: $('#building_geo_data'),
  save: function(geo_json){
    this.element.val(JSON.stringify(geo_json.toGeoJSON()));
  },
  load(){
    const $geo_json = this.element.val();
    if ($geo_json) {
        drawnLayer.addData(JSON.parse($geo_json));
    }
  }
};

var drawnLayer = L.geoJSON().addTo(map);
map.addLayer(drawnLayer);

// Load json from the form
$building_geo_data.load();

var drawControl = new L.Control.Draw({
    edit: {
        featureGroup: drawnLayer
    },
    draw: {
        polyline: false,
        circle: false,
        rectangle: false,
        polygon: {
            allowIntersection: false,
            showArea: true
        }
    }
});

map.on(L.Draw.Event.CREATED, function(event) {
    var layer = event.layer;
    drawnLayer.addLayer(layer);
    $building_geo_data.save(drawnLayer);
});

map.on(L.Draw.Event.EDITED, function(event) {
    $building_geo_data.save(drawnLayer);
});
map.on(L.Draw.Event.DELETED, function(event) {
    $building_geo_data.save(drawnLayer);
});

map.addControl(drawControl);

// TODO:10 Create button to define the location
<commit_msg>More ES 6.0 Fixtures for CI Deploy on Heroku<commit_after>//= require leaflet/draw
//= require leaflet/map

//= require leaflet/draw.translations

const $building_geo_data = {
  element: $('#building_geo_data'),
  save: function(geo_json){
    this.element.val(JSON.stringify(geo_json.toGeoJSON()));
  },
  load: function(){
    const $geo_json = this.element.val();
    if ($geo_json) {
        drawnLayer.addData(JSON.parse($geo_json));
    }
  }
};

var drawnLayer = L.geoJSON().addTo(map);
map.addLayer(drawnLayer);

// Load json from the form
$building_geo_data.load();

var drawControl = new L.Control.Draw({
    edit: {
        featureGroup: drawnLayer
    },
    draw: {
        polyline: false,
        circle: false,
        rectangle: false,
        polygon: {
            allowIntersection: false,
            showArea: true
        }
    }
});

map.on(L.Draw.Event.CREATED, function(event) {
    var layer = event.layer;
    drawnLayer.addLayer(layer);
    $building_geo_data.save(drawnLayer);
});

map.on(L.Draw.Event.EDITED, function(event) {
    $building_geo_data.save(drawnLayer);
});
map.on(L.Draw.Event.DELETED, function(event) {
    $building_geo_data.save(drawnLayer);
});

map.addControl(drawControl);

// TODO:10 Create button to define the location
<|endoftext|>


<commit_before>import {bindable, customAttribute} from 'aurelia-templating';
import {BindingEngine} from 'aurelia-binding';
import {inject} from 'aurelia-dependency-injection';
import {TaskQueue} from 'aurelia-task-queue';
import * as LogManager from 'aurelia-logging';
import {fireEvent} from '../common/events';
import {DOM} from 'aurelia-pal';

@inject(Element, LogManager, BindingEngine, TaskQueue)
@customAttribute('md-select')
export class MdSelect {
  @bindable() disabled = false;
  @bindable() label = '';
  _suspendUpdate = false;
  subscriptions = [];
  input = null;
  dropdownMutationObserver = null;

  constructor(element, logManager, bindingEngine, taskQueue) {
    this.element = element;
    this.taskQueue = taskQueue;
    this.handleChangeFromViewModel = this.handleChangeFromViewModel.bind(this);
    this.handleChangeFromNativeSelect = this.handleChangeFromNativeSelect.bind(this);
    this.handleBlur = this.handleBlur.bind(this);
    this.log = LogManager.getLogger('md-select');
    this.bindingEngine = bindingEngine;
  }

  attached() {
    this.subscriptions.push(this.bindingEngine.propertyObserver(this.element, 'value').subscribe(this.handleChangeFromViewModel));
    // this.subscriptions.push(this.bindingEngine.propertyObserver(this.element, 'selectedOptions').subscribe(this.notifyBindingEngine.bind(this)));
    // $(this.element).material_select(() => {
    //   this.log.warn('materialize callback', $(this.element).val());
    //   this.handleChangeFromNativeSelect();
    // });
    this.createMaterialSelect(false);

    if (this.label) {
      let wrapper = $(this.element).parent('.select-wrapper');
      let div = $('

');
      let va = this.element.attributes.getNamedItem('validate');
      if (va) {
        div.attr(va.name, va.label);
      }
      wrapper.wrap(div);
      $(`<label>${this.label}</label>`).insertAfter(wrapper);
    }
    $(this.element).on('change', this.handleChangeFromNativeSelect);
  }

  detached() {
    $(this.element).off('change', this.handleChangeFromNativeSelect);
    this.observeVisibleDropdownContent(false);
    this.dropdownMutationObserver = null;
    $(this.element).material_select('destroy');
    this.subscriptions.forEach(sub => sub.dispose());
  }

  refresh() {
    this.taskQueue.queueTask(() => {
      this.createMaterialSelect(true);
    });
  }

  disabledChanged(newValue) {
    this.toggleControl(newValue);
  }

  notifyBindingEngine() {
    this.log.debug('selectedOptions changed', arguments);
  }

  handleChangeFromNativeSelect() {
    if (!this._suspendUpdate) {
      this.log.debug('handleChangeFromNativeSelect', this.element.value, $(this.element).val());
      this._suspendUpdate = true;
      fireEvent(this.element, 'change');
      this._suspendUpdate = false;
    }
  }

  handleChangeFromViewModel(newValue) {
    this.log.debug('handleChangeFromViewModel', newValue, $(this.element).val());
    if (!this._suspendUpdate) {
      this.createMaterialSelect(false);
    }
  }

  toggleControl(disable) {
    let $wrapper = $(this.element).parent('.select-wrapper');
    if ($wrapper.length > 0) {
      if (disable) {
        $('.caret', $wrapper).addClass('disabled');
        $('input.select-dropdown', $wrapper).attr('disabled', 'disabled');
        $wrapper.attr('disabled', 'disabled');
      } else {
        $('.caret', $wrapper).removeClass('disabled');
        $('input.select-dropdown', $wrapper).attr('disabled', null);
        $wrapper.attr('disabled', null);
        $('.select-dropdown', $wrapper).dropdown({'hover': false, 'closeOnClick': false});
      }
    }
  }

  createMaterialSelect(destroy) {
    this.observeVisibleDropdownContent(false);
    if (destroy) {
      $(this.element).material_select('destroy');
    }
    $(this.element).material_select();
    this.toggleControl(this.disabled);
    this.observeVisibleDropdownContent(true);
  }

  observeVisibleDropdownContent(attach) {
    if (attach) {
      if (!this.dropdownMutationObserver) {
        this.dropdownMutationObserver = DOM.createMutationObserver(mutations => {
          let isHidden = false;
          for (let mutation of mutations) {
            if (window.getComputedStyle(mutation.target).getPropertyValue('display') === 'none') {
              isHidden = true;
            }
          }
          if (isHidden) {
            this.dropdownMutationObserver.takeRecords();
            this.handleBlur();
          }
        });
      }
      this.dropdownMutationObserver.observe(this.element.parentElement.querySelector('.dropdown-content'), {
        attributes: true,
        attributeFilter: ['style']
      });
    } else {
      if (this.dropdownMutationObserver) {
        this.dropdownMutationObserver.disconnect();
        this.dropdownMutationObserver.takeRecords();
      }
    }
  }

  //
  // Firefox sometimes fire blur several times in a row
  // observable at http://localhost:3000/#/samples/select/
  // when enable 'Disable Functionality', open that list and
  // then open 'Basic use' list.
  // Chrome - ok
  // IE ?
  //
  _taskqueueRunning = false;

  handleBlur() {
    if (this._taskqueueRunning) return;
    this._taskqueueRunning = true;
    this.taskQueue.queueTask(() => {
      this.log.debug('fire blur event');
      fireEvent(this.element, 'blur');
      this._taskqueueRunning = false;
    });
  }
}
<commit_msg>chore(md-select): add compatibility comment<commit_after>import {bindable, customAttribute} from 'aurelia-templating';
import {BindingEngine} from 'aurelia-binding';
import {inject} from 'aurelia-dependency-injection';
import {TaskQueue} from 'aurelia-task-queue';
import * as LogManager from 'aurelia-logging';
import {fireEvent} from '../common/events';
import {DOM} from 'aurelia-pal';

@inject(Element, LogManager, BindingEngine, TaskQueue)
@customAttribute('md-select')
export class MdSelect {
  @bindable() disabled = false;
  @bindable() label = '';
  _suspendUpdate = false;
  subscriptions = [];
  input = null;
  dropdownMutationObserver = null;

  constructor(element, logManager, bindingEngine, taskQueue) {
    this.element = element;
    this.taskQueue = taskQueue;
    this.handleChangeFromViewModel = this.handleChangeFromViewModel.bind(this);
    this.handleChangeFromNativeSelect = this.handleChangeFromNativeSelect.bind(this);
    this.handleBlur = this.handleBlur.bind(this);
    this.log = LogManager.getLogger('md-select');
    this.bindingEngine = bindingEngine;
  }

  attached() {
    this.subscriptions.push(this.bindingEngine.propertyObserver(this.element, 'value').subscribe(this.handleChangeFromViewModel));
    // this.subscriptions.push(this.bindingEngine.propertyObserver(this.element, 'selectedOptions').subscribe(this.notifyBindingEngine.bind(this)));
    // $(this.element).material_select(() => {
    //   this.log.warn('materialize callback', $(this.element).val());
    //   this.handleChangeFromNativeSelect();
    // });
    this.createMaterialSelect(false);

    if (this.label) {
      let wrapper = $(this.element).parent('.select-wrapper');
      let div = $('

');
      let va = this.element.attributes.getNamedItem('validate');
      if (va) {
        div.attr(va.name, va.label);
      }
      wrapper.wrap(div);
      $(`<label>${this.label}</label>`).insertAfter(wrapper);
    }
    $(this.element).on('change', this.handleChangeFromNativeSelect);
  }

  detached() {
    $(this.element).off('change', this.handleChangeFromNativeSelect);
    this.observeVisibleDropdownContent(false);
    this.dropdownMutationObserver = null;
    $(this.element).material_select('destroy');
    this.subscriptions.forEach(sub => sub.dispose());
  }

  refresh() {
    this.taskQueue.queueTask(() => {
      this.createMaterialSelect(true);
    });
  }

  disabledChanged(newValue) {
    this.toggleControl(newValue);
  }

  notifyBindingEngine() {
    this.log.debug('selectedOptions changed', arguments);
  }

  handleChangeFromNativeSelect() {
    if (!this._suspendUpdate) {
      this.log.debug('handleChangeFromNativeSelect', this.element.value, $(this.element).val());
      this._suspendUpdate = true;
      fireEvent(this.element, 'change');
      this._suspendUpdate = false;
    }
  }

  handleChangeFromViewModel(newValue) {
    this.log.debug('handleChangeFromViewModel', newValue, $(this.element).val());
    if (!this._suspendUpdate) {
      this.createMaterialSelect(false);
    }
  }

  toggleControl(disable) {
    let $wrapper = $(this.element).parent('.select-wrapper');
    if ($wrapper.length > 0) {
      if (disable) {
        $('.caret', $wrapper).addClass('disabled');
        $('input.select-dropdown', $wrapper).attr('disabled', 'disabled');
        $wrapper.attr('disabled', 'disabled');
      } else {
        $('.caret', $wrapper).removeClass('disabled');
        $('input.select-dropdown', $wrapper).attr('disabled', null);
        $wrapper.attr('disabled', null);
        $('.select-dropdown', $wrapper).dropdown({'hover': false, 'closeOnClick': false});
      }
    }
  }

  createMaterialSelect(destroy) {
    this.observeVisibleDropdownContent(false);
    if (destroy) {
      $(this.element).material_select('destroy');
    }
    $(this.element).material_select();
    this.toggleControl(this.disabled);
    this.observeVisibleDropdownContent(true);
  }

  observeVisibleDropdownContent(attach) {
    if (attach) {
      if (!this.dropdownMutationObserver) {
        this.dropdownMutationObserver = DOM.createMutationObserver(mutations => {
          let isHidden = false;
          for (let mutation of mutations) {
            if (window.getComputedStyle(mutation.target).getPropertyValue('display') === 'none') {
              isHidden = true;
            }
          }
          if (isHidden) {
            this.dropdownMutationObserver.takeRecords();
            this.handleBlur();
          }
        });
      }
      this.dropdownMutationObserver.observe(this.element.parentElement.querySelector('.dropdown-content'), {
        attributes: true,
        attributeFilter: ['style']
      });
    } else {
      if (this.dropdownMutationObserver) {
        this.dropdownMutationObserver.disconnect();
        this.dropdownMutationObserver.takeRecords();
      }
    }
  }

  //
  // Firefox sometimes fire blur several times in a row
  // observable at http://localhost:3000/#/samples/select/
  // when enable 'Disable Functionality', open that list and
  // then open 'Basic use' list.
  // Chrome - ok
  // IE 11 - ok
  // Edge ?
  //
  _taskqueueRunning = false;

  handleBlur() {
    if (this._taskqueueRunning) return;
    this._taskqueueRunning = true;
    this.taskQueue.queueTask(() => {
      this.log.debug('fire blur event');
      fireEvent(this.element, 'blur');
      this._taskqueueRunning = false;
    });
  }
}
<|endoftext|>


<commit_before>'use strict';

import { Dimensions, Platform } from 'react-native';

const domMutationObserveScript = `
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
var observer = new MutationObserver(updateSize);
observer.observe(document, {
    subtree: true,
    attributes: true
});
`;

const updateSizeWithMessage = element =>
  `
  var lastHeight = 0;
  var heightTheSameTimes = 0;
  var maxHeightTheSameTimes = 5;
  var forceRefreshDelay = 1000;
  var forceRefreshTimeout;

  function updateSize(event) {
    if (
      !window.hasOwnProperty('ReactNativeWebView') ||
      !window.ReactNativeWebView.hasOwnProperty('postMessage')
    ) {
      setTimeout(updateSize, 200);
      return;
    }
    height = ${element}.offsetHeight || document.documentElement.offsetHeight;
    width = ${element}.offsetWidth || document.documentElement.offsetWidth;
    window.ReactNativeWebView.postMessage(JSON.stringify({ width: width, height: height }));

    // Make additional height checks (required to fix issues wit twitter embeds)
    clearTimeout(forceRefreshTimeout);
    if (lastHeight !== height) {
      heightTheSameTimes = 1;
    } else {
      heightTheSameTimes++;
    }

    lastHeight = height;

    if (heightTheSameTimes <= maxHeightTheSameTimes) {
      forceRefreshTimeout = setTimeout(
        updateSize,
        heightTheSameTimes * forceRefreshDelay
      );
    }
  }
  `;

// add viewport setting to meta for WKWebView
const makeScalePageToFit = zoomable => `
var meta = document.createElement('meta');
meta.setAttribute('name', 'viewport');
meta.setAttribute('content', 'width=device-width, user-scalable=${
  zoomable ? 'yes' : 'no'
}'); document.getElementsByTagName('head')[0].appendChild(meta);
`;

const getBaseScript = ({ style, zoomable }) =>
  `
  ;
  if (!document.getElementById("rnahw-wrapper")) {
    var wrapper = document.createElement('div');
    wrapper.id = 'rnahw-wrapper';
    while (document.body.firstChild instanceof Node) {
      wrapper.appendChild(document.body.firstChild);
    }
    document.body.appendChild(wrapper);
  }
  ${updateSizeWithMessage('wrapper')}
  window.addEventListener('load', updateSize);
  window.addEventListener('resize', updateSize);
  ${domMutationObserveScript}
  ${makeScalePageToFit(zoomable)}
  updateSize();
  `;

const appendFilesToHead = ({ files, script }) =>
  files.reduceRight((combinedScript, file) => {
    const { rel, type, href } = file;
    return `
      var link  = document.createElement('link');
      link.rel  = '${rel}';
      link.type = '${type}';
      link.href = '${href}';
      document.head.appendChild(link);
      ${combinedScript}
    `;
  }, script);

const screenWidth = Dimensions.get('window').width;

const bodyStyle = `
body {
  margin: 0;
  padding: 0;
}
`;

const appendStylesToHead = ({ style, script }) => {
  const currentStyles = style ? bodyStyle + style : bodyStyle;
  // Escape any single quotes or newlines in the CSS with .replace()
  const escaped = currentStyles.replace(/\'/g, "\\'").replace(/\n/g, '\\n');
  return `
    var styleElement = document.createElement('style');
    styleElement.innerHTML = '${escaped}';
    document.head.appendChild(styleElement);
    ${script}
  `;
};

const getInjectedSource = ({ html, script }) => `
${html}
<script>
// prevents code colissions with global scope
(() => {
  ${script}
})();
</script>
`;

const getScript = ({ files, customStyle, customScript, style, zoomable }) => {
  let script = getBaseScript({ style, zoomable });
  script = files && files.length > 0 ? appendFilesToHead({ files, script }) : script;
  script = appendStylesToHead({ style: customStyle, script });
  customScript && (script = customScript + script);
  return script;
};

export const getWidth = style => {
  return style && style.width ? style.width : screenWidth;
};

export const isSizeChanged = ({ height, previousHeight, width, previousWidth }) => {
  if (!height || !width) {
    return;
  }
  return height !== previousHeight || width !== previousWidth;
};

export const reduceData = props => {
  const { source } = props;
  const script = getScript(props);
  const { html, baseUrl } = source;
  if (html) {
    return { currentSource: { baseUrl, html: getInjectedSource({ html, script }) } };
  } else {
    return {
      currentSource: source,
      script
    };
  }
};

export const shouldUpdate = ({ prevProps, nextProps }) => {
  if (!(prevProps && nextProps)) {
    return true;
  }
  for (const prop in nextProps) {
    if (nextProps[prop] !== prevProps[prop]) {
      if (typeof nextProps[prop] === 'object' && typeof prevProps[prop] === 'object') {
        if (shouldUpdate({ prevProps: prevProps[prop], nextProps: nextProps[prop] })) {
          return true;
        }
      } else {
        return true;
      }
    }
  }
  return false;
};
<commit_msg>Clean up code styles<commit_after>'use strict';

import { Dimensions, Platform } from 'react-native';

const domMutationObserveScript = `
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
var observer = new MutationObserver(updateSize);
observer.observe(document, {
    subtree: true,
    attributes: true
});
`;

const updateSizeWithMessage = element =>
  `
  var lastHeight = 0;
  var heightTheSameTimes = 0;
  var maxHeightTheSameTimes = 5;
  var forceRefreshDelay = 1000;
  var forceRefreshTimeout;

  function updateSize(event) {
    if (
      !window.hasOwnProperty('ReactNativeWebView') ||
      !window.ReactNativeWebView.hasOwnProperty('postMessage')
    ) {
      setTimeout(updateSize, 200);
      return;
    }
    height = ${element}.offsetHeight || document.documentElement.offsetHeight;
    width = ${element}.offsetWidth || document.documentElement.offsetWidth;
    window.ReactNativeWebView.postMessage(JSON.stringify({ width: width, height: height }));

    // Make additional height checks (required to fix issues wit twitter embeds)
    clearTimeout(forceRefreshTimeout);
    if (lastHeight !== height) {
      heightTheSameTimes = 1;
    } else {
      heightTheSameTimes++;
    }

    lastHeight = height;

    if (heightTheSameTimes <= maxHeightTheSameTimes) {
      forceRefreshTimeout = setTimeout(
        updateSize,
        heightTheSameTimes * forceRefreshDelay
      );
    }
  }
  `;

// add viewport setting to meta
const makeScalePageToFit = zoomable => `
var meta = document.createElement('meta');
meta.setAttribute('name', 'viewport');
meta.setAttribute('content', 'width=device-width, user-scalable=${
  zoomable ? 'yes' : 'no'
}'); document.getElementsByTagName('head')[0].appendChild(meta);
`;

const getBaseScript = ({ style, zoomable }) =>
  `
  ;
  if (!document.getElementById("rnahw-wrapper")) {
    var wrapper = document.createElement('div');
    wrapper.id = 'rnahw-wrapper';
    while (document.body.firstChild instanceof Node) {
      wrapper.appendChild(document.body.firstChild);
    }
    document.body.appendChild(wrapper);
  }
  ${updateSizeWithMessage('wrapper')}
  window.addEventListener('load', updateSize);
  window.addEventListener('resize', updateSize);
  ${domMutationObserveScript}
  ${makeScalePageToFit(zoomable)}
  updateSize();
  `;

const appendFilesToHead = ({ files, script }) =>
  files.reduceRight((combinedScript, file) => {
    const { rel, type, href } = file;
    return `
      var link  = document.createElement('link');
      link.rel  = '${rel}';
      link.type = '${type}';
      link.href = '${href}';
      document.head.appendChild(link);
      ${combinedScript}
    `;
  }, script);

const screenWidth = Dimensions.get('window').width;

const bodyStyle = `
body {
  margin: 0;
  padding: 0;
}
`;

const appendStylesToHead = ({ style, script }) => {
  const currentStyles = style ? bodyStyle + style : bodyStyle;
  // Escape any single quotes or newlines in the CSS with .replace()
  const escaped = currentStyles.replace(/\'/g, "\\'").replace(/\n/g, '\\n');
  return `
    var styleElement = document.createElement('style');
    styleElement.innerHTML = '${escaped}';
    document.head.appendChild(styleElement);
    ${script}
  `;
};

const getInjectedSource = ({ html, script }) => `
${html}
<script>
// prevents code colissions with global scope
(() => {
  ${script}
})();
</script>
`;

const getScript = ({ files, customStyle, customScript, style, zoomable }) => {
  let script = getBaseScript({ style, zoomable });
  script = files && files.length > 0 ? appendFilesToHead({ files, script }) : script;
  script = appendStylesToHead({ style: customStyle, script });
  customScript && (script = customScript + script);
  return script;
};

export const getWidth = style => {
  return style && style.width ? style.width : screenWidth;
};

export const isSizeChanged = ({ height, previousHeight, width, previousWidth }) => {
  if (!height || !width) {
    return;
  }
  return height !== previousHeight || width !== previousWidth;
};

export const reduceData = props => {
  const { source } = props;
  const script = getScript(props);
  const { html, baseUrl } = source;
  if (html) {
    return { currentSource: { baseUrl, html: getInjectedSource({ html, script }) } };
  } else {
    return {
      currentSource: source,
      script
    };
  }
};

export const shouldUpdate = ({ prevProps, nextProps }) => {
  if (!(prevProps && nextProps)) {
    return true;
  }
  for (const prop in nextProps) {
    if (nextProps[prop] !== prevProps[prop]) {
      if (typeof nextProps[prop] === 'object' && typeof prevProps[prop] === 'object') {
        if (shouldUpdate({ prevProps: prevProps[prop], nextProps: nextProps[prop] })) {
          return true;
        }
      } else {
        return true;
      }
    }
  }
  return false;
};
<|endoftext|>