<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import nest from 'recompose/nest';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { MuiThemeProvider } from 'material-ui/styles';
import { I18nextProvider } from 'react-i18next';
import { Provider as BusProvider } from 'react-bus';
import { Mobile, Desktop } from '../components/Responsive';
import ClockProvider from '../components/ClockProvider';
import { closeAll } from '../actions/OverlayActionCreators';
import {
  settingsSelector,
  languageSelector,
  themeSelector,
} from '../selectors/settingSelectors';
import { isConnectedSelector } from '../selectors/serverSelectors';
import DesktopApp from '../components/App';
import MobileApp from '../mobile/components/App';
import FatalError from '../components/FatalError';

const SimpleProviders = nest(BusProvider, ClockProvider);

const mapStateToProps = createStructuredSelector({
  activeOverlay: state => state.activeOverlay,
  isConnected: isConnectedSelector,
  settings: settingsSelector,
  language: languageSelector,
  theme: themeSelector,
  hasAboutPage: (state, props) => (
    props.uwave.getAboutPageComponent() !== null
  ),
});

const mapDispatchToProps = {
  onCloseOverlay: closeAll,
};

const enhance = connect(mapStateToProps, mapDispatchToProps);

class AppContainer extends React.Component {
  static propTypes = {
    mediaSources: PropTypes.object.isRequired,
    uwave: PropTypes.object,
    language: PropTypes.string,
    theme: PropTypes.object,
    locale: PropTypes.object.isRequired,
  };

  static childContextTypes = {
    mediaSources: PropTypes.object,
    uwave: PropTypes.object,
  };

  state = {
    error: null,
  };

  getChildContext() {
    return {
      mediaSources: this.props.mediaSources,
      uwave: this.props.uwave,
    };
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.language !== nextProps.language) {
      this.props.locale.changeLanguage(nextProps.language);
    }
  }

  componentDidCatch(error) {
    this.setState({ error });
  }

  renderApp = () => (
    <React.Fragment>
      <Mobile>
        <MobileApp {...this.props} />
      </Mobile>
      <Desktop>
        <DesktopApp {...this.props} />
      </Desktop>
    </React.Fragment>
  );

  render() {
    if (this.state.error) {
      // Let's hope the ThemeProvider works at least...
      return (
        <MuiThemeProvider theme={this.props.theme}>
          <FatalError error={this.state.error} />
        </MuiThemeProvider>
      );
    }

    return (
      <MuiThemeProvider theme={this.props.theme}>
        <I18nextProvider i18n={this.props.locale}>
          <SimpleProviders>
            {this.renderApp()}
          </SimpleProviders>
        </I18nextProvider>
      </MuiThemeProvider>
    );
  }
}

export default enhance(AppContainer);
<commit_msg>[WLK-INSTANCE] Report to bugsnag in error boundary.<commit_after>/* global bugsnag */
import React from 'react';
import PropTypes from 'prop-types';
import nest from 'recompose/nest';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { MuiThemeProvider } from 'material-ui/styles';
import { I18nextProvider } from 'react-i18next';
import { Provider as BusProvider } from 'react-bus';
import { Mobile, Desktop } from '../components/Responsive';
import ClockProvider from '../components/ClockProvider';
import { closeAll } from '../actions/OverlayActionCreators';
import {
  settingsSelector,
  languageSelector,
  themeSelector,
} from '../selectors/settingSelectors';
import { isConnectedSelector } from '../selectors/serverSelectors';
import DesktopApp from '../components/App';
import MobileApp from '../mobile/components/App';
import FatalError from '../components/FatalError';

const SimpleProviders = nest(BusProvider, ClockProvider);

const mapStateToProps = createStructuredSelector({
  activeOverlay: state => state.activeOverlay,
  isConnected: isConnectedSelector,
  settings: settingsSelector,
  language: languageSelector,
  theme: themeSelector,
  hasAboutPage: (state, props) => (
    props.uwave.getAboutPageComponent() !== null
  ),
});

const mapDispatchToProps = {
  onCloseOverlay: closeAll,
};

const enhance = connect(mapStateToProps, mapDispatchToProps);

class AppContainer extends React.Component {
  static propTypes = {
    mediaSources: PropTypes.object.isRequired,
    uwave: PropTypes.object,
    language: PropTypes.string,
    theme: PropTypes.object,
    locale: PropTypes.object.isRequired,
  };

  static childContextTypes = {
    mediaSources: PropTypes.object,
    uwave: PropTypes.object,
  };

  state = {
    error: null,
  };

  getChildContext() {
    return {
      mediaSources: this.props.mediaSources,
      uwave: this.props.uwave,
    };
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.language !== nextProps.language) {
      this.props.locale.changeLanguage(nextProps.language);
    }
  }

  componentDidCatch(error, info) {
    this.setState({ error });

    bugsnag.notify(error, {
      metaData: {
        componentStack: info.componentStack,
      },
    });
  }

  renderApp = () => (
    <React.Fragment>
      <Mobile>
        <MobileApp {...this.props} />
      </Mobile>
      <Desktop>
        <DesktopApp {...this.props} />
      </Desktop>
    </React.Fragment>
  );

  render() {
    if (this.state.error) {
      // Let's hope the ThemeProvider works at least...
      return (
        <MuiThemeProvider theme={this.props.theme}>
          <FatalError error={this.state.error} />
        </MuiThemeProvider>
      );
    }

    return (
      <MuiThemeProvider theme={this.props.theme}>
        <I18nextProvider i18n={this.props.locale}>
          <SimpleProviders>
            {this.renderApp()}
          </SimpleProviders>
        </I18nextProvider>
      </MuiThemeProvider>
    );
  }
}

export default enhance(AppContainer);
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

import * as TracksActions from '../actions/tracks';
import * as TrackActions from '../actions/track';
import * as MeasureActions from '../actions/measure';
import * as PlayingIndexActions from '../actions/playingIndex';
import * as CursorActions from '../actions/cursor';

import Soundfont from 'soundfont-player';
import audioContext from '../util/audioContext';

import TabStaff from '../components/TabStaff';
import EditorArea from '../components/editor/EditorArea';
import TimeSignatureModal from '../components/editor/TimeSignatureModal';
import TuningModal from '../components/editor/TuningModal';
import BpmModal from '../components/editor/BpmModal';
import Playback from '../components/Playback';
import Metronome from '../components/Metronome';

const Actions = Object.assign(TracksActions, TrackActions, MeasureActions, PlayingIndexActions, CursorActions);

class App extends Component {
  constructor(props) {
    super(props);

    if (typeof window !== 'undefined') {
      window.addEventListener('keydown', this.handleKeyPress);
      window.addEventListener('resize', this.handleResize);
    }

    this.state = {
      openModal: null
    };
  }

  componentWillMount() {
    this.loadSoundfont(this.props.instrument);
  }

  componentWillReceiveProps(nextProps) {
    const { playingIndex } = nextProps;

    if(this.props.playingIndex && playingIndex) {
      if(playingIndex.noteIndex !== this.props.playingIndex.noteIndex
          || playingIndex.measureIndex !== this.props.playingIndex.measureIndex) {
        this.updateScrollPosition(nextProps.playingIndex, nextProps.measures);
      }
    } else if(this.props.instrument !== nextProps.instrument) {
      this.loadSoundfont(nextProps.instrument);
    }
  }

  loadSoundfont = (instrument) => {
    Soundfont.loadBuffers(audioContext, instrument).then((buffers) => {
      this.setState({
        buffers: Object.assign({}, this.state.buffers, { [instrument]: buffers })
      });
    });

    Soundfont.loadBuffers(audioContext, 'woodblock').then((woodblockBuffers) => {
      this.setState({ woodblockBuffers });
    });
  };

  handleResize = () => {
    this.props.actions.resize();
  };

  getXOfCurrentNote = (playingIndex, measures) => {
    const { measureIndex, noteIndex } = playingIndex;
    const xOfMeasures = measures.reduce((acc, curr, i) => {
      if(i >= measureIndex) {
        return acc;
      }
      return acc + curr.width;
    }, 0);

    return xOfMeasures + 55 * noteIndex;
  };

  getYOfCurrentNote = (playingIndex, measures) => {
    const position = measures[playingIndex.measureIndex];
    return (position.rowIndex) * (27 * this.props.tuning.length) + 50;
  };

  updateScrollPosition = (playingIndex, measures) => {
    if(this.props.layout === 'linear') {
      const x = this.getXOfCurrentNote(playingIndex, measures);
      const { scrollX, innerWidth } = window;

      if(x > innerWidth + scrollX - 200) {
        window.scroll(x - 200, 0);
      }
    } else {
      const y = this.getYOfCurrentNote(playingIndex, measures);
      const { innerHeight, scrollY } = window;

      if(y > innerHeight + scrollY - 270) {
        window.scroll(0, y - 100);
      }
    }
  };

  handleStop = () => {
    this.props.actions.setCursor({
      measureIndex: this.props.playingIndex.measureIndex,
      noteIndex: this.props.playingIndex.noteIndex,
      stringIndex: this.props.cursor.stringIndex
    });
    this.props.actions.setPlayingIndex(null);
  };

  handlePlay = () => {
    if(this.props.playingIndex || !this.state.buffers) {
      return;
    }

    const { noteIndex, measureIndex } = this.props.cursor;

    this.props.actions.setPlayingIndex({
      measureIndex,
      noteIndex
    });
  };

  getCurrentNote = () => {
    const { measures } = this.props;
    const { measureIndex, noteIndex } = this.props.cursor;

    return measures[measureIndex].notes[noteIndex];
  };

  navigateCursor = (event) => {
    event.preventDefault();
    if(event.keyCode === 39) { // right arrow
      const { measures } = this.props;
      const { measureIndex, noteIndex } = this.props.cursor;
      if(measureIndex === measures.length - 1 &&
        (noteIndex === measures[measureIndex].notes.length - 1 || measures[measureIndex].notes.length === 0)
      ) {
        this.props.actions.insertMeasure();
      }
      this.props.actions.moveCursorRight();
    } else if(event.keyCode === 37) { // left arrow
      this.props.actions.moveCursorLeft();
    } else if(event.keyCode === 38) { // up arrow
      this.props.actions.moveCursorUp();
    } else if(event.keyCode === 40) { // down arrow
      this.props.actions.moveCursorDown();
    }
  };

  deleteNote = () => {
    const { measureIndex } = this.props.cursor;
    let notes = this.props.measures[measureIndex].notes;

    if(notes.length > 0) {
      this.props.actions.deleteNote(this.props.cursor);
    } else if(notes.length === 0) {
      this.props.actions.deleteMeasure(measureIndex);
    }
  };

  pasteNote = () => {
    if(this.props.clipboard) {
      event.preventDefault();
      this.props.actions.pasteNote(this.props.cursor, this.props.clipboard);
    }
  };

  handleKeyPress = (event) => {
    if(this.state.openModal || (this.props.playingIndex && event.keyCode !== 32)) {
      return;
    }

    if((event.metaKey || event.ctrlKey) && event.keyCode === 67) { // cmd/ctrl+c
      event.preventDefault();
      return this.props.actions.copyNote(this.getCurrentNote());
    }
    if((event.metaKey || event.ctrlKey) && event.keyCode === 86) { // cmd/ctrl+v
      return this.pasteNote();
    }
    if((event.metaKey || event.ctrlKey) && event.keyCode === 88) { // cmd/ctrl+x
      event.preventDefault();
      this.props.actions.cutNote(this.props.cursor, this.getCurrentNote());
    }

    if(event.keyCode <= 57 && event.keyCode >= 48 && !event.metaKey) {
      return this.props.actions.changeNote(this.props.cursor, event.keyCode - 48);
    } else if(event.keyCode === 82 && !event.metaKey && !event.ctrlKey) {
      this.props.actions.changeNote(this.props.cursor, 'rest');
    } else if(event.keyCode === 8) { // delete
      event.preventDefault();
      this.deleteNote();
    } else if(event.keyCode === 73 && !event.metaKey) { // i
      return this.props.actions.insertNote(this.props.cursor);
    } else if(event.keyCode === 32) { // spacebar
      event.preventDefault();
      return this.props.playingIndex ? this.handleStop() : this.handlePlay();
    } else if(event.keyCode === 190) { // period
      this.props.actions.toggleNoteDotted(this.props.cursor);
    } else if(event.shiftKey && event.keyCode === 187) { // plus
      return this.props.actions.increaseNoteLength(this.props.cursor);
    } else if(event.keyCode === 189) { // minus
      return this.props.actions.decreaseNoteLength(this.props.cursor);
    } else if(event.shiftKey && event.keyCode === 222) { // "
      this.props.actions.toggleNoteTremolo(this.props.cursor);
    } else if(event.keyCode === 86) { // v
      this.props.actions.toggleNoteVibrato(this.props.cursor);
    } else if(event.shiftKey && event.keyCode === 78) { // N
      this.props.actions.toggleNoteTrill(this.props.cursor);
    } else if(event.keyCode >= 37 && event.keyCode <= 40) {
      return this.navigateCursor(event);
    }
  };

  openModal = (openModal) => {
    this.setState({ openModal });
  };

  closeModal = () => {
    this.setState({ openModal: null });
  };

  render() {
    const { openModal, buffers, woodblockBuffers } = this.state;

    return (

        { this.props.playingIndex ? <Playback buffers={buffers} /> : null}
        { this.props.playingIndex && this.props.metronome ? <Metronome buffers={woodblockBuffers} /> : null}
        <EditorArea handlePlay={this.handlePlay} openModal={this.openModal} />
        <TabStaff />
        <TimeSignatureModal isOpen={openModal === 'timeSig'} closeModal={this.closeModal} />
        <TuningModal isOpen={openModal === 'tuning'} closeModal={this.closeModal} />
        <BpmModal isOpen={openModal === 'bpm'} closeModal={this.closeModal} />

    );
  }
}

function mapStateToProps(state) {
  return {
    measures: state.tracks[state.currentTrackIndex].measures,
    clipboard: state.clipboard,
    layout: state.layout,
    playingIndex: state.playingIndex,
    cursor: state.cursor,
    tuning: state.tracks[state.currentTrackIndex].tuning,
    instrument: state.tracks[state.currentTrackIndex].instrument,
    metronome: state.metronome
  };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(Actions, dispatch)
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(App);
<commit_msg>fix playback for Safari by falling back to mp3<commit_after>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

import * as TracksActions from '../actions/tracks';
import * as TrackActions from '../actions/track';
import * as MeasureActions from '../actions/measure';
import * as PlayingIndexActions from '../actions/playingIndex';
import * as CursorActions from '../actions/cursor';

import Soundfont from 'soundfont-player';
import audioContext from '../util/audioContext';

import TabStaff from '../components/TabStaff';
import EditorArea from '../components/editor/EditorArea';
import TimeSignatureModal from '../components/editor/TimeSignatureModal';
import TuningModal from '../components/editor/TuningModal';
import BpmModal from '../components/editor/BpmModal';
import Playback from '../components/Playback';
import Metronome from '../components/Metronome';

// Fix for Safari, which can't play .ogg files
if(!!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/)) {
  Soundfont.nameToUrl = function(name) {
    return `https://cdn.rawgit.com/gleitz/midi-js-Soundfonts/master/FluidR3_GM/${name}-mp3.js`;
  };
}

const Actions = Object.assign(TracksActions, TrackActions, MeasureActions, PlayingIndexActions, CursorActions);

class App extends Component {
  constructor(props) {
    super(props);

    if (typeof window !== 'undefined') {
      window.addEventListener('keydown', this.handleKeyPress);
      window.addEventListener('resize', this.handleResize);
    }

    this.state = {
      openModal: null
    };
  }

  componentWillMount() {
    this.loadSoundfont(this.props.instrument);
  }

  componentWillReceiveProps(nextProps) {
    const { playingIndex } = nextProps;

    if(this.props.playingIndex && playingIndex) {
      if(playingIndex.noteIndex !== this.props.playingIndex.noteIndex
          || playingIndex.measureIndex !== this.props.playingIndex.measureIndex) {
        this.updateScrollPosition(nextProps.playingIndex, nextProps.measures);
      }
    } else if(this.props.instrument !== nextProps.instrument) {
      this.loadSoundfont(nextProps.instrument);
    }
  }

  loadSoundfont = (instrument) => {
    Soundfont.loadBuffers(audioContext, instrument).then((buffers) => {
      this.setState({
        buffers: Object.assign({}, this.state.buffers, { [instrument]: buffers })
      });
    });

    Soundfont.loadBuffers(audioContext, 'woodblock').then((woodblockBuffers) => {
      this.setState({ woodblockBuffers });
    });
  };

  handleResize = () => {
    this.props.actions.resize();
  };

  getXOfCurrentNote = (playingIndex, measures) => {
    const { measureIndex, noteIndex } = playingIndex;
    const xOfMeasures = measures.reduce((acc, curr, i) => {
      if(i >= measureIndex) {
        return acc;
      }
      return acc + curr.width;
    }, 0);

    return xOfMeasures + 55 * noteIndex;
  };

  getYOfCurrentNote = (playingIndex, measures) => {
    const position = measures[playingIndex.measureIndex];
    return (position.rowIndex) * (27 * this.props.tuning.length) + 50;
  };

  updateScrollPosition = (playingIndex, measures) => {
    if(this.props.layout === 'linear') {
      const x = this.getXOfCurrentNote(playingIndex, measures);
      const { scrollX, innerWidth } = window;

      if(x > innerWidth + scrollX - 200) {
        window.scroll(x - 200, 0);
      }
    } else {
      const y = this.getYOfCurrentNote(playingIndex, measures);
      const { innerHeight, scrollY } = window;

      if(y > innerHeight + scrollY - 270) {
        window.scroll(0, y - 100);
      }
    }
  };

  handleStop = () => {
    this.props.actions.setCursor({
      measureIndex: this.props.playingIndex.measureIndex,
      noteIndex: this.props.playingIndex.noteIndex,
      stringIndex: this.props.cursor.stringIndex
    });
    this.props.actions.setPlayingIndex(null);
  };

  handlePlay = () => {
    if(this.props.playingIndex || !this.state.buffers) {
      return;
    }

    const { noteIndex, measureIndex } = this.props.cursor;

    this.props.actions.setPlayingIndex({
      measureIndex,
      noteIndex
    });
  };

  getCurrentNote = () => {
    const { measures } = this.props;
    const { measureIndex, noteIndex } = this.props.cursor;

    return measures[measureIndex].notes[noteIndex];
  };

  navigateCursor = (event) => {
    event.preventDefault();
    if(event.keyCode === 39) { // right arrow
      const { measures } = this.props;
      const { measureIndex, noteIndex } = this.props.cursor;
      if(measureIndex === measures.length - 1 &&
        (noteIndex === measures[measureIndex].notes.length - 1 || measures[measureIndex].notes.length === 0)
      ) {
        this.props.actions.insertMeasure();
      }
      this.props.actions.moveCursorRight();
    } else if(event.keyCode === 37) { // left arrow
      this.props.actions.moveCursorLeft();
    } else if(event.keyCode === 38) { // up arrow
      this.props.actions.moveCursorUp();
    } else if(event.keyCode === 40) { // down arrow
      this.props.actions.moveCursorDown();
    }
  };

  deleteNote = () => {
    const { measureIndex } = this.props.cursor;
    let notes = this.props.measures[measureIndex].notes;

    if(notes.length > 0) {
      this.props.actions.deleteNote(this.props.cursor);
    } else if(notes.length === 0) {
      this.props.actions.deleteMeasure(measureIndex);
    }
  };

  pasteNote = () => {
    if(this.props.clipboard) {
      event.preventDefault();
      this.props.actions.pasteNote(this.props.cursor, this.props.clipboard);
    }
  };

  handleKeyPress = (event) => {
    if(this.state.openModal || (this.props.playingIndex && event.keyCode !== 32)) {
      return;
    }

    if((event.metaKey || event.ctrlKey) && event.keyCode === 67) { // cmd/ctrl+c
      event.preventDefault();
      return this.props.actions.copyNote(this.getCurrentNote());
    }
    if((event.metaKey || event.ctrlKey) && event.keyCode === 86) { // cmd/ctrl+v
      return this.pasteNote();
    }
    if((event.metaKey || event.ctrlKey) && event.keyCode === 88) { // cmd/ctrl+x
      event.preventDefault();
      this.props.actions.cutNote(this.props.cursor, this.getCurrentNote());
    }

    if(event.keyCode <= 57 && event.keyCode >= 48 && !event.metaKey) {
      return this.props.actions.changeNote(this.props.cursor, event.keyCode - 48);
    } else if(event.keyCode === 82 && !event.metaKey && !event.ctrlKey) {
      this.props.actions.changeNote(this.props.cursor, 'rest');
    } else if(event.keyCode === 8) { // delete
      event.preventDefault();
      this.deleteNote();
    } else if(event.keyCode === 73 && !event.metaKey) { // i
      return this.props.actions.insertNote(this.props.cursor);
    } else if(event.keyCode === 32) { // spacebar
      event.preventDefault();
      return this.props.playingIndex ? this.handleStop() : this.handlePlay();
    } else if(event.keyCode === 190) { // period
      this.props.actions.toggleNoteDotted(this.props.cursor);
    } else if(event.shiftKey && event.keyCode === 187) { // plus
      return this.props.actions.increaseNoteLength(this.props.cursor);
    } else if(event.keyCode === 189) { // minus
      return this.props.actions.decreaseNoteLength(this.props.cursor);
    } else if(event.shiftKey && event.keyCode === 222) { // "
      this.props.actions.toggleNoteTremolo(this.props.cursor);
    } else if(event.keyCode === 86) { // v
      this.props.actions.toggleNoteVibrato(this.props.cursor);
    } else if(event.shiftKey && event.keyCode === 78) { // N
      this.props.actions.toggleNoteTrill(this.props.cursor);
    } else if(event.keyCode >= 37 && event.keyCode <= 40) {
      return this.navigateCursor(event);
    }
  };

  openModal = (openModal) => {
    this.setState({ openModal });
  };

  closeModal = () => {
    this.setState({ openModal: null });
  };

  render() {
    const { openModal, buffers, woodblockBuffers } = this.state;

    return (

        { this.props.playingIndex ? <Playback buffers={buffers} /> : null}
        { this.props.playingIndex && this.props.metronome ? <Metronome buffers={woodblockBuffers} /> : null}
        <EditorArea handlePlay={this.handlePlay} openModal={this.openModal} />
        <TabStaff />
        <TimeSignatureModal isOpen={openModal === 'timeSig'} closeModal={this.closeModal} />
        <TuningModal isOpen={openModal === 'tuning'} closeModal={this.closeModal} />
        <BpmModal isOpen={openModal === 'bpm'} closeModal={this.closeModal} />

    );
  }
}

function mapStateToProps(state) {
  return {
    measures: state.tracks[state.currentTrackIndex].measures,
    clipboard: state.clipboard,
    layout: state.layout,
    playingIndex: state.playingIndex,
    cursor: state.cursor,
    tuning: state.tracks[state.currentTrackIndex].tuning,
    instrument: state.tracks[state.currentTrackIndex].instrument,
    metronome: state.metronome
  };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(Actions, dispatch)
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(App);
<|endoftext|>


<commit_before>import React from 'react'
import cx from 'classnames'
import { prefetch } from 'react-fetcher'
import { connect } from 'react-redux'
import { find } from 'lodash'
import TopNav from '../components/TopNav'
import Search from '../components/Search'
import Icon from '../components/Icon'
import { LeftNav, leftNavWidth, leftNavEasing } from '../components/LeftNav'
import Notifier from '../components/Notifier'
import LiveStatusPoller from '../components/LiveStatusPoller'
import PageTitleController from '../components/PageTitleController'
import { logout, navigate, removeNotification, toggleMainMenu, updateUserSettings } from '../actions'
import { makeUrl } from '../client/util'
import { VelocityComponent } from 'velocity-react'
import { canInvite, canModerate } from '../models/currentUser'
import { get, pick } from 'lodash'
import { matchEditorUrl } from './StandalonePostEditor'
const { array, bool, func, object, string } = React.PropTypes

@prefetch(({ store, dispatch }) => {
  const { isMobile, people } = store.getState()
  if (!isMobile && typeof window === 'undefined' &&
    get(people.current, 'settings.leftNavIsOpen')) {
    return dispatch(toggleMainMenu())
  }
})
@connect((state, { params: { id } }) => {
  const { isMobile, leftNavIsOpen, notifierMessages } = state
  const currentUser = state.people.current
  const community = find(state.communities, c => c.id === state.currentCommunityId)
  const tags = community ? state.tagsByCommunity[community.slug] : {}

  return {
    isMobile,
    leftNavIsOpen,
    notifierMessages,
    currentUser,
    community,
    tags,
    path: state.routing.path
  }
})
export default class App extends React.Component {
  static propTypes = {
    children: object,
    community: object,
    currentUser: object,
    leftNavIsOpen: bool,
    tags: object,
    notifierMessages: array,
    path: string,
    dispatch: func,
    isMobile: bool
  }

  static childContextTypes = {
    dispatch: func,
    currentUser: object
  }

  getChildContext () {
    return pick(this.props, 'dispatch', 'currentUser')
  }

  render () {
    const {
      children, community, currentUser, dispatch, tags,
      leftNavIsOpen, notifierMessages, isMobile
    } = this.props

    const path = this.props.path.split('?')[0]
    const hideTopNav = matchEditorUrl(path)

    const moveWithMenu = {marginLeft: leftNavIsOpen ? leftNavWidth : 0}
    const toggleLeftNav = open => {
      if (leftNavIsOpen !== open) dispatch(toggleMainMenu())
      if (!isMobile) {
        setTimeout(() => {
          const settings = {leftNavIsOpen: open}
          dispatch(updateUserSettings(currentUser.id, {settings}))
        }, 1000)
      }
    }
    const openLeftNav = () => toggleLeftNav(true)
    const closeLeftNav = () => toggleLeftNav(false)
    const doSearch = text => dispatch(navigate(makeUrl('/search', {q: text})))
    const visitCommunity = community =>
      dispatch(navigate(nextPath(path, community)))

    return

      <LeftNav opened={leftNavIsOpen}
        community={community}
        tags={tags}
        canModerate={canModerate(currentUser, community)}
        canInvite={canInvite(currentUser, community)}
        close={closeLeftNav}/>

      <VelocityComponent animation={moveWithMenu} easing={leftNavEasing}>

          {!hideTopNav && <TopNav currentUser={currentUser}
            community={community}
            onChangeCommunity={visitCommunity}
            openLeftNav={openLeftNav}
            leftNavIsOpen={leftNavIsOpen}
            logout={() => dispatch(logout())}
            path={path}
            search={doSearch}
            opened={leftNavIsOpen}
            isMobile={isMobile}/>}
          {isMobile && <MobileSearch search={doSearch} />}
          {children}

      </VelocityComponent>

      <Notifier messages={notifierMessages}
        remove={id => dispatch(removeNotification(id))}/>
      <LiveStatusPoller/>
      <PageTitleController/>

  }
}

const MobileSearch = ({ search }) => {
  return

    <Icon name='Loupe'/>
    <Search onChange={search}/>

}

const nextPath = (path, community) => {
  const pathStart = community ? `/c/${community.slug}` : ''
  const match = community
    ? path.match(/(events|projects|members|about|invite|notifications)$/)
    : path.match(/(events|projects|notifications)$/)
  const pathEnd = match ? `/${match[1]}` : ''

  return pathStart + pathEnd
}
<commit_msg>hide search bar on search results page<commit_after>import React from 'react'
import cx from 'classnames'
import { prefetch } from 'react-fetcher'
import { connect } from 'react-redux'
import { find } from 'lodash'
import TopNav from '../components/TopNav'
import Search from '../components/Search'
import Icon from '../components/Icon'
import { LeftNav, leftNavWidth, leftNavEasing } from '../components/LeftNav'
import Notifier from '../components/Notifier'
import LiveStatusPoller from '../components/LiveStatusPoller'
import PageTitleController from '../components/PageTitleController'
import { logout, navigate, removeNotification, toggleMainMenu, updateUserSettings } from '../actions'
import { makeUrl } from '../client/util'
import { VelocityComponent } from 'velocity-react'
import { canInvite, canModerate } from '../models/currentUser'
import { get, pick } from 'lodash'
import { matchEditorUrl } from './StandalonePostEditor'
const { array, bool, func, object, string } = React.PropTypes

@prefetch(({ store, dispatch }) => {
  const { isMobile, people } = store.getState()
  if (!isMobile && typeof window === 'undefined' &&
    get(people.current, 'settings.leftNavIsOpen')) {
    return dispatch(toggleMainMenu())
  }
})
@connect((state, { params }) => {
  const { isMobile, leftNavIsOpen, notifierMessages } = state
  const currentUser = state.people.current
  const community = find(state.communities, c => c.id === state.currentCommunityId)
  const tags = community ? state.tagsByCommunity[community.slug] : {}

  return {
    isMobile,
    leftNavIsOpen,
    notifierMessages,
    currentUser,
    community,
    tags,
    path: state.routing.path
  }
})
export default class App extends React.Component {
  static propTypes = {
    children: object,
    community: object,
    currentUser: object,
    leftNavIsOpen: bool,
    tags: object,
    notifierMessages: array,
    path: string,
    dispatch: func,
    isMobile: bool
  }

  static childContextTypes = {
    dispatch: func,
    currentUser: object
  }

  getChildContext () {
    return pick(this.props, 'dispatch', 'currentUser')
  }

  render () {
    const {
      children, community, currentUser, dispatch, tags,
      leftNavIsOpen, notifierMessages, isMobile
    } = this.props

    const path = this.props.path.split('?')[0]
    const hideTopNav = matchEditorUrl(path)
    const hideMobileSearch = path === '/search'

    const moveWithMenu = {marginLeft: leftNavIsOpen ? leftNavWidth : 0}
    const toggleLeftNav = open => {
      if (leftNavIsOpen !== open) dispatch(toggleMainMenu())
      if (!isMobile) {
        setTimeout(() => {
          const settings = {leftNavIsOpen: open}
          dispatch(updateUserSettings(currentUser.id, {settings}))
        }, 1000)
      }
    }
    const openLeftNav = () => toggleLeftNav(true)
    const closeLeftNav = () => toggleLeftNav(false)
    const doSearch = text => dispatch(navigate(makeUrl('/search', {q: text})))
    const visitCommunity = community =>
      dispatch(navigate(nextPath(path, community)))

    return

      <LeftNav opened={leftNavIsOpen}
        community={community}
        tags={tags}
        canModerate={canModerate(currentUser, community)}
        canInvite={canInvite(currentUser, community)}
        close={closeLeftNav}/>

      <VelocityComponent animation={moveWithMenu} easing={leftNavEasing}>

          {!hideTopNav && <TopNav currentUser={currentUser}
            community={community}
            onChangeCommunity={visitCommunity}
            openLeftNav={openLeftNav}
            leftNavIsOpen={leftNavIsOpen}
            logout={() => dispatch(logout())}
            path={path}
            search={doSearch}
            opened={leftNavIsOpen}
            isMobile={isMobile}/>}
          {isMobile && !hideMobileSearch && <MobileSearch search={doSearch} />}
          {children}

      </VelocityComponent>

      <Notifier messages={notifierMessages}
        remove={id => dispatch(removeNotification(id))}/>
      <LiveStatusPoller/>
      <PageTitleController/>

  }
}

const MobileSearch = ({ search }) => {
  return

    <Icon name='Loupe'/>
    <Search onChange={search}/>

}

const nextPath = (path, community) => {
  const pathStart = community ? `/c/${community.slug}` : ''
  const match = community
    ? path.match(/(events|projects|members|about|invite|notifications)$/)
    : path.match(/(events|projects|notifications)$/)
  const pathEnd = match ? `/${match[1]}` : ''

  return pathStart + pathEnd
}
<|endoftext|>


<commit_before>const React = require('react');
const Router = require('react-router').Router;
const Provider = require('react-redux').Provider;

module.exports = class extends React.Component {

    static propTypes = {
        history: React.PropTypes.object.isRequired,
        routes: React.PropTypes.object.isRequired,
        routerKey: React.PropTypes.number,
        store: React.PropTypes.object.isRequired
    }

    render() {

        const { history, routes, routerKey, store } = this.props;

        return (
            <Provider store={store}>

                    <Router history={history} children={routes} key={routerKey} />

            </Provider>
        );
    }

};
<commit_msg>Name App component so that production build does not fail<commit_after>const React = require('react');
const Router = require('react-router').Router;
const Provider = require('react-redux').Provider;

module.exports = class App extends React.Component {

    static propTypes = {
        history: React.PropTypes.object.isRequired,
        routes: React.PropTypes.object.isRequired,
        routerKey: React.PropTypes.number,
        store: React.PropTypes.object.isRequired
    }

    render() {

        const { history, routes, routerKey, store } = this.props;

        return (
            <Provider store={store}>

                    <Router history={history} children={routes} key={routerKey} />

            </Provider>
        );
    }

};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { init } from '../actions';
import Header from '../components/Header';
import List from './List';
import Footer from '../components/Footer';
import DevTools from './DevTools';

class App extends Component {
  componentDidMount() {
    this.props.dispatch(init());
  }

  render() {
    return (

        <List />

        <DevTools />

    );
  }
}
const { object } = React.PropTypes;
App.propTypes = { dispatch: object };

export default App;
<commit_msg>fix wrong PropType<commit_after>import React, { Component } from 'react';
import { init } from '../actions';
import Header from '../components/Header';
import List from './List';
import Footer from '../components/Footer';
import DevTools from './DevTools';

class App extends Component {
  componentDidMount() {
    this.props.dispatch(init());
  }

  render() {
    return (

        <List />

        <DevTools />

    );
  }
}
const { func } = React.PropTypes;
App.propTypes = { dispatch: func };

export default App;
<|endoftext|>


<commit_before>function loadScript(url, callback)
{
    //stolen from http://goo.gl/Iwt7mn
    // Adding the script tag to the head as suggested before
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;

    // Then bind the event to the callback function.
    // There are several events for cross browser compatibility.
    script.onreadystatechange = callback;
    script.onload = callback;

    // Fire the loading
    head.appendChild(script);
}
var findurls = function findUrlsFunc()
{
	var v = textNode.nodeValue;
}

loadScript("https://www.gstatic.com/cv/js/sender/v1/cast_sender.js", findurls);

<commit_msg>Import Example code<commit_after>function loadScript(url, callback)
{
    //stolen from http://goo.gl/Iwt7mn
    // Adding the script tag to the head as suggested before
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;

    // Then bind the event to the callback function.
    // There are several events for cross browser compatibility.
    script.onreadystatechange = callback;
    script.onload = callback;

    // Fire the loading
    head.appendChild(script);
}
var findurls = function findUrlsFunc()
{
	var v = textNode.nodeValue;
}

loadScript("https://www.gstatic.com/cv/js/sender/v1/cast_sender.js", findurls);

/**
 * Cast initialization timer delay
 **/
var CAST_API_INITIALIZATION_DELAY = 1000;
/**
 * Progress bar update timer delay
 **/
var PROGRESS_BAR_UPDATE_DELAY = 1000;
/**
 * Session idle time out in miliseconds
 **/
var SESSION_IDLE_TIMEOUT = 300000;
/**
 * Media source root URL
 **/
var MEDIA_SOURCE_ROOT =
    'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/';

// Cast icon thumbnail active
var CAST_ICON_THUMB_ACTIVE = 'images/cast_icon_active.png';
// Cast icon thumbnail idle
var CAST_ICON_THUMB_IDLE = 'images/cast_icon_idle.png';
// Cast icon thumbnail warning
var CAST_ICON_THUMB_WARNING = 'images/cast_icon_warning.png';

/**
 * global variables
 */
var currentMediaSession = null;
var currentVolume = 0.5;
var progressFlag = 1;
var mediaCurrentTime = 0;
var session = null;
var storedSession = null;
var mediaURLs = [
    'http://www.youtube.com/watch?feature=player_embedded&x-yt-cl=84838260&v=non&x-yt-ts=1422327029',
    'http://playbb.me/embed.php?w=718&h=438&vid=at/nw/absolute_duo_-_04.mp4',
    'http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4',
    'http://commondatastorage.googleapis.com/gtv-videos-bucket/Google%20IO%202011%2045%20Min%20Walk%20Out.mp3'];
var mediaTitles = [
    'Big Buck Bunny',
    'Elephant Dream',
    'Tears of Steel',
    'Reel 2012',
    'Google I/O 2011 Audio'];

var mediaThumbs = [
    'images/BigBuckBunny.jpg',
    'images/ElephantsDream.jpg',
    'images/TearsOfSteel.jpg',
    'images/reel.jpg',
    'images/google-io-2011.jpg'];
var currentMediaURL = mediaURLs[0];
var currentMediaTitle = mediaTitles[0];
var currentMediaThumb = mediaThumbs[0];

var timer = null;

/**
 * Call initialization
 */
if (!chrome.cast || !chrome.cast.isAvailable) {
  setTimeout(initializeCastApi, CAST_API_INITIALIZATION_DELAY);
}

/**
 * initialization
 */
function initializeCastApi() {
  // default app ID to the default media receiver app
  // optional: you may change it to your own app ID/receiver
  var applicationIDs = [
      'BE6E4473', // hosted reference app
      chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID
    ];

  // auto join policy can be one of the following three
  // 1) no auto join
  // 2) same appID, same URL, same tab
  // 3) same appID and same origin URL
  var autoJoinPolicyArray = [
      chrome.cast.AutoJoinPolicy.PAGE_SCOPED,
      chrome.cast.AutoJoinPolicy.TAB_AND_ORIGIN_SCOPED,
      chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
    ];

  // request session
  var sessionRequest = new chrome.cast.SessionRequest(applicationIDs[0]);
  var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
    sessionListener,
    receiverListener,
    autoJoinPolicyArray[1]);

  chrome.cast.initialize(apiConfig, onInitSuccess, onError);
}

/**
 * initialization success callback
 */
function onInitSuccess() {
  console.log('init success');

  // check if a session ID is saved into localStorage
  storedSession = JSON.parse(localStorage.getItem('storedSession'));
  if (storedSession) {
    var dateString = storedSession.timestamp;
    var now = new Date().getTime();

    if (now - dateString < SESSION_IDLE_TIMEOUT) {
      document.getElementById('joinsessionbyid').style.display = 'block';
    }
  }
}

/**
 * generic error callback
 * @param {Object} e A chrome.cast.Error object.
 */
function onError(e) {
  console.log('Error' + e);
  console.log('Error' + e);
}

/**
 * generic success callback
 * @param {string} message from callback
 */
function onSuccess(message) {
  console.log(message);
}

/**
 * callback on success for stopping app
 */
function onStopAppSuccess() {
  console.log('Session stopped');
  console.log('Session stopped');
  document.getElementById('casticon').src = CAST_ICON_THUMB_IDLE;
}

/**
 * session listener during initialization
 * @param {Object} e session object
 * @this sessionListener
 */
function sessionListener(e) {
  console.log('New session ID: ' + e.sessionId);
  console.log('New session ID:' + e.sessionId);
  session = e;
  document.getElementById('casticon').src = CAST_ICON_THUMB_ACTIVE;
  if (session.media.length != 0) {
    console.log(
        'Found ' + session.media.length + ' existing media sessions.');
    onMediaDiscovered('sessionListener', session.media[0]);
  }
  session.addMediaListener(
    onMediaDiscovered.bind(this, 'addMediaListener'));
  session.addUpdateListener(sessionUpdateListener.bind(this));
  // disable join by session id when auto join already
  if (storedSession) {
    document.getElementById('joinsessionbyid').style.display = 'none';
  }
}

/**
 * session update listener
 * @param {boolean} isAlive status from callback
 * @this sessionUpdateListener
 */
function sessionUpdateListener(isAlive) {
  if (!isAlive) {
    session = null;
    document.getElementById('casticon').src = CAST_ICON_THUMB_IDLE;
    var playpauseresume = document.getElementById('playpauseresume');
    playpauseresume.innerHTML = 'Play';
    if (timer) {
      clearInterval(timer);
    }
    else {
      timer = setInterval(updateCurrentTime.bind(this),
          PROGRESS_BAR_UPDATE_DELAY);
      playpauseresume.innerHTML = 'Pause';
    }
  }
}

/**
 * receiver listener during initialization
 * @param {string} e status string from callback
 */
function receiverListener(e) {
  if (e === 'available') {
    console.log('receiver found');
    console.log('receiver found');
  }
  else {
    console.log('receiver list empty');
    console.log('receiver list empty');
  }
}

/**
 * select a media URL
 * @param {string} m An index for media URL
 */
function selectMedia(m) {
  console.log('media selected' + m);
  console.log('media selected' + m);
  currentMediaURL = mediaURLs[m];
  currentMediaTitle = mediaTitles[m];
  currentMediaThumb = mediaThumbs[m];
  var playpauseresume = document.getElementById('playpauseresume');
  document.getElementById('thumb').src = MEDIA_SOURCE_ROOT + mediaThumbs[m];
}

/**
 * launch app and request session
 */
function launchApp() {
  console.log('launching app...');
  console.log('launching app...');
  chrome.cast.requestSession(onRequestSessionSuccess, onLaunchError);
  if (timer) {
    clearInterval(timer);
  }
}

/**
 * callback on success for requestSession call
 * @param {Object} e A non-null new session.
 * @this onRequestSesionSuccess
 */
function onRequestSessionSuccess(e) {
  console.log('session success: ' + e.sessionId);
  console.log('session success: ' + e.sessionId);
  saveSessionID(e.sessionId);
  session = e;
  document.getElementById('casticon').src = CAST_ICON_THUMB_ACTIVE;
  session.addUpdateListener(sessionUpdateListener.bind(this));
  if (session.media.length != 0) {
    onMediaDiscovered('onRequestSession', session.media[0]);
  }
  session.addMediaListener(
    onMediaDiscovered.bind(this, 'addMediaListener'));
}

/**
 * callback on launch error
 */
function onLaunchError() {
  console.log('launch error');
  console.log('launch error');
}

/**
 * save session ID into localStorage for sharing
 * @param {string} sessionId A string for session ID
 */
function saveSessionID(sessionId) {
  // Check browser support of localStorage
  if (typeof(Storage) != 'undefined') {
    // Store sessionId and timestamp into an object
    var object = {id: sessionId, timestamp: new Date().getTime()};
    localStorage.setItem('storedSession', JSON.stringify(object));
  }
}

/**
 * join session by a given session ID
 */
function joinSessionBySessionId() {
  if (storedSession) {
    console.log(
        'Found stored session id: ' + storedSession.id);
    chrome.cast.requestSessionById(storedSession.id);
  }
}

/**
 * stop app/session
 */
function stopApp() {
  session.stop(onStopAppSuccess, onError);
  if (timer) {
    clearInterval(timer);
  }
}

/**
 * load media specified by custom URL IMPORTANT
 */
function loadCustomMedia() {
  var customMediaURL = document.getElementById('customMediaURL').value;
  if (customMediaURL.length > 0) {
    loadMedia(customMediaURL);
  }
}
/**
 * load media specified by custom URL IMPORTANT
 */
function loadCustomMedia(urlSelected) {
  var customMediaURL = urlSelected;
  if (customMediaURL.length > 0) {
    loadMedia(customMediaURL);
  }
}
/**
 * load media
 * @param {string} mediaURL media URL string
 * @this loadMedia
 */
function loadMedia(mediaURL) {
  if (!session) {
    console.log('no session');
    console.log('no session');
    return;
  }

  if (mediaURL) {
    var mediaInfo = new chrome.cast.media.MediaInfo(mediaURL);
    currentMediaTitle = 'custom title needed';
    currentMediaThumb = 'images/video_icon.png';
    document.getElementById('thumb').src = MEDIA_SOURCE_ROOT +
        currentMediaThumb;
  }
  else {
    console.log('loading...' + currentMediaURL);
    console.log('loading...' + currentMediaURL);
    var mediaInfo = new chrome.cast.media.MediaInfo(currentMediaURL);
  }
  mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
  mediaInfo.metadata.metadataType = chrome.cast.media.MetadataType.GENERIC;
  mediaInfo.contentType = 'video/mp4';

  mediaInfo.metadata.title = currentMediaTitle;
  mediaInfo.metadata.images = [{'url': MEDIA_SOURCE_ROOT + currentMediaThumb}];

  var request = new chrome.cast.media.LoadRequest(mediaInfo);
  request.autoplay = true;
  request.currentTime = 0;

  session.loadMedia(request,
    onMediaDiscovered.bind(this, 'loadMedia'),
    onMediaError);

}

/**
 * callback on success for loading media
 * @param {string} how info string from callback
 * @param {Object} mediaSession media session object
 * @this onMediaDiscovered
 */
function onMediaDiscovered(how, mediaSession) {
  console.log('new media session ID:' + mediaSession.mediaSessionId);
  console.log('new media session ID:' + mediaSession.mediaSessionId +
      ' (' + how + ')');
  currentMediaSession = mediaSession;
  currentMediaSession.addUpdateListener(onMediaStatusUpdate);
  mediaCurrentTime = currentMediaSession.currentTime;
  playpauseresume.innerHTML = 'Play';
  document.getElementById('casticon').src = CAST_ICON_THUMB_ACTIVE;
  document.getElementById('playerstate').innerHTML =
      currentMediaSession.playerState;
  if (!timer) {
    timer = setInterval(updateCurrentTime.bind(this),
        PROGRESS_BAR_UPDATE_DELAY);
    playpauseresume.innerHTML = 'Pause';
  }
}

/**
 * callback on media loading error
 * @param {Object} e A non-null media object
 */
function onMediaError(e) {
  console.log('media error' + e);
  console.log('media error' + e);
  document.getElementById('casticon').src = CAST_ICON_THUMB_WARNING;
}

/**
 * get media status initiated by sender when necessary
 * currentMediaSession gets updated
 * @this getMediaStatus
 */
function getMediaStatus() {
  if (!session || !currentMediaSession) {
    return;
  }

  currentMediaSession.getStatus(null,
      mediaCommandSuccessCallback.bind(this, 'got media status'),
      onError);
}

/**
 * callback for media status event
 * @param {boolean} isAlive status from callback
 */
function onMediaStatusUpdate(isAlive) {
  if (!isAlive) {
    currentMediaTime = 0;
  }
  else {
    if (currentMediaSession.playerState == 'PLAYING') {
      if (progressFlag) {
        document.getElementById('progress').value = parseInt(100 *
            currentMediaSession.currentTime /
            currentMediaSession.media.duration);
        document.getElementById('progress_tick').innerHTML =
            currentMediaSession.currentTime;
        document.getElementById('duration').innerHTML =
            currentMediaSession.media.duration;
        progressFlag = 0;
      }
      document.getElementById('playpauseresume').innerHTML = 'Pause';
    }
  }
  document.getElementById('playerstate').innerHTML =
      currentMediaSession.playerState;
}

/**
 * Updates the progress bar shown for each media item.
 */
function updateCurrentTime() {
  if (!session || !currentMediaSession) {
    return;
  }

  if (currentMediaSession.media && currentMediaSession.media.duration != null) {
    var cTime = currentMediaSession.getEstimatedTime();
    document.getElementById('progress').value = parseInt(100 * cTime /
        currentMediaSession.media.duration);
    document.getElementById('progress_tick').innerHTML = cTime;
  }
  else {
    document.getElementById('progress').value = 0;
    document.getElementById('progress_tick').innerHTML = 0;
    if (timer) {
      clearInterval(timer);
    }
  }
}

/**
 * play media
 * @this playMedia
 */
function playMedia() {
  if (!currentMediaSession) {
    return;
  }

  if (timer) {
    clearInterval(timer);
  }

  var playpauseresume = document.getElementById('playpauseresume');
  if (playpauseresume.innerHTML == 'Play') {
    currentMediaSession.play(null,
      mediaCommandSuccessCallback.bind(this, 'playing started for ' +
          currentMediaSession.sessionId),
      onError);
      playpauseresume.innerHTML = 'Pause';
      console.log('play started');
      timer = setInterval(updateCurrentTime.bind(this),
          PROGRESS_BAR_UPDATE_DELAY);
  }
  else {
    if (playpauseresume.innerHTML == 'Pause') {
      currentMediaSession.pause(null,
        mediaCommandSuccessCallback.bind(this, 'paused ' +
            currentMediaSession.sessionId),
        onError);
      playpauseresume.innerHTML = 'Resume';
      console.log('paused');
    }
    else {
      if (playpauseresume.innerHTML == 'Resume') {
        currentMediaSession.play(null,
          mediaCommandSuccessCallback.bind(this, 'resumed ' +
              currentMediaSession.sessionId),
          onError);
        playpauseresume.innerHTML = 'Pause';
        console.log('resumed');
        timer = setInterval(updateCurrentTime.bind(this),
            PROGRESS_BAR_UPDATE_DELAY);
      }
    }
  }
}

/**
 * stop media
 * @this stopMedia
 */
function stopMedia() {
  if (!currentMediaSession)
    return;

  currentMediaSession.stop(null,
    mediaCommandSuccessCallback.bind(this, 'stopped ' +
        currentMediaSession.sessionId),
    onError);
  var playpauseresume = document.getElementById('playpauseresume');
  playpauseresume.innerHTML = 'Play';
  console.log('media stopped');
  if (timer) {
    clearInterval(timer);
  }
}

/**
 * set media volume
 * @param {Number} level A number for volume level
 * @param {Boolean} mute A true/false for mute/unmute
 * @this setMediaVolume
 */
function setMediaVolume(level, mute) {
  if (!currentMediaSession)
    return;

  var volume = new chrome.cast.Volume();
  volume.level = level;
  currentVolume = volume.level;
  volume.muted = mute;
  var request = new chrome.cast.media.VolumeRequest();
  request.volume = volume;
  currentMediaSession.setVolume(request,
    mediaCommandSuccessCallback.bind(this, 'media set-volume done'),
    onError);
}

/**
 * set receiver volume
 * @param {Number} level A number for volume level
 * @param {Boolean} mute A true/false for mute/unmute
 * @this setReceiverVolume
 */
function setReceiverVolume(level, mute) {
  if (!session)
    return;

  if (!mute) {
    session.setReceiverVolumeLevel(level,
      mediaCommandSuccessCallback.bind(this, 'media set-volume done'),
      onError);
    currentVolume = level;
  }
  else {
    session.setReceiverMuted(true,
      mediaCommandSuccessCallback.bind(this, 'media set-volume done'),
      onError);
  }
}

/**
 * mute media
 */
function muteMedia() {
  if (!session || !currentMediaSession) {
    return;
  }

  var muteunmute = document.getElementById('muteunmute');
  // It's recommended that setReceiverVolumeLevel be used
  // but media stream volume can be set instread as shown in the
  // setMediaVolume(currentVolume, true);
  if (muteunmute.innerHTML == 'Mute media') {
    muteunmute.innerHTML = 'Unmute media';
    setReceiverVolume(currentVolume, true);
    console.log('media muted');
  } else {
    muteunmute.innerHTML = 'Mute media';
    setReceiverVolume(currentVolume, false);
    console.log('media unmuted');
  }
}

/**
 * seek media position
 * @param {Number} pos A number to indicate percent
 * @this seekMedia
 */
function seekMedia(pos) {
  console.log('Seeking ' + currentMediaSession.sessionId + ':' +
    currentMediaSession.mediaSessionId + ' to ' + pos + '%');
  progressFlag = 0;
  var request = new chrome.cast.media.SeekRequest();
  request.currentTime = pos * currentMediaSession.media.duration / 100;
  currentMediaSession.seek(request,
    onSeekSuccess.bind(this, 'media seek done'),
    onError);
}

/**
 * callback on success for media commands
 * @param {string} info A message string
 */
function onSeekSuccess(info) {
  console.log(info);
  console.log(info);
  setTimeout(function() {progressFlag = 1},PROGRESS_BAR_UPDATE_DELAY);
}

/**
 * callback on success for media commands
 * @param {string} info A message string
 */
function mediaCommandSuccessCallback(info) {
  console.log(info);

}

function getContentFromIframe(iFrameName)
{

    var myIFrame = document.getElementsByTagName("iframe");
    var content = myIFrame[0].contentWindow.document.body.innerHTML;

    //Do whatever you need with the content

}
function getFrames()
{

var listofframes = document.getElementsByTagName("iframe");
var scriptsiniframe = listofframes[0];
var iframeDocument = scriptsiniframe ;
console.log('log '+iframeDocument.src);
console.log(iframeDocument);
}<|endoftext|>


<commit_before>var template = require('./template');
var View = require('view');
var dom = require('dom');
var Quill = require('quill');

var defaults = {
  toolbar: {
    fontFace: false,
    fontSize: false,
    fontWidth: true
  },
  theme: 'snow'
};

module.exports = RichTextView;

function RichTextView(el, options) {
  if (!(this instanceof RichTextView)) {
    return new RichTextView(el, options);
  }

  // The original input or textarea element
  this.input = 'string' === typeof el ? dom(el) : el;

  // Settings merged with options provided by callee
  // fixme: i can't find a component that extends the defaults object with the options object.
  //this.settings = options || {};
  this.settings = defaults;

  View.call(this, template, this.settings);

  this.editor = new Quill(this.find('#editor')[0], {
    modules: {
      'toolbar': { container: this.find('#toolbar')[0] },
      'link-tooltip': true,
      'image-tooltip': true
    },
    theme: this.settings.theme
  });

  if (this.input.val()) this.editor.setHTML(this.input.val());
  this.render();
};

View(RichTextView);

RichTextView.prototype.switchOn = function() {
  this.editor.on('text-change', this.bound('ontextchange'));
};

RichTextView.prototype.ontextchange = function(delta, source) {
  var contents = this.editor.getHTML();
  this.input.val(contents);
};

RichTextView.prototype.render = function() {
  if (this.input) {
    this.input.addClass('hide');
    this.el.insertAfter(this.input);
  }

  return View.prototype.render.call(this);
};<commit_msg>[richtext] Added description #438<commit_after>var template = require('./template');
var View = require('view');
var dom = require('dom');
var Quill = require('quill');

var defaults = {
  toolbar: {
    fontFace: false,
    fontSize: false,
    fontWidth: true
  },
  theme: 'snow'
};

module.exports = RichTextView;

/**
 * Wraps an input element and converts it in a Quill WYSIWYG control
 * @param {String|HTMLInputElement} Selector or domified single element
 * @param {Object} Customization options
 *
 * Usage:
 *   var richtext = require('richtext');
 *   var input = dom('input#description');
 *   richtext(input);
 *
 */
function RichTextView(el, options) {
  if (!(this instanceof RichTextView)) {
    return new RichTextView(el, options);
  }

  // The original input or textarea element
  this.input = 'string' === typeof el ? dom(el) : el;

  // Settings merged with options provided by callee
  // fixme: i can't find a component that extends the defaults object with the options object.
  //this.settings = options || {};
  this.settings = defaults;

  View.call(this, template, this.settings);

  this.editor = new Quill(this.find('#editor')[0], {
    modules: {
      'toolbar': { container: this.find('#toolbar')[0] },
      'link-tooltip': true,
      'image-tooltip': true
    },
    theme: this.settings.theme
  });

  if (this.input.val()) this.editor.setHTML(this.input.val());
  this.render();
};

View(RichTextView);

RichTextView.prototype.switchOn = function() {
  this.editor.on('text-change', this.bound('ontextchange'));
};

RichTextView.prototype.ontextchange = function(delta, source) {
  var contents = this.editor.getHTML();
  this.input.val(contents);
};

RichTextView.prototype.render = function() {
  if (this.input) {
    this.input.addClass('hide');
    this.el.insertAfter(this.input);
  }

  return View.prototype.render.call(this);
};<|endoftext|>


<commit_before>import copyToClipboard from './clipboard';
import notify from './notify';

const _ = browser.i18n.getMessage;

// Service default.
const default_service = 'isgd';

// Specify 'url' for plain-text GET APIs, or request/result for more complex
// variants. Note: return a fetch() promise.
// Do not forget to add origins to permissions in manifest.
const serviceUrls = {
  isgd: {
    url: 'https://is.gd/api.php?longurl=%URL%'
  },
  tinyurl: {
    url: 'https://tinyurl.com/api-create.php?url=%URL%'
  },
  googl: {
    // https://developers.google.com/url-shortener/v1/getting_started
    request: url => {
      return browser.storage.local.get('prefs').then(ret => {
        let prefs = ret['prefs'] || {};
        if (prefs.google_apikey) {
          let headers = new Headers({
            'Content-Type': 'application/json'
          });
          return fetch('https://www.googleapis.com/urlshortener/v1/url?key=' +
                       prefs.google_apikey, {
            method: 'POST',
            headers: headers,
            body: JSON.stringify({ longUrl: url })
          });
        }
        throw new Error(_('apikey_error'));
      });
    },
    result: response => {
      return response.text().then(txt => {
        let shortened = JSON.parse(txt);
        return shortened.id;
      })
    }
}}

/** Create a short URL from is.gd, tinyurl, etc. */
function createShortUrl(url) {
  let req;

  try {
    // Get shortening service from prefs.
    browser.storage.local.get('prefs').then(ret => {
      let prefs = ret['prefs'] || {};
      let service;
      if (prefs['service'] === 'custom') {
        service = { url: prefs.custom_url };
      } else {
        service = serviceUrls[prefs['service'] || default_service];
      }

      if (service.request) {
        req = service.request(url);
      } else {
        let _uri = service.url.replace('%URL%', encodeURIComponent(url));
        req = fetch(_uri);
      }

      req.then(response => {
        if (response.ok) {
          let result = service.result ? service.result(response) : response.text();
          return result;
        } else {
          throw new Error(_('shorten_error'));
        }
      }).then(result => {
        finalizeUrl(url, result);
      });

    }, err => {
      throw new Error(_('shorten_error'));
    });

  } catch (e) {
    notify(e.message);
    return false;
  }
}

/** Finalize (notify and copy to clipboard) a detected or generated URL. */
function finalizeUrl(long_url, short_url) {
  copyToClipboard(short_url);
  browser.storage.local.get('prefs').then(ret => {
    let prefs = ret['prefs'] || {};
    if (prefs.notify !== false) {
      notify(short_url);
    }
  });
}

/** Handle a URL found on the page */
export default function processUrl(found_url) {
  let url = found_url['url'];

  browser.storage.local.get('prefs').then(ret => {
    let prefs = ret['prefs'] || {};

    // Remove UTM tracking codes (from Google Analytics) if present.
    if (prefs.strip_utm) {
      let parsedUrl = new URL(url);
      if (/[?&]utm_/.test(parsedUrl.search)) {
        // Find and delete all utm_ tracking parameters.
        let utm_match = /[?&](utm_[^=]+)=/;
        while (true) {
          let utm_param = utm_match.exec(parsedUrl.search);
          if (!utm_param) break;
          parsedUrl.searchParams.delete(utm_param[1]);
        }
        url = parsedUrl.toString();
      }
    }

    // Shorten URL if it's not considered "short" or exceeds length limit.
    if (!found_url['short'] || (prefs.shorten_canonical > 0 && url.length > prefs.shorten_canonical)) {
      createShortUrl(url);
    } else {
      finalizeUrl(null, url);
    }
  });
}
<commit_msg>Catch API settings error and bubble up as notification<commit_after>import copyToClipboard from './clipboard';
import notify from './notify';

const _ = browser.i18n.getMessage;

// Service default.
const default_service = 'isgd';

// Specify 'url' for plain-text GET APIs, or request/result for more complex
// variants. Note: return a fetch() promise.
// Do not forget to add origins to permissions in manifest.
const serviceUrls = {
  isgd: {
    url: 'https://is.gd/api.php?longurl=%URL%'
  },
  tinyurl: {
    url: 'https://tinyurl.com/api-create.php?url=%URL%'
  },
  googl: {
    // https://developers.google.com/url-shortener/v1/getting_started
    request: url => {
      return browser.storage.local.get('prefs').then(ret => {
        let prefs = ret['prefs'] || {};
        if (!prefs.google_apikey) {
          throw new Error(_('apikey_error'));
        }

        let headers = new Headers({
          'Content-Type': 'application/json'
        });
        return fetch('https://www.googleapis.com/urlshortener/v1/url?key=' +
                     prefs.google_apikey, {
          method: 'POST',
          headers: headers,
          body: JSON.stringify({ longUrl: url })
        });
      });
    },
    result: response => {
      return response.text().then(txt => {
        let shortened = JSON.parse(txt);
        return shortened.id;
      })
    }
}}

/** Create a short URL from is.gd, tinyurl, etc. */
function createShortUrl(url) {
  let req;

  try {
    // Get shortening service from prefs.
    browser.storage.local.get('prefs').then(ret => {
      let prefs = ret['prefs'] || {};
      let service;
      if (prefs['service'] === 'custom') {
        service = { url: prefs.custom_url };
      } else {
        service = serviceUrls[prefs['service'] || default_service];
      }

      if (service.request) {
        req = service.request(url);
      } else {
        let _uri = service.url.replace('%URL%', encodeURIComponent(url));
        req = fetch(_uri);
      }

      req.then(response => {
        if (response.ok) {
          let result = service.result ? service.result(response) : response.text();
          return result;
        } else {
          throw new Error(_('shorten_error'));
        }
      }).then(result => {
        finalizeUrl(url, result);
      }).catch(err => {
        notify(err.message);
      });

    }, err => {
      throw new Error(_('shorten_error'));
    });

  } catch (e) {
    notify(e.message);
    return false;
  }
}

/** Finalize (notify and copy to clipboard) a detected or generated URL. */
function finalizeUrl(long_url, short_url) {
  copyToClipboard(short_url);
  browser.storage.local.get('prefs').then(ret => {
    let prefs = ret['prefs'] || {};
    if (prefs.notify !== false) {
      notify(short_url);
    }
  });
}

/** Handle a URL found on the page */
export default function processUrl(found_url) {
  let url = found_url['url'];

  browser.storage.local.get('prefs').then(ret => {
    let prefs = ret['prefs'] || {};

    // Remove UTM tracking codes (from Google Analytics) if present.
    if (prefs.strip_utm) {
      let parsedUrl = new URL(url);
      if (/[?&]utm_/.test(parsedUrl.search)) {
        // Find and delete all utm_ tracking parameters.
        let utm_match = /[?&](utm_[^=]+)=/;
        while (true) {
          let utm_param = utm_match.exec(parsedUrl.search);
          if (!utm_param) break;
          parsedUrl.searchParams.delete(utm_param[1]);
        }
        url = parsedUrl.toString();
      }
    }

    // Shorten URL if it's not considered "short" or exceeds length limit.
    if (!found_url['short'] || (prefs.shorten_canonical > 0 && url.length > prefs.shorten_canonical)) {
      createShortUrl(url);
    } else {
      finalizeUrl(null, url);
    }
  });
}
<|endoftext|>


<commit_before>var template = require('./template');
var View = require('view');
var dom = require('dom');
var Quill = require('quill');

var defaults = {
  toolbar: {
    fontFace: false,
    fontSize: false,
    fontWidth: true
  },
  theme: 'snow'
};

module.exports = RichTextView;

function RichTextView(el, options) {
  if (!(this instanceof RichTextView)) {
    return new RichTextView(el, options);
  }

  // The original input or textarea element
  this.input = 'string' === typeof el ? dom(el) : el;

  // Settings merged with options provided by callee
  // fixme: i can't find a component that extends the defaults object with the options object.
  //this.settings = options || {};
  this.settings = defaults;

  View.call(this, template, this.settings);

  this.editor = new Quill(this.find('#editor')[0], {
    modules: {
      'toolbar': { container: this.find('#toolbar')[0] },
      'link-tooltip': true,
      'image-tooltip': true
    },
    theme: this.settings.theme
  });

  this.editor.setHTML(this.input.val());
};

View(RichTextView);

RichTextView.prototype.switchOn = function() {
  this.editor.on('text-change', this.bound('ontextchange'));
};

RichTextView.prototype.ontextchange = function(delta, source) {
  var contents = this.editor.getHTML();
  this.input.val(contents);
};

RichTextView.prototype.render = function() {
  if (this.input) {
    this.input.addClass('hide');
    this.el.insertAfter(this.input);
  }

  return View.prototype.render.call(this);
};<commit_msg>[richtext] Fixed bug when rendering against empty textarea #438<commit_after>var template = require('./template');
var View = require('view');
var dom = require('dom');
var Quill = require('quill');

var defaults = {
  toolbar: {
    fontFace: false,
    fontSize: false,
    fontWidth: true
  },
  theme: 'snow'
};

module.exports = RichTextView;

function RichTextView(el, options) {
  if (!(this instanceof RichTextView)) {
    return new RichTextView(el, options);
  }

  // The original input or textarea element
  this.input = 'string' === typeof el ? dom(el) : el;

  // Settings merged with options provided by callee
  // fixme: i can't find a component that extends the defaults object with the options object.
  //this.settings = options || {};
  this.settings = defaults;

  View.call(this, template, this.settings);

  this.editor = new Quill(this.find('#editor')[0], {
    modules: {
      'toolbar': { container: this.find('#toolbar')[0] },
      'link-tooltip': true,
      'image-tooltip': true
    },
    theme: this.settings.theme
  });

  if (this.input.val()) this.editor.setHTML(this.input.val());
  this.render();
};

View(RichTextView);

RichTextView.prototype.switchOn = function() {
  this.editor.on('text-change', this.bound('ontextchange'));
};

RichTextView.prototype.ontextchange = function(delta, source) {
  var contents = this.editor.getHTML();
  this.input.val(contents);
};

RichTextView.prototype.render = function() {
  if (this.input) {
    this.input.addClass('hide');
    this.el.insertAfter(this.input);
  }

  return View.prototype.render.call(this);
};<|endoftext|>


<commit_before>var logger = require('./logger')
var config = require('./config')
var Promise = require('bluebird')

module.exports = {
  sendToOpbeat: function (data) {
    logger.log('opbeat.transport.sendToOpbeat', data)

    var url = 'https://' + config.get('apiHost') + '/api/v1/organizations/' + config.get('orgId') + '/apps/' + config.get('appId') + '/client-side/errors/'

    var headers = {
      'Authorization': 'Bearer ' + config.get('token'),
      'X-Opbeat-Client': 'opbeat-js/' + config.get('VERSION')
    }

    return _makeRequest(url, 'POST', 'JSON', data, headers)
  },

  getFile: function (fileUrl) {
    return _makeRequest(fileUrl, 'GET', '', {})
  }
}

function _makeRequest (url, method, type, data, headers) {
  return new Promise(function (resolve, reject) {
    var xhr = _createCORSRequest(method, url, data)

    if (!xhr) {
      logger.log('opbeat.transport.error.cors-not-supported')
      return
    }

    if (type === 'JSON') {
      xhr.setRequestHeader('Content-Type', 'application/json')
    }

    if (headers) {
      for (var header in headers) {
        if (headers.hasOwnProperty(header)) {
          xhr.setRequestHeader(header.toLowerCase(), headers[header])
        }
      }
    }

    logger.log('opbeat.transport._makeRequest', url, data, headers)

    if (window.XDomainRequest) {
      // Empty event handlers needs to be there, because IE9 is flawed: http://rudovsky.blogspot.dk/2012/09/microsoft-shit-xdomainrequest.html
      xhr.ontimeout = function () {}
      xhr.onprogress = function () {}
    }

    xhr.onreadystatechange = function (evt) {
      if (xhr.readyState === 4) {
        var status = xhr.status
        if (status > 399 && status < 600) {
          // An http 4xx or 5xx error. Signal an error.
          var err = new Error(url + ' HTTP status: ' + status)
          err.xhr = xhr
          reject(err)
          logger.log('opbeat.transport.error', err)
        } else {
          resolve(xhr.responseText)
          logger.log('opbeat.transport.success')
        }
      }
    }

    xhr.onerror = function (e) {
      reject(e)
      logger.log('opbeat.transport.error', e)
    }

    if (type === 'JSON') {
      xhr.send(JSON.stringify(data))
    } else {
      xhr.send(data)
    }

  })

}

function _createCORSRequest (method, url) {
  var xhr = new window.XMLHttpRequest()

  if ('withCredentials' in xhr) {
    xhr.open(method, url, true)
  } else if (window.XDomainRequest) {
    xhr = new window.XDomainRequest()
    xhr.open(method, url, true)
  }

  xhr.timeout = 10000

  return xhr
}
<commit_msg>Get rid of XDomainRequest logic<commit_after>var logger = require('./logger')
var config = require('./config')
var Promise = require('bluebird')

module.exports = {
  sendToOpbeat: function (data) {
    logger.log('opbeat.transport.sendToOpbeat', data)

    var url = 'https://' + config.get('apiHost') + '/api/v1/organizations/' + config.get('orgId') + '/apps/' + config.get('appId') + '/client-side/errors/'

    var headers = {
      'Authorization': 'Bearer ' + config.get('token'),
      'X-Opbeat-Client': 'opbeat-js/' + config.get('VERSION')
    }

    return _makeRequest(url, 'POST', 'JSON', data, headers)
  },

  getFile: function (fileUrl) {
    return _makeRequest(fileUrl, 'GET', '', {})
  }
}

function _makeRequest (url, method, type, data, headers) {
  return new Promise(function (resolve, reject) {
    var xhr = new window.XMLHttpRequest()

    xhr.open(method, url, true)
    xhr.timeout = 10000

    if (type === 'JSON') {
      xhr.setRequestHeader('Content-Type', 'application/json')
    }

    if (headers) {
      for (var header in headers) {
        if (headers.hasOwnProperty(header)) {
          xhr.setRequestHeader(header.toLowerCase(), headers[header])
        }
      }
    }

    logger.log('opbeat.transport._makeRequest', url, data, headers)

    xhr.onreadystatechange = function (evt) {
      if (xhr.readyState === 4) {
        var status = xhr.status
        if (status > 399 && status < 600) {
          // An http 4xx or 5xx error. Signal an error.
          var err = new Error(url + ' HTTP status: ' + status)
          err.xhr = xhr
          reject(err)
          logger.log('opbeat.transport.error', err)
        } else {
          resolve(xhr.responseText)
          logger.log('opbeat.transport.success')
        }
      }
    }

    xhr.onerror = function (e) {
      reject(e)
      logger.log('opbeat.transport.error', e)
    }

    if (type === 'JSON') {
      xhr.send(JSON.stringify(data))
    } else {
      xhr.send(data)
    }

  })

}
<|endoftext|>


<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Geometry2 = function ( size ) {

	THREE.BufferGeometry.call( this );

	this.addAttribute( 'position', new Float32Array( size * 3 ), 3 );
	this.addAttribute( 'normal', new Float32Array( size * 3 ), 3 );
	this.addAttribute( 'uv', new Float32Array( size * 2 ), 2 );

	this.vertices = this.getAttribute( 'position' ).array;
	this.normals = this.getAttribute( 'normal' ).array;
	this.uvs = this.getAttribute( 'uv' ).array;

	this.boundingBox = null;
	this.boundingSphere = null;

};

THREE.Geometry2.prototype = Object.create( THREE.BufferGeometry.prototype );<commit_msg>Geometry2: Simpler code. See #4509.<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.Geometry2 = function ( size ) {

	THREE.BufferGeometry.call( this );

	this.vertices = new Float32Array( size * 3 );
	this.normals = new Float32Array( size * 3 );
	this.uvs = new Float32Array( size * 2 );

	this.addAttribute( 'position', this.vertices, 3 );
	this.addAttribute( 'normal', this.normals, 3 );
	this.addAttribute( 'uv', this.uvs, 2 );

	this.boundingBox = null;
	this.boundingSphere = null;

};

THREE.Geometry2.prototype = Object.create( THREE.BufferGeometry.prototype );<|endoftext|>


<commit_before>/***********************************************************
 Vue Forms: Validation
 --------------------------
 Defines the available validation rules.
 ************************************************************/

class Validation {

    /**
     * Creates a new Validation instance for the specified form element.
     *
     * @param form The form element to validate.
     */
    constructor(form) {
        this.form = form;
    }

    check(name, rule, inputValue, ruleValue = null) {
        return new Promise((resolve) => {
            switch (rule) {
                case 'required':
                    this.required(inputValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'required_with':
                    this.requiredWith(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'required_if':
                    this.requiredIf(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'min':
                    this.min(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'max':
                    this.max(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'confirmed':
                    this.confirmed(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'email':
                    this.email(inputValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'url':
                    this.url(inputValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'accepted':
                    this.accepted(inputValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'date':
                    this.date(inputValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'after':
                    this.after(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'before':
                    this.before(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'same':
                    this.same(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'custom':
                    if (_.isFunction(ruleValue)) {
                        ruleValue(name, inputValue, (valid, message = null) => {
                            resolve({valid: valid, message: message});
                        });
                    }
                    break;
                default:
                    resolve(true);
                    break;
            }
        });
    }

    required(value) {
        return new Promise((resolve) => {
            let valid = _.isNumber(value) || (!_.isNull(value) && !_.isUndefined(value));
            if (_.isString(value)) {
                valid = !!value && value.length;
            }

            resolve({valid: valid, message: valid ? null : `The field is required.`})
        });
    }

    requiredWith(value, additionalInputs) {
        return new Promise((resolve) => {

            if (!value && !value.length) {
                let inputs = _.split(additionalInputs, ',');
                _.each(inputs, input => {
                    let inputEl = $(this.form).find(':input[name="' + input + '"]').first();
                    if (inputEl.length > 0) {
                        resolve({valid: false, message: `The field is required, if ${input} is present.`});
                    }
                });
            }
            resolve({valid: true, message: null})
        });
    }

    requiredIf(value, keyValue) {
        return new Promise((resolve) => {
            let valid = true;

            if (!value && !value.length) {
                let keyValuePair = _.split(keyValue, ',');
                let input = keyValuePair[0];
                let value = keyValuePair[1];
                valid = value == $(this.form).find(':input[name="' + input + '"]').first().val();
                resolve({valid: valid, message: valid ? null : `The field is required, if ${input} is equal to ${value}.`})
            } else {
                resolve({valid: true, message: null})
            }
        });
    }

    min(value, min) {
        return new Promise((resolve) => {
            let valid = true;
            if (value) {
                valid = value.length >= min;
            }
            resolve({valid: valid, message: valid ? null : `Please enter at least ${min} characters.`})
        });
    }

    max(value, max) {
        return new Promise((resolve) => {
            let valid = true;
            if (value) {
                valid = value.length <= max;
            }
            resolve({valid: valid, message: valid ? null : `The input may not be greater than ${max} characters.`})
        });
    }

    confirmed(value, confirmInputName) {
        return new Promise((resolve) => {
            let valid = true;
            let input = this.findClosestInput(confirmInputName);

            // Only validate if an input to compare exists on the validated form
            if (input && value) {
                valid = value === input.val();

            }

            resolve({valid: valid, message: valid ? null : `The confirmation does not match.`})
        });
    }

    email(value) {
        return new Promise((resolve) => {
            let valid = true;
            if (value) {
                valid = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i.test(value);
            }
            resolve({valid: valid, message: valid ? null : `Please enter a valid email address.`})
        });
    }

    accepted(value) {
        return new Promise((resolve) => {
            let valid = value === 'on' || value === 'true' || value === 1 || value === true;
            resolve({valid: valid, message: valid ? null : `This must be accepted.`})
        });
    }

    url(value) {
        return new Promise((resolve) => {
            let valid = true;
            if (value) {
                valid = /^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/.test(value);
            }
            resolve({valid: valid, message: valid ? null : `Please enter a valid url.`})
        });
    }

    date(value) {
        return new Promise((resolve) => {
            let valid = value ? moment(value).isValid() : true;
            resolve({valid: valid, message: valid ? null : `Please enter a valid date.`})
        });
    }

    after(value, comparisonDateInputName) {
        return new Promise((resolve) => {
            let valid = true;
            let comparisonValue = this.parseComparisonInputValue(comparisonDateInputName);

            // Only validate if a value to compare exists on the validated form
            if (comparisonValue) {
                let dateValue = moment(value);

                if (dateValue.isValid()) {
                    valid = dateValue.isAfter(comparisonValue);
                }
            }

            resolve({valid: valid, message: valid ? null : `The date must be after ${comparisonDateInputName}.`})
        });
    }

    before(value, comparisonDateInputName) {
        return new Promise((resolve) => {
            let valid = true;
            let comparisonValue = this.parseComparisonInputValue(comparisonDateInputName);

            // Only validate if a value to compare exists on the validated form
            if (comparisonValue) {
                let dateValue = moment(value);

                if (dateValue.isValid()) {
                    valid = dateValue.isBefore(comparisonValue);
                }
            }

            resolve({valid: valid, message: valid ? null : `The date must be before ${comparisonDateInputName}.`})
        });
    }

    same(value, comparisonDateInputName) {
        return new Promise((resolve) => {
            let valid = true;
            let comparisonValue = this.parseComparisonInputValue(comparisonDateInputName);

            // Only validate if a value to compare exists on the validated form
            if (comparisonValue) {
                let dateValue = moment(value);

                if (dateValue.isValid()) {
                    valid = dateValue.isSame(comparisonValue);
                }
            }

            resolve({valid: valid, message: valid ? null : `The date must be the same as ${comparisonDateInputName}.`})
        });
    }

    /**
     * Tries to find the closest input with the specified name on the validated form.
     *
     * @param inputName
     */
    findClosestInput(inputName) {

        let selector = ':input[name="' + inputName + '"]';

        // Check if a wildcard is included in the input name. If so, we just use the part after the wildcard to find the input
        if (inputName.indexOf('*') > -1) {
            inputName = inputName.substring(inputName.lastIndexOf('*') + 1, inputName.length); // Make sure we split at the last occurrence of a wildcard
            selector = ':input[name$="' + inputName + '"]'; // Retrieve the input whose name ends with our calculated input name
        }

        let input = $(this.form).find(selector).first();

        return input.length ? input : null;
    }

    /**
     * Tries to find the value for the specified input name. Can also be a date.
     *
     * @param inputName
     */
    parseComparisonInputValue(inputName) {

        // Check if an input with the name exists on the validated form. If so, we retrieve its value.
        let input = this.findClosestInput(inputName);
        if (input) {
            return input.val();
        }

        // Check if the input name represents the today's date
        if (['now', 'today'].indexOf(inputName) > -1) {
            return moment();
        }

        // Check if the input name represents the yesterday's date
        if (['yesterday'].indexOf(inputName) > -1) {
            return moment().subtract(1, 'days');
        }

        // Check if the input name represents the tomorrow's date
        if (['tomorrow'].indexOf(inputName) > -1) {
            return moment().add(1, 'days');
        }

        // Check if the input represents any date
        let dateValue = moment(inputName);
        if (dateValue.isValid()) {
            return dateValue;
        }

        return null;
    }

}

export default Validation;

<commit_msg>Added 'phone' validation rule<commit_after>/***********************************************************
 Vue Forms: Validation
 --------------------------
 Defines the available validation rules.
 ************************************************************/

class Validation {

    /**
     * Creates a new Validation instance for the specified form element.
     *
     * @param form The form element to validate.
     */
    constructor(form) {
        this.form = form;
    }

    check(name, rule, inputValue, ruleValue = null) {
        return new Promise((resolve) => {
            switch (rule) {
                case 'required':
                    this.required(inputValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'required_with':
                    this.requiredWith(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'required_if':
                    this.requiredIf(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'min':
                    this.min(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'max':
                    this.max(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'confirmed':
                    this.confirmed(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'email':
                    this.email(inputValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'phone':
                    this.phone(inputValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'url':
                    this.url(inputValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'accepted':
                    this.accepted(inputValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'date':
                    this.date(inputValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'after':
                    this.after(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'before':
                    this.before(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'same':
                    this.same(inputValue, ruleValue).then((result) => {
                        resolve(result);
                    });
                    break;
                case 'custom':
                    if (_.isFunction(ruleValue)) {
                        ruleValue(name, inputValue, (valid, message = null) => {
                            resolve({valid: valid, message: message});
                        });
                    }
                    break;
                default:
                    resolve(true);
                    break;
            }
        });
    }

    required(value) {
        return new Promise((resolve) => {
            let valid = _.isNumber(value) || (!_.isNull(value) && !_.isUndefined(value));
            if (_.isString(value)) {
                valid = !!value && value.length;
            }

            resolve({valid: valid, message: valid ? null : `The field is required.`})
        });
    }

    requiredWith(value, additionalInputs) {
        return new Promise((resolve) => {

            if (!value && !value.length) {
                let inputs = _.split(additionalInputs, ',');
                _.each(inputs, input => {
                    let inputEl = $(this.form).find(':input[name="' + input + '"]').first();
                    if (inputEl.length > 0) {
                        resolve({valid: false, message: `The field is required, if ${input} is present.`});
                    }
                });
            }
            resolve({valid: true, message: null})
        });
    }

    requiredIf(value, keyValue) {
        return new Promise((resolve) => {
            let valid = true;

            if (!value && !value.length) {
                let keyValuePair = _.split(keyValue, ',');
                let input = keyValuePair[0];
                let value = keyValuePair[1];
                valid = value == $(this.form).find(':input[name="' + input + '"]').first().val();
                resolve({valid: valid, message: valid ? null : `The field is required, if ${input} is equal to ${value}.`})
            } else {
                resolve({valid: true, message: null})
            }
        });
    }

    min(value, min) {
        return new Promise((resolve) => {
            let valid = true;
            if (value) {
                valid = value.length >= min;
            }
            resolve({valid: valid, message: valid ? null : `Please enter at least ${min} characters.`})
        });
    }

    max(value, max) {
        return new Promise((resolve) => {
            let valid = true;
            if (value) {
                valid = value.length <= max;
            }
            resolve({valid: valid, message: valid ? null : `The input may not be greater than ${max} characters.`})
        });
    }

    confirmed(value, confirmInputName) {
        return new Promise((resolve) => {
            let valid = true;
            let input = this.findClosestInput(confirmInputName);

            // Only validate if an input to compare exists on the validated form
            if (input && value) {
                valid = value === input.val();

            }

            resolve({valid: valid, message: valid ? null : `The confirmation does not match.`})
        });
    }

    email(value) {
        return new Promise((resolve) => {
            let valid = true;
            if (value) {
                valid = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i.test(value);
            }
            resolve({valid: valid, message: valid ? null : `Please enter a valid email address.`})
        });
    }

    phone(value) {
        return new Promise((resolve) => {
            let valid = true;
            if (value) {
                valid = /^[0-9 +-]*$/.test(value);
            }
            resolve({valid: valid, message: valid ? null : `Please enter a valid phone number.`})
        });
    }

    accepted(value) {
        return new Promise((resolve) => {
            let valid = value === 'on' || value === 'true' || value === 1 || value === true;
            resolve({valid: valid, message: valid ? null : `This must be accepted.`})
        });
    }

    url(value) {
        return new Promise((resolve) => {
            let valid = true;
            if (value) {
                valid = /^(?:(?:https?|ftp):\/\/)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/\S*)?$/.test(value);
            }
            resolve({valid: valid, message: valid ? null : `Please enter a valid url.`})
        });
    }

    date(value) {
        return new Promise((resolve) => {
            let valid = value ? moment(value).isValid() : true;
            resolve({valid: valid, message: valid ? null : `Please enter a valid date.`})
        });
    }

    after(value, comparisonDateInputName) {
        return new Promise((resolve) => {
            let valid = true;
            let comparisonValue = this.parseComparisonInputValue(comparisonDateInputName);

            // Only validate if a value to compare exists on the validated form
            if (comparisonValue) {
                let dateValue = moment(value);

                if (dateValue.isValid()) {
                    valid = dateValue.isAfter(comparisonValue);
                }
            }

            resolve({valid: valid, message: valid ? null : `The date must be after ${comparisonDateInputName}.`})
        });
    }

    before(value, comparisonDateInputName) {
        return new Promise((resolve) => {
            let valid = true;
            let comparisonValue = this.parseComparisonInputValue(comparisonDateInputName);

            // Only validate if a value to compare exists on the validated form
            if (comparisonValue) {
                let dateValue = moment(value);

                if (dateValue.isValid()) {
                    valid = dateValue.isBefore(comparisonValue);
                }
            }

            resolve({valid: valid, message: valid ? null : `The date must be before ${comparisonDateInputName}.`})
        });
    }

    same(value, comparisonDateInputName) {
        return new Promise((resolve) => {
            let valid = true;
            let comparisonValue = this.parseComparisonInputValue(comparisonDateInputName);

            // Only validate if a value to compare exists on the validated form
            if (comparisonValue) {
                let dateValue = moment(value);

                if (dateValue.isValid()) {
                    valid = dateValue.isSame(comparisonValue);
                }
            }

            resolve({valid: valid, message: valid ? null : `The date must be the same as ${comparisonDateInputName}.`})
        });
    }

    /**
     * Tries to find the closest input with the specified name on the validated form.
     *
     * @param inputName
     */
    findClosestInput(inputName) {

        let selector = ':input[name="' + inputName + '"]';

        // Check if a wildcard is included in the input name. If so, we just use the part after the wildcard to find the input
        if (inputName.indexOf('*') > -1) {
            inputName = inputName.substring(inputName.lastIndexOf('*') + 1, inputName.length); // Make sure we split at the last occurrence of a wildcard
            selector = ':input[name$="' + inputName + '"]'; // Retrieve the input whose name ends with our calculated input name
        }

        let input = $(this.form).find(selector).first();

        return input.length ? input : null;
    }

    /**
     * Tries to find the value for the specified input name. Can also be a date.
     *
     * @param inputName
     */
    parseComparisonInputValue(inputName) {

        // Check if an input with the name exists on the validated form. If so, we retrieve its value.
        let input = this.findClosestInput(inputName);
        if (input) {
            return input.val();
        }

        // Check if the input name represents the today's date
        if (['now', 'today'].indexOf(inputName) > -1) {
            return moment();
        }

        // Check if the input name represents the yesterday's date
        if (['yesterday'].indexOf(inputName) > -1) {
            return moment().subtract(1, 'days');
        }

        // Check if the input name represents the tomorrow's date
        if (['tomorrow'].indexOf(inputName) > -1) {
            return moment().add(1, 'days');
        }

        // Check if the input represents any date
        let dateValue = moment(inputName);
        if (dateValue.isValid()) {
            return dateValue;
        }

        return null;
    }

}

export default Validation;

<|endoftext|>