<commit_before>Package.describe({
    name: 'viewerbase',
    summary: 'Shared components and functions for Meteor DICOM Viewers',
    version: '0.0.1'
});

Package.onUse(function(api) {
    api.versionsFrom('1.4');

    api.use('ecmascript');
    api.use('standard-app-packages');
    api.use('http');
    api.use('jquery');
    api.use('stylus');
    api.use('practicalmeteor:loglevel');
    api.use('momentjs:moment');
    api.use('validatejs');

    // Our custom packages
    api.use('design');
    api.use('ohif:core');
    api.use('cornerstone');

    api.addFiles('log.js');

    api.addAssets('assets/icons.svg', 'client');

    // TODO: Use NPM depends for these
    api.addFiles('client/compatibility/jquery.hotkeys.js', 'client', {
        bare: true
    });
    api.addFiles('client/compatibility/dialogPolyfill.js', 'client', {
        bare: true
    });
    api.addFiles('client/compatibility/dialogPolyfill.styl', 'client');

    // ---------- Collections ----------
    api.addFiles('client/collections.js', 'client');

    // ---------- Components ----------

    // Basic components
    api.addFiles('client/components/basic/layout/layout.html', 'client');
    api.addFiles('client/components/basic/loadingText/loadingText.html', 'client');
    api.addFiles('client/components/basic/loadingText/loadingText.styl', 'client');

    api.addFiles('client/components/basic/removableBackdrop/removableBackdrop.html', 'client');
    api.addFiles('client/components/basic/removableBackdrop/removableBackdrop.styl', 'client');

    api.addFiles('client/components/basic/aboutModal/aboutModal.html', 'client');
    api.addFiles('client/components/basic/aboutModal/aboutModal.js', 'client');
    api.addFiles('client/components/basic/aboutModal/aboutModal.styl', 'client');

    // Study Browser components
    api.addFiles('client/components/studyBrowser/studyBrowser/studyBrowser.html', 'client');
    api.addFiles('client/components/studyBrowser/studyBrowser/studyBrowser.js', 'client');
    api.addFiles('client/components/studyBrowser/studyBrowser/studyBrowser.styl', 'client');

    api.addFiles('client/components/studyBrowser/thumbnailEntry/thumbnailEntry.html', 'client');
    api.addFiles('client/components/studyBrowser/thumbnailEntry/thumbnailEntry.js', 'client');
    api.addFiles('client/components/studyBrowser/thumbnailEntry/thumbnailEntry.styl', 'client');

    api.addFiles('client/components/studyBrowser/imageThumbnail/imageThumbnail.html', 'client');
    api.addFiles('client/components/studyBrowser/imageThumbnail/imageThumbnail.js', 'client');
    api.addFiles('client/components/studyBrowser/imageThumbnail/imageThumbnail.styl', 'client');

    // Viewer components
    api.addFiles('client/components/viewer/imageViewerViewport/imageViewerViewport.html', 'client');
    api.addFiles('client/components/viewer/imageViewerViewport/imageViewerViewport.js', 'client');
    api.addFiles('client/components/viewer/imageViewerViewport/imageViewerViewport.styl', 'client');

    api.addFiles('client/components/viewer/gridLayout/gridLayout.html', 'client');
    api.addFiles('client/components/viewer/gridLayout/gridLayout.js', 'client');
    api.addFiles('client/components/viewer/gridLayout/gridLayout.styl', 'client');

    api.addFiles('client/components/viewer/loadingIndicator/loadingIndicator.html', 'client');
    api.addFiles('client/components/viewer/loadingIndicator/loadingIndicator.js', 'client');
    api.addFiles('client/components/viewer/loadingIndicator/loadingIndicator.styl', 'client');

    api.addFiles('client/components/viewer/annotationDialogs/annotationDialogs.html', 'client');
    api.addFiles('client/components/viewer/annotationDialogs/annotationDialogs.js', 'client');
    api.addFiles('client/components/viewer/annotationDialogs/annotationDialogs.styl', 'client');

    api.addFiles('client/components/viewer/viewportOrientationMarkers/viewportOrientationMarkers.html', 'client');
    api.addFiles('client/components/viewer/viewportOrientationMarkers/viewportOrientationMarkers.js', 'client');
    api.addFiles('client/components/viewer/viewportOrientationMarkers/viewportOrientationMarkers.styl', 'client');

    api.addFiles('client/components/viewer/viewportOverlay/viewportOverlay.html', 'client');
    api.addFiles('client/components/viewer/viewportOverlay/viewportOverlay.js', 'client');
    api.addFiles('client/components/viewer/viewportOverlay/viewportOverlay.styl', 'client');

    api.addFiles('client/components/viewer/viewerMain/viewerMain.html', 'client');
    api.addFiles('client/components/viewer/viewerMain/viewerMain.js', 'client');
    api.addFiles('client/components/viewer/viewerMain/viewerMain.styl', 'client');

    api.addFiles('client/components/viewer/imageControls/imageControls.html', 'client');
    api.addFiles('client/components/viewer/imageControls/imageControls.js', 'client');
    api.addFiles('client/components/viewer/imageControls/imageControls.styl', 'client');

    api.addFiles('client/components/viewer/layoutButton/layoutButton.html', 'client');
    api.addFiles('client/components/viewer/layoutButton/layoutButton.js', 'client');

    api.addFiles('client/components/viewer/layoutChooser/layoutChooser.html', 'client');
    api.addFiles('client/components/viewer/layoutChooser/layoutChooser.js', 'client');
    api.addFiles('client/components/viewer/layoutChooser/layoutChooser.styl', 'client');

    api.addFiles('client/components/viewer/cineDialog/cineDialog.html', 'client');
    api.addFiles('client/components/viewer/cineDialog/cineDialog.js', 'client');
    api.addFiles('client/components/viewer/cineDialog/cineDialog.styl', 'client');

    api.addFiles('client/components/viewer/toolbarSectionButton/toolbarSectionButton.html', 'client');
    api.addFiles('client/components/viewer/toolbarSectionButton/toolbarSectionButton.js', 'client');
    api.addFiles('client/components/viewer/toolbarSectionButton/toolbarSectionButton.styl', 'client');

    api.addFiles('client/components/viewer/toolbarSectionTools/toolbarSectionTools.html', 'client');
    api.addFiles('client/components/viewer/toolbarSectionTools/toolbarSectionTools.js', 'client');
    api.addFiles('client/components/viewer/toolbarSectionTools/toolbarSectionTools.styl', 'client');

    api.addFiles('client/components/viewer/playClipButton/playClipButton.html', 'client');
    api.addFiles('client/components/viewer/playClipButton/playClipButton.js', 'client');

    api.addFiles('client/components/viewer/confirmDeleteDialog/confirmDeleteDialog.js', 'client');
    api.addFiles('client/components/viewer/confirmDeleteDialog/confirmDeleteDialog.html', 'client');
    api.addFiles('client/components/viewer/confirmDeleteDialog/confirmDeleteDialog.styl', 'client');

    // Library functions
    api.addFiles('lib/layoutManager.js', 'client');
    api.addFiles('lib/createStacks.js', 'client');
    api.addFiles('lib/getImageId.js', 'client');
    api.addFiles('lib/getWADORSImageId.js', 'client');
    api.addFiles('lib/metaDataProvider.js', 'client');
    api.addFiles('lib/sortStudy.js', 'client');
    api.addFiles('lib/toolManager.js', 'client');
    api.addFiles('lib/enablePrefetchOnElement.js', 'client');
    api.addFiles('lib/displayReferenceLines.js', 'client');
    api.addFiles('lib/toggleDialog.js', 'client');
    api.addFiles('lib/setActiveViewport.js', 'client');
    api.addFiles('lib/switchToImageByIndex.js', 'client');
    api.addFiles('lib/switchToImageRelative.js', 'client');
    api.addFiles('lib/enableHotkeys.js', 'client');
    api.addFiles('lib/viewportFunctions.js', 'client');
    api.addFiles('lib/WLPresets.js', 'client');
    api.addFiles('lib/resizeViewportElements.js', 'client');
    api.addFiles('lib/setFocusToActiveViewport.js', 'client');
    api.addFiles('lib/updateAllViewports.js', 'client');

    api.addFiles('lib/instanceClassSpecificViewport.js', 'client');
    api.addFiles('lib/setMammogramViewportAlignment.js', 'client');
    api.addFiles('lib/isImage.js', 'client');
    api.addFiles('lib/sopClassDictionary.js', 'client');
    api.addFiles('lib/debugReactivity.js', 'client');

    api.export('resizeViewportElements', 'client');
    api.export('handleResize', 'client');
    api.export('enableHotkeys', 'client');
    api.export('enablePrefetchOnElement', 'client');
    api.export('displayReferenceLines', 'client');
    api.export('setActiveViewport', 'client');
    api.export('createStacks', 'client');
    api.export('getImageId', 'client');
    api.export('getWADORSImageId', 'client');
    api.export('metaDataProvider', 'client');
    api.export('sortStudy', 'client');
    api.export('updateOrientationMarkers', 'client');
    api.export('setFocusToActiveViewport', 'client');
    api.export('updateAllViewports', 'client');
    api.export('queryStudies', 'client');
    api.export('getNumberOfFilesInStudy', 'client');
    api.export('exportStudies', 'client');
    api.export('importStudies', 'client');
    api.export('getActiveViewportElement', 'client');
    api.export('getInstanceClassDefaultViewport', 'client');
    api.export('showConfirmDialog', 'client');
    api.export('applyWLPreset', 'client');
    api.export('toggleDialog', 'client');
    api.export('isImage', 'client');
    api.export('sopClassDictionary', 'client');
    api.export('addMetaData', 'client');

    // Viewer management objects
    api.export('toolManager', 'client');
    api.export('LayoutManager', 'client');

    // Global objects
    api.export('ClientId', 'client');

    // Collections
    api.export('ViewerStudies', 'client');

    // UI Helpers
    api.addFiles([
        'lib/helpers/formatDA.js',
        'lib/helpers/formatJSDate.js',
        'lib/helpers/jsDateFromNow.js',
        'lib/helpers/formatNumberPrecision.js',
        'lib/helpers/formatTM.js',
        'lib/helpers/inlineIf.js',
        'lib/helpers/inc.js',
        'lib/helpers/isDisplaySetActive.js',
        'lib/helpers/getUsername.js',
        'lib/helpers/capitalizeFirstLetter.js',
        'lib/helpers/objectToPairs.js',
        'lib/helpers/objectEach.js',
        'lib/helpers/ifTypeIs.js',
        'lib/helpers/prettyPrintStringify.js',
        'lib/helpers/studyThumbnails.js',
        'lib/helpers/formatPN.js'
    ], 'client');
    api.export('formatPN', 'client');

    api.addFiles('lib/helpers/isTouchDevice.js', 'client');
    api.export('isTouchDevice', 'client');

    // TODO: Clean this up later, no real need to export these
    // Need to move functionList into viewerbase
    api.export('toggleCineDialog', 'client');
    api.export('toggleCinePlay', 'client');
    api.export('clearTools', 'client');
    api.export('resetViewport', 'client');
    api.export('invert', 'client');
});
<commit_msg>add showConfirmDialog necessary files<commit_after>Package.describe({
    name: 'viewerbase',
    summary: 'Shared components and functions for Meteor DICOM Viewers',
    version: '0.0.1'
});

Package.onUse(function(api) {
    api.versionsFrom('1.4');

    api.use('ecmascript');
    api.use('standard-app-packages');
    api.use('http');
    api.use('jquery');
    api.use('stylus');
    api.use('practicalmeteor:loglevel');
    api.use('momentjs:moment');
    api.use('validatejs');

    // Our custom packages
    api.use('design');
    api.use('ohif:core');
    api.use('cornerstone');

    api.addFiles('log.js');

    api.addAssets('assets/icons.svg', 'client');

    // TODO: Use NPM depends for these
    api.addFiles('client/compatibility/jquery.hotkeys.js', 'client', {
        bare: true
    });
    api.addFiles('client/compatibility/dialogPolyfill.js', 'client', {
        bare: true
    });
    api.addFiles('client/compatibility/dialogPolyfill.styl', 'client');

    // ---------- Collections ----------
    api.addFiles('client/collections.js', 'client');

    // ---------- Components ----------

    // Basic components
    api.addFiles('client/components/basic/layout/layout.html', 'client');
    api.addFiles('client/components/basic/loadingText/loadingText.html', 'client');
    api.addFiles('client/components/basic/loadingText/loadingText.styl', 'client');

    api.addFiles('client/components/basic/removableBackdrop/removableBackdrop.html', 'client');
    api.addFiles('client/components/basic/removableBackdrop/removableBackdrop.styl', 'client');

    api.addFiles('client/components/basic/aboutModal/aboutModal.html', 'client');
    api.addFiles('client/components/basic/aboutModal/aboutModal.js', 'client');
    api.addFiles('client/components/basic/aboutModal/aboutModal.styl', 'client');

    // Study Browser components
    api.addFiles('client/components/studyBrowser/studyBrowser/studyBrowser.html', 'client');
    api.addFiles('client/components/studyBrowser/studyBrowser/studyBrowser.js', 'client');
    api.addFiles('client/components/studyBrowser/studyBrowser/studyBrowser.styl', 'client');

    api.addFiles('client/components/studyBrowser/thumbnailEntry/thumbnailEntry.html', 'client');
    api.addFiles('client/components/studyBrowser/thumbnailEntry/thumbnailEntry.js', 'client');
    api.addFiles('client/components/studyBrowser/thumbnailEntry/thumbnailEntry.styl', 'client');

    api.addFiles('client/components/studyBrowser/imageThumbnail/imageThumbnail.html', 'client');
    api.addFiles('client/components/studyBrowser/imageThumbnail/imageThumbnail.js', 'client');
    api.addFiles('client/components/studyBrowser/imageThumbnail/imageThumbnail.styl', 'client');

    // Viewer components
    api.addFiles('client/components/viewer/imageViewerViewport/imageViewerViewport.html', 'client');
    api.addFiles('client/components/viewer/imageViewerViewport/imageViewerViewport.js', 'client');
    api.addFiles('client/components/viewer/imageViewerViewport/imageViewerViewport.styl', 'client');

    api.addFiles('client/components/viewer/gridLayout/gridLayout.html', 'client');
    api.addFiles('client/components/viewer/gridLayout/gridLayout.js', 'client');
    api.addFiles('client/components/viewer/gridLayout/gridLayout.styl', 'client');

    api.addFiles('client/components/viewer/loadingIndicator/loadingIndicator.html', 'client');
    api.addFiles('client/components/viewer/loadingIndicator/loadingIndicator.js', 'client');
    api.addFiles('client/components/viewer/loadingIndicator/loadingIndicator.styl', 'client');

    api.addFiles('client/components/viewer/annotationDialogs/annotationDialogs.html', 'client');
    api.addFiles('client/components/viewer/annotationDialogs/annotationDialogs.js', 'client');
    api.addFiles('client/components/viewer/annotationDialogs/annotationDialogs.styl', 'client');

    api.addFiles('client/components/viewer/viewportOrientationMarkers/viewportOrientationMarkers.html', 'client');
    api.addFiles('client/components/viewer/viewportOrientationMarkers/viewportOrientationMarkers.js', 'client');
    api.addFiles('client/components/viewer/viewportOrientationMarkers/viewportOrientationMarkers.styl', 'client');

    api.addFiles('client/components/viewer/viewportOverlay/viewportOverlay.html', 'client');
    api.addFiles('client/components/viewer/viewportOverlay/viewportOverlay.js', 'client');
    api.addFiles('client/components/viewer/viewportOverlay/viewportOverlay.styl', 'client');

    api.addFiles('client/components/viewer/viewerMain/viewerMain.html', 'client');
    api.addFiles('client/components/viewer/viewerMain/viewerMain.js', 'client');
    api.addFiles('client/components/viewer/viewerMain/viewerMain.styl', 'client');

    api.addFiles('client/components/viewer/imageControls/imageControls.html', 'client');
    api.addFiles('client/components/viewer/imageControls/imageControls.js', 'client');
    api.addFiles('client/components/viewer/imageControls/imageControls.styl', 'client');

    api.addFiles('client/components/viewer/layoutButton/layoutButton.html', 'client');
    api.addFiles('client/components/viewer/layoutButton/layoutButton.js', 'client');

    api.addFiles('client/components/viewer/layoutChooser/layoutChooser.html', 'client');
    api.addFiles('client/components/viewer/layoutChooser/layoutChooser.js', 'client');
    api.addFiles('client/components/viewer/layoutChooser/layoutChooser.styl', 'client');

    api.addFiles('client/components/viewer/cineDialog/cineDialog.html', 'client');
    api.addFiles('client/components/viewer/cineDialog/cineDialog.js', 'client');
    api.addFiles('client/components/viewer/cineDialog/cineDialog.styl', 'client');

    api.addFiles('client/components/viewer/toolbarSectionButton/toolbarSectionButton.html', 'client');
    api.addFiles('client/components/viewer/toolbarSectionButton/toolbarSectionButton.js', 'client');
    api.addFiles('client/components/viewer/toolbarSectionButton/toolbarSectionButton.styl', 'client');

    api.addFiles('client/components/viewer/toolbarSectionTools/toolbarSectionTools.html', 'client');
    api.addFiles('client/components/viewer/toolbarSectionTools/toolbarSectionTools.js', 'client');
    api.addFiles('client/components/viewer/toolbarSectionTools/toolbarSectionTools.styl', 'client');

    api.addFiles('client/components/viewer/playClipButton/playClipButton.html', 'client');
    api.addFiles('client/components/viewer/playClipButton/playClipButton.js', 'client');

    api.addFiles('client/components/viewer/confirmDeleteDialog/confirmDeleteDialog.html', 'client');
    api.addFiles('client/components/viewer/confirmDeleteDialog/confirmDeleteDialog.js', 'client');
    api.addFiles('client/components/viewer/confirmDeleteDialog/confirmDeleteDialog.styl', 'client');

    // Library functions
    api.addFiles('lib/layoutManager.js', 'client');
    api.addFiles('lib/createStacks.js', 'client');
    api.addFiles('lib/getImageId.js', 'client');
    api.addFiles('lib/getWADORSImageId.js', 'client');
    api.addFiles('lib/metaDataProvider.js', 'client');
    api.addFiles('lib/sortStudy.js', 'client');
    api.addFiles('lib/toolManager.js', 'client');
    api.addFiles('lib/enablePrefetchOnElement.js', 'client');
    api.addFiles('lib/displayReferenceLines.js', 'client');
    api.addFiles('lib/toggleDialog.js', 'client');
    api.addFiles('lib/setActiveViewport.js', 'client');
    api.addFiles('lib/switchToImageByIndex.js', 'client');
    api.addFiles('lib/switchToImageRelative.js', 'client');
    api.addFiles('lib/enableHotkeys.js', 'client');
    api.addFiles('lib/viewportFunctions.js', 'client');
    api.addFiles('lib/WLPresets.js', 'client');
    api.addFiles('lib/resizeViewportElements.js', 'client');
    api.addFiles('lib/setFocusToActiveViewport.js', 'client');
    api.addFiles('lib/updateAllViewports.js', 'client');

    api.addFiles('lib/instanceClassSpecificViewport.js', 'client');
    api.addFiles('lib/setMammogramViewportAlignment.js', 'client');
    api.addFiles('lib/isImage.js', 'client');
    api.addFiles('lib/sopClassDictionary.js', 'client');
    api.addFiles('lib/debugReactivity.js', 'client');

    api.export('resizeViewportElements', 'client');
    api.export('handleResize', 'client');
    api.export('enableHotkeys', 'client');
    api.export('enablePrefetchOnElement', 'client');
    api.export('displayReferenceLines', 'client');
    api.export('setActiveViewport', 'client');
    api.export('createStacks', 'client');
    api.export('getImageId', 'client');
    api.export('getWADORSImageId', 'client');
    api.export('metaDataProvider', 'client');
    api.export('sortStudy', 'client');
    api.export('updateOrientationMarkers', 'client');
    api.export('setFocusToActiveViewport', 'client');
    api.export('updateAllViewports', 'client');
    api.export('queryStudies', 'client');
    api.export('getNumberOfFilesInStudy', 'client');
    api.export('exportStudies', 'client');
    api.export('importStudies', 'client');
    api.export('getActiveViewportElement', 'client');
    api.export('getInstanceClassDefaultViewport', 'client');
    api.export('showConfirmDialog', 'client');
    api.export('applyWLPreset', 'client');
    api.export('toggleDialog', 'client');
    api.export('isImage', 'client');
    api.export('sopClassDictionary', 'client');
    api.export('addMetaData', 'client');

    // Viewer management objects
    api.export('toolManager', 'client');
    api.export('LayoutManager', 'client');

    // Global objects
    api.export('ClientId', 'client');

    // Collections
    api.export('ViewerStudies', 'client');

    // UI Helpers
    api.addFiles([
        'lib/helpers/formatDA.js',
        'lib/helpers/formatJSDate.js',
        'lib/helpers/jsDateFromNow.js',
        'lib/helpers/formatNumberPrecision.js',
        'lib/helpers/formatTM.js',
        'lib/helpers/inlineIf.js',
        'lib/helpers/inc.js',
        'lib/helpers/isDisplaySetActive.js',
        'lib/helpers/getUsername.js',
        'lib/helpers/capitalizeFirstLetter.js',
        'lib/helpers/objectToPairs.js',
        'lib/helpers/objectEach.js',
        'lib/helpers/ifTypeIs.js',
        'lib/helpers/prettyPrintStringify.js',
        'lib/helpers/studyThumbnails.js',
        'lib/helpers/formatPN.js'
    ], 'client');
    api.export('formatPN', 'client');

    api.addFiles('lib/helpers/isTouchDevice.js', 'client');
    api.export('isTouchDevice', 'client');

    // TODO: Clean this up later, no real need to export these
    // Need to move functionList into viewerbase
    api.export('toggleCineDialog', 'client');
    api.export('toggleCinePlay', 'client');
    api.export('clearTools', 'client');
    api.export('resetViewport', 'client');
    api.export('invert', 'client');
});
<|endoftext|>


<commit_before>const React = require('react');
const ReactTooltip = require('react-tooltip');
const cn = require('classnames');

const ytCtrl = require('../client-lib/yt-ctrl.js');
const sendMetricsEvent = require('../client-lib/send-metrics-event.js');
const sendToAddon = require('../client-lib/send-to-addon.js');
const GeneralControls = require('./general-controls.js');

function formatTime(seconds) {
  const now = new Date(seconds * 1000);
  const utc = new Date(now.getTime() + (now.getTimezoneOffset() * 60 * 1000));
  return utc.toLocaleTimeString('en-US', {hour12: false})
    .replace(/^00:/, '') // Strip leading "00:" if hours is empty.
    .replace(/^0/, '');  // Strip leading "0" in minutes, if any.
}

module.exports = React.createClass({
  getInitialState: function() {
    return {showVolume: false, hovered: false};
  },
  step: function() {
    const currentTime = this.isYt ? ytCtrl.getTime() : this.refs.video.currentTime;

    window.AppData = Object.assign(window.AppData, {
      currentTime: `${formatTime(currentTime)} / ${formatTime(window.AppData.duration)}`,
      progress: currentTime / window.AppData.duration
    });

    // TODO: the "-1" is a hack to force YouTube embeds to do what we
    // want. #184
    if (currentTime >= window.AppData.duration - 1) {
      window.AppData = Object.assign(window.AppData, {
        playing: false,
        playedCount: (window.AppData.playedCount + 1)
      });

      sendMetricsEvent('player_view', 'video_ended');
    }

    if (window.AppData.playing) requestAnimationFrame(this.step);
  },
  onLoaded: function() {
    sendMetricsEvent('player_view', 'video_loaded');
    const duration = this.isYt ? ytCtrl.getDuration() : this.refs.video.duration;

    // set initial volume
    this.setVolume({
      target: {
        value: this.props.volume
      }
    });

    window.AppData = Object.assign(window.AppData, {
      loaded: true,
      duration: duration
    });

    requestAnimationFrame(this.step);
  },
  componentWillMount: function() {
    this.isYt = !!~this.props.domain.indexOf('youtube.com');
  },
  componentDidMount: function() {
    if (this.isYt) {
      const PLAYING = window.YT.PlayerState.PLAYING;
      const PAUSED = window.YT.PlayerState.PAUSED;

      ytCtrl.init('video', {
        onReady: this.onLoaded,
        onStateChange: (ev) => {
          if (ev.data === PLAYING && !this.props.playing) this.play();
          else if (ev.data === PAUSED && this.props.playing) this.pause();
        },
        onError: (err) => {
          const url = `https://youtube.com/watch?v=${this.props.id}`;
          window.AppData.error = `There was an error loading your video from ${url}`;
          console.error('Error: ytCtrl: ', err); // eslint-disable-line no-console
        }
      });
    } else {
      this.refs.video.addEventListener('canplay', this.onLoaded);
      this.refs.video.addEventListener('durationchange', this.onLoaded);
    }
  },
  play: function() {
    if (this.hasExited() && !this.isYt) {
      if (!this.isYt) {
        return this.replay();
      } else {
        sendMetricsEvent('player_view', 'replay');
      }
    }
    sendMetricsEvent('player_view', 'play');
    if (this.isYt) {
      ytCtrl.play();
    } else {
      this.refs.video.play();
    }
    window.AppData.playing = true;
    requestAnimationFrame(this.step);
  },
  pause: function() {
    sendMetricsEvent('player_view', 'pause');
    if (this.isYt) {
      ytCtrl.pause();
    } else {
      this.refs.video.pause();
    }

    window.AppData.playing = false;
  },
  mute: function() {
    sendMetricsEvent('player_view', 'mute');

    if (this.isYt) {
      ytCtrl.mute();
    } else {
      this.refs.video.muted = true;
    }

    window.AppData = Object.assign(window.AppData, {muted: true});
  },
  unmute: function() {
    sendMetricsEvent('player_view', 'unmute');

    if (this.isYt) {
      ytCtrl.unmute();
      ytCtrl.setVolume(window.AppData.volume * 100);
    } else {
      this.refs.video.muted = false;
    }

    window.AppData = Object.assign(window.AppData, {muted: false});
  },
  setVolume: function(ev) {
    const muted = (ev.target.value === 0);

    if (this.isYt) {
      ytCtrl.setVolume(parseFloat(ev.target.value) * 100);
    } else {
      this.refs.video.volume = ev.target.value;
    }

    window.AppData = Object.assign(window.AppData, {
      muted: muted,
      volume: ev.target.value
    });
  },
  setTime: function(ev) {
    const x = ev.pageX - ev.target.offsetLeft;
    const clickedValue = x * ev.target.max / ev.target.offsetWidth;

    if (this.isYt) {
      ytCtrl.setTime(window.AppData.duration * clickedValue);
    } else {
      this.refs.video.currentTime = window.AppData.duration * clickedValue;
    }
  },
  replay: function() {
    sendMetricsEvent('player_view', 'replay');
    this.refs.video.currentTime = 0;
    this.step(); // step once to set currentTime of window.AppData and progress
    this.play();
  },
  close: function() {
    sendMetricsEvent('player_view', 'close');
    sendToAddon({action: 'close'});
  },
  enterControls: function() {
    this.setState({showVolume: true});
  },
  leaveControls: function() {
    this.setState({showVolume: false});
  },
  enterPlayer: function() {
    this.setState({hovered: true});
  },
  leavePlayer: function() {
    this.setState({hovered: false});
  },
  hasExited: function() {
    if (!this.refs.video || !window.AppData.loaded) return false;
    const currentTime = this.isYt ? ytCtrl.getTime() : this.refs.video.currentTime;
    return (!this.props.playing && (currentTime >= this.props.duration - 1)); // TODO: the "-1" is a hack to force YouTube embeds to do what we want. #184
  },
  handleVideoClick: function(ev) {
    if (!ev.target.classList.contains('video-wrapper')) return;
    if (this.props.playing) this.pause();
    else this.play();
  },
  render: function() {
    const noop = () => false;
    const videoEl = this.isYt ?
          () :
          (<video id={'video'} ref={'video'} src={this.props.src} autoplay={false} onContextMenu={noop} />);

    return (

              <ReactTooltip place='bottom' effect='solid' />

              <input type='range' className={cn('volume', {hidden: !this.state.showVolume})}
                     min='0' max='1' step='.01' value={this.props.muted ? 0 : this.props.volume}
                     onChange={this.setVolume}/>

            <GeneralControls {...this.props} isYt={this.isYt} />

              <button className='exit-replay' onClick={this.replay}></button>
              <button className='exit-close' onClick={this.close}></button>

            {this.props.domain}

{this.props.currentTime}

            <progress className={'video-progress'} onClick={this.setTime}
                      value={this.props.progress + ''}  />

          {videoEl}

    );
  }
});
<commit_msg>Do not show replay view when minimized<commit_after>const React = require('react');
const ReactTooltip = require('react-tooltip');
const cn = require('classnames');

const ytCtrl = require('../client-lib/yt-ctrl.js');
const sendMetricsEvent = require('../client-lib/send-metrics-event.js');
const sendToAddon = require('../client-lib/send-to-addon.js');
const GeneralControls = require('./general-controls.js');

function formatTime(seconds) {
  const now = new Date(seconds * 1000);
  const utc = new Date(now.getTime() + (now.getTimezoneOffset() * 60 * 1000));
  return utc.toLocaleTimeString('en-US', {hour12: false})
    .replace(/^00:/, '') // Strip leading "00:" if hours is empty.
    .replace(/^0/, '');  // Strip leading "0" in minutes, if any.
}

module.exports = React.createClass({
  getInitialState: function() {
    return {showVolume: false, hovered: false};
  },
  step: function() {
    const currentTime = this.isYt ? ytCtrl.getTime() : this.refs.video.currentTime;

    window.AppData = Object.assign(window.AppData, {
      currentTime: `${formatTime(currentTime)} / ${formatTime(window.AppData.duration)}`,
      progress: currentTime / window.AppData.duration
    });

    // TODO: the "-1" is a hack to force YouTube embeds to do what we
    // want. #184
    if (currentTime >= window.AppData.duration - 1) {
      window.AppData = Object.assign(window.AppData, {
        playing: false,
        playedCount: (window.AppData.playedCount + 1)
      });

      sendMetricsEvent('player_view', 'video_ended');
    }

    if (window.AppData.playing) requestAnimationFrame(this.step);
  },
  onLoaded: function() {
    sendMetricsEvent('player_view', 'video_loaded');
    const duration = this.isYt ? ytCtrl.getDuration() : this.refs.video.duration;

    // set initial volume
    this.setVolume({
      target: {
        value: this.props.volume
      }
    });

    window.AppData = Object.assign(window.AppData, {
      loaded: true,
      duration: duration
    });

    requestAnimationFrame(this.step);
  },
  componentWillMount: function() {
    this.isYt = !!~this.props.domain.indexOf('youtube.com');
  },
  componentDidMount: function() {
    if (this.isYt) {
      const PLAYING = window.YT.PlayerState.PLAYING;
      const PAUSED = window.YT.PlayerState.PAUSED;

      ytCtrl.init('video', {
        onReady: this.onLoaded,
        onStateChange: (ev) => {
          if (ev.data === PLAYING && !this.props.playing) this.play();
          else if (ev.data === PAUSED && this.props.playing) this.pause();
        },
        onError: (err) => {
          const url = `https://youtube.com/watch?v=${this.props.id}`;
          window.AppData.error = `There was an error loading your video from ${url}`;
          console.error('Error: ytCtrl: ', err); // eslint-disable-line no-console
        }
      });
    } else {
      this.refs.video.addEventListener('canplay', this.onLoaded);
      this.refs.video.addEventListener('durationchange', this.onLoaded);
    }
  },
  play: function() {
    if (this.hasExited() && !this.isYt) {
      if (!this.isYt) {
        return this.replay();
      } else {
        sendMetricsEvent('player_view', 'replay');
      }
    }
    sendMetricsEvent('player_view', 'play');
    if (this.isYt) {
      ytCtrl.play();
    } else {
      this.refs.video.play();
    }
    window.AppData.playing = true;
    requestAnimationFrame(this.step);
  },
  pause: function() {
    sendMetricsEvent('player_view', 'pause');
    if (this.isYt) {
      ytCtrl.pause();
    } else {
      this.refs.video.pause();
    }

    window.AppData.playing = false;
  },
  mute: function() {
    sendMetricsEvent('player_view', 'mute');

    if (this.isYt) {
      ytCtrl.mute();
    } else {
      this.refs.video.muted = true;
    }

    window.AppData = Object.assign(window.AppData, {muted: true});
  },
  unmute: function() {
    sendMetricsEvent('player_view', 'unmute');

    if (this.isYt) {
      ytCtrl.unmute();
      ytCtrl.setVolume(window.AppData.volume * 100);
    } else {
      this.refs.video.muted = false;
    }

    window.AppData = Object.assign(window.AppData, {muted: false});
  },
  setVolume: function(ev) {
    const muted = (ev.target.value === 0);

    if (this.isYt) {
      ytCtrl.setVolume(parseFloat(ev.target.value) * 100);
    } else {
      this.refs.video.volume = ev.target.value;
    }

    window.AppData = Object.assign(window.AppData, {
      muted: muted,
      volume: ev.target.value
    });
  },
  setTime: function(ev) {
    const x = ev.pageX - ev.target.offsetLeft;
    const clickedValue = x * ev.target.max / ev.target.offsetWidth;

    if (this.isYt) {
      ytCtrl.setTime(window.AppData.duration * clickedValue);
    } else {
      this.refs.video.currentTime = window.AppData.duration * clickedValue;
    }
  },
  replay: function() {
    sendMetricsEvent('player_view', 'replay');
    this.refs.video.currentTime = 0;
    this.step(); // step once to set currentTime of window.AppData and progress
    this.play();
  },
  close: function() {
    sendMetricsEvent('player_view', 'close');
    sendToAddon({action: 'close'});
  },
  enterControls: function() {
    this.setState({showVolume: true});
  },
  leaveControls: function() {
    this.setState({showVolume: false});
  },
  enterPlayer: function() {
    this.setState({hovered: true});
  },
  leavePlayer: function() {
    this.setState({hovered: false});
  },
  hasExited: function() {
    if (!this.refs.video || !window.AppData.loaded) return false;
    const currentTime = this.isYt ? ytCtrl.getTime() : this.refs.video.currentTime;
    return (!this.props.playing && (currentTime >= this.props.duration - 1)); // TODO: the "-1" is a hack to force YouTube embeds to do what we want. #184
  },
  handleVideoClick: function(ev) {
    if (!ev.target.classList.contains('video-wrapper')) return;
    if (this.props.playing) this.pause();
    else this.play();
  },
  render: function() {
    const noop = () => false;
    const videoEl = this.isYt ?
          () :
          (<video id={'video'} ref={'video'} src={this.props.src} autoplay={false} onContextMenu={noop} />);

    return (

              <ReactTooltip place='bottom' effect='solid' />

              <input type='range' className={cn('volume', {hidden: !this.state.showVolume})}
                     min='0' max='1' step='.01' value={this.props.muted ? 0 : this.props.volume}
                     onChange={this.setVolume}/>

            <GeneralControls {...this.props} isYt={this.isYt} />

              <button className='exit-replay' onClick={this.replay}></button>
              <button className='exit-close' onClick={this.close}></button>

            {this.props.domain}

{this.props.currentTime}

            <progress className={'video-progress'} onClick={this.setTime}
                      value={this.props.progress + ''}  />

          {videoEl}

    );
  }
});
<|endoftext|>


<commit_before>const authentication = require('feathers-authentication');
const jwt = require('feathers-authentication-jwt');
<% if(strategies.indexOf('local') !== -1) { %>const local = require('feathers-authentication-local');<% } %>
<% if(oauthProviders.length){ %>const oauth2 = require('feathers-authentication-oauth2');<% } %>
<% oauthProviders.forEach(provider => { %>const <%= provider.strategyName %> = require('<%= provider.module %>');
<% }); %>
module.exports = function () {
  const app = this;
  const config = app.get('authentication');

  // Set up authentication with the secret
  app.configure(authentication(config));
  app.configure(jwt(config.jwt));<% if(strategies.indexOf('local') !== -1) { %>
  app.configure(local(config.local));<% } %>
<% oauthProviders.forEach(provider => { %>
  app.configure(oauth2(Object.assign({
    name: '<%= provider.name %>',
    Strategy: <%= provider.strategyName %>
  }, config.<%= provider.name %>)));
<% }); %>
  // The `authentication` service is used to create a JWT.
  // The before `create` hook registers strategies that can be used
  // to create a new valid JWT (e.g. local or oauth2)
  app.service('authentication').hooks({
    before: {
      create: [
        authentication.hooks.authenticate(config.strategies)
      ],
      remove: [
        authentication.hooks.authenticate('jwt')
      ]
    }
  });
};
<commit_msg>Fix authentication configuration (#280)<commit_after>const authentication = require('feathers-authentication');
const jwt = require('feathers-authentication-jwt');
<% if(strategies.indexOf('local') !== -1) { %>const local = require('feathers-authentication-local');<% } %>
<% if(oauthProviders.length){ %>const oauth2 = require('feathers-authentication-oauth2');<% } %>
<% oauthProviders.forEach(provider => { %>const <%= provider.strategyName %> = require('<%= provider.module %>');
<% }); %>
module.exports = function () {
  const app = this;
  const config = app.get('authentication');

  // Set up authentication with the secret
  app.configure(authentication(config));
  app.configure(jwt());<% if(strategies.indexOf('local') !== -1) { %>
  app.configure(local());<% } %>
<% oauthProviders.forEach(provider => { %>
  app.configure(oauth2(Object.assign({
    name: '<%= provider.name %>',
    Strategy: <%= provider.strategyName %>
  }, config.<%= provider.name %>)));
<% }); %>
  // The `authentication` service is used to create a JWT.
  // The before `create` hook registers strategies that can be used
  // to create a new valid JWT (e.g. local or oauth2)
  app.service('authentication').hooks({
    before: {
      create: [
        authentication.hooks.authenticate(config.strategies)
      ],
      remove: [
        authentication.hooks.authenticate('jwt')
      ]
    }
  });
};
<|endoftext|>


<commit_before>const SubnetsPinger = require('./');

const subnetPinge = new SubnetsPinger();
subnetPinge.on('host:alive', ip => {
  console.log('alive', ip);
});

subnetPinge.ping();<commit_msg>Changed example<commit_after>const SubnetsPinger = require('./');

const subnetPinge = new SubnetsPinger();

subnetPinge.on('host:alive', ip => {
  console.log('alive', ip);
});

subnetPinge.once('ping:end', () => {
  console.log('ping completed');
});

subnetPinge.ping();<|endoftext|>


<commit_before>/**
 * @author benaadams / https://twitter.com/ben_a_adams
 * based on THREE.SphereGeometry
 */

THREE.SphereBufferGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {

	THREE.BufferGeometry.call( this );

	this.type = 'SphereBufferGeometry';

	this.parameters = {
		radius: radius,
		widthSegments: widthSegments,
		heightSegments: heightSegments,
		phiStart: phiStart,
		phiLength: phiLength,
		thetaStart: thetaStart,
		thetaLength: thetaLength
	};

	radius = radius || 50;

	widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 );
	heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 );

	phiStart = phiStart !== undefined ? phiStart : 0;
	phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;

	thetaStart = thetaStart !== undefined ? thetaStart : 0;
	thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;

	var stride = ( 3 + 3 + 2 );
	var vertexBuffer = new THREE.InterleavedBuffer( new Float32Array( ( ( widthSegments + 1 ) * ( heightSegments + 1 ) ) * stride ), stride );

	var positions = new THREE.InterleavedBufferAttribute( vertexBuffer, 3, 0 );
	this.addAttribute( 'position', positions );
	var normals = new THREE.InterleavedBufferAttribute( vertexBuffer, 3, 3 );
	this.addAttribute( 'normal', normals );
	var uvs = new THREE.InterleavedBufferAttribute( vertexBuffer, 2, 6 );
	this.addAttribute( 'uv', uvs );

	var x, y, u, v, px, py, px, index = 0, vertices = [], normal = new THREE.Vector3();

	for ( y = 0; y <= heightSegments; y ++ ) {

		var verticesRow = [];

		v = y / heightSegments;

		for ( x = 0; x <= widthSegments; x ++ ) {

			u = x / widthSegments;

			px = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
			py = radius * Math.cos( thetaStart + v * thetaLength );
			pz = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );

			normal.set( px, py, pz ).normalize();

			positions.setXYZ( index, px, py, pz );
			normals.setXYZ( index, normal.x, normal.y, normal.z );
			uvs.setXY( index, u, 1 - v );

			verticesRow.push( index );

			index++;

		}

		vertices.push( verticesRow );

	}

	var indices = [];

	for ( y = 0, ul = heightSegments - 1; y < ul; y++ ) {

		for ( x = 0; x < widthSegments; x++ ) {

			var v1 = vertices[y][x + 1];
			var v2 = vertices[y][x];
			var v3 = vertices[y + 1][x];
			var v4 = vertices[y + 1][x + 1];

			if ( y !== 0 ) indices.push( v1, v2, v4 );
			indices.push( v2, v3, v4 );

		}
	}

	y = heightSegments;

	for ( x = 0; x < widthSegments; x++ ) {

		var v2 = vertices[y][x];
		var v3 = vertices[y - 1][x];
		var v4 = vertices[y - 1][x + 1];

		indices.push( v2, v4, v3 );

	}

	this.addAttribute( 'index', new THREE.BufferAttribute( new Uint16Array( indices ), 1 ) );

	this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );

};

THREE.SphereBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
THREE.SphereBufferGeometry.prototype.constructor = THREE.SphereBufferGeometry;<commit_msg>Fix minification build error in SphereBufferGeometry.js<commit_after>/**
 * @author benaadams / https://twitter.com/ben_a_adams
 * based on THREE.SphereGeometry
 */

THREE.SphereBufferGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {

	THREE.BufferGeometry.call( this );

	this.type = 'SphereBufferGeometry';

	this.parameters = {
		radius: radius,
		widthSegments: widthSegments,
		heightSegments: heightSegments,
		phiStart: phiStart,
		phiLength: phiLength,
		thetaStart: thetaStart,
		thetaLength: thetaLength
	};

	radius = radius || 50;

	widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 );
	heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 );

	phiStart = phiStart !== undefined ? phiStart : 0;
	phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;

	thetaStart = thetaStart !== undefined ? thetaStart : 0;
	thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;

	var stride = ( 3 + 3 + 2 );
	var vertexBuffer = new THREE.InterleavedBuffer( new Float32Array( ( ( widthSegments + 1 ) * ( heightSegments + 1 ) ) * stride ), stride );

	var positions = new THREE.InterleavedBufferAttribute( vertexBuffer, 3, 0 );
	this.addAttribute( 'position', positions );
	var normals = new THREE.InterleavedBufferAttribute( vertexBuffer, 3, 3 );
	this.addAttribute( 'normal', normals );
	var uvs = new THREE.InterleavedBufferAttribute( vertexBuffer, 2, 6 );
	this.addAttribute( 'uv', uvs );

	var x, y, u, v, px, py, pz, index = 0, vertices = [], normal = new THREE.Vector3();

	for ( y = 0; y <= heightSegments; y ++ ) {

		var verticesRow = [];

		v = y / heightSegments;

		for ( x = 0; x <= widthSegments; x ++ ) {

			u = x / widthSegments;

			px = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
			py = radius * Math.cos( thetaStart + v * thetaLength );
			pz = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );

			normal.set( px, py, pz ).normalize();

			positions.setXYZ( index, px, py, pz );
			normals.setXYZ( index, normal.x, normal.y, normal.z );
			uvs.setXY( index, u, 1 - v );

			verticesRow.push( index );

			index++;

		}

		vertices.push( verticesRow );

	}

	var indices = [];
	var ul;
	for ( y = 0, ul = heightSegments - 1; y < ul; y++ ) {

		for ( x = 0; x < widthSegments; x++ ) {

			var v1 = vertices[y][x + 1];
			var v2 = vertices[y][x];
			var v3 = vertices[y + 1][x];
			var v4 = vertices[y + 1][x + 1];

			if ( y !== 0 ) indices.push( v1, v2, v4 );
			indices.push( v2, v3, v4 );

		}
	}

	y = heightSegments;

	for ( x = 0; x < widthSegments; x++ ) {

		var v2 = vertices[y][x];
		var v3 = vertices[y - 1][x];
		var v4 = vertices[y - 1][x + 1];

		indices.push( v2, v4, v3 );

	}

	this.addAttribute( 'index', new THREE.BufferAttribute( new Uint16Array( indices ), 1 ) );

	this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );

};

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


<commit_before>/* global ciscospark */
import React, {Component} from 'react';
import classNames from 'classnames';
import {Cookies, withCookies} from 'react-cookie';
import {instanceOf} from 'prop-types';
import {autobind} from 'core-decorators';

import RaisedButton from 'material-ui/RaisedButton';
import AppBar from 'material-ui/AppBar';
import {RadioButtonGroup, RadioButton} from 'material-ui/RadioButton';
import {Card, CardActions, CardTitle, CardText} from 'material-ui/Card';
import Checkbox from 'material-ui/Checkbox';

import TokenInput from '../token-input';

import styles from './styles.css';

const MODE_ONE_ON_ONE_ID = 'MODE_ONE_ON_ONE_ID';
const MODE_ONE_ON_ONE = 'MODE_ONE_ON_ONE';
const MODE_SPACE = 'MODE_SPACE';

const spaceWidgetElementId = 'my-ciscospark-space-widget';
const recentsWidgetElementId = 'my-ciscospark-recents-widget';

class DemoWidget extends Component {
  constructor(props) {
    super(props);
    const {cookies} = this.props;
    const mode = cookies.get('destinationMode') || MODE_SPACE;
    const destinationId = cookies.get('destinationId') || '';
    this.state = {
      activities: {
        files: true,
        meet: true,
        message: true,
        people: true
      },
      accessToken: cookies.get('accessToken') || '',
      accessTokenType: cookies.get('accessTokenType') || '',
      destinationId,
      mode,
      spaceRunning: false
    };
  }

  shouldComponentUpdate() {
    return true;
  }

  getDestinationLabels() {
    let ariaLabel, placeholder;
    switch (this.state.mode) {
      case MODE_ONE_ON_ONE:
        ariaLabel = 'To User Email';
        placeholder = 'Spark User Email (For 1:1)';
        break;
      case MODE_ONE_ON_ONE_ID:
        ariaLabel = 'To User Id';
        placeholder = 'Spark User Id (For 1:1)';
        break;
      case MODE_SPACE:
        ariaLabel = 'To Space ID';
        placeholder = 'Spark Space Id';
        break;
      default: {
        ariaLabel = 'unknown mode';
        placeholder = 'Please pick a type';
      }
    }
    return {
      ariaLabel,
      placeholder
    };
  }

  @autobind
  handleOpenSpaceWidget(e) {
    e.preventDefault();
    const {cookies} = this.props;
    cookies.set('accessToken', this.state.accessToken);
    cookies.set('accessTokenType', this.state.accessTokenType);
    cookies.set('destinationId', this.state.destinationId);
    cookies.set('destinationMode', this.state.mode);

    const toPerson = this.state.mode === MODE_ONE_ON_ONE ? this.state.destinationId : '';
    const toPersonId = this.state.mode === MODE_ONE_ON_ONE_ID ? this.state.destinationId : '';
    const toSpace = this.state.mode === MODE_SPACE ? this.state.destinationId : '';
    this.openSpaceWidget({toPerson, toPersonId, toSpace});
  }

  @autobind
  handleOpenRecentsWidget(e) {
    e.preventDefault();
    const {cookies} = this.props;
    cookies.set('accessToken', this.state.accessToken);
    cookies.set('accessTokenType', this.state.accessTokenType);
    const widgetEl = document.getElementById(recentsWidgetElementId);
    const widgetOptions = {
      onEvent: (eventName, detail) => {
        window.ciscoSparkEvents.push({eventName, detail});
        if (eventName === 'rooms:selected') {
          const spaceId = detail.data.id;
          if (this.state.spaceRunning) {
            this.handleRemove();
          }
          this.openSpaceWidget({toSpace: spaceId});
        }
      }
    };
    if (this.state.accessTokenType === 'JWT') {
      widgetOptions.guestToken = this.state.accessToken;
    }
    else {
      widgetOptions.accessToken = this.state.accessToken;
    }
    ciscospark.widget(widgetEl).recentsWidget(widgetOptions);
    this.setState({recentsRunning: true});
  }

  @autobind
  handleRemove() {
    const widgetEl = document.getElementById(spaceWidgetElementId);
    ciscospark.widget(widgetEl).remove();
    this.setState({spaceRunning: false});
  }

  @autobind
  handleRecentsRemove() {
    const widgetEl = document.getElementById(recentsWidgetElementId);
    ciscospark.widget(widgetEl).remove();
    this.setState({recentsRunning: false});
  }

  @autobind
  handleAccessTokenChange(accessToken, accessTokenType) {
    return this.setState({accessToken, accessTokenType});
  }

  @autobind
  handleModeChange(e, value) {
    return this.setState({mode: value, destinationId: ''});
  }

  @autobind
  handleActivitiesChange(event, isInputChecked) {
    const {activities} = this.state;
    activities[event.target.value] = isInputChecked;
    return this.setState({activities});
  }

  @autobind
  handleDestinationChange(e) {
    return this.setState({destinationId: e.target.value});
  }

  @autobind
  openSpaceWidget({toPerson, toPersonId, toSpace}) {
    const widgetEl = document.getElementById(spaceWidgetElementId);
    const widgetOptions = {
      initialActivity: 'message',
      onEvent: (eventName, detail) => {
        window.ciscoSparkEvents.push({eventName, detail});
      },
      spaceActivities: this.state.activities
    };
    if (this.state.accessTokenType === 'JWT') {
      widgetOptions.guestToken = this.state.accessToken;
    }
    else {
      widgetOptions.accessToken = this.state.accessToken;
    }
    if (toPersonId) {
      widgetOptions.toPersonId = toPersonId;
    }
    if (toPerson) {
      widgetOptions.toPersonEmail = toPerson;
    }
    if (toSpace) {
      widgetOptions.spaceId = toSpace;
    }
    ciscospark.widget(widgetEl).spaceWidget(widgetOptions);
    this.setState({spaceRunning: true});
  }

  render() {
    const loadButtonEnabled = this.state.accessToken && this.state.destinationId && !this.state.spaceRunning;
    const loadRecentsButtonEnabled = this.state.accessToken && !this.state.recentsRunning;
    const componentSpaceContainerClassNames = [
      styles.widgetSpaceComponentContainer
    ];
    if (!this.state.spaceRunning) {
      componentSpaceContainerClassNames.push(styles.hidden);
    }
    const componentRecentsContainerClassNames = [
      styles.widgetRecentsComponentContainer
    ];
    if (!this.state.recentsRunning) {
      componentRecentsContainerClassNames.push(styles.hidden);
    }
    const runningDemosContainerClassNames = [
      styles.runningDemosContainer
    ];
    if (!this.state.spaceRunning && !this.state.recentsRunning) {
      runningDemosContainerClassNames.push(styles.hidden);
    }

    const {
      ariaLabel,
      placeholder
    } = this.getDestinationLabels();

    // eslint-disable-reason should not apply to jsx/html markup
    /* eslint-disable max-len */
    return (

        <AppBar title="Cisco Spark Widget" />

          <Card initiallyExpanded style={{margin: '10px'}}>
            <CardTitle
              actAsExpander
              showExpandableButton
              subtitle="The Cisco Spark widgets allow developers to easily incorporate Cisco Spark Widgets into an application."
              title="Cisco Spark Widget Demo"
            />
            <CardText expandable>
              Our widgets are built using React, Redux, and the Spark Javascript SDK .
            </CardText>
          </Card>
          <TokenInput onLogin={this.handleAccessTokenChange} token={this.state.accessToken} tokenType={this.state.accessTokenType} />
          <Card initiallyExpanded style={{margin: '10px'}}>
            <CardTitle
              actAsExpander
              showExpandableButton
              subtitle="Cisco Spark Space Widget can open to a space or person."
              title="Cisco Spark Space Widget"
            />
            <CardText expandable>

 Widget Destination Type

                <RadioButtonGroup
                  aria-label="Widget 'To' Type"
                  name="toType"
                  onChange={this.handleModeChange}
                  valueSelected={this.state.mode}
                >
                  <RadioButton
                    aria-label="To Space"
                    label="To Space"
                    value={MODE_SPACE}
                  />
                  <RadioButton
                    aria-label="To Person Email"
                    label="To Person"
                    value={MODE_ONE_ON_ONE}
                  />
                  <RadioButton
                    aria-label="To Person Id"
                    label="To Person Id"
                    value={MODE_ONE_ON_ONE_ID}
                  />
                </RadioButtonGroup>

 Widget Activities

                <Checkbox
                  checked={this.state.activities.files}
                  label="Files"
                  onCheck={this.handleActivitiesChange}
                  value="files"
                />
                <Checkbox
                  checked={this.state.activities.meet}
                  label="Meet"
                  onCheck={this.handleActivitiesChange}
                  value="meet"
                />
                <Checkbox
                  checked={this.state.activities.message}
                  label="Message"
                  onCheck={this.handleActivitiesChange}
                  value="message"
                />
                <Checkbox
                  checked={this.state.activities.people}
                  label="People"
                  onCheck={this.handleActivitiesChange}
                  value="people"
                />

                <input
                  aria-label={ariaLabel}
                  className={styles.textInput}
                  id="destinationId"
                  onChange={this.handleDestinationChange}
                  placeholder={placeholder}
                  value={this.state.destinationId}
                />

            </CardText>
            <CardActions expandable>
              <RaisedButton
                aria-label="Open Widget"
                disabled={!loadButtonEnabled}
                id="openWidgetButton"
                label="Open Space Widget"
                onClick={this.handleOpenSpaceWidget}
                primary
              />
              <RaisedButton
                aria-label="Remove Widget"
                disabled={!this.state.spaceRunning}
                id="removeWidgetButton"
                label="Remove Space Widget"
                onClick={this.handleRemove}
                primary
              />
            </CardActions>
          </Card>
          <Card initiallyExpanded style={{margin: '10px'}}>
            <CardTitle
              actAsExpander
              showExpandableButton
              title="Cisco Spark Recents Widget Demo"
            />
            <CardActions expandable>
              <RaisedButton
                aria-label="Open Recents Widget"
                disabled={!loadRecentsButtonEnabled}
                label="Open Recents Widget"
                onClick={this.handleOpenRecentsWidget}
                primary
              />
              <RaisedButton
                aria-label="Remove Recents Widget"
                disabled={!this.state.recentsRunning}
                id="removeRecentsWidgetButton"
                label="Remove Recents Widget"
                onClick={this.handleRecentsRemove}
                primary
              />
            </CardActions>
          </Card>

    );
  }
}

DemoWidget.propTypes = {
  cookies: instanceOf(Cookies).isRequired
};

DemoWidget.title = 'Widget Demo';
DemoWidget.path = '/widget-demo';

export default withCookies(DemoWidget);
<commit_msg>feat(widget-demo): add destination support<commit_after>/* global ciscospark */
import React, {Component} from 'react';
import classNames from 'classnames';
import {Cookies, withCookies} from 'react-cookie';
import {instanceOf} from 'prop-types';
import {autobind} from 'core-decorators';

import RaisedButton from 'material-ui/RaisedButton';
import AppBar from 'material-ui/AppBar';
import {RadioButtonGroup, RadioButton} from 'material-ui/RadioButton';
import {Card, CardActions, CardTitle, CardText} from 'material-ui/Card';
import Checkbox from 'material-ui/Checkbox';

import TokenInput from '../token-input';

import styles from './styles.css';

const MODE_ONE_ON_ONE_ID = 'userId';
const MODE_ONE_ON_ONE = 'email';
const MODE_SPACE = 'spaceId';

const DESTINATION_PROP_MODE_LEGACY = 'DESTINATION_PROP_MODE_LEGACY';
const DESTINATION_PROP_MODE_MAIN = 'DESTINATION_PROP_MODE_MAIN';

const spaceWidgetElementId = 'my-ciscospark-space-widget';
const recentsWidgetElementId = 'my-ciscospark-recents-widget';

class DemoWidget extends Component {
  constructor(props) {
    super(props);
    const {cookies} = this.props;
    const mode = cookies.get('destinationMode') || MODE_SPACE;
    const destinationPropMode = cookies.get('destinationPropMode') || DESTINATION_PROP_MODE_MAIN;
    const destinationId = cookies.get('destinationId') || '';
    this.state = {
      activities: {
        files: true,
        meet: true,
        message: true,
        people: true
      },
      accessToken: cookies.get('accessToken') || '',
      accessTokenType: cookies.get('accessTokenType') || '',
      destinationId,
      destinationPropMode,
      mode,
      spaceRunning: false
    };
  }

  shouldComponentUpdate() {
    return true;
  }

  getDestinationLabels() {
    let ariaLabel, placeholder;
    switch (this.state.mode) {
      case MODE_ONE_ON_ONE:
        ariaLabel = 'To User Email';
        placeholder = 'Spark User Email (For 1:1)';
        break;
      case MODE_ONE_ON_ONE_ID:
        ariaLabel = 'To User Id';
        placeholder = 'Spark User Id (For 1:1)';
        break;
      case MODE_SPACE:
        ariaLabel = 'To Space ID';
        placeholder = 'Spark Space Id';
        break;
      default: {
        ariaLabel = 'unknown mode';
        placeholder = 'Please pick a type';
      }
    }
    return {
      ariaLabel,
      placeholder
    };
  }

  @autobind
  handleOpenSpaceWidget(e) {
    e.preventDefault();
    const {cookies} = this.props;
    cookies.set('accessToken', this.state.accessToken);
    cookies.set('accessTokenType', this.state.accessTokenType);
    cookies.set('destinationId', this.state.destinationId);
    cookies.set('destinationMode', this.state.mode);
    cookies.set('destinationPropMode', this.state.destinationPropMode);

    const toPerson = this.state.mode === MODE_ONE_ON_ONE ? this.state.destinationId : '';
    const toPersonId = this.state.mode === MODE_ONE_ON_ONE_ID ? this.state.destinationId : '';
    const toSpace = this.state.mode === MODE_SPACE ? this.state.destinationId : '';
    this.openSpaceWidget({
      toPerson,
      toPersonId,
      toSpace,
      destinationId: this.state.destinationId,
      destinationType: this.state.mode
    });
  }

  @autobind
  handleOpenRecentsWidget(e) {
    e.preventDefault();
    const {cookies} = this.props;
    cookies.set('accessToken', this.state.accessToken);
    cookies.set('accessTokenType', this.state.accessTokenType);
    const widgetEl = document.getElementById(recentsWidgetElementId);
    const widgetOptions = {
      onEvent: (eventName, detail) => {
        window.ciscoSparkEvents.push({eventName, detail});
        if (eventName === 'rooms:selected') {
          const spaceId = detail.data.id;
          if (this.state.spaceRunning) {
            this.handleRemove();
          }
          this.openSpaceWidget({toSpace: spaceId});
        }
      }
    };
    if (this.state.accessTokenType === 'JWT') {
      widgetOptions.guestToken = this.state.accessToken;
    }
    else {
      widgetOptions.accessToken = this.state.accessToken;
    }
    ciscospark.widget(widgetEl).recentsWidget(widgetOptions);
    this.setState({recentsRunning: true});
  }

  @autobind
  handleRemove() {
    const widgetEl = document.getElementById(spaceWidgetElementId);
    ciscospark.widget(widgetEl).remove();
    this.setState({spaceRunning: false});
  }

  @autobind
  handleRecentsRemove() {
    const widgetEl = document.getElementById(recentsWidgetElementId);
    ciscospark.widget(widgetEl).remove();
    this.setState({recentsRunning: false});
  }

  @autobind
  handleAccessTokenChange(accessToken, accessTokenType) {
    return this.setState({accessToken, accessTokenType});
  }

  @autobind
  handleModeChange(e, value) {
    return this.setState({mode: value, destinationId: ''});
  }

  @autobind
  handleActivitiesChange(event, isInputChecked) {
    const {activities} = this.state;
    activities[event.target.value] = isInputChecked;
    return this.setState({activities});
  }

  @autobind
  handleDestinationChange(e) {
    return this.setState({destinationId: e.target.value});
  }

  @autobind
  handleDestinationPropTypeChange(e, value) {
    return this.setState({destinationPropMode: value});
  }

  @autobind
  openSpaceWidget({
    destinationId, destinationType, toPerson, toPersonId, toSpace
  }) {
    const widgetEl = document.getElementById(spaceWidgetElementId);
    const widgetOptions = {
      initialActivity: 'message',
      onEvent: (eventName, detail) => {
        window.ciscoSparkEvents.push({eventName, detail});
      },
      spaceActivities: this.state.activities
    };
    if (this.state.accessTokenType === 'JWT') {
      widgetOptions.guestToken = this.state.accessToken;
    }
    else {
      widgetOptions.accessToken = this.state.accessToken;
    }
    if (this.state.destinationPropMode === DESTINATION_PROP_MODE_LEGACY) {
      if (toPersonId) {
        widgetOptions.toPersonId = toPersonId;
      }
      if (toPerson) {
        widgetOptions.toPersonEmail = toPerson;
      }
      if (toSpace) {
        widgetOptions.spaceId = toSpace;
      }
    }
    else {
      widgetOptions.destinationId = destinationId;
      widgetOptions.destinationType = destinationType;
    }
    ciscospark.widget(widgetEl).spaceWidget(widgetOptions);
    this.setState({spaceRunning: true});
  }

  render() {
    const loadButtonEnabled = this.state.accessToken && this.state.destinationId && !this.state.spaceRunning;
    const loadRecentsButtonEnabled = this.state.accessToken && !this.state.recentsRunning;
    const componentSpaceContainerClassNames = [
      styles.widgetSpaceComponentContainer
    ];
    if (!this.state.spaceRunning) {
      componentSpaceContainerClassNames.push(styles.hidden);
    }
    const componentRecentsContainerClassNames = [
      styles.widgetRecentsComponentContainer
    ];
    if (!this.state.recentsRunning) {
      componentRecentsContainerClassNames.push(styles.hidden);
    }
    const runningDemosContainerClassNames = [
      styles.runningDemosContainer
    ];
    if (!this.state.spaceRunning && !this.state.recentsRunning) {
      runningDemosContainerClassNames.push(styles.hidden);
    }

    const {
      ariaLabel,
      placeholder
    } = this.getDestinationLabels();

    // eslint-disable-reason should not apply to jsx/html markup
    /* eslint-disable max-len */
    return (

        <AppBar title="Cisco Spark Widget" />

          <Card initiallyExpanded style={{margin: '10px'}}>
            <CardTitle
              actAsExpander
              showExpandableButton
              subtitle="The Cisco Spark widgets allow developers to easily incorporate Cisco Spark Widgets into an application."
              title="Cisco Spark Widget Demo"
            />
            <CardText expandable>
              Our widgets are built using React, Redux, and the Spark Javascript SDK .
            </CardText>
          </Card>
          <TokenInput onLogin={this.handleAccessTokenChange} token={this.state.accessToken} tokenType={this.state.accessTokenType} />
          <Card initiallyExpanded style={{margin: '10px'}}>
            <CardTitle
              actAsExpander
              showExpandableButton
              subtitle="Cisco Spark Space Widget can open to a space or person."
              title="Cisco Spark Space Widget"
            />
            <CardText expandable>

 Widget Destination Type

                <RadioButtonGroup
                  aria-label="Widget 'To' Type"
                  name="toType"
                  onChange={this.handleModeChange}
                  valueSelected={this.state.mode}
                >
                  <RadioButton
                    aria-label="To Space"
                    label="To Space"
                    value={MODE_SPACE}
                  />
                  <RadioButton
                    aria-label="To Person Email"
                    label="To Person"
                    value={MODE_ONE_ON_ONE}
                  />
                  <RadioButton
                    aria-label="To Person Id"
                    label="To Person Id"
                    value={MODE_ONE_ON_ONE_ID}
                  />
                </RadioButtonGroup>

 Widget Activities

                <Checkbox
                  checked={this.state.activities.files}
                  label="Files"
                  onCheck={this.handleActivitiesChange}
                  value="files"
                />
                <Checkbox
                  checked={this.state.activities.meet}
                  label="Meet"
                  onCheck={this.handleActivitiesChange}
                  value="meet"
                />
                <Checkbox
                  checked={this.state.activities.message}
                  label="Message"
                  onCheck={this.handleActivitiesChange}
                  value="message"
                />
                <Checkbox
                  checked={this.state.activities.people}
                  label="People"
                  onCheck={this.handleActivitiesChange}
                  value="people"
                />

Widget Destination Prop Type

                <RadioButtonGroup
                  aria-label="Widget 'Destination Prop' Type"
                  name="destinationType"
                  onChange={this.handleDestinationPropTypeChange}
                  valueSelected={this.state.destinationPropMode}
                >
                  <RadioButton
                    aria-label="Destination ID & Type Mode"
                    label="Destination ID & Type Mode"
                    value={DESTINATION_PROP_MODE_MAIN}
                  />
                  <RadioButton
                    aria-label="Destination Legacy Mode"
                    label="Destination Legacy Mode"
                    value={DESTINATION_PROP_MODE_LEGACY}
                  />
                </RadioButtonGroup>

                <input
                  aria-label={ariaLabel}
                  className={styles.textInput}
                  id="destinationId"
                  onChange={this.handleDestinationChange}
                  placeholder={placeholder}
                  value={this.state.destinationId}
                />

            </CardText>
            <CardActions expandable>
              <RaisedButton
                aria-label="Open Widget"
                disabled={!loadButtonEnabled}
                id="openWidgetButton"
                label="Open Space Widget"
                onClick={this.handleOpenSpaceWidget}
                primary
              />
              <RaisedButton
                aria-label="Remove Widget"
                disabled={!this.state.spaceRunning}
                id="removeWidgetButton"
                label="Remove Space Widget"
                onClick={this.handleRemove}
                primary
              />
            </CardActions>
          </Card>
          <Card initiallyExpanded style={{margin: '10px'}}>
            <CardTitle
              actAsExpander
              showExpandableButton
              title="Cisco Spark Recents Widget Demo"
            />
            <CardActions expandable>
              <RaisedButton
                aria-label="Open Recents Widget"
                disabled={!loadRecentsButtonEnabled}
                label="Open Recents Widget"
                onClick={this.handleOpenRecentsWidget}
                primary
              />
              <RaisedButton
                aria-label="Remove Recents Widget"
                disabled={!this.state.recentsRunning}
                id="removeRecentsWidgetButton"
                label="Remove Recents Widget"
                onClick={this.handleRecentsRemove}
                primary
              />
            </CardActions>
          </Card>

    );
  }
}

DemoWidget.propTypes = {
  cookies: instanceOf(Cookies).isRequired
};

DemoWidget.title = 'Widget Demo';
DemoWidget.path = '/widget-demo';

export default withCookies(DemoWidget);
<|endoftext|>


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

define('ace_configuration', ["app", "ace/ace"], function (app, ace) {
  var path = app.host + app.root + 'js/ace';
  var config = require("ace/config");
  config.set("packaged", true);
  config.set("workerPath",path);
  config.set("modePath",path);
  config.set("themePath", path);
  return ace;
});

define([
  "app",
  // Libs
  "api",
  "ace_configuration",
],

function(app, FauxtonAPI, ace) {
  var Components = app.module();

  Components.Pagination = FauxtonAPI.View.extend({
    template: "templates/fauxton/pagination",

    initialize: function(options) {
      this.page = parseInt(options.page, 10);
      this.perPage = options.perPage;
      this.total = options.total;
      this.totalPages = Math.ceil(this.total / this.perPage);
      this.urlFun = options.urlFun;
    },

    serialize: function() {
      return {
        page: this.page,
        perPage: this.perPage,
        total: this.total,
        totalPages: this.totalPages,
        urlFun: this.urlFun
      };
    }
  });

  Components.IndexPagination = FauxtonAPI.View.extend({
    template: "templates/fauxton/index_pagination",
    events: {
      "click a": 'scrollTo',
      "click a#next": 'nextClicked',
      "click a#previous": 'previousClicked'
    },

    previousIds: [],

    scrollTo: function () {
      if (!this.scrollToSelector) { return; }
      $(this.scrollToSelector).animate({ scrollTop: 0 }, 'slow');
    },

    initialize: function (options) {
      this.previousUrlfn = options.previousUrlfn;
      this.nextUrlfn = options.nextUrlfn;
      this.canShowPreviousfn = options.canShowPreviousfn;
      this.canShowNextfn = options.canShowNextfn;
      this.scrollToSelector = options.scrollToSelector;
      _.bindAll(this);
    },

    previousClicked: function (event) {
      event.preventDefault();
      if (!this.canShowPreviousfn()) { return; }
      FauxtonAPI.navigate(this.previousUrlfn(), {trigger: false});
      FauxtonAPI.triggerRouteEvent('paginate', 'previous');
    },

    nextClicked: function (event) {
      event.preventDefault();
      if (!this.canShowNextfn()) { return; }
      var doc = this.collection.first();

      if (doc) {
        this.previousIds.push(doc.id);
      }

      FauxtonAPI.navigate(this.nextUrlfn(), {trigger: false});
      FauxtonAPI.triggerRouteEvent('paginate', 'next');
    },

    serialize: function () {
      return {
        canShowNextfn: this.canShowNextfn,
        canShowPreviousfn: this.canShowPreviousfn,
      };
    }

  });

  //TODO allow more of the typeahead options.
  //Current this just does what we need but we
  //need to support the other typeahead options.
  Components.Typeahead = FauxtonAPI.View.extend({

    initialize: function (options) {
      this.source = options.source;
      _.bindAll(this);
    },

    afterRender: function () {
      var onUpdate = this.onUpdate;

      this.$el.typeahead({
        source: this.source,
        updater: function (item) {
          if (onUpdate) {
            onUpdate(item);
          }

          return item;
        }
      });
    }

  });

  Components.DbSearchTypeahead = Components.Typeahead.extend({
    initialize: function (options) {
      this.dbLimit = options.dbLimit || 30;
      this.onUpdate = options.onUpdate;
      _.bindAll(this);
    },
    source: function(query, process) {
      var url = [
        app.host,
        "/_all_dbs?startkey=%22",
        query,
        "%22&endkey=%22",
        query,
        "\u9999",
        "%22&limit=",
        this.dbLimit
      ].join('');

      if (this.ajaxReq) { this.ajaxReq.abort(); }

      this.ajaxReq = $.ajax({
        cache: false,
        url: url,
        dataType: 'json',
        success: function(data) {
          process(data);
        }
      });
    }
  });

  Components.DocSearchTypeahead = Components.Typeahead.extend({
    initialize: function (options) {
      this.docLimit = options.docLimit || 30;
      this.database = options.database;
      _.bindAll(this);
    },
    source: function(query, process) {
      var url = [
        app.host,
        "/",
        this.database.id,
        "/_all_docs?startkey=%22",
        query,
        "%22&endkey=%22",
        query,
        "\u9999",
        "%22&limit=",
        this.docLimit
      ].join('');

      if (this.ajaxReq) { this.ajaxReq.abort(); }

      this.ajaxReq = $.ajax({
        cache: false,
        url: url,
        dataType: 'json',
        success: function(data) {
          var ids = _.map(data.rows, function (row) {
            return row.id;
          });
          process(ids);
        }
      });
    }
  });

  Components.Editor = FauxtonAPI.View.extend({
    initialize: function (options) {
      this.editorId = options.editorId;
      this.mode = options.mode || "json";
      this.commands = options.commands;
      this.theme = options.theme || 'crimson_editor';
      this.couchJSHINT = options.couchJSHINT;
      this.edited = false;
    },

    afterRender: function () {
      this.editor = ace.edit(this.editorId);
      this.setHeightToLineCount();
      this.editor.setTheme("ace/theme/" + this.theme);
      this.editor.getSession().setMode("ace/mode/" + this.mode);
      this.editor.getSession().setUseWrapMode(true);
      this.editor.setShowPrintMargin(false);
      this.editor.gotoLine(2);
      this.addCommands();

      if (this.couchJSHINT) {
        this.removeIncorrectAnnotations();
      }

      var that = this;
      this.editor.getSession().on('change', function () {
        that.setHeightToLineCount();
        that.edited = true;
      });

      $(window).on('beforeunload.editor', function() {
        if (that.edited) {
          return 'Your changes have not been saved. Click cancel to return to the document.';
        }
      });

      FauxtonAPI.beforeUnload("editor", function (deferred) {
        if (that.edited) {
          return 'Your changes have not been saved. Click cancel to return to the document.';
        }
      });
    },

    cleanup: function () {
      $(window).off('beforeunload.editor');
      FauxtonAPI.removeBeforeUnload("editor");
    },

    setHeightToLineCount: function () {
      var lines = this.editor.getSession().getDocument().getLength();
      this.editor.setOptions({
        maxLines: lines
      });

      this.editor.resize();
    },

    addCommands: function () {
      _.each(this.commands, function (command) {
        this.editor.commands.addCommand(command);
      }, this);
    },

    removeIncorrectAnnotations: function () {
      var editor = this.editor;

      this.editor.getSession().on("changeAnnotation", function(){
        var annotations = editor.getSession().getAnnotations();

        var newAnnotations = _.reduce(annotations, function (annotations, error) {
          if (!FauxtonAPI.isIgnorableError(error.raw)) {
            annotations.push(error);
          }
          return annotations;
        }, []);

        if (annotations.length !== newAnnotations.length) {
          editor.getSession().setAnnotations(newAnnotations);
        }
      });
    },

    editSaved: function () {
      this.edited = false;
    },

    setValue: function (data, lineNumber) {
      lineNumber = lineNumber ? lineNumber : -1;
      this.editor.setValue(data, lineNumber);
    },

    getValue: function () {
      return this.editor.getValue();
    },

    getAnnotations: function () {
      return this.editor.getSession().getAnnotations();
    },

    hadValidCode: function () {
     var errors = this.getAnnotations();
     // By default CouchDB view functions don't pass lint
     return _.every(errors, function(error) {
      return FauxtonAPI.isIgnorableError(error.raw);
      },this);
    }

  });

  return Components;
});

<commit_msg>Fauxton: Prevent propogation on pagination<commit_after>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

define('ace_configuration', ["app", "ace/ace"], function (app, ace) {
  var path = app.host + app.root + 'js/ace';
  var config = require("ace/config");
  config.set("packaged", true);
  config.set("workerPath",path);
  config.set("modePath",path);
  config.set("themePath", path);
  return ace;
});

define([
  "app",
  // Libs
  "api",
  "ace_configuration",
],

function(app, FauxtonAPI, ace) {
  var Components = app.module();

  Components.Pagination = FauxtonAPI.View.extend({
    template: "templates/fauxton/pagination",

    initialize: function(options) {
      this.page = parseInt(options.page, 10);
      this.perPage = options.perPage;
      this.total = options.total;
      this.totalPages = Math.ceil(this.total / this.perPage);
      this.urlFun = options.urlFun;
    },

    serialize: function() {
      return {
        page: this.page,
        perPage: this.perPage,
        total: this.total,
        totalPages: this.totalPages,
        urlFun: this.urlFun
      };
    }
  });

  Components.IndexPagination = FauxtonAPI.View.extend({
    template: "templates/fauxton/index_pagination",
    events: {
      "click a": 'scrollTo',
      "click a#next": 'nextClicked',
      "click a#previous": 'previousClicked'
    },

    previousIds: [],

    scrollTo: function () {
      if (!this.scrollToSelector) { return; }
      $(this.scrollToSelector).animate({ scrollTop: 0 }, 'slow');
    },

    initialize: function (options) {
      this.previousUrlfn = options.previousUrlfn;
      this.nextUrlfn = options.nextUrlfn;
      this.canShowPreviousfn = options.canShowPreviousfn;
      this.canShowNextfn = options.canShowNextfn;
      this.scrollToSelector = options.scrollToSelector;
      _.bindAll(this);
    },

    previousClicked: function (event) {
      event.preventDefault();
      event.stopPropagation();
      if (!this.canShowPreviousfn()) { return; }
      FauxtonAPI.navigate(this.previousUrlfn(), {trigger: false});
      FauxtonAPI.triggerRouteEvent('paginate', 'previous');
    },

    nextClicked: function (event) {
      event.preventDefault();
      event.stopPropagation();
      if (!this.canShowNextfn()) { return; }
      var doc = this.collection.first();

      if (doc) {
        this.previousIds.push(doc.id);
      }

      FauxtonAPI.navigate(this.nextUrlfn(), {trigger: false});
      FauxtonAPI.triggerRouteEvent('paginate', 'next');
    },

    serialize: function () {
      return {
        canShowNextfn: this.canShowNextfn,
        canShowPreviousfn: this.canShowPreviousfn,
      };
    }

  });

  //TODO allow more of the typeahead options.
  //Current this just does what we need but we
  //need to support the other typeahead options.
  Components.Typeahead = FauxtonAPI.View.extend({

    initialize: function (options) {
      this.source = options.source;
      _.bindAll(this);
    },

    afterRender: function () {
      var onUpdate = this.onUpdate;

      this.$el.typeahead({
        source: this.source,
        updater: function (item) {
          if (onUpdate) {
            onUpdate(item);
          }

          return item;
        }
      });
    }

  });

  Components.DbSearchTypeahead = Components.Typeahead.extend({
    initialize: function (options) {
      this.dbLimit = options.dbLimit || 30;
      this.onUpdate = options.onUpdate;
      _.bindAll(this);
    },
    source: function(query, process) {
      var url = [
        app.host,
        "/_all_dbs?startkey=%22",
        query,
        "%22&endkey=%22",
        query,
        "\u9999",
        "%22&limit=",
        this.dbLimit
      ].join('');

      if (this.ajaxReq) { this.ajaxReq.abort(); }

      this.ajaxReq = $.ajax({
        cache: false,
        url: url,
        dataType: 'json',
        success: function(data) {
          process(data);
        }
      });
    }
  });

  Components.DocSearchTypeahead = Components.Typeahead.extend({
    initialize: function (options) {
      this.docLimit = options.docLimit || 30;
      this.database = options.database;
      _.bindAll(this);
    },
    source: function(query, process) {
      var url = [
        app.host,
        "/",
        this.database.id,
        "/_all_docs?startkey=%22",
        query,
        "%22&endkey=%22",
        query,
        "\u9999",
        "%22&limit=",
        this.docLimit
      ].join('');

      if (this.ajaxReq) { this.ajaxReq.abort(); }

      this.ajaxReq = $.ajax({
        cache: false,
        url: url,
        dataType: 'json',
        success: function(data) {
          var ids = _.map(data.rows, function (row) {
            return row.id;
          });
          process(ids);
        }
      });
    }
  });

  Components.Editor = FauxtonAPI.View.extend({
    initialize: function (options) {
      this.editorId = options.editorId;
      this.mode = options.mode || "json";
      this.commands = options.commands;
      this.theme = options.theme || 'crimson_editor';
      this.couchJSHINT = options.couchJSHINT;
      this.edited = false;
    },

    afterRender: function () {
      this.editor = ace.edit(this.editorId);
      this.setHeightToLineCount();
      this.editor.setTheme("ace/theme/" + this.theme);
      this.editor.getSession().setMode("ace/mode/" + this.mode);
      this.editor.getSession().setUseWrapMode(true);
      this.editor.setShowPrintMargin(false);
      this.editor.gotoLine(2);
      this.addCommands();

      if (this.couchJSHINT) {
        this.removeIncorrectAnnotations();
      }

      var that = this;
      this.editor.getSession().on('change', function () {
        that.setHeightToLineCount();
        that.edited = true;
      });

      $(window).on('beforeunload.editor', function() {
        if (that.edited) {
          return 'Your changes have not been saved. Click cancel to return to the document.';
        }
      });

      FauxtonAPI.beforeUnload("editor", function (deferred) {
        if (that.edited) {
          return 'Your changes have not been saved. Click cancel to return to the document.';
        }
      });
    },

    cleanup: function () {
      $(window).off('beforeunload.editor');
      FauxtonAPI.removeBeforeUnload("editor");
    },

    setHeightToLineCount: function () {
      var lines = this.editor.getSession().getDocument().getLength();
      this.editor.setOptions({
        maxLines: lines
      });

      this.editor.resize();
    },

    addCommands: function () {
      _.each(this.commands, function (command) {
        this.editor.commands.addCommand(command);
      }, this);
    },

    removeIncorrectAnnotations: function () {
      var editor = this.editor;

      this.editor.getSession().on("changeAnnotation", function(){
        var annotations = editor.getSession().getAnnotations();

        var newAnnotations = _.reduce(annotations, function (annotations, error) {
          if (!FauxtonAPI.isIgnorableError(error.raw)) {
            annotations.push(error);
          }
          return annotations;
        }, []);

        if (annotations.length !== newAnnotations.length) {
          editor.getSession().setAnnotations(newAnnotations);
        }
      });
    },

    editSaved: function () {
      this.edited = false;
    },

    setValue: function (data, lineNumber) {
      lineNumber = lineNumber ? lineNumber : -1;
      this.editor.setValue(data, lineNumber);
    },

    getValue: function () {
      return this.editor.getValue();
    },

    getAnnotations: function () {
      return this.editor.getSession().getAnnotations();
    },

    hadValidCode: function () {
     var errors = this.getAnnotations();
     // By default CouchDB view functions don't pass lint
     return _.every(errors, function(error) {
      return FauxtonAPI.isIgnorableError(error.raw);
      },this);
    }

  });

  return Components;
});

<|endoftext|>