<commit_before>import React from 'react';

import SPELLS from 'common/SPELLS';
import SpellIcon from 'common/SpellIcon';
import { formatPercentage } from 'common/format';
import Statistic from 'interface/statistics/Statistic';
import STATISTIC_ORDER from 'interface/others/STATISTIC_ORDER';
import Analyzer, { SELECTED_PLAYER } from 'parser/core/Analyzer';
import AbilityTracker from 'parser/shared/modules/AbilityTracker';
import SpellUsable from 'parser/shared/modules/SpellUsable';
import Events from 'parser/core/Events';

/**
 * @property {AbilityTracker} abilityTracker
 * @property {SpellUsable} spellUsable
 */
class DivinePurpose extends Analyzer {
  static dependencies = {
    abilityTracker: AbilityTracker,
    spellUsable: SpellUsable,
  };

  holyShockProcs = 0;
  holyShockProcStreak = 0;
  highestHolyShockProcStreak = 0;
  lightOfDawnProcs = 0;
  lightOfDawnProcStreak = 0;
  highestLightOfDawnProcStreak = 0;

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTalent(SPELLS.DIVINE_PURPOSE_TALENT_HOLY.id);
    // Holy Shock
    this.addEventListener(Events.applybuff.to(SELECTED_PLAYER).spell(SPELLS.DIVINE_PURPOSE_HOLY_SHOCK_BUFF), this._onHolyShockDivinePurposeProc);
    this.addEventListener(Events.refreshbuff.to(SELECTED_PLAYER).spell(SPELLS.DIVINE_PURPOSE_HOLY_SHOCK_BUFF), this._onHolyShockDivinePurposeProc);
    this.addEventListener(Events.cast.by(SELECTED_PLAYER).spell(SPELLS.HOLY_SHOCK_CAST), this._onHolyShockCast);
    // Light of Dawn
    this.addEventListener(Events.applybuff.to(SELECTED_PLAYER).spell(SPELLS.DIVINE_PURPOSE_LIGHT_OF_DAWN_BUFF), this._onLightOfDawnDivinePurposeProc);
    this.addEventListener(Events.refreshbuff.to(SELECTED_PLAYER).spell(SPELLS.DIVINE_PURPOSE_LIGHT_OF_DAWN_BUFF), this._onLightOfDawnDivinePurposeProc);
    this.addEventListener(Events.cast.by(SELECTED_PLAYER).spell(SPELLS.LIGHT_OF_DAWN_CAST), this._onLightOfDawnCast);
  }

  _onHolyShockDivinePurposeProc() {
    this.holyShockProcs += 1;
    if (this.spellUsable.isOnCooldown(SPELLS.HOLY_SHOCK_CAST.id)) {
      this.spellUsable.endCooldown(SPELLS.HOLY_SHOCK_CAST.id);
    }
  }
  _onHolyShockCast() {
    if (this.selectedCombatant.hasBuff(SPELLS.DIVINE_PURPOSE_HOLY_SHOCK_BUFF.id)) {
      this.holyShockProcStreak += 1;
      this.highestHolyShockProcStreak = Math.max(this.highestHolyShockProcStreak, this.holyShockProcStreak);
    } else {
      // When we cast a regular (unbuffed) HS, it's outside of a streak.
      this.holyShockProcStreak = 0;
    }
  }

  _onLightOfDawnDivinePurposeProc() {
    this.lightOfDawnProcs += 1;
    if (this.spellUsable.isOnCooldown(SPELLS.LIGHT_OF_DAWN_CAST.id)) {
      this.spellUsable.endCooldown(SPELLS.LIGHT_OF_DAWN_CAST.id);
    }
  }
  _onLightOfDawnCast() {
    if (this.selectedCombatant.hasBuff(SPELLS.DIVINE_PURPOSE_LIGHT_OF_DAWN_BUFF.id)) {
      this.lightOfDawnProcStreak += 1;
      this.highestLightOfDawnProcStreak = Math.max(this.highestLightOfDawnProcStreak, this.lightOfDawnProcStreak);
    } else {
      // When we cast a regular (unbuffed) LoD, it's outside of a streak.
      this.lightOfDawnProcStreak = 0;
    }
  }

  statistic() {
    const abilityTracker = this.abilityTracker;
    const getAbility = spellId => abilityTracker.getAbility(spellId);

    const lightOfDawnCast = getAbility(SPELLS.LIGHT_OF_DAWN_CAST.id);
    const holyShockHeal = getAbility(SPELLS.HOLY_SHOCK_HEAL.id);

    const lightOfDawnHeals = lightOfDawnCast.casts || 0;
    const holyShockHeals = holyShockHeal.healingHits || 0;

    return (
      <Statistic position={STATISTIC_ORDER.OPTIONAL(75)}>

            <SpellIcon id={SPELLS.DIVINE_PURPOSE_TALENT_HOLY.id} />{' '}
            Divine Purpose procs

              <SpellIcon
                id={SPELLS.HOLY_SHOCK_CAST.id}
                style={{
                  height: '2.5em',
                  marginTop: '-.1em',
                }}
              />

              {this.holyShockProcs}x

              {formatPercentage(this.holyShockProcs / (holyShockHeals - this.holyShockProcs))}%

Best streak: {this.highestHolyShockProcStreak < 2 ? 'N/A' : `${this.highestHolyShockProcStreak}x`}

              <SpellIcon
                id={SPELLS.LIGHT_OF_DAWN_CAST.id}
                style={{
                  height: '2.5em',
                  marginTop: '-.1em',
                }}
              />

              {this.lightOfDawnProcs}x

              {formatPercentage(this.lightOfDawnProcs / (lightOfDawnHeals - this.lightOfDawnProcs))}%

Best streak: {this.highestLightOfDawnProcStreak < 2 ? 'N/A' : `${this.highestLightOfDawnProcStreak}x`}

      </Statistic>
    );
  }
}

export default DivinePurpose;
<commit_msg>Do x6 instead of 6x to be a bit more straight forward<commit_after>import React from 'react';

import SPELLS from 'common/SPELLS';
import SpellIcon from 'common/SpellIcon';
import { formatPercentage } from 'common/format';
import Statistic from 'interface/statistics/Statistic';
import STATISTIC_ORDER from 'interface/others/STATISTIC_ORDER';
import Analyzer, { SELECTED_PLAYER } from 'parser/core/Analyzer';
import AbilityTracker from 'parser/shared/modules/AbilityTracker';
import SpellUsable from 'parser/shared/modules/SpellUsable';
import Events from 'parser/core/Events';

/**
 * @property {AbilityTracker} abilityTracker
 * @property {SpellUsable} spellUsable
 */
class DivinePurpose extends Analyzer {
  static dependencies = {
    abilityTracker: AbilityTracker,
    spellUsable: SpellUsable,
  };

  holyShockProcs = 0;
  holyShockProcStreak = 0;
  highestHolyShockProcStreak = 0;
  lightOfDawnProcs = 0;
  lightOfDawnProcStreak = 0;
  highestLightOfDawnProcStreak = 0;

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTalent(SPELLS.DIVINE_PURPOSE_TALENT_HOLY.id);
    // Holy Shock
    this.addEventListener(Events.applybuff.to(SELECTED_PLAYER).spell(SPELLS.DIVINE_PURPOSE_HOLY_SHOCK_BUFF), this._onHolyShockDivinePurposeProc);
    this.addEventListener(Events.refreshbuff.to(SELECTED_PLAYER).spell(SPELLS.DIVINE_PURPOSE_HOLY_SHOCK_BUFF), this._onHolyShockDivinePurposeProc);
    this.addEventListener(Events.cast.by(SELECTED_PLAYER).spell(SPELLS.HOLY_SHOCK_CAST), this._onHolyShockCast);
    // Light of Dawn
    this.addEventListener(Events.applybuff.to(SELECTED_PLAYER).spell(SPELLS.DIVINE_PURPOSE_LIGHT_OF_DAWN_BUFF), this._onLightOfDawnDivinePurposeProc);
    this.addEventListener(Events.refreshbuff.to(SELECTED_PLAYER).spell(SPELLS.DIVINE_PURPOSE_LIGHT_OF_DAWN_BUFF), this._onLightOfDawnDivinePurposeProc);
    this.addEventListener(Events.cast.by(SELECTED_PLAYER).spell(SPELLS.LIGHT_OF_DAWN_CAST), this._onLightOfDawnCast);
  }

  _onHolyShockDivinePurposeProc() {
    this.holyShockProcs += 1;
    if (this.spellUsable.isOnCooldown(SPELLS.HOLY_SHOCK_CAST.id)) {
      this.spellUsable.endCooldown(SPELLS.HOLY_SHOCK_CAST.id);
    }
  }
  _onHolyShockCast() {
    if (this.selectedCombatant.hasBuff(SPELLS.DIVINE_PURPOSE_HOLY_SHOCK_BUFF.id)) {
      this.holyShockProcStreak += 1;
      this.highestHolyShockProcStreak = Math.max(this.highestHolyShockProcStreak, this.holyShockProcStreak);
    } else {
      // When we cast a regular (unbuffed) HS, it's outside of a streak.
      this.holyShockProcStreak = 0;
    }
  }

  _onLightOfDawnDivinePurposeProc() {
    this.lightOfDawnProcs += 1;
    if (this.spellUsable.isOnCooldown(SPELLS.LIGHT_OF_DAWN_CAST.id)) {
      this.spellUsable.endCooldown(SPELLS.LIGHT_OF_DAWN_CAST.id);
    }
  }
  _onLightOfDawnCast() {
    if (this.selectedCombatant.hasBuff(SPELLS.DIVINE_PURPOSE_LIGHT_OF_DAWN_BUFF.id)) {
      this.lightOfDawnProcStreak += 1;
      this.highestLightOfDawnProcStreak = Math.max(this.highestLightOfDawnProcStreak, this.lightOfDawnProcStreak);
    } else {
      // When we cast a regular (unbuffed) LoD, it's outside of a streak.
      this.lightOfDawnProcStreak = 0;
    }
  }

  statistic() {
    const abilityTracker = this.abilityTracker;
    const getAbility = spellId => abilityTracker.getAbility(spellId);

    const lightOfDawnCast = getAbility(SPELLS.LIGHT_OF_DAWN_CAST.id);
    const holyShockHeal = getAbility(SPELLS.HOLY_SHOCK_HEAL.id);

    const lightOfDawnHeals = lightOfDawnCast.casts || 0;
    const holyShockHeals = holyShockHeal.healingHits || 0;

    return (
      <Statistic position={STATISTIC_ORDER.OPTIONAL(75)}>

            <SpellIcon id={SPELLS.DIVINE_PURPOSE_TALENT_HOLY.id} />{' '}
            Divine Purpose procs

              <SpellIcon
                id={SPELLS.HOLY_SHOCK_CAST.id}
                style={{
                  height: '2.5em',
                  marginTop: '-.1em',
                }}
              />

              {/* I want less than a space of width between the two */}
              x{this.holyShockProcs}

              {formatPercentage(this.holyShockProcs / (holyShockHeals - this.holyShockProcs))}%

Best streak: {this.highestHolyShockProcStreak < 2 ? 'N/A' : `${this.highestHolyShockProcStreak}x`}

              <SpellIcon
                id={SPELLS.LIGHT_OF_DAWN_CAST.id}
                style={{
                  height: '2.5em',
                  marginTop: '-.1em',
                }}
              />

              {/* I want less than a space of width between the two */}
              x{this.lightOfDawnProcs}

              {formatPercentage(this.lightOfDawnProcs / (lightOfDawnHeals - this.lightOfDawnProcs))}%

Best streak: {this.highestLightOfDawnProcStreak < 2 ? 'N/A' : `${this.highestLightOfDawnProcStreak}x`}

      </Statistic>
    );
  }
}

export default DivinePurpose;
<|endoftext|>


<commit_before>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var UIContainerPlugin = require('../../base/ui_container_plugin');
var Styler = require('../../base/styler');
var JST = require('../../base/jst');
var Events = require('../../base/events');

class SpinnerThreeBouncePlugin extends UIContainerPlugin {
  get name() { return 'spinner' }
  get attributes() {
    return {
      'data-spinner':'',
      'class': 'spinner-three-bounce'
    }
  }

  constructor(options) {
    super(options)
    this.template = JST.spinner_three_bounce
    this.listenTo(this.container, Events.CONTAINER_STATE_BUFFERING, this.onBuffering)
    this.listenTo(this.container, Events.CONTAINER_STATE_BUFFERFULL, this.onBufferFull)
    this.listenTo(this.container, Events.CONTAINER_STOP, this.onStop)
    this.render()
  }

  onBuffering() {
    this.$el.show()
  }

  onBufferFull() {
    this.$el.hide()
  }

  onStop() {
    this.$el.hide()
  }

  render() {
    this.$el.html(this.template())
    var style = Styler.getStyleFor('spinner_three_bounce')
    this.container.$el.append(style)
    this.container.$el.append(this.$el)
    this.$el.hide()
    return this
  }
}

module.exports = SpinnerThreeBouncePlugin;
<commit_msg>spinner: add small delay before showing indicator to avoid blinking issues (refs #413)<commit_after>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

var UIContainerPlugin = require('../../base/ui_container_plugin');
var Styler = require('../../base/styler');
var JST = require('../../base/jst');
var Events = require('../../base/events');

class SpinnerThreeBouncePlugin extends UIContainerPlugin {
  get name() { return 'spinner' }
  get attributes() {
    return {
      'data-spinner':'',
      'class': 'spinner-three-bounce'
    }
  }

  constructor(options) {
    super(options)
    this.template = JST.spinner_three_bounce
    this.listenTo(this.container, Events.CONTAINER_STATE_BUFFERING, this.onBuffering)
    this.listenTo(this.container, Events.CONTAINER_STATE_BUFFERFULL, this.onBufferFull)
    this.listenTo(this.container, Events.CONTAINER_STOP, this.onStop)
    this.render()
  }

  onBuffering() {
    this.showTimeout = setTimeout(() => this.$el.show(), 300)
  }

  onBufferFull() {
    clearTimeout(this.showTimeout)
    this.$el.hide()
  }

  onStop() {
    this.$el.hide()
  }

  render() {
    this.$el.html(this.template())
    var style = Styler.getStyleFor('spinner_three_bounce')
    this.container.$el.append(style)
    this.container.$el.append(this.$el)
    this.$el.hide()
    return this
  }
}

module.exports = SpinnerThreeBouncePlugin;
<|endoftext|>


<commit_before>import React from 'react';
import { Button, Form } from 'react-bootstrap';
import { getField, writeActivity, getRefValue } from './activityfns.js';
import * as DB from '../../constants/database.js'
import { countryList } from '../../constants/countries.js';
import * as time from '../Utils/time.js';
import app from '../Firebase';
import * as formElements from './editActivityFormElements.js';
import * as msgs from '../../constants/messages.js';

const db = app.firestore();

/**
 * React component for the form that's used when the user is editing an activity.
 *
 * @property {Object} props ReactJS props.
 * @property {ActivityInfo} props.activity The activity to display.
 * @property {function} props.submitFunction The function to run upon submission.
 */
class EditActivity extends React.Component {
  /** @override */
  constructor(props){
    super(props);

    this.state = {startTzChanged: false, endTzChanged: false};

    // Bind state users/modifiers to `this`.
    this.editActivity = this.editActivity.bind(this);
    this.finishEditActivity = this.finishEditActivity.bind(this);
    this.deleteActivity = this.deleteActivity.bind(this);
    this.timezoneDropdown = this.timezoneDropdown.bind(this);

    // References.
    this.editTitleRef = React.createRef();
    this.editStartDateRef = React.createRef();
    this.editEndDateRef = React.createRef();
    this.editStartTimeRef = React.createRef();
    this.editEndTimeRef = React.createRef();
    this.editDescriptionRef = React.createRef();
    this.editStartLocRef = React.createRef();
    this.editEndLocRef = React.createRef();
    this.editStartTzRef = React.createRef();
    this.editEndTzRef = React.createRef();
  }

  /**
   * Edit an activity in the database upon form submission.
   */
  editActivity() {
    const activity = this.props.activity;

    let newVals = {};
    // All the text fields.
    newVals[DB.ACTIVITIES_TITLE] =
      getRefValue(this.editTitleRef, '', activity[DB.ACTIVITIES_TITLE])
    newVals[DB.ACTIVITIES_DESCRIPTION] =
      getRefValue(this.editDescriptionRef, '', activity[DB.ACTIVITIES_DESCRIPTION]);

    newVals[DB.ACTIVITIES_START_COUNTRY] =
      getRefValue(this.editStartLocRef, 'No Change', activity[DB.ACTIVITIES_START_COUNTRY]);
    newVals[DB.ACTIVITIES_END_COUNTRY] =
      getRefValue(this.editEndLocRef, 'No Change', activity[DB.ACTIVITIES_END_COUNTRY]);

    newVals[DB.ACTIVITIES_START_TZ] = getRefValue(this.editStartTzRef);
    newVals[DB.ACTIVITIES_END_TZ] = getRefValue(this.editEndTzRef);

    // Start time fields!
    const startTime = getRefValue(this.editStartTimeRef);
    const startDate = getRefValue(this.editStartDateRef);
    const startTz = newVals[DB.ACTIVITIES_START_TZ];
    newVals[DB.ACTIVITIES_START_TIME] = time.firebaseTsFromISO(startTime, startDate, startTz);

    // End time fields!
    const endTime = getRefValue(this.editEndTimeRef);
    const endDate = getRefValue(this.editEndDateRef);
    const endTz = newVals[DB.ACTIVITIES_END_TZ];
    newVals[DB.ACTIVITIES_END_TIME] = time.firebaseTsFromISO(endTime, endDate, endTz);

    writeActivity(this.props.activity.tripId, this.props.activity.id, newVals);
  }

  /** Runs when the `submit` button on the form is pressed.  */
  finishEditActivity(event) {
    event.preventDefault();
    this.editActivity();
    this.props.submitFunction();
  }

  // "Flip switch" on timezone dropdown so the dropdown's contents update to the
  // selected country's timezones.
  startTimeTzUpdate = () => { this.setState({startTzChanged : !this.state.startTzChanged})};
  endTimeTzUpdate = () => { this.setState({endTzChanged : !this.state.endTzChanged})};

  /**
   * Returns a dropdown of all the timezones.
   * The dropdown's values change based on the corrresponding country dropdown to
   * reduce scrolling and ensure that the location corresponds to the time zone.
   *
   * Tests done manually using UI.
   *
   * @param {string} st Either 'start' or 'end' depending on whether the
   * timezone is for the start or end timezone.
   * @return {HTML} HTML dropdown item.
   */
  timezoneDropdown(st, defaultTz) {
    const ref = st === 'start' ? this.editStartLocRef : this.editEndLocRef;
    const dbEntry = st === 'start' ? DB.ACTIVITIES_START_COUNTRY : DB.ACTIVITIES_END_COUNTRY;
    let timezones;
    if (ref.current == null) {
      // If activity[key] DNE, then timezones will just return all tzs anyway.
      timezones = time.timezonesForCountry(this.props.activity[dbEntry]);
    } else {
      timezones = time.timezonesForCountry(ref.current.value);
    }

    return (
      <Form.Control as='select'
        ref={st === 'start' ? this.editStartTzRef : this.editEndTzRef}
        key={st === 'start' ? this.state.startTzChanged : this.state.endTzChanged}
        defaultValue={defaultTz}
      >
        {timezones.map((item, index) => {
          return (<option key={index}>{item}</option>);
        })}
      </Form.Control>
    )
  }

  /**
   * Create a dropdown of all the countries.
   * This dropdown is linked to the corresponding timezone dropdown,
   * so when the country changes here, the values in the timezone dropdown
   * change as well.
   *
   * @param {ref} ref The reference to attach to the dropdown.
   * @param {ref} tzref The corresponding time zone reference field.
   * @param {string} defaultCountry The default country for the dropdown.
   * @return {HTML} HTML dropdown of all the countries with timezones.
   */
  countriesDropdown(ref, tzref, defaultCountry) {
    return (
      <Form.Control as='select' ref={ref} onChange={tzref} defaultValue={defaultCountry}>
        {countryList.map((item, index) => {
          return (
            <option key={index}>{item}</option>
          );
        })}
      </Form.Control>
    );
  }

  /**
   * Delete this activity.
   *
   * @return {boolean} true if the activity was successfully deleted.
   */
  async deleteActivity() {
    if (window.confirm(`Are you sure you want to delete ${this.props.activity[DB.ACTIVITIES_TITLE]}?`
        + 'This action cannot be undone!')) {
      await db.collection(DB.COLLECTION_TRIPS).doc(this.props.activity.tripId)
        .collection(DB.COLLECTION_ACTIVITIES).doc(this.props.activity.id)
        .delete();
      return true;
    } else {
      return false;
    }
  }

  render() {
    const activity = this.props.activity;
    const newAct = this.props.new;
    return (
      <Form className='activity-editor' onSubmit={this.finishEditActivity}>
        {formElements.textElementFormGroup( // TITLE
            'formActivityTitle',          // controlId
            'Title:',                     // formLabel
            getField(activity, DB.ACTIVITIES_TITLE, msgs.ACTIVITY_TITLE_PLACEHOLDER), // placeHolder
            this.editTitleRef             // ref
          )}
        {formElements.locationElementFormGroup( // START LOCATION
          'formActivityStartLocation',                 // controlId
          'Start Location:',                           // formLabel
          this.countriesDropdown(this.editStartLocRef, // defaultValue ref
            this.editStartTzRef,                          // countriesDropdown tzref
            getField(activity, DB.ACTIVITIES_START_COUNTRY)) // countriesDropdown defaultCountry
          )}
        {formElements.locationElementFormGroup( // END LOCATION
          'formActivityEndLocation',                 // controlId
          'End Location:',                           // formLabel
          this.countriesDropdown(this.editEndLocRef, // defaultValue ref
            this.editEndTzRef, // countriesDropdown tzref
            getField(activity, DB.ACTIVITIES_END_COUNTRY)) // countriesDropdown defaultCountry
          )}
        {formElements.dateTimeTzFormGroup( // START TIME
          'formActivityStartTime',                         // controlId
          'From:',                                         // formLabel
          this.editStartDateRef,                           // dateRef
          time.getISODate(getField(activity, DB.ACTIVITIES_START_TIME),
              getField(activity, DB.ACTIVITIES_START_TZ)), // dateDefault
          this.editStartTimeRef,                           // timeRef,
          time.get24hTime(getField(activity, DB.ACTIVITIES_START_TIME),
              getField(activity, DB.ACTIVITIES_START_TZ)), //timeDefault,
          this.timezoneDropdown('start', getField(activity, DB.ACTIVITIES_START_TZ)) // tzpicker
          )}
        {formElements.dateTimeTzFormGroup( // END TIME
          'formActivityEndTime',                         // controlId
          'To:',                                         // formLabel
          this.editEndDateRef,                           // dateRef
          time.getISODate(getField(activity, DB.ACTIVITIES_END_TIME),
              getField(activity, DB.ACTIVITIES_END_TZ)), // dateDefault
          this.editEndTimeRef,                           // timeRef,
          time.get24hTime(getField(activity, DB.ACTIVITIES_END_TIME),
              getField(activity, DB.ACTIVITIES_END_TZ)), //timeDefault,
          this.timezoneDropdown('end', getField(activity, DB.ACTIVITIES_END_TZ)) // tzpicker
          )}
        {formElements.textElementFormGroup( // DESCRIPTION
            'formActivityDescription', // controlId
            'Description:', // formLabel
            getField(activity, DB.ACTIVITIES_DESCRIPTION, msgs.ACTIVITY_DESCRIPTION_PLACEHOLDER), // placeHolder
            this.editDescriptionRef // ref
          )}
        <Button type='submit' className='float-right'>Done!</Button>
        <Button type='button' onClick={this.deleteActivity}>
          Delete
        </Button>
      </Form>
    );
  }
}

export default EditActivity;<commit_msg>end location update<commit_after>import React from 'react';
import { Button, Form } from 'react-bootstrap';
import { getField, writeActivity, getRefValue } from './activityfns.js';
import * as DB from '../../constants/database.js'
import { countryList } from '../../constants/countries.js';
import * as time from '../Utils/time.js';
import app from '../Firebase';
import * as formElements from './editActivityFormElements.js';
import * as msgs from '../../constants/messages.js';

const db = app.firestore();

/**
 * React component for the form that's used when the user is editing an activity.
 *
 * @property {Object} props ReactJS props.
 * @property {ActivityInfo} props.activity The activity to display.
 * @property {function} props.submitFunction The function to run upon submission.
 */
class EditActivity extends React.Component {
  /** @override */
  constructor(props){
    super(props);

    this.state = {startTzChanged: false, endTzChanged: false};

    // Bind state users/modifiers to `this`.
    this.editActivity = this.editActivity.bind(this);
    this.finishEditActivity = this.finishEditActivity.bind(this);
    this.deleteActivity = this.deleteActivity.bind(this);
    this.timezoneDropdown = this.timezoneDropdown.bind(this);

    // References.
    this.editTitleRef = React.createRef();
    this.editStartDateRef = React.createRef();
    this.editEndDateRef = React.createRef();
    this.editStartTimeRef = React.createRef();
    this.editEndTimeRef = React.createRef();
    this.editDescriptionRef = React.createRef();
    this.editStartLocRef = React.createRef();
    this.editEndLocRef = React.createRef();
    this.editStartTzRef = React.createRef();
    this.editEndTzRef = React.createRef();
  }

  /**
   * Edit an activity in the database upon form submission.
   */
  editActivity() {
    const activity = this.props.activity;

    let newVals = {};
    // All the text fields.
    newVals[DB.ACTIVITIES_TITLE] =
      getRefValue(this.editTitleRef, '', activity[DB.ACTIVITIES_TITLE])
    newVals[DB.ACTIVITIES_DESCRIPTION] =
      getRefValue(this.editDescriptionRef, '', activity[DB.ACTIVITIES_DESCRIPTION]);

    newVals[DB.ACTIVITIES_START_COUNTRY] =
      getRefValue(this.editStartLocRef, 'No Change', activity[DB.ACTIVITIES_START_COUNTRY]);
    newVals[DB.ACTIVITIES_END_COUNTRY] =
      getRefValue(this.editEndLocRef, 'No Change', activity[DB.ACTIVITIES_END_COUNTRY]);

    newVals[DB.ACTIVITIES_START_TZ] = getRefValue(this.editStartTzRef);
    newVals[DB.ACTIVITIES_END_TZ] = getRefValue(this.editEndTzRef);

    // Start time fields!
    const startTime = getRefValue(this.editStartTimeRef);
    const startDate = getRefValue(this.editStartDateRef);
    const startTz = newVals[DB.ACTIVITIES_START_TZ];
    newVals[DB.ACTIVITIES_START_TIME] = time.firebaseTsFromISO(startTime, startDate, startTz);

    // End time fields!
    const endTime = getRefValue(this.editEndTimeRef);
    const endDate = getRefValue(this.editEndDateRef);
    const endTz = newVals[DB.ACTIVITIES_END_TZ];
    newVals[DB.ACTIVITIES_END_TIME] = time.firebaseTsFromISO(endTime, endDate, endTz);

    writeActivity(this.props.activity.tripId, this.props.activity.id, newVals);
  }

  /** Runs when the `submit` button on the form is pressed.  */
  finishEditActivity(event) {
    event.preventDefault();
    this.editActivity();
    this.props.submitFunction();
  }

  // "Flip switch" on timezone dropdown so the dropdown's contents update to the
  // selected country's timezones.
  startTimeTzUpdate = () => { this.setState({startTzChanged : !this.state.startTzChanged})};
  endTimeTzUpdate = () => { this.setState({endTzChanged : !this.state.endTzChanged})};

  /**
   * Returns a dropdown of all the timezones.
   * The dropdown's values change based on the corrresponding country dropdown to
   * reduce scrolling and ensure that the location corresponds to the time zone.
   *
   * Tests done manually using UI.
   *
   * @param {string} st Either 'start' or 'end' depending on whether the
   * timezone is for the start or end timezone.
   * @return {HTML} HTML dropdown item.
   */
  timezoneDropdown(st, defaultTz) {
    const ref = st === 'start' ? this.editStartLocRef : this.editEndLocRef;
    const dbEntry = st === 'start' ? DB.ACTIVITIES_START_COUNTRY : DB.ACTIVITIES_END_COUNTRY;
    let timezones;
    if (ref.current == null) {
      // If activity[key] DNE, then timezones will just return all tzs anyway.
      timezones = time.timezonesForCountry(this.props.activity[dbEntry]);
    } else {
      timezones = time.timezonesForCountry(ref.current.value);
    }

    return (
      <Form.Control as='select'
        ref={st === 'start' ? this.editStartTzRef : this.editEndTzRef}
        key={st === 'start' ? this.state.startTzChanged : this.state.endTzChanged}
        defaultValue={defaultTz}
      >
        {timezones.map((item, index) => {
          return (<option key={index}>{item}</option>);
        })}
      </Form.Control>
    )
  }

  /**
   * Create a dropdown of all the countries.
   * This dropdown is linked to the corresponding timezone dropdown,
   * so when the country changes here, the values in the timezone dropdown
   * change as well.
   *
   * @param {ref} ref The reference to attach to the dropdown.
   * @param {ref} tzref The corresponding time zone reference field.
   * @param {string} defaultCountry The default country for the dropdown.
   * @return {HTML} HTML dropdown of all the countries with timezones.
   */
  countriesDropdown(ref, tzref, defaultCountry) {
    return (
      <Form.Control as='select' ref={ref} onChange={tzref} defaultValue={defaultCountry}>
        {countryList.map((item, index) => {
          return (
            <option key={index}>{item}</option>
          );
        })}
      </Form.Control>
    );
  }

  /**
   * Delete this activity.
   *
   * @return {boolean} true if the activity was successfully deleted.
   */
  async deleteActivity() {
    if (window.confirm(`Are you sure you want to delete ${this.props.activity[DB.ACTIVITIES_TITLE]}?`
        + 'This action cannot be undone!')) {
      await db.collection(DB.COLLECTION_TRIPS).doc(this.props.activity.tripId)
        .collection(DB.COLLECTION_ACTIVITIES).doc(this.props.activity.id)
        .delete();
      return true;
    } else {
      return false;
    }
  }

  render() {
    const activity = this.props.activity;
    const newAct = this.props.new;
    return (
      <Form className='activity-editor' onSubmit={this.finishEditActivity}>
        {formElements.textElementFormGroup( // TITLE
            'formActivityTitle',          // controlId
            'Title:',                     // formLabel
            getField(activity, DB.ACTIVITIES_TITLE, msgs.ACTIVITY_TITLE_PLACEHOLDER), // placeHolder
            this.editTitleRef             // ref
          )}
        {formElements.locationElementFormGroup( // START LOCATION
          'formActivityStartLocation',                 // controlId
          'Start Location:',                           // formLabel
          this.countriesDropdown(this.editStartLocRef, // defaultValue ref
            this.editStartTzRef,                          // countriesDropdown tzref
            getField(activity, DB.ACTIVITIES_START_COUNTRY)) // countriesDropdown defaultCountry
          )}
        {formElements.locationElementFormGroup( // END LOCATION
          'formActivityEndLocation',                 // controlId
          'End Location:',                           // formLabel
          this.countriesDropdown(this.editEndLocRef, // defaultValue ref
            this.endTimeTzUpdate, // countriesDropdown onChange
            getField(activity, DB.ACTIVITIES_END_COUNTRY)), // countriesDropdown defaultCountry
            this.state.flightCheck //show
          )}
        {formElements.dateTimeTzFormGroup( // START TIME
          'formActivityStartTime',                         // controlId
          'From:',                                         // formLabel
          this.editStartDateRef,                           // dateRef
          time.getISODate(getField(activity, DB.ACTIVITIES_START_TIME),
              getField(activity, DB.ACTIVITIES_START_TZ)), // dateDefault
          this.editStartTimeRef,                           // timeRef,
          time.get24hTime(getField(activity, DB.ACTIVITIES_START_TIME),
              getField(activity, DB.ACTIVITIES_START_TZ)), //timeDefault,
          this.timezoneDropdown('start', getField(activity, DB.ACTIVITIES_START_TZ)) // tzpicker
          )}
        {formElements.dateTimeTzFormGroup( // END TIME
          'formActivityEndTime',                         // controlId
          'To:',                                         // formLabel
          this.editEndDateRef,                           // dateRef
          time.getISODate(getField(activity, DB.ACTIVITIES_END_TIME),
              getField(activity, DB.ACTIVITIES_END_TZ)), // dateDefault
          this.editEndTimeRef,                           // timeRef,
          time.get24hTime(getField(activity, DB.ACTIVITIES_END_TIME),
              getField(activity, DB.ACTIVITIES_END_TZ)), //timeDefault,
          this.timezoneDropdown('end', getField(activity, DB.ACTIVITIES_END_TZ)) // tzpicker
          )}
        {formElements.textElementFormGroup( // DESCRIPTION
            'formActivityDescription', // controlId
            'Description:', // formLabel
            getField(activity, DB.ACTIVITIES_DESCRIPTION, msgs.ACTIVITY_DESCRIPTION_PLACEHOLDER), // placeHolder
            this.editDescriptionRef // ref
          )}
        <Button type='submit' className='float-right'>Done!</Button>
        <Button type='button' onClick={this.deleteActivity}>
          Delete
        </Button>
      </Form>
    );
  }
}

export default EditActivity;<|endoftext|>


<commit_before>/**
 * Follow RSS feeds and publish new articles to channels.
 */

"use strict";

let EventEmitter = require("events");
let FeedParser = require("feedparser");
let request = require("request");
let urllib = require("url");
let util = require("util");
let proxy = require("../core/proxy");

exports.configure = function(connection) {
  let feeds = new FeedManager(connection, connection.config.modules.feeds);
  feeds.watch();
  return feeds;
};

class FeedManager {
  constructor(connection, config) {
    this.connection = connection;
    this.config = config;
    this.events = new EventEmitter;
    this.queue = [];
    this.timers = {
      refresh: null,
      publish: null,
    };
    this.feeds = this.config.sources || [];
  }

  watch() {
    if (this.isWatching) {
      console.error("FeedManager is already running.");
      return false;
    }
    this.refresh();
    this.timers.refresh = setInterval(proxy(this.refresh, this), this.refreshInterval * 1000);
    this.timers.publish = setInterval(proxy(this.publishNext, this), this.publishInterval * 1000);
  }

  stop() {
    if (this.isWatching) {
      clearInterval(this.timers.refresh);
      clearInterval(this.timers.publish);

      this.timers = {
        refresh: null,
        publish: null,
      };
    }
  }

  refresh() {
    return new Promise((resolve, reject) => {
      let now = new Date;

      this.feeds.forEach(feed => {
        if (now - feed.updated >= this.refreshInterval) {
          feed.refresh();
        }
      });
    }, error => {
      console.error("feeds:", error.stack);
    });
  }

  enqueue(article) {
    this.queue.push(article);
  }

  publishNext() {
    if (this.queue.length) {
      let article = this.queue.shift();
      let message = this.formatArticle(article);
      this.connection.amsg(message);
    }
  }

  trimQueryVariables(url) {
    let data = urllib.parse(url, true);
    delete data.search;
    Object.keys(data.query).forEach(key => {
      if (!Number.isInteger(data.query[key])) {
        delete data.query[key];
      }
    });
    return urllib.format(url);
  }

  formatArticle(article) {
    let link = this.trimQueryVariables(article.link);
    return util.format("[%s] %s - %s",
      article.source.toUpperCase().replace(/\W/, ""),
      article.title,
      link);
  }

  get isWatching() {
    return this.timers.refresh != null;
  }

  get refreshInterval() {
    return this.config.refresh;
  }

  get publishInterval() {
    return this.config.publish;
  }

  get feeds() {
    return this._feeds;
  }

  set feeds(sources) {
    this._feeds = [];
    sources.forEach(source => {
      let feed = new Feed(source);
      this._feeds.push(feed);

      feed.on("article", item => {
        this.enqueue(item);
      });
    });
  }
}

class Feed {
  constructor(config) {
    this.config = config;
    this.events = new EventEmitter;
    this.updated = new Date;
    this.updated.setMinutes(this.updated.getMinutes() - 5);
    this.cache = new Map;
  }

  refresh() {
    process.nextTick(() => {
      let req = request(this.url);
      let parser = new FeedParser({feedurl: this.url});
      let updated = this.updated - 1000 * 60 * 30;
      this.updated = new Date;

      req.on("error", error => {
        console.error("feed.refresh:", error.stack);
      })

      req.on("response", res => {
        if (res.statusCode != 200) {
          return console.error("feed.refresh: invalid status code", res.statusCode);
        }
        req.pipe(parser);
      });

      parser.on("error", error => {
        console.error("feed.parser:", error.stack);
      })

      parser.on("readable", () => {
        let item;
        while (item = parser.read()) {
          let cache_key = item.title.substring(0, 30).toLowerCase();
          if (updated < item.pubDate && !this.cache.has(cache_key)) {
            this.events.emit("article", {
              source: this.name,
              title: item.title,
              date: item.pubDate,
              link: item.link,
            });
            this.cache.set(cache_key, new Date);
          }
        }
      });

      let cache_expiry = new Date;
      cache_expiry.setHours(cache_expiry.getHours() - 1);

      this.cache.forEach((expires, key) => {
        if (expires < cache_expiry) {
          this.cache.delete(key);
        }
      });
    });
  }

  on() {
    this.events.on.apply(this.events, arguments);
  }

  get name() {
    return this.config.name;
  }

  get url() {
    return this.config.url;
  }
}
<commit_msg>Fix query crap stripping<commit_after>/**
 * Follow RSS feeds and publish new articles to channels.
 */

"use strict";

let EventEmitter = require("events");
let FeedParser = require("feedparser");
let request = require("request");
let urllib = require("url");
let util = require("util");
let proxy = require("../core/proxy");

exports.configure = function(connection) {
  let feeds = new FeedManager(connection, connection.config.modules.feeds);
  feeds.watch();
  return feeds;
};

class FeedManager {
  constructor(connection, config) {
    this.connection = connection;
    this.config = config;
    this.events = new EventEmitter;
    this.queue = [];
    this.timers = {
      refresh: null,
      publish: null,
    };
    this.feeds = this.config.sources || [];
  }

  watch() {
    if (this.isWatching) {
      console.error("FeedManager is already running.");
      return false;
    }
    this.refresh();
    this.timers.refresh = setInterval(proxy(this.refresh, this), this.refreshInterval * 1000);
    this.timers.publish = setInterval(proxy(this.publishNext, this), this.publishInterval * 1000);
  }

  stop() {
    if (this.isWatching) {
      clearInterval(this.timers.refresh);
      clearInterval(this.timers.publish);

      this.timers = {
        refresh: null,
        publish: null,
      };
    }
  }

  refresh() {
    return new Promise((resolve, reject) => {
      let now = new Date;

      this.feeds.forEach(feed => {
        if (now - feed.updated >= this.refreshInterval) {
          feed.refresh();
        }
      });
    }, error => {
      console.error("feeds:", error.stack);
    });
  }

  enqueue(article) {
    this.queue.push(article);
  }

  publishNext() {
    if (this.queue.length) {
      let article = this.queue.shift();
      let message = this.formatArticle(article);
      this.connection.amsg(message);
    }
  }

  stripQueryVariables(url) {
    let data = urllib.parse(url, true);
    delete data.search;
    Object.keys(data.query).forEach(key => {
      if (Number.isNaN(data.query[key])) {
        delete data.query[key];
      }
    });
    return urllib.format(data);
  }

  formatArticle(article) {
    let link = this.stripQueryVariables(article.link);
    return util.format("[%s] %s - %s",
      article.source.toUpperCase().replace(/\W/, ""),
      article.title,
      link);
  }

  get isWatching() {
    return this.timers.refresh != null;
  }

  get refreshInterval() {
    return this.config.refresh;
  }

  get publishInterval() {
    return this.config.publish;
  }

  get feeds() {
    return this._feeds;
  }

  set feeds(sources) {
    this._feeds = [];
    sources.forEach(source => {
      let feed = new Feed(source);
      this._feeds.push(feed);

      feed.on("article", item => {
        this.enqueue(item);
      });
    });
  }
}

class Feed {
  constructor(config) {
    this.config = config;
    this.events = new EventEmitter;
    this.updated = new Date;
    this.updated.setMinutes(this.updated.getMinutes() - 5);
    this.cache = new Map;
  }

  refresh() {
    process.nextTick(() => {
      let req = request(this.url);
      let parser = new FeedParser({feedurl: this.url});
      let updated = this.updated - 1000 * 60 * 30;
      this.updated = new Date;

      req.on("error", error => {
        console.error("feed.refresh:", error.stack);
      })

      req.on("response", res => {
        if (res.statusCode != 200) {
          return console.error("feed.refresh: invalid status code", res.statusCode);
        }
        req.pipe(parser);
      });

      parser.on("error", error => {
        console.error("feed.parser:", error.stack);
      })

      parser.on("readable", () => {
        let item;
        while (item = parser.read()) {
          let cache_key = item.title.substring(0, 30).toLowerCase();
          if (updated < item.pubDate && !this.cache.has(cache_key)) {
            this.events.emit("article", {
              source: this.name,
              title: item.title,
              date: item.pubDate,
              link: item.link,
            });
            this.cache.set(cache_key, new Date);
          }
        }
      });

      let cache_expiry = new Date;
      cache_expiry.setHours(cache_expiry.getHours() - 1);

      this.cache.forEach((expires, key) => {
        if (expires < cache_expiry) {
          this.cache.delete(key);
        }
      });
    });
  }

  on() {
    this.events.on.apply(this.events, arguments);
  }

  get name() {
    return this.config.name;
  }

  get url() {
    return this.config.url;
  }
}
<|endoftext|>


<commit_before>'use strict'

import { StyleSheet } from 'react-native'
import { Fonts, Colors, Metrics } from '../../Themes/'

export default StyleSheet.create({
  button: {
    height: 45,
    borderRadius: 5,
    marginHorizontal: Metrics.section,
    marginVertical: Metrics.baseMargin,
    backgroundColor: Colors.fire,
    justifyContent: 'center'
  },
  buttonText: {
    color: Colors.snow,
    textAlign: 'center',
    fontWeight: 'bold',
    fontSize: Fonts.size.medium
  }
})
<commit_msg>fix small 1 pixel bug<commit_after>'use strict'

import { StyleSheet } from 'react-native'
import { Fonts, Colors, Metrics } from '../../Themes/'

export default StyleSheet.create({
  button: {
    height: 45,
    borderRadius: 5,
    marginHorizontal: Metrics.section,
    marginVertical: Metrics.baseMargin,
    backgroundColor: Colors.fire,
    justifyContent: 'center'
  },
  buttonText: {
    color: Colors.snow,
    textAlign: 'center',
    fontWeight: 'bold',
    fontSize: Fonts.size.medium,
    paddingVertical: Metrics.baseMargin
  }
})
<|endoftext|>


<commit_before>/* Copyright (c) 2015-2016 The TagSpaces Authors.
 * Use of this source code is governed by the MIT license which can be found in the LICENSE.txt file. */

define(function(require, exports, module) {
  "use strict";

  var extensionTitle = "ImageSwiper"; // should be equal to the name in the bower.json
  var extensionID = "perspectiveImageSwiper"; // ID should be equal to the directory name where the ext. is located
  var extensionIcon = "fa fa-image"; // icon class from font awesome

  console.log("Loading " + extensionID);

  var TSCORE = require("tscore");
  var marked = require('marked');
  var extensionDirectory = TSCORE.Config.getExtensionPath() + "/" + extensionID;
  var UI;
  var $viewContainer = $("#" + extensionID + "Container");
  var homeScreen;
  var template;
  var UI;
  var aboutContent;
  var extensionLoaded;

  function init() {
    console.log("Initializing perspective " + extensionID);

    $viewContainer = $("#" + extensionID + "Container").empty();

    extensionLoaded = new Promise(function(resolve, reject) {
      require([
        extensionDirectory + "/perspectiveUI.js",
        "text!" + extensionDirectory + "/extension.html",
        "css!" + extensionDirectory + "/libs/photoswipe/dist/photoswipe.css",
        "css!" + extensionDirectory + "/libs/photoswipe/dist/default-skin/default-skin.css",
        "css!" + extensionDirectory + "/extension.css",
        ], function(perspectiveUI, tmpl) {
          UI = perspectiveUI;
          template = tmpl;
          UI.initUI(extensionDirectory);
          $('#' + extensionID + 'Container [data-i18n]').i18n();
          resolve(true);
        }
      );
    });
  }

  function load() {
    console.log("Loading perspective " + extensionID);
    extensionLoaded.then(function() {
      UI.load($viewContainer, template);
      TSCORE.hideLoadingAnimation();

      if (!aboutContent) {
        $.ajax({
          url: extensionDirectory + '/README.md',
          type: 'GET'
        })
        .done(function(mdData) {
          if (marked) {
            aboutContent = marked(mdData, { sanitize: true });
            var modalBody = $("#aboutExtensionModalImageSwiper .modal-body");
            modalBody.html(aboutContent);
            handleLinks(modalBody);
          }
        })
        .fail(function(data) {
          console.log("Loading about content failed " + data);
        });
      }
    });
  }

  function handleLinks($element) {
    $element.find("a[href]").each(function() {
      var currentSrc = $(this).attr("href");
      $(this).bind('click', function(e) {
        e.preventDefault();
        var msg = {command: "openLinkExternally", link : currentSrc};
        window.parent.postMessage(JSON.stringify(msg), "*");
      });
    });
  }

  function clearSelectedFiles() {}

  function removeFileUI(filePath) {}

  function updateFileUI(oldFilePath, newFilePath) {}

  function getNextFile(filePath) {}

  function getPrevFile(filePath) {}

  function updateTreeData(fsTreeData) {

    console.log("Updating tree data not implemented");
  }

  function setReadOnly(filePath) {
    return UI.setReadOnly(filePath);
  }

  // API Vars
  exports.Title = extensionTitle;
  exports.ID = extensionID;
  exports.Icon = extensionIcon;

  // API Methods
  exports.init = init;
  exports.load = load;
  exports.clearSelectedFiles = clearSelectedFiles;
  exports.getNextFile = getNextFile;
  exports.getPrevFile = getPrevFile;
  exports.removeFileUI = removeFileUI;
  exports.updateFileUI = updateFileUI;
  exports.updateTreeData = updateTreeData;
  exports.setReadOnly = setReadOnly;
});<commit_msg>readonly mode<commit_after>/* Copyright (c) 2015-2016 The TagSpaces Authors.
 * Use of this source code is governed by the MIT license which can be found in the LICENSE.txt file. */

define(function(require, exports, module) {
  "use strict";

  var extensionTitle = "ImageSwiper"; // should be equal to the name in the bower.json
  var extensionID = "perspectiveImageSwiper"; // ID should be equal to the directory name where the ext. is located
  var extensionIcon = "fa fa-image"; // icon class from font awesome

  console.log("Loading " + extensionID);

  var TSCORE = require("tscore");
  var marked = require('marked');
  var extensionDirectory = TSCORE.Config.getExtensionPath() + "/" + extensionID;
  var UI;
  var $viewContainer = $("#" + extensionID + "Container");
  var homeScreen;
  var template;
  var UI;
  var aboutContent;
  var extensionLoaded;

  function init() {
    console.log("Initializing perspective " + extensionID);

    $viewContainer = $("#" + extensionID + "Container").empty();

    extensionLoaded = new Promise(function(resolve, reject) {
      require([
        extensionDirectory + "/perspectiveUI.js",
        "text!" + extensionDirectory + "/extension.html",
        "css!" + extensionDirectory + "/libs/photoswipe/dist/photoswipe.css",
        "css!" + extensionDirectory + "/libs/photoswipe/dist/default-skin/default-skin.css",
        "css!" + extensionDirectory + "/extension.css",
        ], function(perspectiveUI, tmpl) {
          UI = perspectiveUI;
          template = tmpl;
          UI.initUI(extensionDirectory);
          $('#' + extensionID + 'Container [data-i18n]').i18n();
          resolve(true);
        }
      );
    });
  }

  function load() {
    console.log("Loading perspective " + extensionID);
    extensionLoaded.then(function() {
      UI.load($viewContainer, template);
      TSCORE.hideLoadingAnimation();

      if (!aboutContent) {
        $.ajax({
          url: extensionDirectory + '/README.md',
          type: 'GET'
        })
        .done(function(mdData) {
          if (marked) {
            aboutContent = marked(mdData, { sanitize: true });
            var modalBody = $("#aboutExtensionModalImageSwiper .modal-body");
            modalBody.html(aboutContent);
            handleLinks(modalBody);
          }
        })
        .fail(function(data) {
          console.log("Loading about content failed " + data);
        });
      }
    });
  }

  function handleLinks($element) {
    $element.find("a[href]").each(function() {
      var currentSrc = $(this).attr("href");
      $(this).bind('click', function(e) {
        e.preventDefault();
        var msg = {command: "openLinkExternally", link : currentSrc};
        window.parent.postMessage(JSON.stringify(msg), "*");
      });
    });
  }

  function clearSelectedFiles() {}

  function removeFileUI(filePath) {}

  function updateFileUI(oldFilePath, newFilePath) {}

  function getNextFile(filePath) {}

  function getPrevFile(filePath) {}

  function updateTreeData(fsTreeData) {

    console.log("Updating tree data not implemented");
  }

  function setReadOnly(filePath) {
    $('#tagMenuEditTag').hide();
    $('#tagTreeMenuEditTag').hide();
    $('#tagFile').hide();
    $('#duplicateFile').hide();
    $('#renameFile').hide();
    $('#addTagFileViewer').hide();
    $('#fileMenuAddTag').hide();
    $('#fileMenuMoveCopyFile').hide();
    $('#fileMenuRenameFile').hide();
    $('#editDocument').hide();
    //$('.flexMaxWidth .editable .editable-click').off('click');

    $(document).off('drop dragend dragenter dragover dragleave', function(event) {
      event.preventDefault();
    });
  }

  // API Vars
  exports.Title = extensionTitle;
  exports.ID = extensionID;
  exports.Icon = extensionIcon;

  // API Methods
  exports.init = init;
  exports.load = load;
  exports.clearSelectedFiles = clearSelectedFiles;
  exports.getNextFile = getNextFile;
  exports.getPrevFile = getPrevFile;
  exports.removeFileUI = removeFileUI;
  exports.updateFileUI = updateFileUI;
  exports.updateTreeData = updateTreeData;
  exports.setReadOnly = setReadOnly;
});<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import React from 'react';
import Subheader from 'material-ui/Subheader';
import Paper from 'material-ui/Paper';
import PaperCard from '../../layouts/paper-card';

import * as Colors from 'material-ui/styles/colors';
import * as Helper from '../../../util/helper';
import * as GiveawaysHelper from '../../../util/giveaways';
import * as AvatarHelper from '../../../util/avatar';
import * as IconsHelper from '../../../util/icons';

import { flagGiveaway } from '../../../api/giveaways/methods';

let giveaway = null;

const iconRow = (icon, content) => {
  if (content)
    return (

          { IconsHelper.icon(icon, { fontSize: 18, lineHeight: "25px" }) }

{ content }

    );
};

const flagCTA = (self) => (

    You can bring this giveaway to moderators' attention by flagging it.

    If this giveaway is a duplicate/does not exist, please flag and also leave a comment.

);

const hasFlagged = (self) => (

    You have flagged this giveaway for moderators' attention. We will be reviewing this giveaway shortly.

);

export class GiveawaySingleCard extends React.Component {

  handleFlagGiveaway(event) {
    flagGiveaway.call({ _id: this.props.ga._id, userId: Meteor.userId() }, function(error) {
      if (error) {
        Bert.alert(error.reason, 'danger');
      } else {
        Bert.alert('Thanks for flagging, we will be reviewing this shortly.', 'success');
      }
    });
  }

  render() {
    const ga = this.props.ga;

    return (
      <PaperCard className="giveaway giveaway-single">

              { GiveawaysHelper.makeAvatarLegacy(ga, 700) }

{ ga.title }

{ GiveawaysHelper.categoryBreadcrumbs(ga) }

{ GiveawaysHelper.description(ga) }

            { iconRow("date_range", GiveawaysHelper.dateRange(ga)) }
            { iconRow("location_on", ga.location ) }
            { GiveawaysHelper.is_ongoing(ga) ? iconRow("info_outline", "Status: " + GiveawaysHelper.getLastOwnerStatusType(ga).label ) : null }
            { iconRow("link", Helper.makeLink(ga.website, "Website")) }

            { Meteor.userId() && ga.userId !== Meteor.userId() ?
                GiveawaysHelper.userHasFlagged(ga, Meteor.user()) ? hasFlagged(this) : flagCTA(this)
              : null }

      </PaperCard>
    );
  }
}
<commit_msg>Make SingleCard Avatar half size<commit_after>import { Meteor } from 'meteor/meteor';
import React from 'react';
import Subheader from 'material-ui/Subheader';
import Paper from 'material-ui/Paper';
import PaperCard from '../../layouts/paper-card';

import * as Colors from 'material-ui/styles/colors';
import * as Helper from '../../../util/helper';
import * as GiveawaysHelper from '../../../util/giveaways';
import * as AvatarHelper from '../../../util/avatar';
import * as IconsHelper from '../../../util/icons';

import { flagGiveaway } from '../../../api/giveaways/methods';

let giveaway = null;

const iconRow = (icon, content) => {
  if (content)
    return (

          { IconsHelper.icon(icon, { fontSize: 18, lineHeight: "25px" }) }

{ content }

    );
};

const flagCTA = (self) => (

    You can bring this giveaway to moderators' attention by flagging it.

    If this giveaway is a duplicate/does not exist, please flag and also leave a comment.

);

const hasFlagged = (self) => (

    You have flagged this giveaway for moderators' attention. We will be reviewing this giveaway shortly.

);

export class GiveawaySingleCard extends React.Component {

  handleFlagGiveaway(event) {
    flagGiveaway.call({ _id: this.props.ga._id, userId: Meteor.userId() }, function(error) {
      if (error) {
        Bert.alert(error.reason, 'danger');
      } else {
        Bert.alert('Thanks for flagging, we will be reviewing this shortly.', 'success');
      }
    });
  }

  render() {
    const ga = this.props.ga;

    return (
      <PaperCard className="giveaway giveaway-single">

              { GiveawaysHelper.makeAvatarLegacy(ga, 350) }

{ ga.title }

{ GiveawaysHelper.categoryBreadcrumbs(ga) }

{ GiveawaysHelper.description(ga) }

            { iconRow("date_range", GiveawaysHelper.dateRange(ga)) }
            { iconRow("location_on", ga.location ) }
            { GiveawaysHelper.is_ongoing(ga) ? iconRow("info_outline", "Status: " + GiveawaysHelper.getLastOwnerStatusType(ga).label ) : null }
            { iconRow("link", Helper.makeLink(ga.website, "Website")) }

            { Meteor.userId() && ga.userId !== Meteor.userId() ?
                GiveawaysHelper.userHasFlagged(ga, Meteor.user()) ? hasFlagged(this) : flagCTA(this)
              : null }

      </PaperCard>
    );
  }
}
<|endoftext|>


<commit_before>"use strict";

const Clutter = imports.gi.Clutter;
const GnomeDesktop = imports.gi.GnomeDesktop;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const St = imports.gi.St;
const ExtensionUtils = imports.misc.extensionUtils;
const Gio = imports.gi.Gio;
const Me = ExtensionUtils.getCurrentExtension();
const Convenience = Me.imports.convenience;
const PopupMenu = imports.ui.popupMenu;

let UTCClock = GObject.registerClass(
    class UTCCLock extends PanelMenu.Button {

        _init() {
            super._init(0, "UTCClock", false);

            // Label
            this.timeText = new St.Label({
                y_align: Clutter.ActorAlign.CENTER,
                text: "..."
            });

            let topBox = new St.BoxLayout();
            topBox.add_actor(this.timeText);
            this.add_actor(topBox);

            this.enable();
        }

        updateTime() {
            let now = new Date();
            let utc = new Date(
                now.getUTCFullYear(),
                now.getUTCMonth(),
                now.getUTCDate(),
                now.getUTCHours(),
                now.getUTCMinutes(),
                now.getUTCSeconds()
            );
            this.timeText.set_text(
                new Intl.DateTimeFormat(
                    "default", this.format_params
                ).format(utc) + " " + this.time_text
            );
        }

        setSecondsDisplayed() {
            let secondsDisplayed = this.settings.get_boolean("show-seconds");
            if (secondsDisplayed) {
                this.format_params["second"] = "2-digit";
            } else {
                delete this.format_params["second"];
            }
            this.updateTime();
        }

        setTimeText() {
            this.time_text = this.settings.get_string("time-text");
            this.updateTime();
        }

        setDateDisplayed() {
            let dateDisplayed = this.settings.get_boolean("show-date");
            if (dateDisplayed) {
                this.format_params["weekday"] = "short";
                this.format_params["month"] = "short";
                this.format_params["day"] = "numeric";
            } else {
                delete this.format_params["weekday"];
                delete this.format_params["month"];
                delete this.format_params["day"];
            }
            this.updateTime();
        }

        setLightOpacity() {
            this.timeText.opacity =
                this.settings.get_boolean("light-opacity") ? 255 : 200;
            this.updateTime();
        }

        buildMenu() {
            this.ClockMenuItemSeconds = new PopupMenu.PopupSwitchMenuItem(
                "Show seconds",
                this.settings.get_boolean("show-seconds"),
                { reactive: true }
            );
            this.ClockMenuItemSeconds.connect(
                "toggled",
                Lang.bind(
                    this, function(object, value) {
                        this.settings.set_boolean("show-seconds", value);
                    }
                )
            );
            this.menu.addMenuItem(this.ClockMenuItemSeconds);

            this.ClockMenuItemText = new PopupMenu.PopupSubMenuMenuItem(
                "Time text to show",
                true
            );
            const PopupMenuItemUTC = new PopupMenu.PopupMenuItem("UTC");
            PopupMenuItemUTC.connect('activate', Lang.bind(this, function(){
                this.settings.set_string("time-text", "UTC");
            }));
            this.ClockMenuItemText.menu.addMenuItem(PopupMenuItemUTC);
            const PopupMenuItemGMT = new PopupMenu.PopupMenuItem("GMT");
            PopupMenuItemGMT.connect('activate', Lang.bind(this, function(){
                this.settings.set_string("time-text", "GMT");
            }));
            this.ClockMenuItemText.menu.addMenuItem(PopupMenuItemGMT);
            const PopupMenuItemZ = new PopupMenu.PopupMenuItem("Z");
            PopupMenuItemZ.connect('activate', Lang.bind(this, function(){
                this.settings.set_string("time-text", "Z");
            }));
            this.ClockMenuItemText.menu.addMenuItem(PopupMenuItemZ);
            this.menu.addMenuItem(this.ClockMenuItemText);

            this.ClockMenuItemDate = new PopupMenu.PopupSwitchMenuItem(
                "Show date",
                this.settings.get_boolean("show-date"),
                { reactive: true }
            );
            this.ClockMenuItemDate.connect(
                "toggled",
                Lang.bind(
                    this, function(object, value) {
                        this.settings.set_boolean("show-date", value);
                    }
                )
            );
            this.menu.addMenuItem(this.ClockMenuItemDate);

            this.ClockMenuItemOpacity = new PopupMenu.PopupSwitchMenuItem(
                "Light opacity",
                this.settings.get_boolean("light-opacity"),
                { reactive: true }
            );
            this.ClockMenuItemOpacity.connect(
                "toggled",
                Lang.bind(
                    this, function(object, value) {
                        this.settings.set_boolean("light-opacity", value);
                    }
                )
            );
            this.menu.addMenuItem(this.ClockMenuItemOpacity);
        }

        enable() {
            this.time_text = "UTC";

            this.format_params = {
                hour: "2-digit",
                minute: "2-digit",
                hour12: false
            }

            this.settings = Convenience.getSettings();

            this.signals = [];

            this.clock = new GnomeDesktop.WallClock();
            this.signals[0] = this.clock.connect(
                "notify::clock",
                Lang.bind(this, this.updateTime)
            );

            this.setSecondsDisplayed();
            this.signals[1] = this.settings.connect(
                "changed::show-seconds",
                Lang.bind(this, this.setSecondsDisplayed)
            );

            this.setTimeText();
            this.signals[2] = this.settings.connect(
                "changed::time-text",
                Lang.bind(this, this.setTimeText)
            );

            this.setDateDisplayed();
            this.signals[3] = this.settings.connect(
                "changed::show-date",
                Lang.bind(this, this.setDateDisplayed)
            );

            this.setLightOpacity();
            this.signals[4] = this.settings.connect(
                "changed::light-opacity",
                Lang.bind(this, this.setLightOpacity)
            );

            this.buildMenu();
        }

        disable() {
            this.clock.disconnect(this.signals[0]);
            this.settings.disconnect(this.signals[1]);
            this.settings.disconnect(this.signals[2]);
            this.settings.disconnect(this.signals[3]);
            this.settings.disconnect(this.signals[4]);
        }
    }
);

let utcclock;

function init() {

}

function enable() {
    utcclock = new UTCClock();
    Main.panel._addToPanelBox("utcclock", utcclock, 1, Main.panel._centerBox);
}

function disable() {
    utcclock.disable();
    utcclock.destroy();
}<commit_msg>Minor correction<commit_after>"use strict";

const Clutter = imports.gi.Clutter;
const GnomeDesktop = imports.gi.GnomeDesktop;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const St = imports.gi.St;
const ExtensionUtils = imports.misc.extensionUtils;
const Gio = imports.gi.Gio;
const Me = ExtensionUtils.getCurrentExtension();
const Convenience = Me.imports.convenience;
const PopupMenu = imports.ui.popupMenu;

let UTCClock = GObject.registerClass(
    class UTCCLock extends PanelMenu.Button {

        _init() {
            super._init(0, "UTCClock", false);

            // Label
            this.timeText = new St.Label({
                y_align: Clutter.ActorAlign.CENTER,
                text: "..."
            });

            let topBox = new St.BoxLayout();
            topBox.add_actor(this.timeText);
            this.add_actor(topBox);

            this.enable();
        }

        updateTime() {
            let now = new Date();
            let utc = new Date(
                now.getUTCFullYear(),
                now.getUTCMonth(),
                now.getUTCDate(),
                now.getUTCHours(),
                now.getUTCMinutes(),
                now.getUTCSeconds()
            );
            this.timeText.set_text(
                new Intl.DateTimeFormat(
                    "default", this.format_params
                ).format(utc) + " " + this.time_text
            );
        }

        setSecondsDisplayed() {
            let secondsDisplayed = this.settings.get_boolean("show-seconds");
            if (secondsDisplayed) {
                this.format_params["second"] = "2-digit";
            } else {
                delete this.format_params["second"];
            }
            this.updateTime();
        }

        setTimeText() {
            this.time_text = this.settings.get_string("time-text");
            this.updateTime();
        }

        setDateDisplayed() {
            let dateDisplayed = this.settings.get_boolean("show-date");
            if (dateDisplayed) {
                this.format_params["weekday"] = "short";
                this.format_params["month"] = "short";
                this.format_params["day"] = "numeric";
            } else {
                delete this.format_params["weekday"];
                delete this.format_params["month"];
                delete this.format_params["day"];
            }
            this.updateTime();
        }

        setLightOpacity() {
            this.timeText.opacity =
                this.settings.get_boolean("light-opacity") ? 255 : 200;
            this.updateTime();
        }

        buildMenu() {
            this.ClockMenuItemSeconds = new PopupMenu.PopupSwitchMenuItem(
                "Show seconds",
                this.settings.get_boolean("show-seconds"),
                { reactive: true }
            );
            this.ClockMenuItemSeconds.connect(
                "toggled",
                Lang.bind(
                    this, function(object, value) {
                        this.settings.set_boolean("show-seconds", value);
                    }
                )
            );
            this.ClockMenuItemSeconds.connect('open-state-changed', Lang.bind(this, function(){
                log('Menu opened');
            }));
            this.menu.addMenuItem(this.ClockMenuItemSeconds);

            this.ClockMenuItemText = new PopupMenu.PopupSubMenuMenuItem(
                "Time text to show",
                true
            );
            const PopupMenuItemUTC = new PopupMenu.PopupMenuItem("UTC");
            PopupMenuItemUTC.connect('activate', Lang.bind(this, function(){
                this.settings.set_string("time-text", "UTC");
            }));
            this.ClockMenuItemText.menu.addMenuItem(PopupMenuItemUTC);
            const PopupMenuItemGMT = new PopupMenu.PopupMenuItem("GMT");
            PopupMenuItemGMT.connect('activate', Lang.bind(this, function(){
                this.settings.set_string("time-text", "GMT");
            }));
            this.ClockMenuItemText.menu.addMenuItem(PopupMenuItemGMT);
            const PopupMenuItemZ = new PopupMenu.PopupMenuItem("Z");
            PopupMenuItemZ.connect('activate', Lang.bind(this, function(){
                this.settings.set_string("time-text", "Z");
            }));
            this.ClockMenuItemText.menu.addMenuItem(PopupMenuItemZ);
            this.menu.addMenuItem(this.ClockMenuItemText);

            this.ClockMenuItemDate = new PopupMenu.PopupSwitchMenuItem(
                "Show date",
                this.settings.get_boolean("show-date"),
                { reactive: true }
            );
            this.ClockMenuItemDate.connect(
                "toggled",
                Lang.bind(
                    this, function(object, value) {
                        this.settings.set_boolean("show-date", value);
                    }
                )
            );
            this.menu.addMenuItem(this.ClockMenuItemDate);

            this.ClockMenuItemOpacity = new PopupMenu.PopupSwitchMenuItem(
                "Light opacity",
                this.settings.get_boolean("light-opacity"),
                { reactive: true }
            );
            this.ClockMenuItemOpacity.connect(
                "toggled",
                Lang.bind(
                    this, function(object, value) {
                        this.settings.set_boolean("light-opacity", value);
                    }
                )
            );
            this.menu.addMenuItem(this.ClockMenuItemOpacity);
        }

        enable() {
            this.time_text = "UTC";

            this.format_params = {
                hour: "2-digit",
                minute: "2-digit",
                hour12: false
            }

            this.settings = Convenience.getSettings();

            this.signals = [];

            this.clock = new GnomeDesktop.WallClock();
            this.signals[0] = this.clock.connect(
                "notify::clock",
                Lang.bind(this, this.updateTime)
            );

            this.setSecondsDisplayed();
            this.signals[1] = this.settings.connect(
                "changed::show-seconds",
                Lang.bind(this, this.setSecondsDisplayed)
            );

            this.setTimeText();
            this.signals[2] = this.settings.connect(
                "changed::time-text",
                Lang.bind(this, this.setTimeText)
            );

            this.setDateDisplayed();
            this.signals[3] = this.settings.connect(
                "changed::show-date",
                Lang.bind(this, this.setDateDisplayed)
            );

            this.setLightOpacity();
            this.signals[4] = this.settings.connect(
                "changed::light-opacity",
                Lang.bind(this, this.setLightOpacity)
            );

            this.buildMenu();
        }

        disable() {
            this.clock.disconnect(this.signals[0]);
            this.settings.disconnect(this.signals[1]);
            this.settings.disconnect(this.signals[2]);
            this.settings.disconnect(this.signals[3]);
            this.settings.disconnect(this.signals[4]);
        }
    }
);

let utcclock;

function init() {

}

function enable() {
    utcclock = new UTCClock();
    Main.panel._addToPanelBox("utcclock", utcclock, 1, Main.panel._centerBox);
}

function disable() {
    utcclock.disable();
    utcclock.destroy();
}<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { TAPi18n } from 'meteor/tap:i18n';
import { $ } from 'meteor/jquery';
import { Session } from 'meteor/session';
import { Tracker } from 'meteor/tracker';

import { sendDelegationVotes } from '/imports/startup/both/modules/Contract';
import { displayModal } from '/imports/ui/modules/modal';
import { Vote } from '/imports/ui/modules/Vote';
import { contractReady, purgeBallot, candidateBallot } from '/imports/ui/modules/ballot';
import { clearPopups } from '/imports/ui/modules/popup';

import './power.html';
import '../action/action.js';

/**
* @summary converts a percentage value to pixels for current power bar
* @param {number} percentage percentage value to be converted
* @param {string} voteId where to store the vote
* @return {number} pixels
*/
function percentageToPixel(percentage, voteId) {
  return parseInt(((percentage * $(`#voteBar-${voteId}`).width()) / 100), 10);
}

/**
* @summary given absolute value returns relative pixel width
* @param {number} value nominal votes to pixel width
* @param {object} bar the item being rendered
* @param {string} voteId session var containing vote info
* @param {boolean} interactive return value from slider
*/
function getBarWidth(value, voteId, editable, interactive) {
  if (editable) {
    const wallet = Session.get(voteId);
    if (wallet !== undefined) {
      const percentage = parseFloat((value * 100) / wallet.balance, 10).toFixed(2);
      if (value === 0) {
        return '0px';
      } else if (interactive) {
        return `${parseInt(wallet.sliderWidth, 10)}px`;
      }
      return `${percentageToPixel(percentage, voteId)}px`;
    }
  }
  // profile, only logged user
  const wallet = Meteor.user().profile.wallet;
  return `${percentageToPixel(parseFloat((value * 100) / wallet.balance, 10).toFixed(2), voteId)}px`;
}

/**
* @summary decides what to display in liquid bar as counterparty value
* @param {string} voteId vote controller for gui
* @param {boolean} editable if its an editable liquid vote
*/
function agreement(voteId, editable) {
  if (Session.get(voteId).voteType === 'BALANCE') {
    return getBarWidth(Session.get(voteId).placed, voteId, true);
  }
  return getBarWidth(parseFloat((Session.get(voteId).placed - Session.get(voteId).inBallot) + Session.get(voteId).delegated, 10), voteId, editable);
}

Template.power.onCreated(function () {
  const wallet = new Vote(this.data.wallet, this.data.targetId, this.data._id);
  Session.set(this.data._id, wallet);
});

Template.power.onRendered(function render() {
  if (!Meteor.user()) {
    return;
  }

  const wallet = new Vote(this.data.wallet, this.data.targetId, this.data._id);
  Session.set(this.data._id, wallet);

  // real time update
  Tracker.autorun(() => {
    if (this.data.sourceId === Meteor.userId()) {
      const newWallet = new Vote(Meteor.user().profile.wallet, this.data.targetId, this.data._id);
      newWallet.resetSlider();
      Session.set(this.data._id, newWallet);
    }
  });

  // redraw power bar if resize
  $(`#voteBar-${this.data._id}`).resize(function () {
    const voteId = this.id.replace('voteBar-', '');
    $(`#voteSlider-${voteId}`).width(getBarWidth(Session.get(voteId).inBallot, voteId, true));
    $(`#votePlaced-${voteId}`).width(agreement(voteId, true));
  });
  if (this.data.editable) {
    // drag event
    $(`#voteHandle-${this.data._id}`).draggable({
      axis: 'x',
      create() {
        const voteId = this.id.replace('voteHandle-', '');
        this.newVote = new Vote(Session.get(voteId), Session.get(voteId).targetId, voteId);
        Session.set(voteId, this.newVote);
      },
      start(event, ui) {
        const voteId = ui.helper.context.id.replace('voteHandle-', '');
        this.newVote = new Vote(Session.get(voteId), Session.get(voteId).targetId, voteId);
        Session.set(voteId, this.newVote);
        if (Session.get(voteId) !== undefined) {
          $(`#voteSlider-${voteId}`).velocity('stop');
        }
        if (Session.get('candidateBallot') === undefined) {
          candidateBallot(Meteor.userId());
        }
        Session.set('dragging', voteId);
      },
      drag(event, ui) {
        const voteId = ui.helper.context.id.replace('voteHandle-', '');
        this.newVote.sliderInput(ui.position.left);
        Session.set(voteId, this.newVote);
        ui.position.left = 0;
      },
      stop(event, ui) {
        // executes the vote
        const voteId = ui.helper.context.id.replace('voteHandle-', '');

        const cancel = () => {
          if (this.newVote.inBallot === 0 && this.newVote.voteType === 'VOTE') {
            Session.set('candidateBallot', undefined);
          }
          Session.set('dragging', false);
          this.newVote.resetSlider();
          Session.set(voteId, this.newVote);
        };

        if ((this.newVote.allocateQuantity === 0 && this.newVote.inBallot === 0) || (this.newVote.voteType === 'VOTE' && purgeBallot(Session.get('candidateBallot')).length === 0)) {
          cancel();
          if (this.newVote.voteType === 'VOTE') {
            Session.set('noSelectedOption', true);
          }
        } else if (contractReady(this.newVote) || this.newVote.voteType === 'DELEGATION') {
          clearPopups();

          // democracy wins
          this.newVote.execute(cancel);
        }
      },
    });
  }
});

Template.power.helpers({
  isDelegation() {
    return (Session.get(this._id).voteType === 'DELEGATION');
  },
  rightToVote() {
    return Session.get('rightToVote');
  },
  confirmationRequired() {
    if (Session.get('contract').kind === 'DELEGATION') {
      const signatures = Session.get('contract').signatures;
      for (const i in signatures) {
        if (signatures[i].role === 'DELEGATE' && signatures[i].status === 'PENDING' && signatures[i]._id === Meteor.user()._id) {
          return true;
        }
      }
    }
    return false;
  },
});

Template.power.events({
  'click #confirmation'() {
    let counterPartyId;
    for (const stamp in Session.get('contract').signatures) {
      if (Session.get('contract').signatures[stamp]._id !== Meteor.user()._id) {
        counterPartyId = Session.get('contract').signatures[stamp]._id;
      }
    }
    displayModal(
      true,
      {
        icon: 'images/modal-delegation.png',
        title: TAPi18n.__('confirm-delegation-votes'),
        message: TAPi18n.__('confirm-delegation-warning').replace('<quantity>', Session.get('contract').wallet.available),
        cancel: TAPi18n.__('not-now'),
        action: TAPi18n.__('confirm-votes'),
        displayProfile: true,
        profileId: counterPartyId,
      },
      function () {
        const settings = {
          condition: {
            transferable: Session.get('contract').transferable,
            portable: Session.get('contract').portable,
            tags: Session.get('contract').tags,
          },
          currency: 'VOTES',
          kind: Session.get('contract').kind,
          contractId: Session.get('contract')._id, // _getContractId(senderId, receiverId, settings.kind),
        };
        sendDelegationVotes(
          Session.get('contract')._id,
          Session.get('contract').signatures[1]._id,
          Session.get('contract').wallet.available,
          settings,
          'CONFIRMED'
        );
      }
    );
  },
  'click #rejection'() {
    let counterPartyId;
    for (const stamp in Session.get('contract').signatures) {
      if (Session.get('contract').signatures[stamp]._id !== Meteor.user()._id) {
        counterPartyId = Session.get('contract').signatures[stamp]._id;
      }
    }
    displayModal(
      true,
      {
        icon: 'images/modal-delegation.png',
        title: TAPi18n.__('reject-delegation-votes'),
        message: TAPi18n.__('reject-delegation-warning').replace('<quantity>', Session.get('contract').wallet.available),
        cancel: TAPi18n.__('not-now'),
        action: TAPi18n.__('reject-votes'),
        displayProfile: true,
        profileId: counterPartyId,
      },
      function () {
        const settings = {
          condition: {
            transferable: Session.get('contract').transferable,
            portable: Session.get('contract').portable,
            tags: Session.get('contract').tags,
          },
          currency: 'VOTES',
          kind: Session.get('contract').kind,
          contractId: Session.get('contract')._id, // _getContractId(senderId, receiverId, settings.kind),
        };
        sendDelegationVotes(
          Session.get('contract')._id,
          Session.get('contract').signatures[0]._id,
          Session.get('contract').wallet.available,
          settings,
          'REJECTED'
        );
      }
    );
  },
});

Template.capital.helpers({
  getVotes(value) {
    let label;
    const inBallot = Session.get(this._id).inBallot;
    if (Session.get(this._id) !== undefined) {
      switch (value) {
        case 'available': {
          if (inBallot === 0) {
            let available;
            if (Session.get(this._id).voteType === 'BALANCE') {
              available = Session.get(this._id).available;
              if (available === 0) { available = TAPi18n.__('none'); }
            } else {
              available = parseInt((Session.get(this._id).available + Session.get(this._id).inBallot) - Session.get(this._id).allocateQuantity, 10);
            }
            if (Session.get(this._id).allocateQuantity > 0 && (available <= 0)) {
              label = `<strong>${TAPi18n.__('none')}</strong> ${TAPi18n.__('available-votes')}`;
            } else {
              label = `<strong>${available.toLocaleString()}</strong> ${TAPi18n.__('available-votes')}`;
            }
          }
          break;
        }
        case 'inBallot':
          if (Session.get(this._id).voteType === 'DELEGATION') {
            if (inBallot === 0) {
              label = `<strong>${TAPi18n.__('no')}</strong> ${TAPi18n.__('sent-votes')}`;
            } else {
              label = `<strong>${inBallot.toLocaleString()}</strong> ${TAPi18n.__('sent-votes')}`;
            }
          } else if (inBallot === 0) {
            label = `<strong>${TAPi18n.__('none')}</strong> ${TAPi18n.__('on-this-ballot')}`;
          } else if (Session.get(this._id).voteType === 'BALANCE') {
            label = `<strong>${inBallot.toLocaleString()}</strong> ${TAPi18n.__('available-votes')}`;
          } else {
            label = `<strong>${inBallot.toLocaleString()}</strong> ${TAPi18n.__('on-this-ballot')}`;
          }
          break;
        case 'allocateQuantity': {
          const quantity = parseInt(Session.get(this._id)[value] - inBallot, 10);
          if (Math.abs(quantity) === inBallot && (quantity < 0)) {
            label = TAPi18n.__('remove-all-votes');
          } else if (Session.get(this._id).voteType === 'DELEGATION') {
            label = `<strong>${Math.abs(inBallot + quantity).toLocaleString()}</strong> ${TAPi18n.__('votes-to-delegate')}`;
          } else {
            label = `<strong>${Math.abs(inBallot + quantity).toLocaleString()}</strong> ${TAPi18n.__('place-in-ballot')}`;
          }
          break;
        }
        case 'received':
          label = `<strong>${Session.get(this._id).delegated.toLocaleString()}</strong> ${TAPi18n.__('received-votes')}`;
          break;
        case 'placed':
        default:
          if (Meteor.user().profile.wallet.placed === 0) {
            label = `<strong>${TAPi18n.__('none')}</strong>  ${TAPi18n.__('placed-votes')}`;
          } else if (Session.get(this._id).voteType === 'BALANCE') {
            label = `<strong>${Meteor.user().profile.wallet.placed.toLocaleString()}</strong>  ${TAPi18n.__('placed')}`;
          } else {
            label = `<strong>${parseInt(Meteor.user().profile.wallet.placed - inBallot, 10).toLocaleString()}</strong>  ${TAPi18n.__('placed-votes')}`;
          }
          break;
      }
    }
    return label;
  },
  style(value) {
    const inBallot = Session.get(this._id).inBallot;
    switch (value) {
      case 'available': {
        if (inBallot === 0 && (Session.get('dragging') === false || Session.get('dragging') === undefined || Session.get('dragging') !== this._id)) {
          const available = parseInt((Session.get(this._id).available + Session.get(this._id).inBallot) - Session.get(this._id).allocateQuantity, 10);
          if (Session.get(this._id).allocateQuantity > 0 && (available <= 0)) {
            return 'stage-finish-rejected';
          }
          return 'stage-inballot';
        }
        return 'hide';
      }
      case 'inBallot':
        if (Session.get('dragging') === false || Session.get('dragging') === undefined || Session.get('dragging') !== this._id) {
          if (inBallot === 0) {
            if (Session.get(this._id).voteType === 'DELEGATION') {
              return 'stage-placed';
            }
            return 'hide';
          }
          return 'stage-finish-approved';
        }
        return 'hide';
      case 'allocateQuantity': {
        const quantity = parseInt(Session.get(this._id)[value] - inBallot, 10);
        if (Session.get('dragging') === this._id) {
          if (Math.abs(quantity) === inBallot && (quantity < 0)) {
            return 'stage-finish-rejected';
          }
          return 'stage-live';
        }
        return 'hide';
      }
      case 'placed':
        return 'stage-placed';
      case 'received':
        if (Session.get(this._id).delegated === 0) {
          return 'hide';
        }
        return 'stage-delegated';
      default:
        return 'stage-finish-alternative';
    }
  },
  negativeAllocation() {
    return (Session.get(this._id).inBallot > Session.get(this._id).allocateQuantity);
  },
});

Template.bar.helpers({
  available() {
    return getBarWidth(Session.get(this._id).available, this._id, this.editable, true);
  },
  placed() {
    return agreement(this._id, this.editable);
  },
  unanimous(value) {
    if (Session.get(this._id)[value] === Session.get(this._id).balance) {
      return 'unanimous';
    }
    return '';
  },
  isDelegation() {
    if (Session.get(this._id).delegated > 0) {
      return 'vote-bar-delegated';
    }
    return '';
  },
});
<commit_msg>avoids ghost refresh of fork tick while dragging liquid<commit_after>import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { TAPi18n } from 'meteor/tap:i18n';
import { $ } from 'meteor/jquery';
import { Session } from 'meteor/session';
import { Tracker } from 'meteor/tracker';

import { sendDelegationVotes } from '/imports/startup/both/modules/Contract';
import { displayModal } from '/imports/ui/modules/modal';
import { Vote } from '/imports/ui/modules/Vote';
import { contractReady, purgeBallot, candidateBallot } from '/imports/ui/modules/ballot';
import { clearPopups } from '/imports/ui/modules/popup';

import './power.html';
import '../action/action.js';

/**
* @summary converts a percentage value to pixels for current power bar
* @param {number} percentage percentage value to be converted
* @param {string} voteId where to store the vote
* @return {number} pixels
*/
function percentageToPixel(percentage, voteId) {
  return parseInt(((percentage * $(`#voteBar-${voteId}`).width()) / 100), 10);
}

/**
* @summary given absolute value returns relative pixel width
* @param {number} value nominal votes to pixel width
* @param {object} bar the item being rendered
* @param {string} voteId session var containing vote info
* @param {boolean} interactive return value from slider
*/
function getBarWidth(value, voteId, editable, interactive) {
  if (editable) {
    const wallet = Session.get(voteId);
    if (wallet !== undefined) {
      const percentage = parseFloat((value * 100) / wallet.balance, 10).toFixed(2);
      if (value === 0) {
        return '0px';
      } else if (interactive) {
        return `${parseInt(wallet.sliderWidth, 10)}px`;
      }
      return `${percentageToPixel(percentage, voteId)}px`;
    }
  }
  // profile, only logged user
  const wallet = Meteor.user().profile.wallet;
  return `${percentageToPixel(parseFloat((value * 100) / wallet.balance, 10).toFixed(2), voteId)}px`;
}

/**
* @summary decides what to display in liquid bar as counterparty value
* @param {string} voteId vote controller for gui
* @param {boolean} editable if its an editable liquid vote
*/
function agreement(voteId, editable) {
  if (Session.get(voteId).voteType === 'BALANCE') {
    return getBarWidth(Session.get(voteId).placed, voteId, true);
  }
  return getBarWidth(parseFloat((Session.get(voteId).placed - Session.get(voteId).inBallot) + Session.get(voteId).delegated, 10), voteId, editable);
}

Template.power.onCreated(function () {
  const wallet = new Vote(this.data.wallet, this.data.targetId, this.data._id);
  Session.set(this.data._id, wallet);
});

Template.power.onRendered(function render() {
  if (!Meteor.user()) {
    return;
  }

  const wallet = new Vote(this.data.wallet, this.data.targetId, this.data._id);
  Session.set(this.data._id, wallet);

  // real time update
  Tracker.autorun(() => {
    if (this.data.sourceId === Meteor.userId()) {
      const newWallet = new Vote(Meteor.user().profile.wallet, this.data.targetId, this.data._id);
      newWallet.resetSlider();
      Session.set(this.data._id, newWallet);
    }
  });

  // redraw power bar if resize
  $(`#voteBar-${this.data._id}`).resize(function () {
    const voteId = this.id.replace('voteBar-', '');
    $(`#voteSlider-${voteId}`).width(getBarWidth(Session.get(voteId).inBallot, voteId, true));
    $(`#votePlaced-${voteId}`).width(agreement(voteId, true));
  });
  if (this.data.editable) {
    // drag event
    $(`#voteHandle-${this.data._id}`).draggable({
      axis: 'x',
      create() {
        const voteId = this.id.replace('voteHandle-', '');
        this.newVote = new Vote(Session.get(voteId), Session.get(voteId).targetId, voteId);
        Session.set(voteId, this.newVote);
      },
      start(event, ui) {
        const voteId = ui.helper.context.id.replace('voteHandle-', '');
        this.newVote = new Vote(Session.get(voteId), Session.get(voteId).targetId, voteId);
        Session.set(voteId, this.newVote);
        if (Session.get(voteId) !== undefined) {
          $(`#voteSlider-${voteId}`).velocity('stop');
        }
        if (Session.get('candidateBallot') === undefined && this.newVote.voteType === 'VOTE') {
          if (this.newVote.inBallot > 0) {
            candidateBallot(Meteor.userId());
          }
        }
        Session.set('dragging', voteId);
      },
      drag(event, ui) {
        const voteId = ui.helper.context.id.replace('voteHandle-', '');
        this.newVote.sliderInput(ui.position.left);
        Session.set(voteId, this.newVote);
        ui.position.left = 0;
      },
      stop(event, ui) {
        // executes the vote
        const voteId = ui.helper.context.id.replace('voteHandle-', '');

        const cancel = () => {
          if (this.newVote.inBallot === 0 && this.newVote.voteType === 'VOTE') {
            Session.set('candidateBallot', undefined);
          }
          Session.set('dragging', false);
          this.newVote.resetSlider();
          Session.set(voteId, this.newVote);
        };

        if ((this.newVote.allocateQuantity === 0 && this.newVote.inBallot === 0) || (this.newVote.voteType === 'VOTE' && purgeBallot(Session.get('candidateBallot')).length === 0)) {
          cancel();
          if (this.newVote.voteType === 'VOTE') {
            Session.set('noSelectedOption', true);
          }
        } else if (contractReady(this.newVote) || this.newVote.voteType === 'DELEGATION') {
          clearPopups();

          // democracy wins
          this.newVote.execute(cancel);
        }
      },
    });
  }
});

Template.power.helpers({
  isDelegation() {
    return (Session.get(this._id).voteType === 'DELEGATION');
  },
  rightToVote() {
    return Session.get('rightToVote');
  },
  confirmationRequired() {
    if (Session.get('contract').kind === 'DELEGATION') {
      const signatures = Session.get('contract').signatures;
      for (const i in signatures) {
        if (signatures[i].role === 'DELEGATE' && signatures[i].status === 'PENDING' && signatures[i]._id === Meteor.user()._id) {
          return true;
        }
      }
    }
    return false;
  },
});

Template.power.events({
  'click #confirmation'() {
    let counterPartyId;
    for (const stamp in Session.get('contract').signatures) {
      if (Session.get('contract').signatures[stamp]._id !== Meteor.user()._id) {
        counterPartyId = Session.get('contract').signatures[stamp]._id;
      }
    }
    displayModal(
      true,
      {
        icon: 'images/modal-delegation.png',
        title: TAPi18n.__('confirm-delegation-votes'),
        message: TAPi18n.__('confirm-delegation-warning').replace('<quantity>', Session.get('contract').wallet.available),
        cancel: TAPi18n.__('not-now'),
        action: TAPi18n.__('confirm-votes'),
        displayProfile: true,
        profileId: counterPartyId,
      },
      function () {
        const settings = {
          condition: {
            transferable: Session.get('contract').transferable,
            portable: Session.get('contract').portable,
            tags: Session.get('contract').tags,
          },
          currency: 'VOTES',
          kind: Session.get('contract').kind,
          contractId: Session.get('contract')._id, // _getContractId(senderId, receiverId, settings.kind),
        };
        sendDelegationVotes(
          Session.get('contract')._id,
          Session.get('contract').signatures[1]._id,
          Session.get('contract').wallet.available,
          settings,
          'CONFIRMED'
        );
      }
    );
  },
  'click #rejection'() {
    let counterPartyId;
    for (const stamp in Session.get('contract').signatures) {
      if (Session.get('contract').signatures[stamp]._id !== Meteor.user()._id) {
        counterPartyId = Session.get('contract').signatures[stamp]._id;
      }
    }
    displayModal(
      true,
      {
        icon: 'images/modal-delegation.png',
        title: TAPi18n.__('reject-delegation-votes'),
        message: TAPi18n.__('reject-delegation-warning').replace('<quantity>', Session.get('contract').wallet.available),
        cancel: TAPi18n.__('not-now'),
        action: TAPi18n.__('reject-votes'),
        displayProfile: true,
        profileId: counterPartyId,
      },
      function () {
        const settings = {
          condition: {
            transferable: Session.get('contract').transferable,
            portable: Session.get('contract').portable,
            tags: Session.get('contract').tags,
          },
          currency: 'VOTES',
          kind: Session.get('contract').kind,
          contractId: Session.get('contract')._id, // _getContractId(senderId, receiverId, settings.kind),
        };
        sendDelegationVotes(
          Session.get('contract')._id,
          Session.get('contract').signatures[0]._id,
          Session.get('contract').wallet.available,
          settings,
          'REJECTED'
        );
      }
    );
  },
});

Template.capital.helpers({
  getVotes(value) {
    let label;
    const inBallot = Session.get(this._id).inBallot;
    if (Session.get(this._id) !== undefined) {
      switch (value) {
        case 'available': {
          if (inBallot === 0) {
            let available;
            if (Session.get(this._id).voteType === 'BALANCE') {
              available = Session.get(this._id).available;
              if (available === 0) { available = TAPi18n.__('none'); }
            } else {
              available = parseInt((Session.get(this._id).available + Session.get(this._id).inBallot) - Session.get(this._id).allocateQuantity, 10);
            }
            if (Session.get(this._id).allocateQuantity > 0 && (available <= 0)) {
              label = `<strong>${TAPi18n.__('none')}</strong> ${TAPi18n.__('available-votes')}`;
            } else {
              label = `<strong>${available.toLocaleString()}</strong> ${TAPi18n.__('available-votes')}`;
            }
          }
          break;
        }
        case 'inBallot':
          if (Session.get(this._id).voteType === 'DELEGATION') {
            if (inBallot === 0) {
              label = `<strong>${TAPi18n.__('no')}</strong> ${TAPi18n.__('sent-votes')}`;
            } else {
              label = `<strong>${inBallot.toLocaleString()}</strong> ${TAPi18n.__('sent-votes')}`;
            }
          } else if (inBallot === 0) {
            label = `<strong>${TAPi18n.__('none')}</strong> ${TAPi18n.__('on-this-ballot')}`;
          } else if (Session.get(this._id).voteType === 'BALANCE') {
            label = `<strong>${inBallot.toLocaleString()}</strong> ${TAPi18n.__('available-votes')}`;
          } else {
            label = `<strong>${inBallot.toLocaleString()}</strong> ${TAPi18n.__('on-this-ballot')}`;
          }
          break;
        case 'allocateQuantity': {
          const quantity = parseInt(Session.get(this._id)[value] - inBallot, 10);
          if (Math.abs(quantity) === inBallot && (quantity < 0)) {
            label = TAPi18n.__('remove-all-votes');
          } else if (Session.get(this._id).voteType === 'DELEGATION') {
            label = `<strong>${Math.abs(inBallot + quantity).toLocaleString()}</strong> ${TAPi18n.__('votes-to-delegate')}`;
          } else {
            label = `<strong>${Math.abs(inBallot + quantity).toLocaleString()}</strong> ${TAPi18n.__('place-in-ballot')}`;
          }
          break;
        }
        case 'received':
          label = `<strong>${Session.get(this._id).delegated.toLocaleString()}</strong> ${TAPi18n.__('received-votes')}`;
          break;
        case 'placed':
        default:
          if (Meteor.user().profile.wallet.placed === 0) {
            label = `<strong>${TAPi18n.__('none')}</strong>  ${TAPi18n.__('placed-votes')}`;
          } else if (Session.get(this._id).voteType === 'BALANCE') {
            label = `<strong>${Meteor.user().profile.wallet.placed.toLocaleString()}</strong>  ${TAPi18n.__('placed')}`;
          } else {
            label = `<strong>${parseInt(Meteor.user().profile.wallet.placed - inBallot, 10).toLocaleString()}</strong>  ${TAPi18n.__('placed-votes')}`;
          }
          break;
      }
    }
    return label;
  },
  style(value) {
    const inBallot = Session.get(this._id).inBallot;
    switch (value) {
      case 'available': {
        if (inBallot === 0 && (Session.get('dragging') === false || Session.get('dragging') === undefined || Session.get('dragging') !== this._id)) {
          const available = parseInt((Session.get(this._id).available + Session.get(this._id).inBallot) - Session.get(this._id).allocateQuantity, 10);
          if (Session.get(this._id).allocateQuantity > 0 && (available <= 0)) {
            return 'stage-finish-rejected';
          }
          return 'stage-inballot';
        }
        return 'hide';
      }
      case 'inBallot':
        if (Session.get('dragging') === false || Session.get('dragging') === undefined || Session.get('dragging') !== this._id) {
          if (inBallot === 0) {
            if (Session.get(this._id).voteType === 'DELEGATION') {
              return 'stage-placed';
            }
            return 'hide';
          }
          return 'stage-finish-approved';
        }
        return 'hide';
      case 'allocateQuantity': {
        const quantity = parseInt(Session.get(this._id)[value] - inBallot, 10);
        if (Session.get('dragging') === this._id) {
          if (Math.abs(quantity) === inBallot && (quantity < 0)) {
            return 'stage-finish-rejected';
          }
          return 'stage-live';
        }
        return 'hide';
      }
      case 'placed':
        return 'stage-placed';
      case 'received':
        if (Session.get(this._id).delegated === 0) {
          return 'hide';
        }
        return 'stage-delegated';
      default:
        return 'stage-finish-alternative';
    }
  },
  negativeAllocation() {
    return (Session.get(this._id).inBallot > Session.get(this._id).allocateQuantity);
  },
});

Template.bar.helpers({
  available() {
    return getBarWidth(Session.get(this._id).available, this._id, this.editable, true);
  },
  placed() {
    return agreement(this._id, this.editable);
  },
  unanimous(value) {
    if (Session.get(this._id)[value] === Session.get(this._id).balance) {
      return 'unanimous';
    }
    return '';
  },
  isDelegation() {
    if (Session.get(this._id).delegated > 0) {
      return 'vote-bar-delegated';
    }
    return '';
  },
});
<|endoftext|>