<commit_before>import React, { useState, useRef, useContext } from 'react';
import { t } from 'ttag';

import { makeStyles } from '@material-ui/core/styles';
import HelpIcon from '@material-ui/icons/Help';
import CloseIcon from '@material-ui/icons/Close';
import { Box, SvgIcon } from '@material-ui/core';
import { TYPE_SUGGESTION_OPTIONS } from 'constants/replyType';
import { EDITOR_FACEBOOK_GROUP, EDITOR_REFERENCE } from 'constants/urls';
import FormatListNumberedIcon from '@material-ui/icons/FormatListNumbered';
import FormatListBulletedIcon from '@material-ui/icons/FormatListBulleted';
import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos';
import { Picker } from 'emoji-mart';
import { LIST_STYLES, addListStyle } from 'lib/editor';
import SearchBar from '../ReplySearch/SearchBar';
import ReplySearch from '../ReplySearch/ReplySearch';
import ReplySearchContext from '../ReplySearch/context';
import ReplyFormContext from './context';
import cx from 'clsx';

const useStyles = makeStyles(theme => ({
  editor: {
    position: 'relative',
    flex: 1,
    display: 'flex',
    flexDirection: 'column',
    [theme.breakpoints.up('md')]: {
      border: `1px solid ${theme.palette.secondary[100]}`,
      borderRadius: 8,
    },
  },
  tools: {
    display: 'flex',
    alignItems: 'center',
    flexDirection: 'row-reverse',
    background: theme.palette.secondary[50],
    padding: 12,
    [theme.breakpoints.up('sm')]: {
      // issue Fix editor RWD breakpoints #363
      background: theme.palette.common.white,
      borderTopLeftRadius: 8,
      borderTopRightRadius: 8,
      padding: 14,
      order: 1,
      // 把區塊調整到editor上面
    },
    '& > $tool:not(:first-child)': {
      borderRight: `1px solid ${theme.palette.secondary[100]}`,
    },
  },
  tool: {
    '& > button': {
      marginRight: 4,
      cursor: 'pointer',
      outline: 'none',
      borderRadius: 4,
      background: 'inherit',
      color: theme.palette.secondary[300],
      verticalAlign: 'middle',
      border: `1px solid transparent`,
      lineHeight: 0,
      padding: 4,
    },
    '&:not(:first-child) > button': {
      marginLeft: 4,
    },
    '&.active > button': {
      border: `1px solid ${theme.palette.secondary[200]}`,
    },
  },
  searchPanel: {
    position: 'absolute',
    top: 0,
    width: '100%',
    height: 'calc(100% - 60px)',
    background: theme.palette.common.white,
    borderTop: `2px solid ${theme.palette.secondary[100]}`,
    padding: '0 9px',
    overflow: 'auto',
    [theme.breakpoints.up('md')]: {
      top: 62,
      height: 'calc(100% - 62px)',
    },
  },
  searchContainer: {
    flex: 1,
    [theme.breakpoints.down('md')]: {
      '&:focus-within ~ $tool': {
        display: 'none',
      },
      '&:focus-within ~ $caret': {
        display: 'block',
      },
    },
  },
  caret: {
    display: 'none',
    fontSize: 17,
    color: theme.palette.secondary[300],
  },
  search: {
    borderRadius: 30,
    border: 'none',
    background: theme.palette.common.white,
    [theme.breakpoints.down('sm')]: {
      marginLeft: 10,
    },
  },
  suggestions: {
    background: theme.palette.common.white,
    color: theme.palette.secondary[300],
    padding: 12,
    whiteSpace: 'nowrap',
    overflowX: 'auto',
    [theme.breakpoints.up('sm')]: {
      order: 2,
      background: theme.palette.secondary[50],
    },
  },
  suggestion: {
    background: 'transparent',
    border: `1px solid ${theme.palette.secondary[300]}`,
    borderRadius: 20,
    padding: 8,
    margin: '0 4px',
    fontSize: 12,
    cursor: 'pointer',
  },
  help: {
    padding: '4px 8px',
    background: theme.palette.secondary[400],
    color: theme.palette.common.white,
    fontSize: 12,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'space-between',
    '& a': {
      color: theme.palette.common.white,
    },
    [theme.breakpoints.up('sm')]: {
      order: 3,
    },
  },
  inputArea: {
    height: 'calc(100% - 60px)',
    padding: '9px 17px',
    border: 'none',
    width: '100%',
    outline: 'none',
    [theme.breakpoints.up('sm')]: {
      height: 'auto',
      order: 4,
    },
  },
  closeIcon: {
    cursor: 'pointer',
  },
}));

const StickerIcon = props => (
  <SvgIcon viewBox="0 0 20 20" {...props}>
    <path d="M3.5 0C1.56 0 0 1.56 0 3.5V16.5C0 18.44 1.56 20 3.5 20H14L20 14V3.5C20 1.56 18.44 0 16.5 0H3.5ZM3.75 2H16.25C16.7141 2 17.1592 2.18437 17.4874 2.51256C17.8156 2.84075 18 3.28587 18 3.75V13H16.5C14.56 13 13 14.56 13 16.5V18H3.75C3.28587 18 2.84075 17.8156 2.51256 17.4874C2.18437 17.1592 2 16.7141 2 16.25V3.75C2 3.28587 2.18437 2.84075 2.51256 2.51256C2.84075 2.18437 3.28587 2 3.75 2ZM12.44 4.77C12.28 4.77 12.12 4.79 11.97 4.83C11.03 5.09 10.5 6.05 10.74 7C10.79 7.15 10.86 7.3 10.95 7.44L14.18 6.56C14.18 6.39 14.16 6.22 14.12 6.05C13.91 5.3 13.22 4.77 12.44 4.77ZM6.17 6.5C6 6.5 5.85 6.5 5.7 6.55C4.77 6.81 4.22 7.77 4.47 8.7C4.5 8.86 4.59 9 4.68 9.16L7.91 8.28C7.91 8.11 7.89 7.94 7.85 7.78C7.75217 7.41021 7.53386 7.08359 7.2296 6.85177C6.92534 6.61995 6.55249 6.49617 6.17 6.5ZM14.72 9.26L5.59 11.77C6.23838 12.5203 7.08543 13.0723 8.03367 13.3624C8.98191 13.6525 9.9928 13.669 10.95 13.41C11.9051 13.1428 12.7654 12.6117 13.4323 11.8776C14.0991 11.1435 14.5455 10.2363 14.72 9.26Z" />
  </SvgIcon>
);

const { BULLETED, NUMBERED } = LIST_STYLES;

const ReasonEditor = ({
  value,
  onSuggestionAdd,
  onChange,
  replyType,
  relatedArticleReplies,
  existingReplyIds,
}) => {
  const editorRef = useRef(null);
  const lastKey = useRef(null);
  const [listStyle, setListStyle] = useState(null);
  const [showEmojiPicker, setShowEmojiPicker] = useState(false);
  const classes = useStyles();
  const [showHelp, setShowHelp] = useState(true);
  const { search, setSearch } = useContext(ReplySearchContext);
  const { fields, handlers } = useContext(ReplyFormContext);

  const toggleListStyle = type => () =>
    setListStyle(v => (v === type ? null : type));

  const handleKeyPress = e => void (lastKey.current = e.key);

  const handleChange = e => {
    if (lastKey.current === 'Enter') {
      const element = e.target;
      const { value, selectionStart, selectionEnd } = addListStyle(
        element,
        listStyle
      );
      element.value = value;
      element.selectionStart = selectionStart;
      element.selectionEnd = selectionEnd;
    }
    onChange(e);
  };

  const addEmoji = emoji => {
    const element = editorRef.current;
    const index = element.selectionStart;
    const raw = element.value;
    element.value = raw.slice(0, index) + emoji.native + raw.slice(index);
    // mock a onchange event
    onChange({ target: { value: element.value } });
    setShowEmojiPicker(false);
  };

  const handleConnect = reply => {
    const element = editorRef.current;
    const text = `${reply.text}\n${reply.reference}\n${element.value}`;
    handlers.set('text', text);

    if (replyType !== 'NOT_ARTICLE') {
      handlers.set('reference', reply.reference + '\n' + fields.reference);
    }
    setSearch('');
  };

  return (

      {showHelp && (

          <Box display="flex" alignItems="center" component="span">
            <HelpIcon />
            <Box component="span" px={1}>
              不知道從何下手嗎？

                Cofacts 編輯規則

              、

                Facebook 編輯求助區

              歡迎您 :)
            </Box>
          </Box>
          <CloseIcon
            className={classes.closeIcon}
            onClick={() => setShowHelp(false)}
          />

      )}

      <textarea
        required
        className={classes.inputArea}
        ref={editorRef}
        placeholder={(() => {
          if (replyType === 'NOT_ARTICLE') {
            return t`Please briefly explain why this message should not be processed in Cofacts.`;
          } else if (replyType === 'NOT_RUMOR') {
            return t`As a brief intro for the references, please point out which part of the message is correct.`;
          } else if (replyType === 'OPINIONATED') {
            return t`Please briefly
1. explain which part of the message contains personal opinion
2. remind the audience that this is not factual`;
          } else if (replyType === 'RUMOR') {
            return t`As a brief intro for the references, please point out which part of the message is incorrect.`;
          } else {
            return '';
          }
        })()}
        onChange={handleChange}
        onKeyDown={handleKeyPress}
        value={value}
        rows={10}
      />

      {TYPE_SUGGESTION_OPTIONS[replyType] && (

          常用模板
          {TYPE_SUGGESTION_OPTIONS[replyType].map(({ label, value }) => (
            <button
              key={label}
              className={classes.suggestion}
              type="button"
              value={value}
              onClick={onSuggestionAdd}
            >
              {label}
            </button>
          ))}

      )}

      {search && (

          <ReplySearch
            relatedArticleReplies={relatedArticleReplies}
            existingReplyIds={existingReplyIds}
            onConnect={handleConnect}
            actionText={t`Keep composing my reply with this`}
          />

      )}

          <SearchBar className={classes.search} />

        <ArrowForwardIosIcon className={classes.caret} />

          <button
            type="button"
            onClick={() => setShowEmojiPicker(show => !show)}
          >
            <StickerIcon />
          </button>
          {showEmojiPicker && (
            <Box position="absolute">
              <Picker onSelect={addEmoji} />
            </Box>
          )}

          <button type="button" onClick={toggleListStyle(BULLETED)}>
            <FormatListBulletedIcon />
          </button>

          <button type="button" onClick={toggleListStyle(NUMBERED)}>
            <FormatListNumberedIcon />
          </button>

  );
};

ReasonEditor.displayName = 'ReasonEditor';

export default ReasonEditor;
<commit_msg>delete comment<commit_after>import React, { useState, useRef, useContext } from 'react';
import { t } from 'ttag';

import { makeStyles } from '@material-ui/core/styles';
import HelpIcon from '@material-ui/icons/Help';
import CloseIcon from '@material-ui/icons/Close';
import { Box, SvgIcon } from '@material-ui/core';
import { TYPE_SUGGESTION_OPTIONS } from 'constants/replyType';
import { EDITOR_FACEBOOK_GROUP, EDITOR_REFERENCE } from 'constants/urls';
import FormatListNumberedIcon from '@material-ui/icons/FormatListNumbered';
import FormatListBulletedIcon from '@material-ui/icons/FormatListBulleted';
import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos';
import { Picker } from 'emoji-mart';
import { LIST_STYLES, addListStyle } from 'lib/editor';
import SearchBar from '../ReplySearch/SearchBar';
import ReplySearch from '../ReplySearch/ReplySearch';
import ReplySearchContext from '../ReplySearch/context';
import ReplyFormContext from './context';
import cx from 'clsx';

const useStyles = makeStyles(theme => ({
  editor: {
    position: 'relative',
    flex: 1,
    display: 'flex',
    flexDirection: 'column',
    [theme.breakpoints.up('md')]: {
      border: `1px solid ${theme.palette.secondary[100]}`,
      borderRadius: 8,
    },
  },
  tools: {
    display: 'flex',
    alignItems: 'center',
    flexDirection: 'row-reverse',
    background: theme.palette.secondary[50],
    padding: 12,
    [theme.breakpoints.up('sm')]: {
      background: theme.palette.common.white,
      borderTopLeftRadius: 8,
      borderTopRightRadius: 8,
      padding: 14,
      order: 1,
    },
    '& > $tool:not(:first-child)': {
      borderRight: `1px solid ${theme.palette.secondary[100]}`,
    },
  },
  tool: {
    '& > button': {
      marginRight: 4,
      cursor: 'pointer',
      outline: 'none',
      borderRadius: 4,
      background: 'inherit',
      color: theme.palette.secondary[300],
      verticalAlign: 'middle',
      border: `1px solid transparent`,
      lineHeight: 0,
      padding: 4,
    },
    '&:not(:first-child) > button': {
      marginLeft: 4,
    },
    '&.active > button': {
      border: `1px solid ${theme.palette.secondary[200]}`,
    },
  },
  searchPanel: {
    position: 'absolute',
    top: 0,
    width: '100%',
    height: 'calc(100% - 60px)',
    background: theme.palette.common.white,
    borderTop: `2px solid ${theme.palette.secondary[100]}`,
    padding: '0 9px',
    overflow: 'auto',
    [theme.breakpoints.up('md')]: {
      top: 62,
      height: 'calc(100% - 62px)',
    },
  },
  searchContainer: {
    flex: 1,
    [theme.breakpoints.down('md')]: {
      '&:focus-within ~ $tool': {
        display: 'none',
      },
      '&:focus-within ~ $caret': {
        display: 'block',
      },
    },
  },
  caret: {
    display: 'none',
    fontSize: 17,
    color: theme.palette.secondary[300],
  },
  search: {
    borderRadius: 30,
    border: 'none',
    background: theme.palette.common.white,
    [theme.breakpoints.down('sm')]: {
      marginLeft: 10,
    },
  },
  suggestions: {
    background: theme.palette.common.white,
    color: theme.palette.secondary[300],
    padding: 12,
    whiteSpace: 'nowrap',
    overflowX: 'auto',
    [theme.breakpoints.up('sm')]: {
      order: 2,
      background: theme.palette.secondary[50],
    },
  },
  suggestion: {
    background: 'transparent',
    border: `1px solid ${theme.palette.secondary[300]}`,
    borderRadius: 20,
    padding: 8,
    margin: '0 4px',
    fontSize: 12,
    cursor: 'pointer',
  },
  help: {
    padding: '4px 8px',
    background: theme.palette.secondary[400],
    color: theme.palette.common.white,
    fontSize: 12,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'space-between',
    '& a': {
      color: theme.palette.common.white,
    },
    [theme.breakpoints.up('sm')]: {
      order: 3,
    },
  },
  inputArea: {
    height: 'calc(100% - 60px)',
    padding: '9px 17px',
    border: 'none',
    width: '100%',
    outline: 'none',
    [theme.breakpoints.up('sm')]: {
      height: 'auto',
      order: 4,
    },
  },
  closeIcon: {
    cursor: 'pointer',
  },
}));

const StickerIcon = props => (
  <SvgIcon viewBox="0 0 20 20" {...props}>
    <path d="M3.5 0C1.56 0 0 1.56 0 3.5V16.5C0 18.44 1.56 20 3.5 20H14L20 14V3.5C20 1.56 18.44 0 16.5 0H3.5ZM3.75 2H16.25C16.7141 2 17.1592 2.18437 17.4874 2.51256C17.8156 2.84075 18 3.28587 18 3.75V13H16.5C14.56 13 13 14.56 13 16.5V18H3.75C3.28587 18 2.84075 17.8156 2.51256 17.4874C2.18437 17.1592 2 16.7141 2 16.25V3.75C2 3.28587 2.18437 2.84075 2.51256 2.51256C2.84075 2.18437 3.28587 2 3.75 2ZM12.44 4.77C12.28 4.77 12.12 4.79 11.97 4.83C11.03 5.09 10.5 6.05 10.74 7C10.79 7.15 10.86 7.3 10.95 7.44L14.18 6.56C14.18 6.39 14.16 6.22 14.12 6.05C13.91 5.3 13.22 4.77 12.44 4.77ZM6.17 6.5C6 6.5 5.85 6.5 5.7 6.55C4.77 6.81 4.22 7.77 4.47 8.7C4.5 8.86 4.59 9 4.68 9.16L7.91 8.28C7.91 8.11 7.89 7.94 7.85 7.78C7.75217 7.41021 7.53386 7.08359 7.2296 6.85177C6.92534 6.61995 6.55249 6.49617 6.17 6.5ZM14.72 9.26L5.59 11.77C6.23838 12.5203 7.08543 13.0723 8.03367 13.3624C8.98191 13.6525 9.9928 13.669 10.95 13.41C11.9051 13.1428 12.7654 12.6117 13.4323 11.8776C14.0991 11.1435 14.5455 10.2363 14.72 9.26Z" />
  </SvgIcon>
);

const { BULLETED, NUMBERED } = LIST_STYLES;

const ReasonEditor = ({
  value,
  onSuggestionAdd,
  onChange,
  replyType,
  relatedArticleReplies,
  existingReplyIds,
}) => {
  const editorRef = useRef(null);
  const lastKey = useRef(null);
  const [listStyle, setListStyle] = useState(null);
  const [showEmojiPicker, setShowEmojiPicker] = useState(false);
  const classes = useStyles();
  const [showHelp, setShowHelp] = useState(true);
  const { search, setSearch } = useContext(ReplySearchContext);
  const { fields, handlers } = useContext(ReplyFormContext);

  const toggleListStyle = type => () =>
    setListStyle(v => (v === type ? null : type));

  const handleKeyPress = e => void (lastKey.current = e.key);

  const handleChange = e => {
    if (lastKey.current === 'Enter') {
      const element = e.target;
      const { value, selectionStart, selectionEnd } = addListStyle(
        element,
        listStyle
      );
      element.value = value;
      element.selectionStart = selectionStart;
      element.selectionEnd = selectionEnd;
    }
    onChange(e);
  };

  const addEmoji = emoji => {
    const element = editorRef.current;
    const index = element.selectionStart;
    const raw = element.value;
    element.value = raw.slice(0, index) + emoji.native + raw.slice(index);
    // mock a onchange event
    onChange({ target: { value: element.value } });
    setShowEmojiPicker(false);
  };

  const handleConnect = reply => {
    const element = editorRef.current;
    const text = `${reply.text}\n${reply.reference}\n${element.value}`;
    handlers.set('text', text);

    if (replyType !== 'NOT_ARTICLE') {
      handlers.set('reference', reply.reference + '\n' + fields.reference);
    }
    setSearch('');
  };

  return (

      {showHelp && (

          <Box display="flex" alignItems="center" component="span">
            <HelpIcon />
            <Box component="span" px={1}>
              不知道從何下手嗎？

                Cofacts 編輯規則

              、

                Facebook 編輯求助區

              歡迎您 :)
            </Box>
          </Box>
          <CloseIcon
            className={classes.closeIcon}
            onClick={() => setShowHelp(false)}
          />

      )}

      <textarea
        required
        className={classes.inputArea}
        ref={editorRef}
        placeholder={(() => {
          if (replyType === 'NOT_ARTICLE') {
            return t`Please briefly explain why this message should not be processed in Cofacts.`;
          } else if (replyType === 'NOT_RUMOR') {
            return t`As a brief intro for the references, please point out which part of the message is correct.`;
          } else if (replyType === 'OPINIONATED') {
            return t`Please briefly
1. explain which part of the message contains personal opinion
2. remind the audience that this is not factual`;
          } else if (replyType === 'RUMOR') {
            return t`As a brief intro for the references, please point out which part of the message is incorrect.`;
          } else {
            return '';
          }
        })()}
        onChange={handleChange}
        onKeyDown={handleKeyPress}
        value={value}
        rows={10}
      />

      {TYPE_SUGGESTION_OPTIONS[replyType] && (

          常用模板
          {TYPE_SUGGESTION_OPTIONS[replyType].map(({ label, value }) => (
            <button
              key={label}
              className={classes.suggestion}
              type="button"
              value={value}
              onClick={onSuggestionAdd}
            >
              {label}
            </button>
          ))}

      )}

      {search && (

          <ReplySearch
            relatedArticleReplies={relatedArticleReplies}
            existingReplyIds={existingReplyIds}
            onConnect={handleConnect}
            actionText={t`Keep composing my reply with this`}
          />

      )}

          <SearchBar className={classes.search} />

        <ArrowForwardIosIcon className={classes.caret} />

          <button
            type="button"
            onClick={() => setShowEmojiPicker(show => !show)}
          >
            <StickerIcon />
          </button>
          {showEmojiPicker && (
            <Box position="absolute">
              <Picker onSelect={addEmoji} />
            </Box>
          )}

          <button type="button" onClick={toggleListStyle(BULLETED)}>
            <FormatListBulletedIcon />
          </button>

          <button type="button" onClick={toggleListStyle(NUMBERED)}>
            <FormatListNumberedIcon />
          </button>

  );
};

ReasonEditor.displayName = 'ReasonEditor';

export default ReasonEditor;
<|endoftext|>


<commit_before>/*
*
* OverlayBlocker
*
*/

import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import cn from 'classnames';

import styles from './styles.scss';

const DELAY = 1000;

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

    this.state = { elapsed: 0, start: 0 };
    this.overlayContainer = document.createElement('div');

    document.body.appendChild(this.overlayContainer);
  }

  componentDidUpdate(prevProps) {
    const { isOpen } = this.props;

    if (prevProps.isOpen !== this.props.isOpen && isOpen) {
      this.startTimer();
    }

    if (prevProps.isOpen !== isOpen && !isOpen) {
      this.stopTimer();
    }
  }

  componentWillUnmount() {
    document.body.removeChild(this.overlayContainer);
  }

  tick = () => {
    const { elapsed } = this.state;

    if (elapsed > 30) {
      clearInterval(this.timer);

      return;
    }

    this.setState(prevState => ({ elapsed: (Math.round(Date.now() - prevState.start) / 1000) }));
  }

  startTimer = () => {
    this.setState({ start: Date.now() });
    this.timer = setInterval(this.tick, DELAY);
  }

  stopTimer = () => {
    this.setState({ elapsed: 0 });
    clearInterval(this.timer);
  }

  render() {
    let { title, description, icon } = this.props;
    const { elapsed } = this.state;

    if (elapsed > 30) {
      title = 'components.OverlayBlocker.title.serverError';
      description = 'components.OverlayBlocker.description.serverError';
      icon = 'fa fa-clock-o';
    }

    const content = this.props.children ? (
      this.props.children
    ) : (

        <div className={cn(styles.icoContainer, elapsed < 30 && styles.spin)}>

            <FormattedMessage id={title} />

            <FormattedMessage id={description} />

          { elapsed < 30 && (

              Read the documentation

          )}

    );

    if (this.props.isOpen) {
      return ReactDOM.createPortal(

            {content}

,
        this.overlayContainer
      );
    }

    return '';
  }
}

OverlayBlocker.defaultProps = {
  children: null,
  description: 'components.OverlayBlocker.description',
  icon: 'fa fa-refresh',
  isOpen: false,
  title: 'components.OverlayBlocker.title',
};

OverlayBlocker.propTypes = {
  children: PropTypes.node,
  description: PropTypes.string,
  icon: PropTypes.string,
  isOpen: PropTypes.bool,
  title: PropTypes.string,
};

export default OverlayBlocker;
<commit_msg>Fix button delay<commit_after>/*
*
* OverlayBlocker
*
*/

import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import cn from 'classnames';

import styles from './styles.scss';

const DELAY = 1000;

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

    this.state = { elapsed: 0, start: 0 };
    this.overlayContainer = document.createElement('div');

    document.body.appendChild(this.overlayContainer);
  }

  componentDidUpdate(prevProps) {
    const { isOpen } = this.props;

    if (prevProps.isOpen !== this.props.isOpen && isOpen) {
      this.startTimer();
    }

    if (prevProps.isOpen !== isOpen && !isOpen) {
      this.stopTimer();
    }
  }

  componentWillUnmount() {
    document.body.removeChild(this.overlayContainer);
  }

  tick = () => {
    const { elapsed } = this.state;

    if (elapsed > 30) {
      clearInterval(this.timer);

      return;
    }

    this.setState(prevState => ({ elapsed: (Math.round(Date.now() - prevState.start) / 1000) }));
  }

  startTimer = () => {
    this.setState({ start: Date.now() });
    this.timer = setInterval(this.tick, DELAY);
  }

  stopTimer = () => {
    this.setState({ elapsed: 0 });
    clearInterval(this.timer);
  }

  render() {
    let { title, description, icon } = this.props;
    const { elapsed } = this.state;

    let button = (

        Read the documentation

    );

    if (elapsed > 30) {
      button = null;
      icon = 'fa fa-clock-o';
      description = 'components.OverlayBlocker.description.serverError';
      title = 'components.OverlayBlocker.title.serverError';
    }

    const content = this.props.children ? (
      this.props.children
    ) : (

        <div className={cn(styles.icoContainer, elapsed < 30 && styles.spin)}>

            <FormattedMessage id={title} />

            <FormattedMessage id={description} />

          {button}

    );

    if (this.props.isOpen) {
      return ReactDOM.createPortal(

            {content}

,
        this.overlayContainer
      );
    }

    return '';
  }
}

OverlayBlocker.defaultProps = {
  children: null,
  description: 'components.OverlayBlocker.description',
  icon: 'fa fa-refresh',
  isOpen: false,
  title: 'components.OverlayBlocker.title',
};

OverlayBlocker.propTypes = {
  children: PropTypes.node,
  description: PropTypes.string,
  icon: PropTypes.string,
  isOpen: PropTypes.bool,
  title: PropTypes.string,
};

export default OverlayBlocker;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import styles from './styles.scss';
import DeleteIcon from 'material-ui-icons/Delete';
import IconButton from 'material-ui/IconButton';
import {
    object
  } from 'prop-types';

class FileListItem extends Component {
    state = {
        dataUrl: ""
    }

    componentWillMount() {
        const fileReader = new FileReader();
        fileReader.onload = (e) => {
            this.setState({
                file: this.props.file,
                dataUrl: fileReader.result
            });
        }
        fileReader.readAsDataURL(this.props.file);
    }

    render() {
        return (

                        {this.props.file.name}

                        {this.formatBytes(this.props.file.size)}

                <IconButton className={styles.fileListItemDeleteIcon}
                            aria-label="Delete">
                    <DeleteIcon />
                </IconButton>

        );
    }
}

FileListItem.propTypes = {
    file: object.isRequired
}

export default FileListItem;<commit_msg>Added a file size formating function that I got from stack overflow and fixed an issue where the list wasn't getting updated after changing files.<commit_after>import React, { Component } from 'react';
import styles from './styles.scss';
import DeleteIcon from 'material-ui-icons/Delete';
import IconButton from 'material-ui/IconButton';
import {
    object
  } from 'prop-types';

class FileListItem extends Component {
    state = {
        dataUrl: ""
    }

    // taken from https://stackoverflow.com/questions/15900485/correct-way-to-convert-size-in-bytes-to-kb-mb-gb-in-javascript
    formatBytes = (bytes) => {
        if(bytes == 0) return '0 Bytes';
        var k = 1024,
            sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
            i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
     }

    readImageFile = file => {
        const fileReader = new FileReader();
        fileReader.onload = (e) => {
            this.setState({
                dataUrl: fileReader.result
            });
        }
        fileReader.readAsDataURL(file);
    }

    componentWillReceiveProps = nextProps => {
        this.readImageFile(nextProps.file);
    }

    componentWillMount() {
        this.readImageFile(this.props.file);
    }

    render() {
        return (

                        {this.props.file.name}

                        {this.formatBytes(this.props.file.size)}

                <IconButton className={styles.fileListItemDeleteIcon}
                            aria-label="Delete">
                    <DeleteIcon />
                </IconButton>

        );
    }
}

FileListItem.propTypes = {
    file: object.isRequired
}

export default FileListItem;<|endoftext|>


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

var Template = require('./Template');

class RefinementList extends React.Component {
  refine(value) {
    this.props.toggleRefinement(value);
  }

  // Click events on DOM tree like LABEL > INPUT will result in two click events
  // instead of one. No matter the framework: see
  // a label, you will get two click events instead of one.
  // No matter the framework, see https://www.google.com/search?q=click+label+twice
  //
  // Thus making it hard to distinguish activation from deactivation because both click events
  // are very close. Debounce is a solution but hacky.
  //
  // So the code here checks if the click was done on or in a LABEL. If this LABEL
  // has a checkbox inside, we ignore the first click event because we will get another one.
  handleClick(value, e) {
    if (e.target.tagName === 'INPUT') {
      this.refine(value);
      return;
    }

    var parent = e.target;

    while (parent !== e.currentTarget) {
      if (parent.tagName === 'LABEL' && parent.querySelector('input[type="checkbox"]')) {
        return;
      }

      parent = parent.parentNode;
    }

    this.refine(value);
  }

  render() {
    var facetValues = this.props.facetValues;
    var template = this.props.template;

    return (

        {facetValues.map(facetValue => {
          return (

              <Template data={facetValue} template={template} />

          );
        })}

    );
  }
}

RefinementList.propTypes = {
  rootClass: React.PropTypes.oneOfType([
    React.PropTypes.string,
    React.PropTypes.arrayOf(React.PropTypes.string)
  ]),
  itemClass: React.PropTypes.oneOfType([
    React.PropTypes.string,
    React.PropTypes.arrayOf(React.PropTypes.string)
  ]),
  facetValues: React.PropTypes.array,
  template: React.PropTypes.oneOfType([
    React.PropTypes.string,
    React.PropTypes.func
  ]).isRequired,
  toggleRefinement: React.PropTypes.func.isRequired
};

module.exports = RefinementList;
<commit_msg>fix: switch back to divs, rendering glitch<commit_after>var React = require('react');

var Template = require('./Template');

class RefinementList extends React.Component {
  refine(value) {
    this.props.toggleRefinement(value);
  }

  // Click events on DOM tree like LABEL > INPUT will result in two click events
  // instead of one. No matter the framework: see
  // a label, you will get two click events instead of one.
  // No matter the framework, see https://www.google.com/search?q=click+label+twice
  //
  // Thus making it hard to distinguish activation from deactivation because both click events
  // are very close. Debounce is a solution but hacky.
  //
  // So the code here checks if the click was done on or in a LABEL. If this LABEL
  // has a checkbox inside, we ignore the first click event because we will get another one.
  handleClick(value, e) {
    if (e.target.tagName === 'INPUT') {
      this.refine(value);
      return;
    }

    var parent = e.target;

    while (parent !== e.currentTarget) {
      if (parent.tagName === 'LABEL' && parent.querySelector('input[type="checkbox"]')) {
        return;
      }

      parent = parent.parentNode;
    }

    this.refine(value);
  }

  render() {
    var facetValues = this.props.facetValues;
    var template = this.props.template;

    return (

        {facetValues.map(facetValue => {
          return (

              <Template data={facetValue} template={template} />

          );
        })}

    );
  }
}

RefinementList.propTypes = {
  rootClass: React.PropTypes.oneOfType([
    React.PropTypes.string,
    React.PropTypes.arrayOf(React.PropTypes.string)
  ]),
  itemClass: React.PropTypes.oneOfType([
    React.PropTypes.string,
    React.PropTypes.arrayOf(React.PropTypes.string)
  ]),
  facetValues: React.PropTypes.array,
  template: React.PropTypes.oneOfType([
    React.PropTypes.string,
    React.PropTypes.func
  ]).isRequired,
  toggleRefinement: React.PropTypes.func.isRequired
};

module.exports = RefinementList;
<|endoftext|>


<commit_before>// @flow
import * as React from 'react';
import { View, TextInput as TextInputNative } from 'react-native';
import withTheme, { type Theme } from './withTheme';
import Text from './Text';
import type { TextStyleProp } from 'react-native/Libraries/StyleSheet/StyleSheet';
import ErrorMessage, { type MessageError } from './ErrorMessage';
import throttle from 'lodash/throttle';

export type TextInputProps = {|
  disabled?: boolean,
  label?: string | React.Element<any>,
  error?: ?MessageError,
  size?: number,
  style?: TextStyleProp,
  value?: string,
  focusOnError?: ?Object,
  secureTextEntry?: boolean,
  placeholder: string,
  onChangeText?: string => void,
  onChangeTextThrottled?: string => void,
  name?: string,
  keyboardType?: string,
  autoComplete?: string,
  onSubmitEditing?: () => void,
  defaultValue?: string,
  // Feel free to add any missing prop.
  // https://github.com/este/este/issues/1557
|};

// That's because TextInputProps is exported to reuse.
type TextInputPropsWithTheme = {|
  ...TextInputProps,
  theme: Theme,
|};

class TextInput extends React.PureComponent<TextInputPropsWithTheme> {
  inputRef = React.createRef();

  handleOnChangeTextThrottled = throttle(value => {
    const { onChangeTextThrottled } = this.props;
    if (onChangeTextThrottled) onChangeTextThrottled(value);
  }, 1000);

  componentDidUpdate(prevProps) {
    this.maybeFocusOnError(prevProps);
  }

  handleOnChangeText = value => {
    const { onChangeText } = this.props;
    if (onChangeText) onChangeText(value);
    this.handleOnChangeTextThrottled(value);
  };

  maybeFocusOnError(prevProps) {
    const doFocus =
      this.props.error != null &&
      // Simple trick not trick. Validation creates a new object, which we can
      // use to detect whether validation happen, therefore, focus this input.
      // Otherwise, we would have to expose input ref and maintain list of
      // focusable fields in form with switch with manual mapping... omg.
      this.props.focusOnError !== prevProps.focusOnError;
    if (!doFocus || !this.inputRef.current) return;
    this.inputRef.current.focus();
  }

  render() {
    const {
      disabled,
      label,
      error,
      size = 0,
      style,
      theme,
      focusOnError,
      placeholder,
      onChangeText,
      onChangeTextThrottled,
      ...props
    } = this.props;

    return (
      <View>
        {label != null && (
          <Text color="gray" size={size - 1}>
            {label}
          </Text>
        )}
        <TextInputNative
          disabled={disabled}
          placeholderTextColor={theme.placeholderTextColor}
          style={[
            theme.styles.textInput,
            theme.typography.fontSizeWithLineHeight(size),
            style,
          ]}
          ref={this.inputRef}
          placeholder={`${placeholder}…`}
          blurOnSubmit={false}
          onChangeText={this.handleOnChangeText}
          {...props}
        />
        <View style={theme.styles.textInputError}>
          <ErrorMessage size={size - 1} error={error} />
        </View>
      </View>
    );
  }
}

export default withTheme(TextInput);
<commit_msg>Export onChangeTextThrottle<commit_after>// @flow
import * as React from 'react';
import { View, TextInput as TextInputNative } from 'react-native';
import withTheme, { type Theme } from './withTheme';
import Text from './Text';
import type { TextStyleProp } from 'react-native/Libraries/StyleSheet/StyleSheet';
import ErrorMessage, { type MessageError } from './ErrorMessage';
import throttle from 'lodash/throttle';

export const onChangeTextThrottle = 1000;

export type TextInputProps = {|
  disabled?: boolean,
  label?: string | React.Element<any>,
  error?: ?MessageError,
  size?: number,
  style?: TextStyleProp,
  value?: string,
  focusOnError?: ?Object,
  secureTextEntry?: boolean,
  placeholder: string,
  onChangeText?: string => void,
  onChangeTextThrottled?: string => void,
  name?: string,
  keyboardType?: string,
  autoComplete?: string,
  onSubmitEditing?: () => void,
  defaultValue?: string,
  // Feel free to add any missing prop.
  // https://github.com/este/este/issues/1557
|};

// That's because TextInputProps is exported to reuse.
type TextInputPropsWithTheme = {|
  ...TextInputProps,
  theme: Theme,
|};

class TextInput extends React.PureComponent<TextInputPropsWithTheme> {
  inputRef = React.createRef();

  handleOnChangeTextThrottled = throttle(value => {
    const { onChangeTextThrottled } = this.props;
    if (onChangeTextThrottled) onChangeTextThrottled(value);
  }, onChangeTextThrottle);

  componentDidUpdate(prevProps) {
    this.maybeFocusOnError(prevProps);
  }

  handleOnChangeText = value => {
    const { onChangeText } = this.props;
    if (onChangeText) onChangeText(value);
    this.handleOnChangeTextThrottled(value);
  };

  maybeFocusOnError(prevProps) {
    const doFocus =
      this.props.error != null &&
      // Simple trick not trick. Validation creates a new object, which we can
      // use to detect whether validation happen, therefore, focus this input.
      // Otherwise, we would have to expose input ref and maintain list of
      // focusable fields in form with switch with manual mapping... omg.
      this.props.focusOnError !== prevProps.focusOnError;
    if (!doFocus || !this.inputRef.current) return;
    this.inputRef.current.focus();
  }

  render() {
    const {
      disabled,
      label,
      error,
      size = 0,
      style,
      theme,
      focusOnError,
      placeholder,
      onChangeText,
      onChangeTextThrottled,
      ...props
    } = this.props;

    return (
      <View>
        {label != null && (
          <Text color="gray" size={size - 1}>
            {label}
          </Text>
        )}
        <TextInputNative
          disabled={disabled}
          placeholderTextColor={theme.placeholderTextColor}
          style={[
            theme.styles.textInput,
            theme.typography.fontSizeWithLineHeight(size),
            style,
          ]}
          ref={this.inputRef}
          placeholder={`${placeholder}…`}
          blurOnSubmit={false}
          onChangeText={this.handleOnChangeText}
          {...props}
        />
        <View style={theme.styles.textInputError}>
          <ErrorMessage size={size - 1} error={error} />
        </View>
      </View>
    );
  }
}

export default withTheme(TextInput);
<|endoftext|>


<commit_before>var _ = require('lodash'),
    assert = require('assert');

describe('Association Interface', function() {

  describe('1:1 Association', function() {

    /////////////////////////////////////////////////////
    // TEST SETUP
    ////////////////////////////////////////////////////

    var users, profiles;

    before(function(done) {
      Associations.User_resource.createEach([{ name: 'foo1' }, { name: 'bar1' }], function(err, models) {
        if(err) return done(err);

        Associations.User_resource.find()
        .sort('id asc')
        .exec(function(err, models) {
          if(err) return done(err);

          users = models;

          var profileRecords = [
            { name: 'profile one', user: users[0].id },
            { name: 'profile two', user: users[1].id }
          ];

          Associations.Profile.createEach(profileRecords, function(err, models) {
            if(err) return done(err);

            Associations.User_resource.update({ name: 'foo1' }, { profile: models[0].id }).exec(function(err, user) {
              if(err) return done(err);

              Associations.User_resource.update({ name: 'bar1' }, { profile: models[1].id }).exec(function(err, user) {
                if(err) return done(err);
                profiles = models;
                done();
              });
            });
          });
        });
      });
    });

    describe('.find()', function() {

      /////////////////////////////////////////////////////
      // TEST METHODS
      ////////////////////////////////////////////////////

      it('should return user when the populate criteria is added on profile', function(done) {
        Associations.Profile.find()
        .sort('id asc')
        .populate('user')
        .exec(function(err, profiles) {
          assert(!err);

          assert(profiles[0].user);
          assert(profiles[1].user);

          assert(profiles[0].user.name === 'foo1');
          assert(profiles[1].user.name === 'bar1');

          done();
        });
      });

      it('should return profile when the populate criteria is added on user', function(done) {
        Associations.User_resource.find()
        .populate('profile')
        .sort('id asc')
        .exec(function(err, users) {
          assert(!err);

          assert(users[0].profile);
          assert(users[1].profile);

          assert(users[0].profile.name === 'profile one');
          assert(users[1].profile.name === 'profile two');

          done();
        });
      });

      it('should return a user object when the profile is undefined', function(done) {
        Associations.User_resource.create({ name: 'foobar', profile: undefined }).exec(function(err, usr) {
          assert(!err, err);

          Associations.User_resource.find({ name: 'foobar' })
          .populate('profile')
          .exec(function(err, users) {
            assert(!err);
            assert(users[0].name);
            assert(!users[0].profile, 'Expected `users[0].profile` to be falsy, but instead users[0] looks like ==> '+require('util').inspect(users[0], false, null));
            done();
          });
        });
      });

    });

  });
});
<commit_msg>Added test for https://github.com/balderdashy/sails/issues/2033<commit_after>var _ = require('lodash'),
    assert = require('assert');

describe('Association Interface', function() {

  describe('1:1 Association', function() {

    /////////////////////////////////////////////////////
    // TEST SETUP
    ////////////////////////////////////////////////////

    var users, profiles;

    before(function(done) {
      Associations.User_resource.createEach([{ name: 'foo1' }, { name: 'bar1' }], function(err, models) {
        if(err) return done(err);

        Associations.User_resource.find()
        .sort('id asc')
        .exec(function(err, models) {
          if(err) return done(err);

          users = models;

          var profileRecords = [
            { name: 'profile one', user: users[0].id },
            { name: 'profile two', user: users[1].id }
          ];

          Associations.Profile.createEach(profileRecords, function(err, models) {
            if(err) return done(err);

            Associations.User_resource.update({ name: 'foo1' }, { profile: models[0].id }).exec(function(err, user) {
              if(err) return done(err);

              Associations.User_resource.update({ name: 'bar1' }, { profile: models[1].id }).exec(function(err, user) {
                if(err) return done(err);
                profiles = models;
                done();
              });
            });
          });
        });
      });
    });

    describe('.find()', function() {

      /////////////////////////////////////////////////////
      // TEST METHODS
      ////////////////////////////////////////////////////

      it('should return user when the populate criteria is added on profile', function(done) {
        Associations.Profile.find()
        .sort('id asc')
        .populate('user')
        .exec(function(err, profiles) {
          assert(!err);

          assert(profiles[0].user);
          assert(profiles[1].user);

          assert(profiles[0].user.name === 'foo1');
          assert(profiles[1].user.name === 'bar1');

          done();
        });
      });

      it('should return profile when the populate criteria is added on user', function(done) {
        Associations.User_resource.find()
        .populate('profile')
        .sort('id asc')
        .exec(function(err, users) {
          assert(!err);

          assert(users[0].profile);
          assert(users[1].profile);

          assert(users[0].profile.name === 'profile one');
          assert(users[1].profile.name === 'profile two');

          done();
        });
      });

      it('should return a user object when the profile is undefined', function(done) {
        Associations.User_resource.create({ name: 'foobar', profile: undefined }).exec(function(err, usr) {
          assert(!err, err);

          Associations.User_resource.find({ name: 'foobar' })
          .populate('profile')
          .exec(function(err, users) {
            assert(!err);
            assert(users[0].name);
            assert(!users[0].profile, 'Expected `users[0].profile` to be falsy, but instead users[0] looks like ==> '+require('util').inspect(users[0], false, null));
            done();
          });
        });
      });

      it('should return undefined for profile when the profile is a non-existent foreign key', function(done) {
        Associations.User_resource.create({ name: 'foobar2', profile: "xyz123" }).exec(function(err, usr) {
          assert(!err, err);

          Associations.User_resource.find({ name: 'foobar2' })
          .populate('profile')
          .exec(function(err, users) {
            assert(!err);
            assert(users[0].name);
            assert(!users[0].profile, 'Expected `users[0].profile` to be falsy, but instead users[0] looks like ==> '+require('util').inspect(users[0], false, null));
            done();
          });
        });
      });

    });

  });
});
<|endoftext|>


<commit_before>var secondsSet, autoStart, currentSeconds = false;

// COUNTDOWN

function run(){
	countdown(secondsSet);
	chrome.browserAction.setIcon({path: '/icons/icon19_active.png'});
	console.log("starting countdown");
}

function stop(){
	try{
		clearInterval(timer);
	} catch(e){
		console.log("no timer defined..");
	}
	currentSeconds = false;
	clearNotification();
	chrome.browserAction.setIcon({path: '/icons/icon19.png'});
	console.log("stopping countdown");
}

function countdown(seconds) {
	currentSeconds = seconds;
	timer = setInterval(function() {
		if(currentSeconds >= 0) {
			console.log("seconds: " + currentSeconds);
			chrome.runtime.sendMessage({seconds: currentSeconds});
		} else {
			// clearInterval(timer);
			// currentSeconds = false;
			stop();
			createNotification();
			updateNotification();
		}
		currentSeconds--;
	}, 1000);
}

// NOTIFICATIONS

function buttonClicked(notId, button) { // buttonIndex: 0 = ok || 1 = shut up
	if (button == 0) {
		clearInterval(updateLoop);
		clearNotification();
		run();
	}
	else if (button == 1) {
		stop();
	}
}

function createNotification() {
	var opt = {
		type: "basic",
		title: "IT'S TIME TO DRINK!",
		message: "Drink some water now.",
		iconUrl: "../icons/popup_icon.png",
		priority: 2,
		buttons: [{
			title: "Ok, done. Restart."
		}, {
			title: "Shut up!"
		}]
	};
	chrome.notifications.create("popup", opt);
}

function updateNotification() { // update every 60 seconds
	updateLoop = setInterval(function() {
		chrome.notifications.update("popup", {priority: 0}, function() {
			chrome.notifications.update("popup", {priority: 2});
		});
		console.log("updated");
	}, 10000);
}

function clearNotification() { // clear all notifications
	chrome.notifications.getAll(function(cb) {
		for(var prop in cb){
			if(cb.hasOwnProperty(prop)) chrome.notifications.clear(prop);
		}
	});
}

// SYNC OPTIONS

function syncOptions() {
	chrome.storage.sync.get({secondsSet: '3600', autoStart: false}, function(options) {
		secondsSet = options.secondsSet;
		if(options.autoStart) run();
		console.log("seconds set: " + secondsSet);
		console.log("auto-start: " + options.autoStart);
	});
}

// LISTEN TO CONTENT

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
	if(request.Alarm == 'start') {
		run();
	} else if(request.Alarm == 'stop'){
		stop();
	} else if(request.Alarm == 'state') {
		sendResponse({seconds: currentSeconds});
	} else if(request.Options == 'saved') {
		syncOptions();
	}
})

// VERSION UPDATE NOTIFICATION

chrome.runtime.onInstalled.addListener(function(installed) {
	//console.log(installed);
	var version = chrome.runtime.getManifest().version
	if(installed.reason == "update") {
		var opt = {
			type: "basic",
			title: "Drink! Update",
			message: "Drink! has been updated to version " + version + ". Get full changelog on chrome webstore.",
			iconUrl: "../icons/popup_icon.png",
			priority: 1
		}
		chrome.notifications.create("update", opt);
	}
});

// ON LOAD

onload = function() {
	syncOptions();
	chrome.notifications.onButtonClicked.addListener(buttonClicked);
}<commit_msg>Update background.js<commit_after>var secondsSet, autoStart, currentSeconds = false;

// COUNTDOWN

function run(){
	countdown(secondsSet);
	chrome.browserAction.setIcon({path: '/icons/icon19_active.png'});
	console.log("starting countdown");
}

function stop(){
	try{
		clearInterval(timer);
	} catch(e){
		console.log("no timer defined..");
	}
	currentSeconds = false;
	clearNotification();
	chrome.browserAction.setIcon({path: '/icons/icon19.png'});
	console.log("stopping countdown");
}

function countdown(seconds) {
	currentSeconds = seconds;
	timer = setInterval(function() {
		if(currentSeconds >= 0) {
			console.log("seconds: " + currentSeconds);
			chrome.runtime.sendMessage({seconds: currentSeconds});
		} else {
			// clearInterval(timer);
			// currentSeconds = false;
			stop();
			createNotification();
			updateNotification();
		}
		currentSeconds--;
	}, 1000);
}

// NOTIFICATIONS

function buttonClicked(notId, button) { // buttonIndex: 0 = ok || 1 = shut up
	if (button == 0) {
		clearInterval(updateLoop);
		clearNotification();
		run();
	}
	else if (button == 1) {
		stop();
	}
}

function createNotification() {
	var opt = {
		type: "basic",
		title: "REALITY CHECK TIME!",
		message: "Can you push your thumb through your other hand.",
		iconUrl: "../icons/popup_icon.png",
		priority: 2,
		buttons: [{
			title: "Ok, done. Restart."
		}, {
			title: "Shut up!"
		}]
	};
	chrome.notifications.create("popup", opt);
}

function updateNotification() { // update every 60 seconds
	updateLoop = setInterval(function() {
		chrome.notifications.update("popup", {priority: 0}, function() {
			chrome.notifications.update("popup", {priority: 2});
		});
		console.log("updated");
	}, 10000);
}

function clearNotification() { // clear all notifications
	chrome.notifications.getAll(function(cb) {
		for(var prop in cb){
			if(cb.hasOwnProperty(prop)) chrome.notifications.clear(prop);
		}
	});
}

// SYNC OPTIONS

function syncOptions() {
	chrome.storage.sync.get({secondsSet: '3600', autoStart: false}, function(options) {
		secondsSet = options.secondsSet;
		if(options.autoStart) run();
		console.log("seconds set: " + secondsSet);
		console.log("auto-start: " + options.autoStart);
	});
}

// LISTEN TO CONTENT

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
	if(request.Alarm == 'start') {
		run();
	} else if(request.Alarm == 'stop'){
		stop();
	} else if(request.Alarm == 'state') {
		sendResponse({seconds: currentSeconds});
	} else if(request.Options == 'saved') {
		syncOptions();
	}
})

// VERSION UPDATE NOTIFICATION

chrome.runtime.onInstalled.addListener(function(installed) {
	//console.log(installed);
	var version = chrome.runtime.getManifest().version
	if(installed.reason == "update") {
		var opt = {
			type: "basic",
			title: "Lucid! Update",
			message: "Lucid! has been updated to version " + version + ". Get full changelog on chrome webstore.",
			iconUrl: "../icons/popup_icon.png",
			priority: 1
		}
		chrome.notifications.create("update", opt);
	}
});

// ON LOAD

onload = function() {
	syncOptions();
	chrome.notifications.onButtonClicked.addListener(buttonClicked);
}
<|endoftext|>


<commit_before>// JavaScript Document

var aCollege = new Array("生物科学技术学院", "资源环境学院", "动物科学技术学院", "农学院", "动物医学院", "园艺园林学院", "植物保护学院", "其他");
var aClass = new Array("sk_college", "zh_college", "dw_college", "nx_college", "dy_college", "yx_college", "zb_college", "other_college");
$(function() {
    var options = {
        width: 20,
        float: true,
        disableDrag: true,
        disableResize: true
    };
    $('.grid-stack').gridstack(options);
    /*获得基地------start*/
    $.ajax({ //页面加载时自动执行
        type: 'POST',
        dataType: 'json',
        url: 'getBase_deptInfo.do',
        async: false,
        cache: false,
        error: function(request) {
            bootbox.alert({
                message: "加载区域失败",
                size: 'small'
            });
        },
        success: function(data) {
            var i = 0;
            var array1 = data.base;
            var array2 = data.xy;
            var stime = data.stime;
            var etime = data.etime;
            if (stime == '' || etime == '') {
                bootbox.alert({
                    message: "土地租赁尚未开放，请等候通知",
                    size: 'small'
                });
                return false;
            }
            $('#stime').val(stime);
            $('#etime').val(etime);
            for (var item in array1) {
                $("#choose-gridh").after(
                    "<option value=" + array1[i].bid + ">" +
                    array1[i].bname + "</option>");
                i++;
            }
            i = 0;
            for (var item in array2) {
                $("#scollageh").after(
                    "<option value=" + array2[i].aid + ">" +
                    array2[i].dept + "</option>");
                i++;
            }
        }
    });

    var tu_zl = new function() {
            this.choose_count = 0;
            this.serializedData = []; //在loadGrid中构成布局对象，关联土地编号id
            this.dialog;
            this.grid = $('.grid-stack').data('gridstack');

            function fill(id, name, aptCollege, plantingContent, landArea, buildingArea, tudi_Afford, img) {
                $('#tudi_id').val(id);
                $('#tudi_name').val(name);
                $("#tudi_college").val(aCollege[aptCollege]);
                $('#tudi_plantingContent').val(plantingContent);
                $('#tudi_landArea').val(landArea);
                $('#tudi_buildingArea').val(buildingArea);
                $('#tudi_Afford').val(tudi_Afford);
                $('#imghead').prop("src", img);
            };

            function closeboxEX() {
                $('#land_lease_table').html('');
                tu_zl.loadGrid();
                tu_zl.dialog.modal('hide');
                $('#landModal').modal('hide');
            }

            function closebox() {
                tu_zl.dialog.modal('hide');
            }
            this.loadGrid = function() {
                var bid = $('#choose-grid').children('option:selected').val();
                var obj = this;
                fill('', '', '', '', '', '', '', '');
                $('#field_rent tbody').html('');
                this.grid.removeAll();
                var obj = this;
                if (bid == "") {
                    return;
                }
                $.ajax({
                    type: 'POST',
                    dataType: 'json',
                    data: {
                        "bid": bid
                    },
                    url: 'getRentCollection.do', ////修改此处服务器文件即可
                    async: false,
                    cache: false,
                    error: function(request) {
                        bootbox.alert({
                            message: "数据加载失败！",
                            size: 'small'
                        });
                    },
                    success: function(data) {
                            obj.serializedData = data;
                            var items = GridStackUI.Utils.sort(obj.serializedData);
                            _.each(items, function(node) {

                                if (node.name != '')
                                    obj.grid.addWidget($('

从事：' + node.planting + '' + node.name + '

'), node.x, node.y, node.width, node.height, false, 1, 4, 1, 4, node.id);
                                else if (node.tag == 1 && node.name == '') {
                                    obj.grid.addWidget($('

锁定：等候缴费' + node.name + '

'), node.x, node.y, node.width, node.height, false, 1, 4, 1, 4, node.id);
                                } else
                                    obj.grid.addWidget($('

<input type="checkbox" class="ck" id=' + node.id + ' value=' + node.id + '>' + node.lname + '' + node.lineup + '

'), node.x, node.y, node.width, node.height, false, 1, 4, 1, 4, node.id);
                            }, obj); //end each
                        } //end success
                }); //end ajax
            }.bind(this);

            this.savedate = function() {
                if (this.choose_count <= 0) {
                    bootbox.alert({
                        message: "您没有选择土地",
                        size: 'small'
                    });
                    return false;
                }
                var str = ' ';
                var plan;
                var landid;
                var userid = $.cookie("username"); ////////////此处需要修改
                if (userid == '' || userid == undefined) {
                    bootbox.alert({
                        message: "登录失效，请正返回首页",
                        size: 'small'
                    });
                    window.location.href = "../login_soft.html";
                }

                var stime = $('#stime').val();
                var etime = $('#etime').val();
                var lidList = '(';
                var bname = $('#choose-grid').children('option:selected').html(); //选中的基地编号
                var info_str = '[';

                for (var i = 1; i <= this.choose_count; i++) {
                    plan = $('#plan' + i).val();
                    xy = $('#scollage').val();
                    if (plan == '' || xy == '') {
                        bootbox.alert({
                            message: "从事工作和申报学院为必填项目",
                            size: 'small'
                        });
                        $('#plan' + i)[0].focus();
                        return false;
                    }
                    landid = $('#tuname' + i).attr('tid');
                    lidList = lidList + "'" + landid + "'";
                    if (i == 1) {
                        str = str + "('" + landid + "','" + stime + "','" + etime + "','" + plan + "','" + userid + "'," + xy;
                        info_str = info_str + '{userid:"' + userid + '",msg:"' + bname + '#' + landid + '"}';
                    } else {
                        str = str + "('" + landid + "','" + stime + "','" + etime + "','" + plan + "','" + userid + "'," + xy;
                        info_str = info_str + ',{userid:"' + userid + '",msg:"' + bname + '#' + landid + '"}';
                    }

                    if (i == this.choose_count) {
                        str = str + ",2)";
                        lidList = lidList + ")";
                    } else {
                        str = str + ",2),";
                        lidList = lidList + ",";
                    }
                }
                info_str = info_str + ']';
                userid = "'" + userid + "'";
                //end for
                // alert(str);////INSERT INTO tab_comp VALUES(item1, price1, qty1),(item2, price2, qty2),(item3, price3, qty3);批量插入语句
                var obj = this;
                $.ajax({ //以文本方式提交申请
                    type: 'POST',
                    dataType: 'text',
                    data: {
                        "str": str,
                        "info_str": info_str,
                        "lidList": lidList,
                        "userid": userid
                    },
                    url: 'submitLandApply.do', //修改
                    async: false,
                    cache: false,
                    error: function(request) {
                        obj.dialog = bootbox.alert({
                            message: "网络故障，请稍后重试",
                            size: 'small'
                        });
                    }, ///error
                    success: function(data) {
                            var position = data.indexOf('$');
                            var flag = data.substring(0, position);

                            if (flag != 1) {

                                bootbox.alert({
                                    message: "请先撤回相同的土地申请",
                                    size: 'small',
                                    title: "申请失败",
                                });

                            } else {

                                fill('', '', '', '', '', '', '', '');
                                $('#field_rent tbody').html('');
                                obj.dialog = bootbox.dialog({
                                    message: '
数据提交成功，正返回中......
',
                                    closeButton: false
                                });
                                window.setTimeout(closeboxEX, 1000);
                            }
                        } //success
                }); //ajax

            }.bind(this);
            ////滚轮缩放/////////////////////////////////////////
            $('#belowImg').on('mousewheel', function(event) {
                if (event.deltaY > 0) {
                    if ($('#belowImg').width() <= 1400){
                        $('#belowImg').width($('#gridmouse').width() + 100);
                        $('#belowImg').height($('#gridmouse').width());
                      }
                } else {
                    if ($('#belowImg').width() >= 868){
                        $('#belowImg').width($('#gridmouse').width() - 100);
                        $('#belowImg').height($('#gridmouse').width());
                      }
                }
                return false;
            });
            $(document).on("click", "#girdin", function() {
              if ($('#gridmouse').width() <= 1700)
                  $('#gridmouse').width($('#gridmouse').width() + 100);
            });
            $(document).on("click", "#girdout", function() {
              if ($('#gridmouse').width() >= 868)
                  $('#gridmouse').width($('#gridmouse').width() - 100);
            });
            $(document).on("click", ".grid-stack-item", function() {
                var id = $(this).attr('data-gs-id');
                var oBox = document.getElementById(id);
                oBox.click();
            }).bind(this);

            $(document).on("click", "#sum_app", function() {
                var i = 1;
                var str = '';
                var id = -1;
                var n = -1;
                $('#scollage').val("");
                $.each($('.ck'), function() {
                    if ($(this).is(':checked')) {
                        id = $(this).attr('id');
                        n = _.findIndex(tu_zl.serializedData, 'id', id);
                        str = str + '
\

\
					  土地租赁' + i + '：\
					  <input class="form-control" type="text" value=' + tu_zl.serializedData[n].lname + ' id="tuname' + i + '" tid=' + id + ' disabled>\

\

\

\

\
						推荐从事：\
						<input class="form-control" type="text" value="' + tu_zl.serializedData[n].plantingContent + '"  id="tplan' + i + '" disabled>\

\

\

\

\
					  申请从事：\
					  <input type="text" class="form-control" id="plan' + i + '" placeholder="必填从事项目">\

\

\

 '

                        i++;
                    } //end if
                }); //end each
                if (str == '') {
                    $('#sub_land_apply').attr('disabled', "true");
                    return false;
                }
                $('#land_lease_table').html(str);
                $('#sub_land_apply').removeAttr("disabled");
                tu_zl.choose_count = i - 1;
            });

            $(document).on("click", ".ck", function() {
                var id = $(this).attr('id');
                var n = _.findIndex(tu_zl.serializedData, 'id', id);
                if (tu_zl.serializedData[n].name != '') return false;
                if ($(this).is(':checked')) {
                    fill(id, tu_zl.serializedData[n].lname, tu_zl.serializedData[n].aptCollege, tu_zl.serializedData[n].plantingContent, tu_zl.serializedData[n].landArea, tu_zl.serializedData[n].buildingArea,
                        tu_zl.serializedData[n].afford, tu_zl.serializedData[n].img);
                    var testArray = tu_zl.serializedData[n].data;
                    var data = new Array();
                    i = 0;
                    _.map(testArray, function(el) {
                        data[i] = new Array();
                        data[i][0] = el.name;
                        data[i][1] = el.planting;
                        data[i][2] = el.ptime;
                        i++;
                    });
                    $('#field_rent').dataTable({
                        "destroy": true,
                        "data": data,
                        "paging": false,
                        "searching": false,
                        "ordering": false,
                        "info": false,
                        "order": [
                            [2, "asc"]
                        ]
                    });
                } else {
                    fill('', '', '', '', '', '', '', '');
                    $('#field_rent tbody').html('');
                }
            }); //end click

            $('#choose-grid').change(this.loadGrid);
            $('#sub_land_apply').click(this.savedate);
        } //end tu_zl

}); //end function

function displayImg() {

    var img = document.getElementById('belowImg');
    img.src = document.getElementById('imghead').src;

}
<commit_msg>租赁复选按钮修复，租赁界面文字截取<commit_after>// JavaScript Document

var aCollege = new Array("生物科学技术学院", "资源环境学院", "动物科学技术学院", "农学院", "动物医学院", "园艺园林学院", "植物保护学院", "其他");
var aClass = new Array("sk_college", "zh_college", "dw_college", "nx_college", "dy_college", "yx_college", "zb_college", "other_college");
$(function() {
    var options = {
        width: 20,
        float: true,
        disableDrag: true,
        disableResize: true
    };
    $('.grid-stack').gridstack(options);
    /*获得基地------start*/
    $.ajax({ //页面加载时自动执行
        type: 'POST',
        dataType: 'json',
        url: 'getBase_deptInfo.do',
        async: false,
        cache: false,
        error: function(request) {
            bootbox.alert({
                message: "加载区域失败",
                size: 'small'
            });
        },
        success: function(data) {
            var i = 0;
            var array1 = data.base;
            var array2 = data.xy;
            var stime = data.stime;
            var etime = data.etime;
            if (stime == '' || etime == '') {
                bootbox.alert({
                    message: "土地租赁尚未开放，请等候通知",
                    size: 'small'
                });
                return false;
            }
            $('#stime').val(stime);
            $('#etime').val(etime);
            for (var item in array1) {
                $("#choose-gridh").after(
                    "<option value=" + array1[i].bid + ">" +
                    array1[i].bname + "</option>");
                i++;
            }
            i = 0;
            for (var item in array2) {
                $("#scollageh").after(
                    "<option value=" + array2[i].aid + ">" +
                    array2[i].dept + "</option>");
                i++;
            }
        }
    });

    var tu_zl = new function() {
            this.choose_count = 0;
            this.serializedData = []; //在loadGrid中构成布局对象，关联土地编号id
            this.dialog;
            this.grid = $('.grid-stack').data('gridstack');

            function fill(id, name, aptCollege, plantingContent, landArea, buildingArea, tudi_Afford, img) {
                $('#tudi_id').val(id);
                $('#tudi_name').val(name);
                $("#tudi_college").val(aCollege[aptCollege]);
                $('#tudi_plantingContent').val(plantingContent);
                $('#tudi_landArea').val(landArea);
                $('#tudi_buildingArea').val(buildingArea);
                $('#tudi_Afford').val(tudi_Afford);
                $('#imghead').prop("src", img);
            };

            function closeboxEX() {
                $('#land_lease_table').html('');
                tu_zl.loadGrid();
                tu_zl.dialog.modal('hide');
                $('#landModal').modal('hide');
            }

            function closebox() {
                tu_zl.dialog.modal('hide');
            }
            function subString(str, len, hasDot)
            {
                var newLength = 0;
                var newStr = "";
                var chineseRegex = /[^\x00-\xff]/g;
                var singleChar = "";
                var strLength = str.replace(chineseRegex,"**").length;
                for(var i = 0;i < strLength;i++)
                {
                    singleChar = str.charAt(i).toString();
                    if(singleChar.match(chineseRegex) != null)
                    {
                        newLength += 2;
                    }
                    else
                    {
                        newLength++;
                    }
                    if(newLength > len)
                    {
                        break;
                    }
                    newStr += singleChar;
                }

                if(hasDot && strLength > len)
                {
                    newStr += "...";
                }
                return newStr;
            }

            this.loadGrid = function() {
                var bid = $('#choose-grid').children('option:selected').val();
                var obj = this;
                fill('', '', '', '', '', '', '', '');
                $('#field_rent tbody').html('');
                this.grid.removeAll();
                var obj = this;
                if (bid == "") {
                    return;
                }
                $.ajax({
                    type: 'POST',
                    dataType: 'json',
                    data: {
                        "bid": bid
                    },
                    url: 'getRentCollection.do', ////修改此处服务器文件即可
                    async: false,
                    cache: false,
                    error: function(request) {
                        bootbox.alert({
                            message: "数据加载失败！",
                            size: 'small'
                        });
                    },
                    success: function(data) {
                            obj.serializedData = data;
                            var items = GridStackUI.Utils.sort(obj.serializedData);
                            _.each(items, function(node) {

                                if (node.name != '')
                                    obj.grid.addWidget($('

从事：' + node.planting + '' + node.name + '

'), node.x, node.y, node.width, node.height, false, 1, 4, 1, 4, node.id);
                                else if (node.tag == 1 && node.name == '') {
                                    obj.grid.addWidget($('

锁定：等候缴费' + node.name + '

'), node.x, node.y, node.width, node.height, false, 1, 4, 1, 4, node.id);
                                } else
                                    obj.grid.addWidget($('

<input type="checkbox" class="ck" id=' + node.id + ' value=' + node.id + '>' + subString(node.lname,4) + '' + node.lineup + '

'), node.x, node.y, node.width, node.height, false, 1, 4, 1, 4, node.id);
                            }, obj); //end each
                        } //end success
                }); //end ajax
            }.bind(this);

            this.savedate = function() {
                if (this.choose_count <= 0) {
                    bootbox.alert({
                        message: "您没有选择土地",
                        size: 'small'
                    });
                    return false;
                }
                var str = ' ';
                var plan;
                var landid;
                var userid = $.cookie("username"); ////////////此处需要修改
                if (userid == '' || userid == undefined) {
                    bootbox.alert({
                        message: "登录失效，请正返回首页",
                        size: 'small'
                    });
                    window.location.href = "../login_soft.html";
                }

                var stime = $('#stime').val();
                var etime = $('#etime').val();
                var lidList = '(';
                var bname = $('#choose-grid').children('option:selected').html(); //选中的基地编号
                var info_str = '[';

                for (var i = 1; i <= this.choose_count; i++) {
                    plan = $('#plan' + i).val();
                    xy = $('#scollage').val();
                    if (plan == '' || xy == '') {
                        bootbox.alert({
                            message: "从事工作和申报学院为必填项目",
                            size: 'small'
                        });
                        $('#plan' + i)[0].focus();
                        return false;
                    }
                    landid = $('#tuname' + i).attr('tid');
                    lidList = lidList + "'" + landid + "'";
                    if (i == 1) {
                        str = str + "('" + landid + "','" + stime + "','" + etime + "','" + plan + "','" + userid + "'," + xy;
                        info_str = info_str + '{userid:"' + userid + '",msg:"' + bname + '#' + landid + '"}';
                    } else {
                        str = str + "('" + landid + "','" + stime + "','" + etime + "','" + plan + "','" + userid + "'," + xy;
                        info_str = info_str + ',{userid:"' + userid + '",msg:"' + bname + '#' + landid + '"}';
                    }

                    if (i == this.choose_count) {
                        str = str + ",2)";
                        lidList = lidList + ")";
                    } else {
                        str = str + ",2),";
                        lidList = lidList + ",";
                    }
                }
                info_str = info_str + ']';
                userid = "'" + userid + "'";
                //end for
                // alert(str);////INSERT INTO tab_comp VALUES(item1, price1, qty1),(item2, price2, qty2),(item3, price3, qty3);批量插入语句
                var obj = this;
                $.ajax({ //以文本方式提交申请
                    type: 'POST',
                    dataType: 'text',
                    data: {
                        "str": str,
                        "info_str": info_str,
                        "lidList": lidList,
                        "userid": userid
                    },
                    url: 'submitLandApply.do', //修改
                    async: false,
                    cache: false,
                    error: function(request) {
                        obj.dialog = bootbox.alert({
                            message: "网络故障，请稍后重试",
                            size: 'small'
                        });
                    }, ///error
                    success: function(data) {
                            var position = data.indexOf('$');
                            var flag = data.substring(0, position);

                            if (flag != 1) {

                                bootbox.alert({
                                    message: "请先撤回相同的土地申请",
                                    size: 'small',
                                    title: "申请失败",
                                });

                            } else {

                                fill('', '', '', '', '', '', '', '');
                                $('#field_rent tbody').html('');
                                obj.dialog = bootbox.dialog({
                                    message: '
数据提交成功，正返回中......
',
                                    closeButton: false
                                });
                                window.setTimeout(closeboxEX, 1000);
                            }
                        } //success
                }); //ajax

            }.bind(this);
            ////滚轮缩放/////////////////////////////////////////
            $('#belowImg').on('mousewheel', function(event) {
                if (event.deltaY > 0) {
                    if ($('#belowImg').width() <= 1400){
                        $('#belowImg').width($('#gridmouse').width() + 100);
                        $('#belowImg').height($('#gridmouse').width());
                      }
                } else {
                    if ($('#belowImg').width() >= 868){
                        $('#belowImg').width($('#gridmouse').width() - 100);
                        $('#belowImg').height($('#gridmouse').width());
                      }
                }
                return false;
            });
            $(document).on("click", "#girdin", function() {
              if ($('#gridmouse').width() <= 1700)
                  $('#gridmouse').width($('#gridmouse').width() + 100);
            });
            $(document).on("click", "#girdout", function() {
              if ($('#gridmouse').width() >= 868)
                  $('#gridmouse').width($('#gridmouse').width() - 100);
            });

            $(document).on("click", ".grid-stack-item", function() {
              //if(e.target.tagName=="INPUT")
                  //return;
                var id = $(this).attr('data-gs-id');
                //var oBox = document.getElementById(id);
                //oBox.click();
                var cvalue=$("#"+id).prop("checked");
                $("#"+id).prop("checked",!cvalue);

                var n = _.findIndex(tu_zl.serializedData, 'id', id);
                if (tu_zl.serializedData[n].name != '') return false;
                if (!cvalue) {
                    fill(id, tu_zl.serializedData[n].lname, tu_zl.serializedData[n].aptCollege, tu_zl.serializedData[n].plantingContent, tu_zl.serializedData[n].landArea, tu_zl.serializedData[n].buildingArea,
                        tu_zl.serializedData[n].afford, tu_zl.serializedData[n].img);
                    var testArray = tu_zl.serializedData[n].data;
                    var data = new Array();
                    i = 0;
                    _.map(testArray, function(el) {
                        data[i] = new Array();
                        data[i][0] = el.name;
                        data[i][1] = el.planting;
                        data[i][2] = el.ptime;
                        i++;
                    });
                    $('#field_rent').dataTable({
                        "destroy": true,
                        "data": data,
                        "paging": false,
                        "searching": false,
                        "ordering": false,
                        "info": false,
                        "order": [
                            [2, "asc"]
                        ]
                    });
                } else {
                    fill('', '', '', '', '', '', '', '');
                    $('#field_rent tbody').html('');
                }

            }).bind(this);

            $(document).on("click", "#sum_app", function() {
                var i = 1;
                var str = '';
                var id = -1;
                var n = -1;
                $('#scollage').val("");
                $.each($('.ck'), function() {
                    if ($(this).is(':checked')) {
                        id = $(this).attr('id');
                        n = _.findIndex(tu_zl.serializedData, 'id', id);
                        str = str + '
\

\
					  土地租赁' + i + '：\
					  <input class="form-control" type="text" value=' + tu_zl.serializedData[n].lname + ' id="tuname' + i + '" tid=' + id + ' disabled>\

\

\

\

\
						推荐从事：\
						<input class="form-control" type="text" value="' + tu_zl.serializedData[n].plantingContent + '"  id="tplan' + i + '" disabled>\

\

\

\

\
					  申请从事：\
					  <input type="text" class="form-control" id="plan' + i + '" placeholder="必填从事项目">\

\

\

 '

                        i++;
                    } //end if
                }); //end each
                if (str == '') {
                    $('#sub_land_apply').attr('disabled', "true");
                    return false;
                }
                $('#land_lease_table').html(str);
                $('#sub_land_apply').removeAttr("disabled");
                tu_zl.choose_count = i - 1;
            });

          /*  $(document).on("click", ".ck", function() {
                var id = $(this).attr('id');
                var n = _.findIndex(tu_zl.serializedData, 'id', id);
                if (tu_zl.serializedData[n].name != '') return false;
                if ($(this).is(':checked')) {
                    fill(id, tu_zl.serializedData[n].lname, tu_zl.serializedData[n].aptCollege, tu_zl.serializedData[n].plantingContent, tu_zl.serializedData[n].landArea, tu_zl.serializedData[n].buildingArea,
                        tu_zl.serializedData[n].afford, tu_zl.serializedData[n].img);
                    var testArray = tu_zl.serializedData[n].data;
                    var data = new Array();
                    i = 0;
                    _.map(testArray, function(el) {
                        data[i] = new Array();
                        data[i][0] = el.name;
                        data[i][1] = el.planting;
                        data[i][2] = el.ptime;
                        i++;
                    });
                    $('#field_rent').dataTable({
                        "destroy": true,
                        "data": data,
                        "paging": false,
                        "searching": false,
                        "ordering": false,
                        "info": false,
                        "order": [
                            [2, "asc"]
                        ]
                    });
                } else {
                    fill('', '', '', '', '', '', '', '');
                    $('#field_rent tbody').html('');
                }
            }); //end click*/

            $('#choose-grid').change(this.loadGrid);
            $('#sub_land_apply').click(this.savedate);
        } //end tu_zl

}); //end function

function displayImg() {

    var img = document.getElementById('belowImg');
    img.src = document.getElementById('imghead').src;

}
<|endoftext|>


<commit_before>/*
 * Chrome token signing extension
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

var NO_NATIVE_URL = "https://open-eid.github.io/chrome-token-signing/missing.html";
var HELLO_URL = "https://open-eid.github.io/chrome-token-signing/hello.html";
var DEVELOPER_URL = "https://github.com/open-eid/chrome-token-signing/wiki/DeveloperTips";

var NATIVE_HOST = "ee.ria.esteid";

var K_SRC = "src";
var K_ORIGIN = "origin";
var K_NONCE = "nonce";
var K_RESULT = "result";
var K_TAB = "tab";
var K_EXTENSION = "extension";

// Stores the longrunning ports per tab
// Used to route all request from a tab to the same host instance
var ports = {};

// Probed to false if host component is OK.
var missing = true;

console.log("Background page activated");

// XXX: probe test, because connectNative() does not allow to check the presence
// of native component for some reason
chrome.runtime.onStartup.addListener(function() {
	_testNativeComponent().then(function(result) {
		if (result === "ok") {
			missing = false;
		}
	});
});

// Force kill of native process
// Becasue Port.disconnect() does not work
function _killPort(tab) {
	if (tab in ports) {
		console.log("KILL " + tab);
		// Force killing with an empty message
		ports[tab].postMessage({});
	}
}

// Check if native implementation is OK resolves with "ok", "missing" or "forbidden"
function _testNativeComponent() {
	return new Promise(function(resolve, reject) {
		chrome.runtime.sendNativeMessage(NATIVE_HOST, {}, function(response) {
			if (!response) {
				console.log("TEST: ERROR " + JSON.stringify(chrome.runtime.lastError));
				// Try to be smart and do some string matching
				var permissions = "Access to the specified native messaging host is forbidden.";
				var missing = "Specified native messaging host not found.";
				if (chrome.runtime.lastError.message === permissions) {
					resolve("forbidden")
				} else if (chrome.runtime.lastError.message === missing) {
					resolve("missing");
				} else {
					resolve("missing");
				}
			} else {
				console.log("TEST: " + JSON.stringify(response));
				if (response["result"] === "invalid_argument") {
					resolve("ok");
				} else {
					resolve("missing"); // TODO: something better here
				}
			}
		});
	});
}

// When extension is installed, check for native component or direct to helping page
chrome.runtime.onInstalled.addListener(function(details) {
	if (details.reason === "install" || details.reason === "update") {
		_testNativeComponent().then(function(result) {
				var url = null;
				if (result === "ok" && details.reason === "install") {
					url = HELLO_URL;
				} else if (result === "forbidden") {
					url = DEVELOPER_URL;
				} else if (result === "missing"){
					url = NO_NATIVE_URL;
				}
				if (url) {
					chrome.tabs.create({'url': url + "?" + details.reason});
				}
		});
	}
});

// When message is received from page send it to native
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
	if(sender.id !== chrome.runtime.id) {
		console.log('WARNING: Ignoring message not from our extension');
		// Not our extension, do nothing
		return;
	}
	if (sender.tab) {
		// Check if page is DONE and close the native component without doing anything else
		if (request["type"] === "DONE") {
			console.log("DONE " + sender.tab.id);
			if (sender.tab.id in ports) {
				// FIXME: would want to use Port.disconnect() here
				_killPort(sender.tab.id);
			}
		} else {
			request[K_TAB] = sender.tab.id;
			if (missing)
				return _fail_with(request, "no_implementation");
			// TODO: Check if the URL is in allowed list or not
			// Either way forward to native currently
			_forward(request);
		}
	}
});

// Send the message back to the originating tab
function _reply(tab, msg) {
	msg[K_SRC] = "background.js";
	msg[K_EXTENSION] = chrome.app.getDetails().version;
	chrome.tabs.sendMessage(tab, msg);
}

// Fail an incoming message if the underlying implementation is not
// present
function _fail_with(msg, result) {
	var resp = {};
	resp[K_NONCE] = msg[K_NONCE];
	resp[K_RESULT] = result;
	_reply(msg[K_TAB], resp);
}

// Forward a message to the native component
function _forward(message) {
	var tabid = message[K_TAB];
	console.log("SEND " + tabid + ": " + JSON.stringify(message));
	// Open a port if necessary
	if(!ports[tabid]) {
		// For some reason there does not seem to be a way to detect missing components from longrunning ports
		// So we probe before opening a new port.
		console.log("OPEN " + tabid + ": " + NATIVE_HOST);
		// create a new port
		var port = chrome.runtime.connectNative(NATIVE_HOST);
		// XXX: does not indicate anything for some reason.
		if (!port) {
			console.log("OPEN ERROR: " + JSON.stringify(chrome.runtime.lastError));
		}
		port.onMessage.addListener(function(response) {
			if (response) {
				console.log("RECV "+tabid+": " + JSON.stringify(response));
				_reply(tabid, response);
			} else {
				console.log("ERROR "+tabid+": " + JSON.stringify(chrome.runtime.lastError));
				_fail_with(message, "technical_error");
			}
		});
		port.onDisconnect.addListener(function() {
			console.log("QUIT " + tabid);
			delete ports[tabid];
			// TODO: reject all pending promises for tab, if any
		});
		ports[tabid] = port;
		ports[tabid].postMessage(message);
	} else {
		// Port already open
		ports[tabid].postMessage(message);
	}
}
<commit_msg>Remove HELLO page for now.<commit_after>/*
 * Chrome token signing extension
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

var NO_NATIVE_URL = "https://open-eid.github.io/chrome-token-signing/missing.html";
var HELLO_URL = "https://open-eid.github.io/chrome-token-signing/hello.html";
var DEVELOPER_URL = "https://github.com/open-eid/chrome-token-signing/wiki/DeveloperTips";

var NATIVE_HOST = "ee.ria.esteid";

var K_SRC = "src";
var K_ORIGIN = "origin";
var K_NONCE = "nonce";
var K_RESULT = "result";
var K_TAB = "tab";
var K_EXTENSION = "extension";

// Stores the longrunning ports per tab
// Used to route all request from a tab to the same host instance
var ports = {};

// Probed to false if host component is OK.
var missing = true;

console.log("Background page activated");

// XXX: probe test, because connectNative() does not allow to check the presence
// of native component for some reason
chrome.runtime.onStartup.addListener(function() {
	_testNativeComponent().then(function(result) {
		if (result === "ok") {
			missing = false;
		}
	});
});

// Force kill of native process
// Becasue Port.disconnect() does not work
function _killPort(tab) {
	if (tab in ports) {
		console.log("KILL " + tab);
		// Force killing with an empty message
		ports[tab].postMessage({});
	}
}

// Check if native implementation is OK resolves with "ok", "missing" or "forbidden"
function _testNativeComponent() {
	return new Promise(function(resolve, reject) {
		chrome.runtime.sendNativeMessage(NATIVE_HOST, {}, function(response) {
			if (!response) {
				console.log("TEST: ERROR " + JSON.stringify(chrome.runtime.lastError));
				// Try to be smart and do some string matching
				var permissions = "Access to the specified native messaging host is forbidden.";
				var missing = "Specified native messaging host not found.";
				if (chrome.runtime.lastError.message === permissions) {
					resolve("forbidden")
				} else if (chrome.runtime.lastError.message === missing) {
					resolve("missing");
				} else {
					resolve("missing");
				}
			} else {
				console.log("TEST: " + JSON.stringify(response));
				if (response["result"] === "invalid_argument") {
					resolve("ok");
				} else {
					resolve("missing"); // TODO: something better here
				}
			}
		});
	});
}

// When extension is installed, check for native component or direct to helping page
chrome.runtime.onInstalled.addListener(function(details) {
	if (details.reason === "install" || details.reason === "update") {
		_testNativeComponent().then(function(result) {
				var url = null;
				if (result === "ok" && details.reason === "install") {
					// TODO: Add back HELLO pag on install
					// once there is a nice tutorial
					// url = HELLO_URL;
				} else if (result === "forbidden") {
					url = DEVELOPER_URL;
				} else if (result === "missing"){
					url = NO_NATIVE_URL;
				}
				if (url) {
					chrome.tabs.create({'url': url + "?" + details.reason});
				}
		});
	}
});

// When message is received from page send it to native
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
	if(sender.id !== chrome.runtime.id) {
		console.log('WARNING: Ignoring message not from our extension');
		// Not our extension, do nothing
		return;
	}
	if (sender.tab) {
		// Check if page is DONE and close the native component without doing anything else
		if (request["type"] === "DONE") {
			console.log("DONE " + sender.tab.id);
			if (sender.tab.id in ports) {
				// FIXME: would want to use Port.disconnect() here
				_killPort(sender.tab.id);
			}
		} else {
			request[K_TAB] = sender.tab.id;
			if (missing)
				return _fail_with(request, "no_implementation");
			// TODO: Check if the URL is in allowed list or not
			// Either way forward to native currently
			_forward(request);
		}
	}
});

// Send the message back to the originating tab
function _reply(tab, msg) {
	msg[K_SRC] = "background.js";
	msg[K_EXTENSION] = chrome.app.getDetails().version;
	chrome.tabs.sendMessage(tab, msg);
}

// Fail an incoming message if the underlying implementation is not
// present
function _fail_with(msg, result) {
	var resp = {};
	resp[K_NONCE] = msg[K_NONCE];
	resp[K_RESULT] = result;
	_reply(msg[K_TAB], resp);
}

// Forward a message to the native component
function _forward(message) {
	var tabid = message[K_TAB];
	console.log("SEND " + tabid + ": " + JSON.stringify(message));
	// Open a port if necessary
	if(!ports[tabid]) {
		// For some reason there does not seem to be a way to detect missing components from longrunning ports
		// So we probe before opening a new port.
		console.log("OPEN " + tabid + ": " + NATIVE_HOST);
		// create a new port
		var port = chrome.runtime.connectNative(NATIVE_HOST);
		// XXX: does not indicate anything for some reason.
		if (!port) {
			console.log("OPEN ERROR: " + JSON.stringify(chrome.runtime.lastError));
		}
		port.onMessage.addListener(function(response) {
			if (response) {
				console.log("RECV "+tabid+": " + JSON.stringify(response));
				_reply(tabid, response);
			} else {
				console.log("ERROR "+tabid+": " + JSON.stringify(chrome.runtime.lastError));
				_fail_with(message, "technical_error");
			}
		});
		port.onDisconnect.addListener(function() {
			console.log("QUIT " + tabid);
			delete ports[tabid];
			// TODO: reject all pending promises for tab, if any
		});
		ports[tabid] = port;
		ports[tabid].postMessage(message);
	} else {
		// Port already open
		ports[tabid].postMessage(message);
	}
}
<|endoftext|>


<commit_before>'use strict'

const webpack = require('webpack')

module.exports = {
  devtool: '#source-map',
  externals: ['cozy'],
  module: {
    loaders: [{
      test: require.resolve('cozy-bar/dist/cozy-bar.js'),
      loader: 'imports?css=./cozy-bar.css'
    }]
  },
  plugins: [
    new webpack.DefinePlugin({
      __SERVER__: JSON.stringify('http://app.cozy.local:8080'),
      __STACK_ASSETS__: false,
      __DEV__: true
    }),
    new webpack.ProvidePlugin({
      'cozy.client': 'cozy-client-js/dist/cozy-client.js',
      'cozy.bar': 'cozy-bar/dist/cozy-bar.js'
    })
  ]
}
<commit_msg>chore: quicker webpack incremental build time<commit_after>'use strict'

const webpack = require('webpack')

module.exports = {
  devtool: 'inline-eval-cheap-source-map',
  externals: ['cozy'],
  module: {
    loaders: [{
      test: require.resolve('cozy-bar/dist/cozy-bar.js'),
      loader: 'imports?css=./cozy-bar.css'
    }]
  },
  plugins: [
    new webpack.DefinePlugin({
      __SERVER__: JSON.stringify('http://app.cozy.local:8080'),
      __STACK_ASSETS__: false,
      __DEV__: true
    }),
    new webpack.ProvidePlugin({
      'cozy.client': 'cozy-client-js/dist/cozy-client.js',
      'cozy.bar': 'cozy-bar/dist/cozy-bar.js'
    })
  ]
}
<|endoftext|>


<commit_before>
angular.module('forms', [
	'duScroll', 'ngResource', 'NodeForm.templates', 'pascalprecht.translate',
	'angular-input-stars',
	'ui.select'
]);

angular.module('NodeForm', [
    'ui.select', 'cgBusy', 'ngSanitize', 'vButton', 'ngResource',
    'ui.router', 'ui.bootstrap', 'ui.utils', 'ngRaven', 'forms',
	'ui.select'
]);

angular.module('forms').factory('Auth', [
  function() {
    var service = {
      _currentUser: null,
      get currentUser(){
        return this._currentUser;
      },
      ensureHasCurrentUser: function() {
        return null;
      },
      isAuthenticated: function() {
        return false;
      },
      getUserState: function() {
        return '';
      },
      login: function() {
      },
      logout: function() {
      },
    };
    return service;
  }
]);
angular.module('forms').factory('$state', [function() {
    return {
        go: function() {}
    };
}]);
angular.module('forms').factory('myForm', ['Forms', function(Forms) {
    var form = window.form;
    form.visible_form_fields = _.filter(form.form_fields, function(field){
    	return (field.deletePreserved === false);
    });
    return form;
}]);
angular.module('forms').constant('FORM_URL', '/form/:formId');

angular.element(document).ready(function() {
	//Then init the app
	angular.bootstrap(document, ['forms']);
});
<commit_msg>reorder dependencies<commit_after>
angular.module('forms', [
	'duScroll', 'ngResource', 'NodeForm.templates', 'pascalprecht.translate',
	'angular-input-stars',
	'ui.select'
]);

angular.module('NodeForm', [
    'ui.select', 'cgBusy', 'ngSanitize', 'vButton', 'ngResource',
    'ui.router', 'ui.bootstrap', 'ui.utils', 'ngRaven', 'forms',
	'ui.select'
]);

angular.module('forms').factory('Auth', [
  function() {
    var service = {
      _currentUser: null,
      get currentUser(){
        return this._currentUser;
      },
      ensureHasCurrentUser: function() {
        return null;
      },
      isAuthenticated: function() {
        return false;
      },
      getUserState: function() {
        return '';
      },
      login: function() {
      },
      logout: function() {
      },
    };
    return service;
  }
]);
angular.module('forms').factory('$state', [function() {
    return {
        go: function() {}
    };
}]);
angular.module('forms').factory('myForm', ['Forms', function(Forms) {
    var form = window.form;
    form.visible_form_fields = _.filter(form.form_fields, function(field){
    	return (field.deletePreserved === false);
    });
    return form;
}]);
angular.module('forms').constant('FORM_URL', '/form/:formId');

angular.element(document).ready(function() {
	//Then init the app
	angular.bootstrap(document, ['forms']);
});
<|endoftext|>