<commit_before>import PropTypes from "prop-types";
import React, {
  useCallback,
  useEffect,
  useRef,
  useState,
  Suspense,
} from "react";
import styled from "styled-components";

import style from "@agir/front/genericComponents/_variables.scss";

import { useIsDesktop } from "@agir/front/genericComponents/grid";
import { lazy } from "@agir/front/app/utils";

import AnimatedMoreHorizontal from "@agir/front/genericComponents/AnimatedMoreHorizontal";
import Avatar from "@agir/front/genericComponents/Avatar";
import { RawFeatherIcon } from "@agir/front/genericComponents/FeatherIcon";
import TextField from "@agir/front/formComponents/TextField";
import StaticToast from "@agir/front/genericComponents/StaticToast";

const EmojiPicker = lazy(() =>
  import("@agir/front/formComponents/EmojiPicker")
);

const StyledCommentButton = styled.button`
  @media (max-width: ${style.collapse}px) {
    display: flex;
    width: 100%;
    margin: 0;
    border-radius: ${style.borderRadius};
    border: none;
    padding: 0.5rem 0.75rem;
    text-decoration: none;
    background-color: ${({ $disabled }) =>
      $disabled ? style.black100 : style.black50};
    font-size: 1rem;
    line-height: 1.65;
    color: ${style.black500};
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
    cursor: pointer;
    -webkit-appearance: none;
    -moz-appearance: none;

    &:hover,
    &:focus {
      outline: none;
      background-color: ${style.black50};
      transition: background-color 250ms ease-in-out;
    }
  }
`;
const StyledField = styled.div``;
const StyledAction = styled.div``;
const StyledMessage = styled.div``;
const StyledWrapper = styled.form`
  display: flex;
  margin-top: auto;
  max-width: 100%;

  @media (max-width: ${style.collapse}px) {
    max-height: 50vh;
  }

  & > ${Avatar} {
    flex: 0 0 auto;
    width: 2rem;
    height: 2rem;
    margin-top: 5px;
    margin-right: 0.5rem;

    @media (max-width: ${style.collapse}px) {
      display: none;
    }
  }

  ${StyledMessage} {
    display: flex;
    flex: 1 1 auto;
    border-radius: ${style.borderRadius};
    background-color: ${({ $disabled }) =>
      $disabled ? style.black100 : style.black50};
    border: none;
    flex-flow: row nowrap;
    padding: ${({ $isExpanded }) =>
      $isExpanded ? "0.75rem" : ".5rem 0.75rem"};
    transition: background-color 250ms ease-in-out;

    @media (max-width: ${style.collapse}px) {
      position: fixed;
      bottom: 0;
      left: 0;
      right: 0;
      z-index: 1;
      border: none;
      border-radius: 0;
      max-height: 50vh;
      overflow: hidden;
      overflow-y: auto;
      padding: 1rem;
      background-color: white;
      box-shadow: 0px -3px 3px rgba(0, 35, 44, 0.1),
        0px 2px 0px rgba(0, 35, 44, 0.08);
      align-items: ${({ $isExpanded }) =>
        $isExpanded ? "flex-start" : "center"};
    }

    &:hover {
      ${({ $isExpanded }) =>
        !$isExpanded ? `background-color: ${style.black100};` : ""}

      @media (max-width: ${style.collapse}px) {
        background-color: white;
      }
    }

    & > ${Avatar} {
      display: none;

      @media (max-width: ${style.collapse}px) {
        display: ${({ $isExpanded }) => ($isExpanded ? "none" : "block")};
        flex: 0 0 auto;
        width: 2rem;
        height: 2rem;
        margin: 0;
        margin-right: 0.5rem;
      }
    }
  }

  ${StyledField} {
    flex: 1 1 auto;
    display: flex;
    flex-flow: column nowrap;
    align-items: flex-start nowrap;
    cursor: ${({ $isExpanded, $disabled }) =>
      $disabled || $isExpanded ? "default" : "pointer"};
    font-size: 1rem;

    ${StyledCommentButton} {
      flex: 1 1 auto;
      margin: 0;
      padding: 0;
      font-size: inherit;
      line-height: 1.65;
      color: ${style.black500};
      white-space: nowrap;
      text-overflow: ellipsis;
      overflow: hidden;
      border: none;
      text-align: left;
      background-color: transparent;
      cursor: pointer;
    }

    label {
      font-size: inherit;
    }

    textarea {
      ${({ $isExpanded }) =>
        !$isExpanded &&
        `
      flex: 1 1 auto;
      margin: 0;
      padding: 0;
      font-size: inherit;
      line-height: 1.65;
      `}

      &,
      &:focus,
      &:hover {
        border: none;
        outline: none;
        padding-left: 0;
        padding-right: 0;
        font-size: inherit;
        margin: 0;
        background-color: transparent;
      }
    }

    & > :last-child {
      @media (max-width: ${style.collapse}px) {
        visibility: ${({ $isExpanded }) =>
          $isExpanded ? "hidden" : "visible"};
      }
    }

    & > ${RawFeatherIcon} {
      display: none;
      @media (max-width: ${style.collapse}px) {
        display: inline-block;
        opacity: 0.3;
        transform: rotate(45deg);
      }
    }
  }

  ${StyledAction} {
    flex: 0 0 40px;
    text-align: center;

    button {
      border: none;
      padding: 0;
      margin: 0;
      text-decoration: none;
      background: inherit;
      color: inherit;
      font-size: 0;
      line-height: 0;
      cursor: pointer;
      text-align: center;
      -webkit-appearance: none;
      -moz-appearance: none;
      transform: rotate(45deg);
      transform-origin: center center;

      &:hover,
      &:focus {
        border: none;
        outline: none;
        opacity: 0.6;
      }

      &[disabled],
      &[disabled]:hover,
      &[disabled]:focus {
        opacity: 1;
        cursor: default;
      }
    }
  }
`;

const PLACEHOLDER_MESSAGE = "Écrire une réponse";

export const CommentButton = (props) => {
  const { onClick } = props;
  return onClick ? (
    <StyledCommentButton onClick={onClick}>
      {PLACEHOLDER_MESSAGE}
    </StyledCommentButton>
  ) : null;
};
CommentButton.propTypes = {
  onClick: PropTypes.func,
};

const CommentField = (props) => {
  const {
    user,
    initialValue,
    id,
    onSend,
    isLoading,
    disabled,
    isLocked,
    autoScroll,
    placeholder,
    scrollerRef,
  } = props;

  const hasSubmitted = useRef(false);

  const rootElementRef = useRef();
  const messageRef = useRef();
  const fieldWrapperRef = useRef();
  const textFieldRef = useRef();
  const textFieldCursorPosition = useRef();
  const isDesktop = useIsDesktop();

  const [isFocused, setIsFocused] = useState(false);
  const [value, setValue] = useState(initialValue || "");

  const isExpanded = !!value || isFocused;
  const maySend = !isLoading && value && value.trim().length <= 1000;

  const updateScroll = () => {
    setTimeout(() => {
      scrollerRef.current.scrollTo(0, scrollerRef.current.scrollHeight);
    }, 50);
  };

  const handleFocus = () => {
    setIsFocused(true);
    updateScroll();
  };

  const blurOnClickOutside = useCallback(
    (event) => {
      if (!fieldWrapperRef.current?.contains(event.target)) {
        setIsFocused(false);
      }
      if (autoScroll) {
        updateScroll(
          rootElementRef.current,
          !isDesktop ? messageRef.current : null
        );
      }
    },
    [isDesktop, autoScroll]
  );

  const blurOnFocusOutside = useCallback(() => {
    if (
      document.activeElement &&
      !fieldWrapperRef.current?.contains(document.activeElement)
    ) {
      setIsFocused(false);
    }
    if (autoScroll) {
      updateScroll(
        rootElementRef.current,
        !isDesktop ? messageRef.current : null
      );
    }
  }, [isDesktop, autoScroll]);

  useEffect(() => {
    if (typeof window !== "undefined") {
      if (isFocused && !value) {
        document.addEventListener("click", blurOnClickOutside);
        document.addEventListener("keyup", blurOnFocusOutside);
      }

      return () => {
        document.removeEventListener("click", blurOnClickOutside);
        document.removeEventListener("keyup", blurOnFocusOutside);
      };
    }
  }, [isFocused, value, blurOnClickOutside, blurOnFocusOutside]);

  const handleInputChange = useCallback((e) => {
    setValue(e.target.value);
  }, []);

  const handleEmojiSelect = useCallback(
    (emoji) => {
      if (!Array.isArray(textFieldCursorPosition.current)) {
        setValue(value + emoji);
        return;
      }
      const [start, end] = textFieldCursorPosition.current;
      const newValue = value.slice(0, start) + emoji + value.slice(end);
      textFieldCursorPosition.current = [
        start + emoji.length,
        start + emoji.length,
      ];
      setValue(newValue);
    },
    [value]
  );

  const handleEmojiOpen = useCallback(() => {
    if (
      typeof textFieldRef.current?.selectionStart === "number" &&
      typeof textFieldRef.current?.selectionEnd === "number"
    ) {
      textFieldCursorPosition.current = [
        textFieldRef.current.selectionStart,
        textFieldRef.current.selectionEnd,
      ];
    }
  }, []);

  const handleSend = useCallback(
    (e) => {
      e.preventDefault();
      blurOnClickOutside(e);
      if (maySend) {
        onSend(value);
        hasSubmitted.current = true;
      }
    },
    [maySend, onSend, value]
  );

  useEffect(() => {
    if (!isLoading && hasSubmitted.current) {
      hasSubmitted.current = false;
      setValue("");
    }
  }, [isLoading]);

  const handleInputKeyDown = useCallback(
    (e) => {
      if (maySend && e.ctrlKey && e.keyCode === 13) {
        onSend(value);
        hasSubmitted.current = true;
      }
    },
    [maySend, value, onSend]
  );

  useEffect(() => {
    updateScroll();
  }, [isFocused, value]);

  if (isLocked) {
    return (
      <StaticToast $color="grey" style={{ marginTop: 0 }}>
        Cette conversation a été close par les gestionnaires du groupe. Vous ne
        pouvez plus y écrire de réponse.
      </StaticToast>
    );
  }

  return (
    <StyledWrapper
      $isExpanded={isExpanded}
      $disabled={disabled || isLoading}
      onSubmit={handleSend}
      ref={rootElementRef}
    >
      <Avatar name={user.displayName} image={user.image} />
      <StyledMessage ref={messageRef}>
        <Avatar name={user.displayName} image={user.image} />
        <StyledField
          ref={fieldWrapperRef}
          onClick={!disabled ? handleFocus : undefined}
          onTouchStart={!disabled ? handleFocus : undefined}
        >
          <Suspense fallback={null}>
            <TextField
              ref={textFieldRef}
              textArea
              id={id}
              value={value}
              onChange={handleInputChange}
              onKeyDown={handleInputKeyDown}
              autoFocus={isFocused}
              label={isFocused && user.displayName}
              disabled={disabled || isLoading}
              placeholder={placeholder || PLACEHOLDER_MESSAGE}
              maxLength={1000}
              hasCounter={false}
            />
            {isFocused && (
              <EmojiPicker
                onOpen={handleEmojiOpen}
                onSelect={handleEmojiSelect}
                small
              />
            )}
          </Suspense>
        </StyledField>
        {isFocused ? (
          <StyledAction>
            {isLoading ? (
              <AnimatedMoreHorizontal />
            ) : (
              <button
                type="submit"
                disabled={!maySend}
                aria-label="Envoyer le commentaire"
              >
                <RawFeatherIcon
                  name="send"
                  color={maySend ? style.primary500 : style.black500}
                />
              </button>
            )}
          </StyledAction>
        ) : null}
      </StyledMessage>
    </StyledWrapper>
  );
};
CommentField.propTypes = {
  user: PropTypes.shape({
    displayName: PropTypes.string.isRequired,
    image: PropTypes.string,
  }).isRequired,
  initialValue: PropTypes.string,
  id: PropTypes.string,
  onSend: PropTypes.func.isRequired,
  isLoading: PropTypes.bool,
  disabled: PropTypes.bool,
  autoScroll: PropTypes.bool,
};
export default CommentField;
<commit_msg>fix: replace by clearinterval until dom element is catched<commit_after>import PropTypes from "prop-types";
import React, {
  useCallback,
  useEffect,
  useRef,
  useState,
  Suspense,
} from "react";
import styled from "styled-components";

import style from "@agir/front/genericComponents/_variables.scss";

import { useIsDesktop } from "@agir/front/genericComponents/grid";
import { lazy } from "@agir/front/app/utils";

import AnimatedMoreHorizontal from "@agir/front/genericComponents/AnimatedMoreHorizontal";
import Avatar from "@agir/front/genericComponents/Avatar";
import { RawFeatherIcon } from "@agir/front/genericComponents/FeatherIcon";
import TextField from "@agir/front/formComponents/TextField";
import StaticToast from "@agir/front/genericComponents/StaticToast";

const EmojiPicker = lazy(() =>
  import("@agir/front/formComponents/EmojiPicker")
);

const StyledCommentButton = styled.button`
  @media (max-width: ${style.collapse}px) {
    display: flex;
    width: 100%;
    margin: 0;
    border-radius: ${style.borderRadius};
    border: none;
    padding: 0.5rem 0.75rem;
    text-decoration: none;
    background-color: ${({ $disabled }) =>
      $disabled ? style.black100 : style.black50};
    font-size: 1rem;
    line-height: 1.65;
    color: ${style.black500};
    white-space: nowrap;
    text-overflow: ellipsis;
    overflow: hidden;
    cursor: pointer;
    -webkit-appearance: none;
    -moz-appearance: none;

    &:hover,
    &:focus {
      outline: none;
      background-color: ${style.black50};
      transition: background-color 250ms ease-in-out;
    }
  }
`;
const StyledField = styled.div``;
const StyledAction = styled.div``;
const StyledMessage = styled.div``;
const StyledWrapper = styled.form`
  display: flex;
  margin-top: auto;
  max-width: 100%;

  @media (max-width: ${style.collapse}px) {
    max-height: 50vh;
  }

  & > ${Avatar} {
    flex: 0 0 auto;
    width: 2rem;
    height: 2rem;
    margin-top: 5px;
    margin-right: 0.5rem;

    @media (max-width: ${style.collapse}px) {
      display: none;
    }
  }

  ${StyledMessage} {
    display: flex;
    flex: 1 1 auto;
    border-radius: ${style.borderRadius};
    background-color: ${({ $disabled }) =>
      $disabled ? style.black100 : style.black50};
    border: none;
    flex-flow: row nowrap;
    padding: ${({ $isExpanded }) =>
      $isExpanded ? "0.75rem" : ".5rem 0.75rem"};
    transition: background-color 250ms ease-in-out;

    @media (max-width: ${style.collapse}px) {
      position: fixed;
      bottom: 0;
      left: 0;
      right: 0;
      z-index: 1;
      border: none;
      border-radius: 0;
      max-height: 50vh;
      overflow: hidden;
      overflow-y: auto;
      padding: 1rem;
      background-color: white;
      box-shadow: 0px -3px 3px rgba(0, 35, 44, 0.1),
        0px 2px 0px rgba(0, 35, 44, 0.08);
      align-items: ${({ $isExpanded }) =>
        $isExpanded ? "flex-start" : "center"};
    }

    &:hover {
      ${({ $isExpanded }) =>
        !$isExpanded ? `background-color: ${style.black100};` : ""}

      @media (max-width: ${style.collapse}px) {
        background-color: white;
      }
    }

    & > ${Avatar} {
      display: none;

      @media (max-width: ${style.collapse}px) {
        display: ${({ $isExpanded }) => ($isExpanded ? "none" : "block")};
        flex: 0 0 auto;
        width: 2rem;
        height: 2rem;
        margin: 0;
        margin-right: 0.5rem;
      }
    }
  }

  ${StyledField} {
    flex: 1 1 auto;
    display: flex;
    flex-flow: column nowrap;
    align-items: flex-start nowrap;
    cursor: ${({ $isExpanded, $disabled }) =>
      $disabled || $isExpanded ? "default" : "pointer"};
    font-size: 1rem;

    ${StyledCommentButton} {
      flex: 1 1 auto;
      margin: 0;
      padding: 0;
      font-size: inherit;
      line-height: 1.65;
      color: ${style.black500};
      white-space: nowrap;
      text-overflow: ellipsis;
      overflow: hidden;
      border: none;
      text-align: left;
      background-color: transparent;
      cursor: pointer;
    }

    label {
      font-size: inherit;
    }

    textarea {
      ${({ $isExpanded }) =>
        !$isExpanded &&
        `
      flex: 1 1 auto;
      margin: 0;
      padding: 0;
      font-size: inherit;
      line-height: 1.65;
      `}

      &,
      &:focus,
      &:hover {
        border: none;
        outline: none;
        padding-left: 0;
        padding-right: 0;
        font-size: inherit;
        margin: 0;
        background-color: transparent;
      }
    }

    & > :last-child {
      @media (max-width: ${style.collapse}px) {
        visibility: ${({ $isExpanded }) =>
          $isExpanded ? "hidden" : "visible"};
      }
    }

    & > ${RawFeatherIcon} {
      display: none;
      @media (max-width: ${style.collapse}px) {
        display: inline-block;
        opacity: 0.3;
        transform: rotate(45deg);
      }
    }
  }

  ${StyledAction} {
    flex: 0 0 40px;
    text-align: center;

    button {
      border: none;
      padding: 0;
      margin: 0;
      text-decoration: none;
      background: inherit;
      color: inherit;
      font-size: 0;
      line-height: 0;
      cursor: pointer;
      text-align: center;
      -webkit-appearance: none;
      -moz-appearance: none;
      transform: rotate(45deg);
      transform-origin: center center;

      &:hover,
      &:focus {
        border: none;
        outline: none;
        opacity: 0.6;
      }

      &[disabled],
      &[disabled]:hover,
      &[disabled]:focus {
        opacity: 1;
        cursor: default;
      }
    }
  }
`;

const PLACEHOLDER_MESSAGE = "Écrire une réponse";

export const CommentButton = (props) => {
  const { onClick } = props;
  return onClick ? (
    <StyledCommentButton onClick={onClick}>
      {PLACEHOLDER_MESSAGE}
    </StyledCommentButton>
  ) : null;
};
CommentButton.propTypes = {
  onClick: PropTypes.func,
};

const CommentField = (props) => {
  const {
    user,
    initialValue,
    id,
    onSend,
    isLoading,
    disabled,
    isLocked,
    autoScroll,
    placeholder,
    scrollerRef,
  } = props;

  const hasSubmitted = useRef(false);

  const rootElementRef = useRef();
  const messageRef = useRef();
  const fieldWrapperRef = useRef();
  const textFieldRef = useRef();
  const textFieldCursorPosition = useRef();
  const isDesktop = useIsDesktop();

  const [isFocused, setIsFocused] = useState(false);
  const [value, setValue] = useState(initialValue || "");

  const isExpanded = !!value || isFocused;
  const maySend = !isLoading && value && value.trim().length <= 1000;

  const updateScroll = () => {
    const pid = setInterval(() => {
      const scrollerElement = scrollerRef.current;
      if (!!scrollerElement) {
        scrollerElement.scrollTo(0, scrollerElement.scrollHeight);
        clearInterval(pid);
      }
    }, 50);
  };

  const handleFocus = () => {
    setIsFocused(true);
    updateScroll();
  };

  const blurOnClickOutside = useCallback(
    (event) => {
      if (!fieldWrapperRef.current?.contains(event.target)) {
        setIsFocused(false);
      }
      if (autoScroll) {
        updateScroll(
          rootElementRef.current,
          !isDesktop ? messageRef.current : null
        );
      }
    },
    [isDesktop, autoScroll]
  );

  const blurOnFocusOutside = useCallback(() => {
    if (
      document.activeElement &&
      !fieldWrapperRef.current?.contains(document.activeElement)
    ) {
      setIsFocused(false);
    }
    if (autoScroll) {
      updateScroll(
        rootElementRef.current,
        !isDesktop ? messageRef.current : null
      );
    }
  }, [isDesktop, autoScroll]);

  useEffect(() => {
    if (typeof window !== "undefined") {
      if (isFocused && !value) {
        document.addEventListener("click", blurOnClickOutside);
        document.addEventListener("keyup", blurOnFocusOutside);
      }

      return () => {
        document.removeEventListener("click", blurOnClickOutside);
        document.removeEventListener("keyup", blurOnFocusOutside);
      };
    }
  }, [isFocused, value, blurOnClickOutside, blurOnFocusOutside]);

  const handleInputChange = useCallback((e) => {
    setValue(e.target.value);
  }, []);

  const handleEmojiSelect = useCallback(
    (emoji) => {
      if (!Array.isArray(textFieldCursorPosition.current)) {
        setValue(value + emoji);
        return;
      }
      const [start, end] = textFieldCursorPosition.current;
      const newValue = value.slice(0, start) + emoji + value.slice(end);
      textFieldCursorPosition.current = [
        start + emoji.length,
        start + emoji.length,
      ];
      setValue(newValue);
    },
    [value]
  );

  const handleEmojiOpen = useCallback(() => {
    if (
      typeof textFieldRef.current?.selectionStart === "number" &&
      typeof textFieldRef.current?.selectionEnd === "number"
    ) {
      textFieldCursorPosition.current = [
        textFieldRef.current.selectionStart,
        textFieldRef.current.selectionEnd,
      ];
    }
  }, []);

  const handleSend = useCallback(
    (e) => {
      e.preventDefault();
      blurOnClickOutside(e);
      if (maySend) {
        onSend(value);
        hasSubmitted.current = true;
      }
    },
    [maySend, onSend, value]
  );

  useEffect(() => {
    if (!isLoading && hasSubmitted.current) {
      hasSubmitted.current = false;
      setValue("");
    }
  }, [isLoading]);

  const handleInputKeyDown = useCallback(
    (e) => {
      if (maySend && e.ctrlKey && e.keyCode === 13) {
        onSend(value);
        hasSubmitted.current = true;
      }
    },
    [maySend, value, onSend]
  );

  useEffect(() => {
    updateScroll();
  }, [isFocused, value]);

  if (isLocked) {
    return (
      <StaticToast $color="grey" style={{ marginTop: 0 }}>
        Cette conversation a été close par les gestionnaires du groupe. Vous ne
        pouvez plus y écrire de réponse.
      </StaticToast>
    );
  }

  return (
    <StyledWrapper
      $isExpanded={isExpanded}
      $disabled={disabled || isLoading}
      onSubmit={handleSend}
      ref={rootElementRef}
    >
      <Avatar name={user.displayName} image={user.image} />
      <StyledMessage ref={messageRef}>
        <Avatar name={user.displayName} image={user.image} />
        <StyledField
          ref={fieldWrapperRef}
          onClick={!disabled ? handleFocus : undefined}
          onTouchStart={!disabled ? handleFocus : undefined}
        >
          <Suspense fallback={null}>
            <TextField
              ref={textFieldRef}
              textArea
              id={id}
              value={value}
              onChange={handleInputChange}
              onKeyDown={handleInputKeyDown}
              autoFocus={isFocused}
              label={isFocused && user.displayName}
              disabled={disabled || isLoading}
              placeholder={placeholder || PLACEHOLDER_MESSAGE}
              maxLength={1000}
              hasCounter={false}
            />
            {isFocused && (
              <EmojiPicker
                onOpen={handleEmojiOpen}
                onSelect={handleEmojiSelect}
                small
              />
            )}
          </Suspense>
        </StyledField>
        {isFocused ? (
          <StyledAction>
            {isLoading ? (
              <AnimatedMoreHorizontal />
            ) : (
              <button
                type="submit"
                disabled={!maySend}
                aria-label="Envoyer le commentaire"
              >
                <RawFeatherIcon
                  name="send"
                  color={maySend ? style.primary500 : style.black500}
                />
              </button>
            )}
          </StyledAction>
        ) : null}
      </StyledMessage>
    </StyledWrapper>
  );
};
CommentField.propTypes = {
  user: PropTypes.shape({
    displayName: PropTypes.string.isRequired,
    image: PropTypes.string,
  }).isRequired,
  initialValue: PropTypes.string,
  id: PropTypes.string,
  onSend: PropTypes.func.isRequired,
  isLoading: PropTypes.bool,
  disabled: PropTypes.bool,
  autoScroll: PropTypes.bool,
};
export default CommentField;
<|endoftext|>


<commit_before>/* jslint node: true */
/* global chrome: true */

'use strict';

var _ = require('lodash');

var tracks = [];

// executed at the extension installation
chrome.runtime.onInstalled.addListener(function() {
  tracks = [];
  console.log('on installed');
});

// new player detected
chrome.runtime.onMessage.addListener(function(request, sender) {
  console.log('chrome events', arguments);
  if (request.cmd === 'player_detected') {

    console.log('player detected', request.player);

    // we create a new track in function of the player datas and tab
    var track = _.extend({}, request.player, {
      currentTime: 0,
      loop: true,
      pause: true,
      play: false,
      playbackRate: 0,
      tab: sender.tab.id,
      volume: 1,
    });

    // send created track to the current tab
    notifyTab(track);

    // send the tracks to the options view
    tracks.push(track);
    tracks = _.uniq(tracks, 'id');

    notifyOptionsView(tracks);
    return;
  }

});

function notifyTab(track) {
  chrome.tabs.sendMessage(track.tab, {
    cmd: 'update_track',
    track: track
  });
}

function notifyOptionsView(tracks) {
  chrome.runtime.sendMessage({
    cmd: 'update_option_view',
    tracks: tracks
  });
}
<commit_msg>- remove coma<commit_after>/* jslint node: true */
/* global chrome: true */

'use strict';

var _ = require('lodash');

var tracks = [];

// executed at the extension installation
chrome.runtime.onInstalled.addListener(function() {
  tracks = [];
  console.log('on installed');
});

// new player detected
chrome.runtime.onMessage.addListener(function(request, sender) {
  console.log('chrome events', arguments);
  if (request.cmd === 'player_detected') {

    console.log('player detected', request.player);

    // we create a new track in function of the player datas and tab
    var track = _.extend({}, request.player, {
      currentTime: 0,
      loop: true,
      pause: true,
      play: false,
      playbackRate: 0,
      tab: sender.tab.id,
      volume: 1
    });

    // send created track to the current tab
    notifyTab(track);

    // send the tracks to the options view
    tracks.push(track);
    tracks = _.uniq(tracks, 'id');

    notifyOptionsView(tracks);
    return;
  }

});

function notifyTab(track) {
  chrome.tabs.sendMessage(track.tab, {
    cmd: 'update_track',
    track: track
  });
}

function notifyOptionsView(tracks) {
  chrome.runtime.sendMessage({
    cmd: 'update_option_view',
    tracks: tracks
  });
}
<|endoftext|>


<commit_before>import _ from 'lodash'
import d3 from 'd3'

import formatUtil from 'util/format'

function _sortValue (s, sortCol) {
  // jshint validthis: true
  var options = this._options

  var val = (sortCol === null)
    ? options.seriesName(s)
    : options.value(_.find(options.values(s), d => options.column(d) === sortCol))

  return val
}

var DEFAULTS = {
  cellSize: 16,
  column: _.property('indicator.short_name'),
  sourceColumn: _.property('short_name'),
  fontSize: 12,
  format: formatUtil.general,
  headerText: _.property('short_name'),
  headers: [],
  onClick: null,
  onColumnHeadOver: null,
  onColumnHeadOut: null,
  onMouseMove: null,
  onMouseOut: null,
  onRowClick: null,
  seriesName: _.property('name'),
  sortValue: _sortValue,
  values: _.property('values'),
  value: _.property('value')
}

function TableChart () {}

_.extend(TableChart.prototype, {
  defaults: DEFAULTS,
  sortCol: null,

  initialize: function (el, data, options) {
    options = this._options = _.defaults({}, options, DEFAULTS)

    var svg = this._svg = d3.select(el)
        .append('svg')
        .attr('class', 'heatmap sortable')

    var g = svg.append('g').attr('class', 'margin')

    g.append('g').attr('class', 'z axis')
    g.append('g').attr('class', 'y axis')
    g.append('g').attr('class', 'x axis')
    g.append('g').attr('class', 'data')
    g.append('g').attr('class', 'source-footer')
    g.append('g').attr('class', 'legend')

    this.update(data)
  },

  update: function (data, options) {
    console.log('update function')
    options = _.extend(this._options, options)
    var margin = options.margin
    // console.log('DATA', data)

    var self = this
    var parentLocationMap = options.parentLocationMap

    var w = 3 * Math.max(options.headers.length * options.cellSize, 0)
    var h = Math.max(data.length * options.cellSize, 0)
    var z = 160 //  extra margin space needed to add the "z" (parent) axis"

    // hacky way to sclae the view box.. this shoudl be done by taking into
    // account the user's screen size... needs some time to get 100% right.. //
    var viewBoxHeightScale = 1 + (options.headers.length - 8) / 10
    if (viewBoxHeightScale < 1) {
      viewBoxHeightScale = 1
    }
    var viewBox = '0 0 ' + (w + margin.left + margin.right) + ' ' + ((h * viewBoxHeightScale) + margin.top + margin.bottom)

    var svg = this._svg
      .attr({
        'viewBox': viewBox,
        'width': (w + margin.left + margin.right),
        'height': (h + margin.top + margin.bottom)
      })
      .datum(data)

    var xScale = d3.scale.ordinal()
        .domain(_.map(options.headers, options.headerText))
        .rangeBands([0, w], 0.1)

    var x = _.flow(options.column, xScale)
    var sourceFlow = _.flow(options.sourceColumn, xScale)

    var domain = options.defaultSortOrder
    if (this.sortCol) {
      let sortValue = _.partial(options.sortValue.bind(this), _, this.sortCol)
      domain = _(data).sortBy(sortValue, this).map(options.seriesName).value()
    }

    var yScale = d3.scale.ordinal()
      .domain(domain)
      .rangeBands([0, h], 0.1)

    var y = _.flow(options.seriesName, yScale)

    var transform = function (d, i) {
      var yVal = y(d) + 10
      return 'translate(' + z + ' , ' + yVal + ')'
    }

    // THIS SETS THE COLOR... MOVE FROM HERE ONCE THE USER CAN SET A PALLETTE
    var targets = _(options.headers)
      .indexBy('id')
      .mapValues(ind => {
        var extents = [ ind.low_bound, ind.high_bound ]
        var names = ['bad', 'ok', 'good']

        if (ind.low_bound > ind.high_bound) {
          names = ['good', 'ok', 'bad']
        }

        return d3.scale.threshold()
          .domain(extents)
          .range(names)
      })
      .value()

    var scale = d3.scale.ordinal()
      .domain(['bad', 'ok', 'good'])
      .range(['#DB5344', '#79909F', '#2FB0D3'])

    var fill = d => scale(_.get(targets, d.indicator.id, _.noop)(d.value))

    svg.select('.margin')
        .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')')

    var g = svg.select('.data')

    g.on('mouseout', function () { self._onRowOut.apply(self) })

    var row = g.selectAll('.row').data(data)

    row.enter().append('g')
        .attr({
          'class': 'row',
          'transform': transform
        })

    row.exit()
      .transition().duration(300)
      .style('opacity', 0)
      .remove()

    row.on('mouseover', function (d, i) {
      self._onRowOver([d, i])
    })
    .transition()
    .duration(750)
    .attr('transform', transform)

    // Add cells to each row
    var cell = row.selectAll('.cell').data(options.values)

    cell.transition()
      .duration(500)
      .style('fill', fill)
      .attr({
        'height': yScale.rangeBand(),
        'width': xScale.rangeBand(),
        'x': x
      })

    var cg = cell.enter().append('g')

    cg.append('rect')
        .attr({
          'class': 'cell',
          'height': yScale.rangeBand(),
          'x': x,
          'width': xScale.rangeBand()
        })
        .style({
          'opacity': 0,
          'fill': fill
        })
        .transition()
        .duration(500)
        .style('opacity', 1)

    cg.append('text')
          .attr({
            'height': yScale.rangeBand(),
            'x': function (d) { return x(d) + xScale.rangeBand() / 2 },
            'y': options.cellSize / 2,
            'width': xScale.rangeBand(),
            'dominant-baseline': 'central',
            'text-anchor': 'middle',
            'font-weight': 'bold'
          })
          .style({'font-size': options.cellFontSize})
          .text(function (d) { return d.displayValue })
          .transition()
          .duration(500)

    cell.exit()
      .transition()
      .duration(300)
      .style('opacity', 0)
      .remove()

    cell
      .attr('id', d => [d.location.name, d.indicator.short_name].join('-'))
        .style('cursor', _.isFunction(options.onClick) ? 'pointer' : 'initial')
        .on('mousemove', options.onMouseMove)
        .on('mouseout', options.onMouseOut)
        .on('click', options.onClick)

    // Begin X Axis //

    svg.select('.x.axis')
      .transition().duration(500)
      .attr({'transform': 'translate(' + z + ',0)'})
      .call(d3.svg.axis()
        .scale(xScale)
        .orient('top')
        .outerTickSize(0))

    svg.selectAll('.x.axis text')
      .on('click', function (d, i) { self._setSort(d, i) })
    //   .style({
    //     'text-anchor': 'start',
    //     'font-size': options.fontSize,
    //     'fontWeight': function (d) {
    //       return (d === sortCol)
    //         ? 'bold'
    //         : 'normal'
    //     }
    //   })
    //   .attr('transform', 'translate(' + (xScale.rangeBand() / 30) + ', 0) rotate(-35)')
    //   .on('mouseover', function (d, i) {
    //     options.onColumnHeadOver(d, i, this)
    //   })
    //   .on('mouseout', function (d, i) {
    //     options.onColumnHeadOut(d, i, this)
    //   })

    svg.selectAll('.x.axis text').call(this._wrap, xScale.rangeBand())

    // the z axis shows the parent location//
    svg.select('.z.axis')
      .transition().duration(500)
      .attr({'transform': 'translate(0,10)'})
      .call(d3.svg.axis()
        .scale(yScale)
        .tickFormat(function (d) {
          return parentLocationMap[d].parent_location__name
        })
        .orient('left')
        .outerTickSize(0))

    svg.selectAll('.z.axis text')
      .style('font-size', options.fontSize)
      .on('click', function (d, i) {
        options.onRowClick(d, i, this)
      })

    svg.select('.y.axis')
      .transition().duration(500)
      .attr({'transform': 'translate(' + z + ',10)'})
      .call(d3.svg.axis()
        .scale(yScale)
        .orient('left')
        .outerTickSize(0))

    svg.selectAll('.y.axis text')
      .style('font-size', options.fontSize)
      .on('click', function (d, i) {
        options.onRowClick(d, i, this)
      })

    // BEGIN SOURCE FOOTER //

    var singleRowIndicators = options.headers // chartData[0].values
    var sourceFooter = svg.select('.source-footer').attr({'transform': 'translate(0,' + 10 + ')'})
    var sourceCell = sourceFooter.selectAll('.source-cell').data(singleRowIndicators)
    var sourceG = sourceCell.enter().append('g')

    sourceG.append('rect')
        .attr({
          'class': 'cell',
          'height': yScale.rangeBand() * 1.5,
          'transform': 'translate(' + z + ',' + h + ')',
          'x': sourceFlow,
          'width': xScale.rangeBand()
        })
        .style({
          'opacity': 0,
          'fill': '#CCFFFF'
        })
        .transition()
        .duration(500)
      .style('opacity', 1)

    sourceG.append('text')
            .attr({
              'height': yScale.rangeBand(),
              'transform': 'translate(' + z + ',' + h + ')',
              'x': function (d) { return sourceFlow(d) + 45 },
              'y': options.cellSize / 2,
              'width': xScale.rangeBand(),
              'dominant-baseline': 'central',
              'text-anchor': 'middle',
              'font-weight': 'bold'
            })
            .text(function (d) { return d.source_name })
              .transition()
              .duration(500)

    // END SOURCE FOOTER //

    if (options.legend) {
      svg.select('.legend')
        .call(options.legend)
        .attr('transform', function () {
          var bbox = this.getBoundingClientRect()
          var dx = w + margin.right - bbox.width
          var dy = 0

          return 'translate(' + dx + ', ' + dy + ')'
        })
    } else {
      svg.select('.legend').selectAll('*').remove()
    }
  },

  _wrap: function (text, width) {
    text.each(function () {
      var text = d3.select(this)
      var words = text.text().split(/\s+/)
      var line = []
      var lineNumber = 0
      var lineHeight = 1.1 // ems
      var y = text.attr('y') - 10
      var dy = parseFloat(text.attr('dy'))
      var tspan = text.text(null).append('tspan').attr('x', 0).attr('y', y).attr('dy', dy + 'em')
      var i = 0
      for (i = 0; i < words.length; i += 1) {
        var word = words[i]
        line.push(word)
        tspan.text(line.join(' '))
        if (tspan.node().getComputedTextLength() > width) {
          line.pop()
          tspan.text(line.join(' '))
          line = [word]
          tspan = text.append('tspan').attr('x', 0).attr('y', y).attr('dy', ++lineNumber * lineHeight + dy + 'em').text(word)
        }
      }
    })
  },

  _onRowOver: function (d) {
    var seriesName = this._options.seriesName
    this._svg.selectAll('.row')
      .transition().duration(300)
      .style('opacity', function (e) {
        return (seriesName(e) === d[0].name) ? 1 : 0.4
      })
  },

  _onRowOut: function () {
    this._svg.selectAll('.row')
      .transition().duration(300)
      .style('opacity', 1)
  },

  _setSort: function (d) {
    this.sortCol = (d === this.sortCol) ? null : d
    console.log('updateSort')
    this.update(this._svg.selectAll('.row').data())
  }
})

export default TableChart
<commit_msg>ability to sort ascending and descending<commit_after>import _ from 'lodash'
import d3 from 'd3'

import formatUtil from 'util/format'

function _sortValue (s, sortCol) {
  // jshint validthis: true
  var options = this._options

  var val = (sortCol === null)
    ? options.seriesName(s)
    : options.value(_.find(options.values(s), d => options.column(d) === sortCol))

  return val
}

var DEFAULTS = {
  cellSize: 16,
  column: _.property('indicator.short_name'),
  sourceColumn: _.property('short_name'),
  fontSize: 12,
  format: formatUtil.general,
  headerText: _.property('short_name'),
  headers: [],
  onClick: null,
  onColumnHeadOver: null,
  onColumnHeadOut: null,
  onMouseMove: null,
  onMouseOut: null,
  onRowClick: null,
  seriesName: _.property('name'),
  sortValue: _sortValue,
  values: _.property('values'),
  value: _.property('value'),
  sortDirection: 1
}

function TableChart () {}

_.extend(TableChart.prototype, {
  defaults: DEFAULTS,
  sortCol: null,

  initialize: function (el, data, options) {
    options = this._options = _.defaults({}, options, DEFAULTS)

    var svg = this._svg = d3.select(el)
        .append('svg')
        .attr('class', 'heatmap sortable')

    var g = svg.append('g').attr('class', 'margin')

    g.append('g').attr('class', 'z axis')
    g.append('g').attr('class', 'y axis')
    g.append('g').attr('class', 'x axis')
    g.append('g').attr('class', 'data')
    g.append('g').attr('class', 'source-footer')
    g.append('g').attr('class', 'legend')

    this.update(data)
  },

  update: function (data, options) {
    options = _.extend(this._options, options)
    var margin = options.margin

    var self = this
    var parentLocationMap = options.parentLocationMap

    var w = 3 * Math.max(options.headers.length * options.cellSize, 0)
    var h = Math.max(data.length * options.cellSize, 0)
    var z = 160 //  extra margin space needed to add the "z" (parent) axis"

    // hacky way to sclae the view box.. this shoudl be done by taking into
    // account the user's screen size... needs some time to get 100% right.. //
    var viewBoxHeightScale = 1 + (options.headers.length - 8) / 10
    if (viewBoxHeightScale < 1) {
      viewBoxHeightScale = 1
    }
    var viewBox = '0 0 ' + (w + margin.left + margin.right) + ' ' + ((h * viewBoxHeightScale) + margin.top + margin.bottom)

    var svg = this._svg
      .attr({
        'viewBox': viewBox,
        'width': (w + margin.left + margin.right),
        'height': (h + margin.top + margin.bottom)
      })
      .datum(data)

    var xScale = d3.scale.ordinal()
        .domain(_.map(options.headers, options.headerText))
        .rangeBands([0, w], 0.1)

    var x = _.flow(options.column, xScale)
    var sourceFlow = _.flow(options.sourceColumn, xScale)

    // if there is a sortCol set, order the data that way. //
    if (this.sortCol) {
      let sortValue = _.partial(options.sortValue.bind(this), _, this.sortCol)
      var domain = _(data).sortBy(sortValue, this).map(options.seriesName).value()
    } else {
      // if not, show default.  This also applies to the third click of a header
      domain = options.defaultSortOrder
      this.sortDirection = 1
    }

    if (this.sortDirection === -1) {
      domain = domain.reverse()
    }

    var yScale = d3.scale.ordinal()
      .domain(domain)
      .rangeBands([0, h], 0.1)

    var y = _.flow(options.seriesName, yScale)

    var transform = function (d, i) {
      var yVal = y(d) + 10
      return 'translate(' + z + ' , ' + yVal + ')'
    }

    // THIS SETS THE COLOR... MOVE FROM HERE ONCE THE USER CAN SET A PALLETTE
    var targets = _(options.headers)
      .indexBy('id')
      .mapValues(ind => {
        var extents = [ ind.low_bound, ind.high_bound ]
        var names = ['bad', 'ok', 'good']

        if (ind.low_bound > ind.high_bound) {
          names = ['good', 'ok', 'bad']
        }

        return d3.scale.threshold()
          .domain(extents)
          .range(names)
      })
      .value()

    var scale = d3.scale.ordinal()
      .domain(['bad', 'ok', 'good'])
      .range(['#DB5344', '#79909F', '#2FB0D3'])

    var fill = d => scale(_.get(targets, d.indicator.id, _.noop)(d.value))

    svg.select('.margin')
        .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')')

    var g = svg.select('.data')

    g.on('mouseout', function () { self._onRowOut.apply(self) })

    var row = g.selectAll('.row').data(data)

    row.enter().append('g')
        .attr({
          'class': 'row',
          'transform': transform
        })

    row.exit()
      .transition().duration(300)
      .style('opacity', 0)
      .remove()

    row.on('mouseover', function (d, i) {
      self._onRowOver([d, i])
    })
    .transition()
    .duration(750)
    .attr('transform', transform)

    // Add cells to each row
    var cell = row.selectAll('.cell').data(options.values)

    cell.transition()
      .duration(500)
      .style('fill', fill)
      .attr({
        'height': yScale.rangeBand(),
        'width': xScale.rangeBand(),
        'x': x
      })

    var cg = cell.enter().append('g')

    cg.append('rect')
        .attr({
          'class': 'cell',
          'height': yScale.rangeBand(),
          'x': x,
          'width': xScale.rangeBand()
        })
        .style({
          'opacity': 0,
          'fill': fill
        })
        .transition()
        .duration(500)
        .style('opacity', 1)

    cg.append('text')
          .attr({
            'height': yScale.rangeBand(),
            'x': function (d) { return x(d) + xScale.rangeBand() / 2 },
            'y': options.cellSize / 2,
            'width': xScale.rangeBand(),
            'dominant-baseline': 'central',
            'text-anchor': 'middle',
            'font-weight': 'bold'
          })
          .style({'font-size': options.cellFontSize})
          .text(function (d) { return d.displayValue })
          .transition()
          .duration(500)

    cell.exit()
      .transition()
      .duration(300)
      .style('opacity', 0)
      .remove()

    cell
      .attr('id', d => [d.location.name, d.indicator.short_name].join('-'))
        .style('cursor', _.isFunction(options.onClick) ? 'pointer' : 'initial')
        .on('mousemove', options.onMouseMove)
        .on('mouseout', options.onMouseOut)
        .on('click', options.onClick)

    // Begin X Axis //

    svg.select('.x.axis')
      .transition().duration(500)
      .attr({'transform': 'translate(' + z + ',0)'})
      .call(d3.svg.axis()
        .scale(xScale)
        .orient('top')
        .outerTickSize(0))

    svg.selectAll('.x.axis text')
      .on('click', function (d, i) { self._setSort(d, i) })

    svg.selectAll('.x.axis text').call(this._wrap, xScale.rangeBand())

    // the z axis shows the parent location//
    svg.select('.z.axis')
      .transition().duration(500)
      .attr({'transform': 'translate(0,10)'})
      .call(d3.svg.axis()
        .scale(yScale)
        .tickFormat(function (d) {
          return parentLocationMap[d].parent_location__name
        })
        .orient('left')
        .outerTickSize(0))

    svg.selectAll('.z.axis text')
      .style('font-size', options.fontSize)
      .on('click', function (d, i) {
        options.onRowClick(d, i, this)
      })

    svg.select('.y.axis')
      .transition().duration(500)
      .attr({'transform': 'translate(' + z + ',10)'})
      .call(d3.svg.axis()
        .scale(yScale)
        .orient('left')
        .outerTickSize(0))

    svg.selectAll('.y.axis text')
      .style('font-size', options.fontSize)
      .on('click', function (d, i) {
        options.onRowClick(d, i, this)
      })

    // BEGIN SOURCE FOOTER //

    var singleRowIndicators = options.headers // chartData[0].values
    var sourceFooter = svg.select('.source-footer').attr({'transform': 'translate(0,' + 10 + ')'})
    var sourceCell = sourceFooter.selectAll('.source-cell').data(singleRowIndicators)
    var sourceG = sourceCell.enter().append('g')

    sourceG.append('rect')
        .attr({
          'class': 'cell',
          'height': yScale.rangeBand() * 1.5,
          'transform': 'translate(' + z + ',' + h + ')',
          'x': sourceFlow,
          'width': xScale.rangeBand()
        })
        .style({
          'opacity': 0,
          'fill': '#CCFFFF'
        })
        .transition()
        .duration(500)
      .style('opacity', 1)

    sourceG.append('text')
            .attr({
              'height': yScale.rangeBand(),
              'transform': 'translate(' + z + ',' + h + ')',
              'x': function (d) { return sourceFlow(d) + 45 },
              'y': options.cellSize / 2,
              'width': xScale.rangeBand(),
              'dominant-baseline': 'central',
              'text-anchor': 'middle',
              'font-weight': 'bold'
            })
            .text(function (d) { return d.source_name })
              .transition()
              .duration(500)

    // END SOURCE FOOTER //

    if (options.legend) {
      svg.select('.legend')
        .call(options.legend)
        .attr('transform', function () {
          var bbox = this.getBoundingClientRect()
          var dx = w + margin.right - bbox.width
          var dy = 0

          return 'translate(' + dx + ', ' + dy + ')'
        })
    } else {
      svg.select('.legend').selectAll('*').remove()
    }
  },

  _wrap: function (text, width) {
    text.each(function () {
      var text = d3.select(this)
      var words = text.text().split(/\s+/)
      var line = []
      var lineNumber = 0
      var lineHeight = 1.1 // ems
      var y = text.attr('y') - 10
      var dy = parseFloat(text.attr('dy'))
      var tspan = text.text(null).append('tspan').attr('x', 0).attr('y', y).attr('dy', dy + 'em')
      var i = 0
      for (i = 0; i < words.length; i += 1) {
        var word = words[i]
        line.push(word)
        tspan.text(line.join(' '))
        if (tspan.node().getComputedTextLength() > width) {
          line.pop()
          tspan.text(line.join(' '))
          line = [word]
          tspan = text.append('tspan').attr('x', 0).attr('y', y).attr('dy', ++lineNumber * lineHeight + dy + 'em').text(word)
        }
      }
    })
  },

  _onRowOver: function (d) {
    var seriesName = this._options.seriesName
    this._svg.selectAll('.row')
      .transition().duration(300)
      .style('opacity', function (e) {
        return (seriesName(e) === d[0].name) ? 1 : 0.4
      })
  },

  _onRowOut: function () {
    this._svg.selectAll('.row')
      .transition().duration(300)
      .style('opacity', 1)
  },

  _setSort: function (d) {
    // Fist click, order ascending, Second order descending, third order default
    if (d === this.sortCol && this.sortDirection === -1) {
      this.sortCol = null
    } else if (d === this.sortCol && this.sortDirection === 1) {
      this.sortCol = d
      this.sortDirection = -1
    } else {
      this.sortCol = d
      this.sortDirection = 1
    }

    this.update(this._svg.selectAll('.row').data())
  }
})

export default TableChart
<|endoftext|>


<commit_before>jQuery(document).ready(function(){
	var intro = $('.cd-intro-block'),
		projectsContainer = $('.cd-projects-wrapper'),
		projectsSlider = projectsContainer.children('.cd-slider'),
		singleProjectContent = $('.cd-project-content'),
		sliderNav = $('.cd-slider-navigation');

	var resizing = false;

    var BV = new $.BigVideo({container: $('#video-landing')});
	BV.init();
	if (Modernizr.touch) {
	    BV.show('../static/img/back.jpg');
	} else {
	    BV.show('../static/video/background.mp4',{ambient:true});
	}

	//if on desktop - set a width for the projectsSlider element
	setSliderContainer();
	$(window).on('resize', function(){
		//on resize - update projectsSlider width and translate value
		if( !resizing ) {
			(!window.requestAnimationFrame) ? setSliderContainer() : window.requestAnimationFrame(setSliderContainer);
			resizing = true;
		}
	});

	//show the projects slider if user clicks the show-projects button
	intro.on('click', 'a[data-action="show-projects"]', function(event) {
		event.preventDefault
        var BV = new $.BigVideo({container: $('#video-landing')});
        BV.pause();
		intro.addClass('projects-visible');
		projectsContainer.addClass('projects-visible');
		//animate single project - entrance animation
		setTimeout(function(){
			showProjectPreview(projectsSlider.children('li').eq(0));
		}, 200);
	});

	intro.on('click', function(event) {
		//projects slider is visible - hide slider and show the intro panel
		if( intro.hasClass('projects-visible') && !$(event.target).is('a[data-action="show-projects"]') ) {
			intro.removeClass('projects-visible');
			projectsContainer.removeClass('projects-visible');
		}
	});

	//select a single project - open project-content panel
	projectsContainer.on('click', '.cd-slider a', function(event) {
		event.preventDefault();
        var video = $(this).attr('href');
		if( $(this).parent('li').next('li').is('.current') ) {
			prevSides(projectsSlider);
		} else if ( $(this).parent('li').prev('li').prev('li').prev('li').is('.current')) {
			nextSides(projectsSlider);
		} else {
			$(video).addClass('is-visible');
		}
	});

	//close single project content
	singleProjectContent.on('click', '.close', function(event){
		event.preventDefault();
		singleProjectContent.removeClass('is-visible');
        var video_id = $(this).attr('href');
            videojs(video_id).pause();

	});

	//go to next/pre slide - clicking on the next/prev arrow
	sliderNav.on('click', '.next', function(){
		nextSides(projectsSlider);
	});
	sliderNav.on('click', '.prev', function(){
		prevSides(projectsSlider);
	});

	//go to next/pre slide - keyboard navigation
	$(document).keyup(function(event){
		var mq = checkMQ();
		if(event.which=='37' &&  intro.hasClass('projects-visible') && !(sliderNav.find('.prev').hasClass('inactive')) && (mq == 'desktop') ) {
			prevSides(projectsSlider);
		} else if( event.which=='39' &&  intro.hasClass('projects-visible') && !(sliderNav.find('.next').hasClass('inactive')) && (mq == 'desktop') ) {
			nextSides(projectsSlider);
		} else if(event.which=='27' && singleProjectContent.hasClass('is-visible')) {
			singleProjectContent.removeClass('is-visible');
		}
	});

	projectsSlider.on('swipeleft', function(){
		var mq = checkMQ();
		if( !(sliderNav.find('.next').hasClass('inactive')) && (mq == 'desktop') ) nextSides(projectsSlider);
	});

	projectsSlider.on('swiperight', function(){
		var mq = checkMQ();
		if ( !(sliderNav.find('.prev').hasClass('inactive')) && (mq == 'desktop') ) prevSides(projectsSlider);
	});

	function showProjectPreview(project) {
		if(project.length > 0 ) {
			setTimeout(function(){
				project.addClass('slides-in');
				showProjectPreview(project.next());
			}, 50);
		}
	}

	function checkMQ() {
		//check if mobile or desktop device
		return window.getComputedStyle(document.querySelector('.cd-projects-wrapper'), '::before').getPropertyValue('content').replace(/'/g, "").replace(/"/g, "");
	}

	function setSliderContainer() {
		var mq = checkMQ();
		if(mq == 'desktop') {
			var	slides = projectsSlider.children('li'),
				slideWidth = slides.eq(0).width(),
				marginLeft = Number(projectsSlider.children('li').eq(1).css('margin-left').replace('px', '')),
				sliderWidth = ( slideWidth + marginLeft )*( slides.length + 1 ) + 'px',
				slideCurrentIndex = projectsSlider.children('li.current').index();
			projectsSlider.css('width', sliderWidth);
			( slideCurrentIndex != 0 ) && setTranslateValue(projectsSlider, (  slideCurrentIndex * (slideWidth + marginLeft) + 'px'));
		} else {
			projectsSlider.css('width', '');
			setTranslateValue(projectsSlider, 0);
		}
		resizing = false;
	}

	function nextSides(slider) {
		var actual = slider.children('.current'),
			index = actual.index(),
			following = actual.nextAll('li').length,
			width = actual.width(),
			marginLeft = Number(slider.children('li').eq(1).css('margin-left').replace('px', ''));

		index = (following > 4 ) ? index + 3 : index + following - 2;
		//calculate the translate value of the slider container
		translate = index * (width + marginLeft) + 'px';

		slider.addClass('next');
		setTranslateValue(slider, translate);
		slider.one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function(){
			updateSlider('next', actual, slider, following);
		});

		if( $('.no-csstransitions').length > 0 ) updateSlider('next', actual, slider, following);
	}

	function prevSides(slider) {
		var actual = slider.children('.previous'),
			index = actual.index(),
			width = actual.width(),
			marginLeft = Number(slider.children('li').eq(1).css('margin-left').replace('px', ''));
		console.log(marginLeft);

		translate = index * (width + marginLeft) + 'px';

		slider.addClass('prev');
		setTranslateValue(slider, translate);
		slider.one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function(){
			updateSlider('prev', actual, slider);
		});

		if( $('.no-csstransitions').length > 0 ) updateSlider('prev', actual, slider);
	}

	function updateSlider(direction, actual, slider, numerFollowing) {
		if( direction == 'next' ) {
			slider.removeClass('next').find('.previous').removeClass('previous');
			actual.removeClass('current');
			if( numerFollowing > 4 ) {
				actual.addClass('previous').next('li').next('li').next('li').addClass('current');
			} else if ( numerFollowing == 4 ) {
				actual.next('li').next('li').addClass('current');
				actual.prev('li').addClass('previous');
			} else if( numerFollowing == 3 ) {
				actual.next('li').addClass('current');
				actual.prev('li').prev('li').addClass('previous');
			}
		} else {
			slider.removeClass('prev').find('.current').removeClass('current');
			actual.removeClass('previous').addClass('current');
			if(actual.prevAll('li').length > 2 ) {
				actual.prev('li').prev('li').prev('li').addClass('previous');
			} else {
				( !slider.children('li').eq(0).hasClass('current') ) && slider.children('li').eq(0).addClass('previous');
			}
		}

		updateNavigation();
	}

	function updateNavigation() {
		//update visibility of next/prev buttons according to the visible slides
		var current = projectsContainer.find('li.current');
		(current.is(':first-child')) ? sliderNav.find('.prev').addClass('inactive') : sliderNav.find('.prev').removeClass('inactive');
		(current.nextAll('li').length < 3 ) ? sliderNav.find('.next').addClass('inactive') : sliderNav.find('.next').removeClass('inactive');
	}

	function setTranslateValue(item, translate) {
		item.css({
		    '-moz-transform': 'translateX(-' + translate + ')',
		    '-webkit-transform': 'translateX(-' + translate + ')',
			'-ms-transform': 'translateX(-' + translate + ')',
			'-o-transform': 'translateX(-' + translate + ')',
			'transform': 'translateX(-' + translate + ')',
		});
	}
    //open popup
	$('.cd-popup-trigger').on('click', function(event){
		event.preventDefault();
		$('.cd-popup').addClass('is-visible');
	});

	//close popup
	$('.cd-popup').on('click', function(event){
		if( $(event.target).is('.cd-popup-close') || $(event.target).is('.cd-popup') ) {
			event.preventDefault();
			$(this).removeClass('is-visible');
		}
	});
	//close popup when clicking the esc keyboard button
	$(document).keyup(function(event){
    	if(event.which=='27'){
    		$('.cd-popup').removeClass('is-visible');
	    }
    });
});<commit_msg>Video<commit_after>jQuery(document).ready(function(){
	var intro = $('.cd-intro-block'),
		projectsContainer = $('.cd-projects-wrapper'),
		projectsSlider = projectsContainer.children('.cd-slider'),
		singleProjectContent = $('.cd-project-content'),
		sliderNav = $('.cd-slider-navigation');

	var resizing = false;

    var BV = new $.BigVideo({container: $('#video-landing')});
	BV.init();
	if (Modernizr.touch) {
	    BV.show('../static/img/back.jpg');
	} else {
	    BV.show('../static/video/background.mp4',{ambient:true});
	}

	//if on desktop - set a width for the projectsSlider element
	setSliderContainer();
	$(window).on('resize', function(){
		//on resize - update projectsSlider width and translate value
		if( !resizing ) {
			(!window.requestAnimationFrame) ? setSliderContainer() : window.requestAnimationFrame(setSliderContainer);
			resizing = true;
		}
	});

	//show the projects slider if user clicks the show-projects button
	intro.on('click', 'a[data-action="show-projects"]', function(event) {
		event.preventDefault
        BV.getPlayer().pause();
		intro.addClass('projects-visible');
		projectsContainer.addClass('projects-visible');
		//animate single project - entrance animation
		setTimeout(function(){
			showProjectPreview(projectsSlider.children('li').eq(0));
		}, 200);
	});

	intro.on('click', function(event) {
		//projects slider is visible - hide slider and show the intro panel
		if( intro.hasClass('projects-visible') && !$(event.target).is('a[data-action="show-projects"]') ) {
			intro.removeClass('projects-visible');
            BV.getPlayer().play();
			projectsContainer.removeClass('projects-visible');
		}
	});

	//select a single project - open project-content panel
	projectsContainer.on('click', '.cd-slider a', function(event) {
		event.preventDefault();
        var video = $(this).attr('href');
		if( $(this).parent('li').next('li').is('.current') ) {
			prevSides(projectsSlider);
		} else if ( $(this).parent('li').prev('li').prev('li').prev('li').is('.current')) {
			nextSides(projectsSlider);
		} else {
			$(video).addClass('is-visible');
		}
	});

	//close single project content
	singleProjectContent.on('click', '.close', function(event){
		event.preventDefault();
		singleProjectContent.removeClass('is-visible');
        var video_id = $(this).attr('href');
            videojs(video_id).pause();

	});

	//go to next/pre slide - clicking on the next/prev arrow
	sliderNav.on('click', '.next', function(){
		nextSides(projectsSlider);
	});
	sliderNav.on('click', '.prev', function(){
		prevSides(projectsSlider);
	});

	//go to next/pre slide - keyboard navigation
	$(document).keyup(function(event){
		var mq = checkMQ();
		if(event.which=='37' &&  intro.hasClass('projects-visible') && !(sliderNav.find('.prev').hasClass('inactive')) && (mq == 'desktop') ) {
			prevSides(projectsSlider);
		} else if( event.which=='39' &&  intro.hasClass('projects-visible') && !(sliderNav.find('.next').hasClass('inactive')) && (mq == 'desktop') ) {
			nextSides(projectsSlider);
		} else if(event.which=='27' && singleProjectContent.hasClass('is-visible')) {
			singleProjectContent.removeClass('is-visible');
		}
	});

	projectsSlider.on('swipeleft', function(){
		var mq = checkMQ();
		if( !(sliderNav.find('.next').hasClass('inactive')) && (mq == 'desktop') ) nextSides(projectsSlider);
	});

	projectsSlider.on('swiperight', function(){
		var mq = checkMQ();
		if ( !(sliderNav.find('.prev').hasClass('inactive')) && (mq == 'desktop') ) prevSides(projectsSlider);
	});

	function showProjectPreview(project) {
		if(project.length > 0 ) {
			setTimeout(function(){
				project.addClass('slides-in');
				showProjectPreview(project.next());
			}, 50);
		}
	}

	function checkMQ() {
		//check if mobile or desktop device
		return window.getComputedStyle(document.querySelector('.cd-projects-wrapper'), '::before').getPropertyValue('content').replace(/'/g, "").replace(/"/g, "");
	}

	function setSliderContainer() {
		var mq = checkMQ();
		if(mq == 'desktop') {
			var	slides = projectsSlider.children('li'),
				slideWidth = slides.eq(0).width(),
				marginLeft = Number(projectsSlider.children('li').eq(1).css('margin-left').replace('px', '')),
				sliderWidth = ( slideWidth + marginLeft )*( slides.length + 1 ) + 'px',
				slideCurrentIndex = projectsSlider.children('li.current').index();
			projectsSlider.css('width', sliderWidth);
			( slideCurrentIndex != 0 ) && setTranslateValue(projectsSlider, (  slideCurrentIndex * (slideWidth + marginLeft) + 'px'));
		} else {
			projectsSlider.css('width', '');
			setTranslateValue(projectsSlider, 0);
		}
		resizing = false;
	}

	function nextSides(slider) {
		var actual = slider.children('.current'),
			index = actual.index(),
			following = actual.nextAll('li').length,
			width = actual.width(),
			marginLeft = Number(slider.children('li').eq(1).css('margin-left').replace('px', ''));

		index = (following > 4 ) ? index + 3 : index + following - 2;
		//calculate the translate value of the slider container
		translate = index * (width + marginLeft) + 'px';

		slider.addClass('next');
		setTranslateValue(slider, translate);
		slider.one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function(){
			updateSlider('next', actual, slider, following);
		});

		if( $('.no-csstransitions').length > 0 ) updateSlider('next', actual, slider, following);
	}

	function prevSides(slider) {
		var actual = slider.children('.previous'),
			index = actual.index(),
			width = actual.width(),
			marginLeft = Number(slider.children('li').eq(1).css('margin-left').replace('px', ''));
		console.log(marginLeft);

		translate = index * (width + marginLeft) + 'px';

		slider.addClass('prev');
		setTranslateValue(slider, translate);
		slider.one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function(){
			updateSlider('prev', actual, slider);
		});

		if( $('.no-csstransitions').length > 0 ) updateSlider('prev', actual, slider);
	}

	function updateSlider(direction, actual, slider, numerFollowing) {
		if( direction == 'next' ) {
			slider.removeClass('next').find('.previous').removeClass('previous');
			actual.removeClass('current');
			if( numerFollowing > 4 ) {
				actual.addClass('previous').next('li').next('li').next('li').addClass('current');
			} else if ( numerFollowing == 4 ) {
				actual.next('li').next('li').addClass('current');
				actual.prev('li').addClass('previous');
			} else if( numerFollowing == 3 ) {
				actual.next('li').addClass('current');
				actual.prev('li').prev('li').addClass('previous');
			}
		} else {
			slider.removeClass('prev').find('.current').removeClass('current');
			actual.removeClass('previous').addClass('current');
			if(actual.prevAll('li').length > 2 ) {
				actual.prev('li').prev('li').prev('li').addClass('previous');
			} else {
				( !slider.children('li').eq(0).hasClass('current') ) && slider.children('li').eq(0).addClass('previous');
			}
		}

		updateNavigation();
	}

	function updateNavigation() {
		//update visibility of next/prev buttons according to the visible slides
		var current = projectsContainer.find('li.current');
		(current.is(':first-child')) ? sliderNav.find('.prev').addClass('inactive') : sliderNav.find('.prev').removeClass('inactive');
		(current.nextAll('li').length < 3 ) ? sliderNav.find('.next').addClass('inactive') : sliderNav.find('.next').removeClass('inactive');
	}

	function setTranslateValue(item, translate) {
		item.css({
		    '-moz-transform': 'translateX(-' + translate + ')',
		    '-webkit-transform': 'translateX(-' + translate + ')',
			'-ms-transform': 'translateX(-' + translate + ')',
			'-o-transform': 'translateX(-' + translate + ')',
			'transform': 'translateX(-' + translate + ')',
		});
	}
    //open popup
	$('.cd-popup-trigger').on('click', function(event){
		event.preventDefault();
		$('.cd-popup').addClass('is-visible');
	});

	//close popup
	$('.cd-popup').on('click', function(event){
		if( $(event.target).is('.cd-popup-close') || $(event.target).is('.cd-popup') ) {
			event.preventDefault();
			$(this).removeClass('is-visible');
		}
	});
	//close popup when clicking the esc keyboard button
	$(document).keyup(function(event){
    	if(event.which=='27'){
    		$('.cd-popup').removeClass('is-visible');
	    }
    });
});<|endoftext|>


<commit_before>// This file contains webpack configuration settings that allow
// examples to be built against the deck.gl source code in this repo instead
// of building against their installed version of deck.gl.
//
// This enables using the examples to debug the main deck.gl library source
// without publishing or npm linking, with conveniences such hot reloading etc.

// avoid destructuring for older Node version support
const resolve = require('path').resolve;

const ROOT_DIR = resolve(__dirname, '..');
const LIB_DIR = resolve(__dirname, '..');

const ALIASES = require('ocular-dev-tools/config/ocular.config')({
  root: resolve(__dirname, '..')
}).aliases;

// Support for hot reloading changes to the deck.gl library:
function makeLocalDevConfig(EXAMPLE_DIR = LIB_DIR, linkToLuma) {
  const LUMA_LINK_ALIASES = {
    '@luma.gl/constants': `${ROOT_DIR}/../luma.gl/modules/constants/src`,
    '@luma.gl/core': `${ROOT_DIR}/../luma.gl/modules/core/src`,
    '@luma.gl/debug': `${ROOT_DIR}/../luma.gl/modules/debug/src`,
    '@luma.gl/webgl': `${ROOT_DIR}/../luma.gl/modules/webgl/src`,
    '@luma.gl/webgl-state-tracker': `${ROOT_DIR}/../luma.gl/modules/webgl-state-tracker/src`,
    '@luma.gl/webgl2-polyfill': `${ROOT_DIR}/../luma.gl/modules/webgl2-polyfill/src`
  };
  const LUMA_LOCAL_ALIASES = {
    '@luma.gl/core': `${ROOT_DIR}/node_modules/@luma.gl/core/src`,
    '@luma.gl/webgl': `${ROOT_DIR}/node_modules/@luma.gl/webgl/src`,
    '@luma.gl/webgl-state-tracker': `${ROOT_DIR}/node_modules/@luma.gl/webgl-state-tracker/src`,
    '@luma.gl/webgl2-polyfill': `${ROOT_DIR}/node_modules/@luma.gl/webgl2-polyfill/src`
  };

  const LUMA_ALIASES = linkToLuma ? LUMA_LINK_ALIASES : LUMA_LOCAL_ALIASES;
  // console.warn(JSON.stringify(LUMA_ALIASES, null, 2)); // uncomment to debug config
  // require('fs').writeFileSync('/tmp/ocular.log', JSON.stringify(config, null, 2));

  return {
    // TODO - Uncomment when all examples use webpack 4 for faster bundling
    // mode: 'development',

    // suppress warnings about bundle size
    devServer: {
      stats: {
        warnings: false
      }
    },

    devtool: 'source-map',

    node: {
      fs: 'empty'
    },

    resolve: {
      // mainFields: ['esnext', 'module', 'main'],

      alias: Object.assign({}, ALIASES, LUMA_ALIASES, {
        // Use luma.gl installed in parallel with deck.gl
        // Important: ensure shared dependencies come from the main node_modules dir
        // Versions will be controlled by the deck.gl top level package.json
        'math.gl': resolve(LIB_DIR, './node_modules/math.gl'),
        'viewport-mercator-project': resolve(LIB_DIR, './node_modules/viewport-mercator-project'),
        seer: resolve(LIB_DIR, './node_modules/seer'),
        react: resolve(LIB_DIR, './node_modules/react')
      })
    },
    module: {
      rules: [
        {
          // Unfortunately, webpack doesn't import library sourcemaps on its own...
          test: /\.js$/,
          use: ['source-map-loader'],
          enforce: 'pre'
        },
        {
          // Compile source using buble
          test: /\.js$/,
          loader: 'buble-loader',
          include: [`${ROOT_DIR}/modules`],
          options: {
            objectAssign: 'Object.assign',
            transforms: {
              dangerousForOf: true,
              modules: false
            }
          }
        }
      ]
    }
  };
}

function addLocalDevSettings(config, exampleDir, linkToLuma) {
  const LOCAL_DEV_CONFIG = makeLocalDevConfig(exampleDir, linkToLuma);
  config = Object.assign({}, LOCAL_DEV_CONFIG, config);
  config.resolve = Object.assign({}, LOCAL_DEV_CONFIG.resolve, config.resolve || {});
  config.resolve.alias = config.resolve.alias || {};
  Object.assign(config.resolve.alias, LOCAL_DEV_CONFIG.resolve.alias);

  config.module = config.module || {};
  Object.assign(config.module, {
    rules: (config.module.rules || []).concat(LOCAL_DEV_CONFIG.module.rules)
  });
  return config;
}

module.exports = (config, exampleDir) => env => {
  // npm run start-local now transpiles the lib
  if (!env) {
    return config;
  }

  if (env.local) {
    config = addLocalDevSettings(config, exampleDir, env['local-luma']);
  }

  // npm run start-es6 does not transpile the lib
  if (env && env.es6) {
    config = addLocalDevSettings(config, exampleDir, env['local-luma']);
  }

  if (env && env.production) {
    config.mode = 'production';
  }

  // console.warn(JSON.stringify(config, null, 2)); // uncomment to debug config
  return config;
};
<commit_msg>Fix layer-browser configs (#2875)<commit_after>// This file contains webpack configuration settings that allow
// examples to be built against the deck.gl source code in this repo instead
// of building against their installed version of deck.gl.
//
// This enables using the examples to debug the main deck.gl library source
// without publishing or npm linking, with conveniences such hot reloading etc.

// avoid destructuring for older Node version support
const resolve = require('path').resolve;

const ROOT_DIR = resolve(__dirname, '..');
const LIB_DIR = resolve(__dirname, '..');

const ALIASES = require('ocular-dev-tools/config/ocular.config')({
  root: resolve(__dirname, '..')
}).aliases;

// Support for hot reloading changes to the deck.gl library:
function makeLocalDevConfig(EXAMPLE_DIR = LIB_DIR, linkToLuma) {
  const LUMA_LINK_ALIASES = {
    '@luma.gl/constants': `${ROOT_DIR}/../luma.gl/modules/constants/src`,
    '@luma.gl/core': `${ROOT_DIR}/../luma.gl/modules/core/src`,
    '@luma.gl/debug': `${ROOT_DIR}/../luma.gl/modules/debug/src`,
    '@luma.gl/webgl': `${ROOT_DIR}/../luma.gl/modules/webgl/src`,
    '@luma.gl/webgl-state-tracker': `${ROOT_DIR}/../luma.gl/modules/webgl-state-tracker/src`,
    '@luma.gl/webgl2-polyfill': `${ROOT_DIR}/../luma.gl/modules/webgl2-polyfill/src`,
    '@luma.gl/shadertools': `${ROOT_DIR}/../luma.gl/modules/shadertools/src`
  };
  const LUMA_LOCAL_ALIASES = {
    '@luma.gl/core': `${ROOT_DIR}/node_modules/@luma.gl/core`,
    '@luma.gl/webgl': `${ROOT_DIR}/node_modules/@luma.gl/webgl`,
    '@luma.gl/webgl-state-tracker': `${ROOT_DIR}/node_modules/@luma.gl/webgl-state-tracker`,
    '@luma.gl/webgl2-polyfill': `${ROOT_DIR}/node_modules/@luma.gl/webgl2-polyfill`,
    '@luma.gl/shadertools': `${ROOT_DIR}/node_modules/@luma.gl/shadertools`
  };

  const LUMA_ALIASES = linkToLuma ? LUMA_LINK_ALIASES : LUMA_LOCAL_ALIASES;
  // console.warn(JSON.stringify(LUMA_ALIASES, null, 2)); // uncomment to debug config
  // require('fs').writeFileSync('/tmp/ocular.log', JSON.stringify(config, null, 2));

  return {
    // TODO - Uncomment when all examples use webpack 4 for faster bundling
    // mode: 'development',

    // suppress warnings about bundle size
    devServer: {
      stats: {
        warnings: false
      }
    },

    devtool: 'source-map',

    node: {
      fs: 'empty'
    },

    resolve: {
      // mainFields: ['esnext', 'module', 'main'],

      alias: Object.assign({}, ALIASES, LUMA_ALIASES, {
        // Use luma.gl installed in parallel with deck.gl
        // Important: ensure shared dependencies come from the main node_modules dir
        // Versions will be controlled by the deck.gl top level package.json
        'math.gl': resolve(LIB_DIR, './node_modules/math.gl'),
        'viewport-mercator-project': resolve(LIB_DIR, './node_modules/viewport-mercator-project'),
        seer: resolve(LIB_DIR, './node_modules/seer'),
        react: resolve(LIB_DIR, './node_modules/react')
      })
    },
    module: {
      rules: [
        {
          // Unfortunately, webpack doesn't import library sourcemaps on its own...
          test: /\.js$/,
          use: ['source-map-loader'],
          enforce: 'pre'
        },
        {
          // Compile source using babel. This is not necessary for src to run in the browser
          // However class inheritance cannot happen between transpiled/non-transpiled code
          // Which affects some examples
          test: /\.js$/,
          loader: 'babel-loader',
          options: {
            presets: ['@babel/env']
          },
          include: [`${ROOT_DIR}/modules`, `${ROOT_DIR}/../luma.gl/modules`]
        }
      ]
    }
  };
}

function addLocalDevSettings(config, exampleDir, linkToLuma) {
  const LOCAL_DEV_CONFIG = makeLocalDevConfig(exampleDir, linkToLuma);
  config = Object.assign({}, LOCAL_DEV_CONFIG, config);
  config.resolve = Object.assign({}, LOCAL_DEV_CONFIG.resolve, config.resolve || {});
  config.resolve.alias = config.resolve.alias || {};
  Object.assign(config.resolve.alias, LOCAL_DEV_CONFIG.resolve.alias);

  config.module = config.module || {};
  Object.assign(config.module, {
    rules: (config.module.rules || []).concat(LOCAL_DEV_CONFIG.module.rules)
  });
  return config;
}

module.exports = (config, exampleDir) => env => {
  // npm run start-local now transpiles the lib
  if (!env) {
    return config;
  }

  if (env.local) {
    config = addLocalDevSettings(config, exampleDir, env['local-luma']);
  }

  // npm run start-es6 does not transpile the lib
  if (env && env.es6) {
    config = addLocalDevSettings(config, exampleDir, env['local-luma']);
  }

  if (env && env.production) {
    config.mode = 'production';
  }

  // console.warn(JSON.stringify(config, null, 2)); // uncomment to debug config
  return config;
};
<|endoftext|>


<commit_before>'use strict';

angular.module('sumaAnalysis')
  .directive('sumaHourlyLineChart', function () {
    var HourlyLine = function () {
      function chart(selection) {

        var displayFormat = d3.timeFormat('%a %I %p');

        function calcDate(day, hour) {
          var d,
              h;

          d = 4 + (day - 1);
          h = hour - 1;

          return new Date(2013, 7, d, h);
        }

        function setTitle(date, value) {
          var text;

          if (value === null) {
            text = 'No Data Found';
          } else {
            text = value.toFixed(2);
          }
          return displayFormat(date) + ' : ' + text;
        }

        function setColor(value) {
          if (value === null) {
            return 'darkred';
          }

          return 'steelblue';
        }

        selection.each(function (counts) {
            var w,
                h,
                dateMap,
                padding,
                xScale,
                yScale,
                xAxis,
                yAxis,
                area,
                svg,
                gRect,
                x,
                y,
                areaChart,
                circles,
                legend,
                circle,
                text,
                interaction;

            w = 960;
            h = 300;
            padding = 50;

            _.each(counts, function (obj) {
              obj.date = calcDate(obj.day, obj.hour);
            });

            dateMap = counts.map(function (d) {return d.date; });

            //Create scale functions
            xScale = d3.scaleTime()
                    .domain(d3.extent(counts.map(function (d) {return d.date; })))
                    .range([padding, w - padding]);

            yScale = d3.scaleLinear()
                     .domain([0, d3.max(counts, function (d) { return d.value || 0; })])
                     .range([h - padding, padding]);

            //Define X axis
            xAxis = d3.svg.axis()
              .scale(xScale)
              .orient('bottom')
              .ticks(5)
              .tickFormat(d3.time.format('%a %I %p'));

            //Define Y axis
            yAxis = d3.svg.axis()
              .scale(yScale)
              .orient('left')
              .ticks(5);

            // // Define area
            area = d3.svg.area()
              .interpolate('linear')
              .x(function (d) {return xScale(d.date); })
              .y0(h - padding)
              .y1(function (d) {return yScale(d.value); });

            //Create SVG element
            svg = d3.select(this).selectAll('svg').data([counts]);

            svg.enter().append('svg')
              .append('g')
              .attr('class', 'gRect');

            svg.attr('width', w)
              .attr('height', h);

            gRect = svg.select('.gRect');

            // Create x-axis
            x = gRect.selectAll('.xAxis').data([counts]);

            // ENTER
            x.enter()
              .append('g')
              .attr('class', 'xAxis');

            // UPDATE
            x.attr('transform', 'translate(0,' + (h - padding) + ')')
              .call(xAxis);

            // Create y-axis
            y = gRect.selectAll('.yAxis').data([counts]);

            // ENTER
            y.enter()
              .append('g')
              .attr('class', 'yAxis');

            // UPDATE
            y.attr('transform', 'translate(' + padding + ',0)')
              .transition().duration(750)
              .call(yAxis);

            // Apply axis styling
            d3.selectAll('.xAxis path, .yAxis path')
              .attr('fill', 'none')
              .attr('stroke', '#000');

            // Create area
            areaChart = gRect.selectAll('.mainGraph').data([counts]);

            // ENTER
            areaChart.enter()
              .append('path')
              .attr('clip-path', 'url(#clip)')
              .attr('fill', 'steelblue')
              .attr('class', 'mainGraph');

            // UPDATE
            areaChart.transition().duration(750)
              .attr('d', area);

            // Create points
            circles = gRect.selectAll('.dot').data(counts);

            // ENTER
            circles.enter()
              .append('circle')
              .attr('class', 'dot')
              .attr('r', 5)
              .attr('fill', function (d) {return setColor(d.value); })
              .attr('stroke', '#f7f7f7')
              .attr('stroke-width', 2)
              .attr('opacity', 0);

            // UPDATE
            circles.attr('cx', function (d) {return xScale(d.date); })
              .attr('cy', function (d) {return yScale(d.value); });

            // Create interaction layer
            interaction = gRect.selectAll('#interaction').data([counts]);

            // ENTER
            interaction.enter()
              .append('g')
              .attr('id', 'interaction')
              .append('rect')
              .attr('opacity', 0)
              .attr('x', padding)
              .attr('y', padding)
              .attr('height', h - (padding * 2))
              .attr('width', w - (padding * 2));

              // UPDATE
            interaction.on('mousemove', function () {
              var xCoord      = d3.mouse(this)[0],  // X coordinate of mouse over primary graph
                  xInvert     = xScale.invert(xCoord), // Convert xCoord to date value using x scale
                  cut         = d3.bisectLeft(dateMap, xInvert), // Return index to right of xInvert
                  cut2        = (cut > 0) ? cut - 1 : 0, // Return index to left of xInvert
                  leftPoint   = counts[cut2].date, // Convert cut2 to date (milliseconds from Epoch)
                  rightPoint  = counts[cut].date, // Convert cut to date (milliseconds from Epoch)
                  midpoint    = (leftPoint.getTime() + rightPoint.getTime()) / 2; // Calculate midpoint

              // Is current postion less than the midpoint?
              if (xInvert.getTime() < midpoint) {
                cut -= 1;
              }

              // Display closest dot
              d3.selectAll('.dot')
                .attr('opacity', 0)
                .filter(function (d) {return d.date === counts[cut].date; })
                .attr('opacity', 1);

              //Display legend
              d3.select('#tsLegend')
                .attr('opacity', 1);

              // Update legend text
              d3.select('#legendText')
                .text(function () {
                  return setTitle(counts[cut].date, counts[cut].value);
                });

              // Update circle color
              d3.select('#legendCircle')
                .attr('fill', function () {return setColor(counts[cut].value); });
            }).on('mouseout', function () {
              d3.selectAll('.dot')
                .attr('opacity', 0);

              d3.select('#tsLegend')
                .attr('opacity', 0);
            });

            // Create legend wrapper
            legend = gRect.selectAll('#tsLegend').data([counts]);

            // ENTER
            legend.enter()
              .append('g')
              .attr('id', 'tsLegend')
              .attr('opacity', 0);

              // Create circle in legend
            circle = legend.selectAll('#legendCircle').data([counts]);

            // ENTER
            circle.enter()
              .append('circle')
              .attr('id', 'legendCircle')
              .attr('cx', 60)
              .attr('cy', 10)
              .attr('r', 5)
              .attr('stroke', '#f7f7f7')
              .attr('stroke-width', 2);

            // Create text in legend
            text = legend.selectAll('#legendText').data([counts]);

            // ENTER
            text.enter()
              .append('text')
              .attr('id', 'legendText')
              .attr('x', 70)
              .attr('y', 13);
          });
      }

      return chart;
    };

    return {
      restrict: 'A',
      scope: {data: '='},
      link: function postLink(scope, element, attrs) {
        var chart = new HourlyLine();

        scope.render = function (data) {
          d3.select(element[0])
            .datum(data.data)
            .call(chart);
        };

        scope.$watch('data', function (newData) {
          if (!newData) {
            return;
          }

          scope.render(newData);
        });
      }
    };
  });
<commit_msg>Modified axes in sumaHourlyLineChart.js<commit_after>'use strict';

angular.module('sumaAnalysis')
  .directive('sumaHourlyLineChart', function () {
    var HourlyLine = function () {
      function chart(selection) {

        var displayFormat = d3.timeFormat('%a %I %p');

        function calcDate(day, hour) {
          var d,
              h;

          d = 4 + (day - 1);
          h = hour - 1;

          return new Date(2013, 7, d, h);
        }

        function setTitle(date, value) {
          var text;

          if (value === null) {
            text = 'No Data Found';
          } else {
            text = value.toFixed(2);
          }
          return displayFormat(date) + ' : ' + text;
        }

        function setColor(value) {
          if (value === null) {
            return 'darkred';
          }

          return 'steelblue';
        }

        selection.each(function (counts) {
            var w,
                h,
                dateMap,
                padding,
                xScale,
                yScale,
                xAxis,
                yAxis,
                area,
                svg,
                gRect,
                x,
                y,
                areaChart,
                circles,
                legend,
                circle,
                text,
                interaction;

            w = 960;
            h = 300;
            padding = 50;

            _.each(counts, function (obj) {
              obj.date = calcDate(obj.day, obj.hour);
            });

            dateMap = counts.map(function (d) {return d.date; });

            //Create scale functions
            xScale = d3.scaleTime()
                    .domain(d3.extent(counts.map(function (d) {return d.date; })))
                    .range([padding, w - padding]);

            yScale = d3.scaleLinear()
                     .domain([0, d3.max(counts, function (d) { return d.value || 0; })])
                     .range([h - padding, padding]);

            //Define X axis
            xAxis = d3.axisBottom(x)
              .ticks(5)
              .tickFormat(d3.timeFormat('%a %I %p'));

            //Define Y axis
            yAxis = d3.axisLeft(y)
              .ticks(5);

            // // Define area
            area = d3.svg.area()
              .interpolate('linear')
              .x(function (d) {return xScale(d.date); })
              .y0(h - padding)
              .y1(function (d) {return yScale(d.value); });

            //Create SVG element
            svg = d3.select(this).selectAll('svg').data([counts]);

            svg.enter().append('svg')
              .append('g')
              .attr('class', 'gRect');

            svg.attr('width', w)
              .attr('height', h);

            gRect = svg.select('.gRect');

            // Create x-axis
            x = gRect.selectAll('.xAxis').data([counts]);

            // ENTER
            x.enter()
              .append('g')
              .attr('class', 'xAxis');

            // UPDATE
            x.attr('transform', 'translate(0,' + (h - padding) + ')')
              .call(xAxis);

            // Create y-axis
            y = gRect.selectAll('.yAxis').data([counts]);

            // ENTER
            y.enter()
              .append('g')
              .attr('class', 'yAxis');

            // UPDATE
            y.attr('transform', 'translate(' + padding + ',0)')
              .transition().duration(750)
              .call(yAxis);

            // Apply axis styling
            d3.selectAll('.xAxis path, .yAxis path')
              .attr('fill', 'none')
              .attr('stroke', '#000');

            // Create area
            areaChart = gRect.selectAll('.mainGraph').data([counts]);

            // ENTER
            areaChart.enter()
              .append('path')
              .attr('clip-path', 'url(#clip)')
              .attr('fill', 'steelblue')
              .attr('class', 'mainGraph');

            // UPDATE
            areaChart.transition().duration(750)
              .attr('d', area);

            // Create points
            circles = gRect.selectAll('.dot').data(counts);

            // ENTER
            circles.enter()
              .append('circle')
              .attr('class', 'dot')
              .attr('r', 5)
              .attr('fill', function (d) {return setColor(d.value); })
              .attr('stroke', '#f7f7f7')
              .attr('stroke-width', 2)
              .attr('opacity', 0);

            // UPDATE
            circles.attr('cx', function (d) {return xScale(d.date); })
              .attr('cy', function (d) {return yScale(d.value); });

            // Create interaction layer
            interaction = gRect.selectAll('#interaction').data([counts]);

            // ENTER
            interaction.enter()
              .append('g')
              .attr('id', 'interaction')
              .append('rect')
              .attr('opacity', 0)
              .attr('x', padding)
              .attr('y', padding)
              .attr('height', h - (padding * 2))
              .attr('width', w - (padding * 2));

              // UPDATE
            interaction.on('mousemove', function () {
              var xCoord      = d3.mouse(this)[0],  // X coordinate of mouse over primary graph
                  xInvert     = xScale.invert(xCoord), // Convert xCoord to date value using x scale
                  cut         = d3.bisectLeft(dateMap, xInvert), // Return index to right of xInvert
                  cut2        = (cut > 0) ? cut - 1 : 0, // Return index to left of xInvert
                  leftPoint   = counts[cut2].date, // Convert cut2 to date (milliseconds from Epoch)
                  rightPoint  = counts[cut].date, // Convert cut to date (milliseconds from Epoch)
                  midpoint    = (leftPoint.getTime() + rightPoint.getTime()) / 2; // Calculate midpoint

              // Is current postion less than the midpoint?
              if (xInvert.getTime() < midpoint) {
                cut -= 1;
              }

              // Display closest dot
              d3.selectAll('.dot')
                .attr('opacity', 0)
                .filter(function (d) {return d.date === counts[cut].date; })
                .attr('opacity', 1);

              //Display legend
              d3.select('#tsLegend')
                .attr('opacity', 1);

              // Update legend text
              d3.select('#legendText')
                .text(function () {
                  return setTitle(counts[cut].date, counts[cut].value);
                });

              // Update circle color
              d3.select('#legendCircle')
                .attr('fill', function () {return setColor(counts[cut].value); });
            }).on('mouseout', function () {
              d3.selectAll('.dot')
                .attr('opacity', 0);

              d3.select('#tsLegend')
                .attr('opacity', 0);
            });

            // Create legend wrapper
            legend = gRect.selectAll('#tsLegend').data([counts]);

            // ENTER
            legend.enter()
              .append('g')
              .attr('id', 'tsLegend')
              .attr('opacity', 0);

              // Create circle in legend
            circle = legend.selectAll('#legendCircle').data([counts]);

            // ENTER
            circle.enter()
              .append('circle')
              .attr('id', 'legendCircle')
              .attr('cx', 60)
              .attr('cy', 10)
              .attr('r', 5)
              .attr('stroke', '#f7f7f7')
              .attr('stroke-width', 2);

            // Create text in legend
            text = legend.selectAll('#legendText').data([counts]);

            // ENTER
            text.enter()
              .append('text')
              .attr('id', 'legendText')
              .attr('x', 70)
              .attr('y', 13);
          });
      }

      return chart;
    };

    return {
      restrict: 'A',
      scope: {data: '='},
      link: function postLink(scope, element, attrs) {
        var chart = new HourlyLine();

        scope.render = function (data) {
          d3.select(element[0])
            .datum(data.data)
            .call(chart);
        };

        scope.$watch('data', function (newData) {
          if (!newData) {
            return;
          }

          scope.render(newData);
        });
      }
    };
  });
<|endoftext|>


<commit_before>const glob = require('glob');
const path = require('path');
const merge = require('webpack-merge');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const PurifyCSSPlugin = require('purifycss-webpack');
const MinifyPlugin = require('babel-minify-webpack-plugin');
const WebpackPlugin = require('webpack');
// const WebpackMonitor = require('webpack-monitor');

const mainConfig = require('./webpack.config');
// const serverConfig = require('./config/server.config');

const minifyOpts = {
  removeConsole: true,
  removeDebugger: true,
};

module.exports = merge(mainConfig, {
  devtool: 'none',
  entry: {
    main: ['./index.js'],
  },
  plugins: [
    new WebpackPlugin.optimize.OccurrenceOrderPlugin(),
    new MinifyPlugin(minifyOpts, {}),
    new ExtractTextPlugin({ filename: '[name].bundle.css', allChunks: true, disable: false }),
    new CleanWebpackPlugin(['dist']),
    new UglifyJSPlugin(),
    new PurifyCSSPlugin({
      styleExtensions: ['.css', '.scss'],
      moduleExtensions: ['.html'],
      purifyOptions: {
        info: true,
        rejected: false,
        minify: true,
      },
      paths: glob.sync(path.join(__dirname, 'app/*.html')),
    }),
    /* new WebpackMonitor({
      capture: true,
      target: serverConfig.monitor.target,
      launch: true,
      port: serverConfig.monitor.port,
      purifyOptions: {
        output: path.join(__dirname, 'dist'),
      },
    }), */
  ],
});
<commit_msg>update build command<commit_after>const glob = require('glob');
const path = require('path');
const merge = require('webpack-merge');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const PurifyCSSPlugin = require('purifycss-webpack');
const MinifyPlugin = require('babel-minify-webpack-plugin');
const WebpackPlugin = require('webpack');
// const WebpackMonitor = require('webpack-monitor');

const mainConfig = require('./webpack.config');
// const serverConfig = require('./config/server.config');

module.exports = merge(mainConfig, {
  context: path.resolve(__dirname, 'app'),
  devtool: 'none',
  entry: {
    main: ['./index.js'],
  },
  plugins: [
    new WebpackPlugin.optimize.OccurrenceOrderPlugin(),
    new MinifyPlugin({
      removeConsole: true,
      removeDebugger: true,
    }, {}),
    new ExtractTextPlugin({ filename: '[name].bundle.css', allChunks: true, disable: false }),
    new CleanWebpackPlugin(['dist']),
    new UglifyJSPlugin(),
    new PurifyCSSPlugin({
      styleExtensions: ['.css', '.scss'],
      moduleExtensions: ['.html'],
      purifyOptions: {
        info: true,
        rejected: false,
        minify: true,
      },
      paths: glob.sync(path.join(__dirname, 'app/*.html')),
    }),
    /* new WebpackMonitor({
      capture: true,
      target: serverConfig.monitor.target,
      launch: true,
      port: serverConfig.monitor.port,
      purifyOptions: {
        output: path.join(__dirname, 'dist'),
      },
    }), */
  ],
});
<|endoftext|>