<commit_before>import React, { Component } from 'react'
import update from 'immutability-helper'
import _ from 'lodash'
import './App.css'

import Button from './components/Button'
import Tickets from './components/Tickets'
import TicketForm from './components/TicketForm'
import StripeCheckout from './components/StripeCheckout'

// Production Picatic API host
// const host = 'https://api.picatic.com/v2'

// Picatic API Staging Host
const host = 'https://api-staging.picatic.com/v2'

class App extends Component {
  state = {
    event: null,
    tickets: [],
    checkoutObj: null,
    formSubmitted: false,
    selectedTickets: [],
    checkoutStatus: null,
  }

  componentWillMount = () => {
    const paramsId = this.props.match.params.id
    const hasParamsId = paramsId !== undefined

    // TODO: Replace with your event id
    let eventSlug = 74701

    eventSlug = hasParamsId ? paramsId : eventSlug

    this.getEvent(eventSlug)
  }

  /**
   * getEvent() gets information about an event.
   *
   * Example endpoint:
   * https://api.picatic.com/v2/event/74701
   *
   * API Doc Reference:
   * http://developer.picatic.com/v2/api/#methods-event-read
   */
  getEvent = eventSlug => {
    const url = `${host}/event/${eventSlug}`

    fetch(url, { method: 'GET' })
      .then(res => res.json())
      .then(json => {
        const event = json.data

        this.getStripeKey(event.id)
        this.getTickets(event.id)
        this.setState({ event })
      })
      .catch(err => console.log(err))
  }

  getStripeKey = eventId => {
    const url = `${host}/event?filter[id]=${eventId}&page[limit]=10&page[offset]=0&include=event_owner`

    fetch(url, { method: 'GET' })
      .then(res => res.json())
      .then(event =>
        this.setState({
          stripeKey: event.included[0].attributes.stripe_publishable_key
        })
      )
      .catch(err => console.log(err))
  }

  /**
   * getTickets() sets an array of tickets to state.
   * The array of tickets are filtered by a particular event
   *
   * Example endpoint:
   * https://api.picatic.com/v2/ticket_price?filter[event_id]=49366&page[limit]=10&page[offset]=0
   *
   * API Doc Reference:
   * http://developer.picatic.com/v2/api/#methods-ticketprice-find
   */
  getTickets = eventId => {
    const url = `${host}/ticket_price?filter[event_id]=${eventId}&page[limit]=10&page[offset]=0`

    fetch(url, { method: 'GET' })
      .then(res => res.json())
      .then(response => this.setState({ tickets: response.data }))
      .catch(err => console.log(err))
  }

  /**
   * createCheckout() creates a checkout order and reserve tickets for an event.
   * Mandatory body fields: event id and ticket id
   *
   * Example endpoint:
   * https://api.picatic.com/v2/checkout
   *
   * API Doc Reference:
   * http://developer.picatic.com/v2/api/#methods-checkout-create
   */
  createCheckout = ticket => {
    const { event, selectedTickets } = this.state
    const url = `${host}/checkout`

    let tickets = []

    // Create array of selected tickets
    selectedTickets.map(ticket => {
      for (let i = 0; i < ticket.quantity; i++) {
        tickets.push({
          ticket_price: { ticket_price_id: Number(ticket.ticket_id) }
        })
      }
      return tickets
    })

    const body = JSON.stringify({
      data: {
        attributes: {
          event_id: Number(event.id),
          tickets
        },
        type: 'checkout'
      }
    })

    fetch(url, {
      method: 'POST',
      body: body
    })
      .then(res => res.json())
      .then(response => this.setState({ checkoutObj: response.data }))
      .catch(err => console.log(err))
  }

  /**
   * updateCheckout() PATCH checkout object with invoice and tickets information
   *
   * Example endpoint:
   * https://api.picatic.com/v2/checkout/:id
   *
   * API Doc Reference:
   * http://developer.picatic.com/v2/api/#methods-checkout-update
   */
  updateCheckout = form => {
    const { checkoutObj } = this.state

    const url = `${host}/checkout/${checkoutObj.id}`

    fetch(url, {
      method: 'PATCH',
      body: JSON.stringify({ data: checkoutObj })
    })
      .then(res => res.json())
      .then(response => this.setState({ checkoutObj: response.data }))
      .catch(err => console.log(err))

    this.setState({ formSubmitted: true })
  }

  /**
   * checkoutPayment() must pass a Stripe card token and the event id.
   *
   * Example endpoint:
   * https://api.picatic.com/v2/checkout/:id/payment
   *
   * API Doc Reference:
   * http://developer.picatic.com/v2/api/#methods-checkout-update
   */
  checkoutPayment = payload => {
    const cardError = payload.error
    if (cardError) {
      return false
    }

    const { event, checkoutObj } = this.state

    const url = `${host}/checkout/${checkoutObj.id}/payment`

    const body = JSON.stringify({
      data: {
        attributes: {
          event_id: Number(event.id),
          payment: {
            source: {
              card_token: payload.token.id
            }
          }
        },
        id: checkoutObj.id,
        type: 'checkout'
      }
    })

    fetch(url, {
      method: 'POST',
      body: body
    })
      .then(res => res.json())
      .then(response => this.confirmCheckout())
      .catch(err => console.log(err))
  }

  /**
   * confirmCheckout() confirm validates and completes a registration/purchase
   * of a checkout.
   * Unconfirmed checkouts expire after 20 minutes
   *
   * Example endpoint:
   * https://api.picatic.com/v2/checkout/:id/confirm
   *
   * API Doc Reference:
   * http://developer.picatic.com/v2/api/#methods-checkout-confirm
   */
  confirmCheckout = () => {
    const { checkoutObj } = this.state

    const url = `${host}/checkout/${checkoutObj.id}/confirm`

    fetch(url, {
      method: 'POST'
    })
      .then(res => res.json())
      .then(response =>
        this.setState({ status: response.data.attributes.status })
      )
      .catch(err => console.log(err))
  }

  updateCheckoutObj = (name, value) => {
    const { checkoutObj } = this.state
    const { invoice, tickets } = checkoutObj.attributes

    const updatedInvoice = update(invoice, {
      $merge: {
        [name]: value
      }
    })

    let updatedTickets = tickets
    tickets.map((ticket, index) => {
      updatedTickets = update(updatedTickets, {
        [index]: {
          $merge: {
            [name]: value
          }
        }
      })
      return tickets
    })

    // Input new invoice and tickets into checkout object
    const newCheckoutObj = update(checkoutObj, {
      attributes: {
        invoice: { $set: updatedInvoice },
        tickets: { $set: updatedTickets }
      }
    })

    this.setState({ checkoutObj: newCheckoutObj })
  }

  selectTickets = (id, quantity) => {
    const { selectedTickets } = this.state

    // Check if ticket has been selected
    const index = _.findIndex(
      selectedTickets,
      selected => selected.ticket_id === id
    )

    const ticketIndex = index === -1 ? selectedTickets.length : index

    // Update quantity of ticket selection
    const updatedSelection = update(selectedTickets, {
      [ticketIndex]: {
        $set: {
          ticket_id: id,
          quantity: quantity
        }
      }
    })

    this.setState({ selectedTickets: updatedSelection })
  }

  render() {
    const {
      event,
      tickets,
      checkoutObj,
      formSubmitted,
      status,
      selectedTickets,
      stripeKey
    } = this.state

    const noEvent = event === null
    if (noEvent) {
      return (

      )
    }

    const cardBackground = {
      background: `linear-gradient(rgba(7,8,38,.28), rgba(7,8,38,.28)), url(${event
        .attributes.cover_image_uri}) no-repeat center center / cover`
    }

    const renderTickets = tickets.map(ticket => (
      <Tickets
        key={ticket.id}
        ticket={ticket}
        selectTickets={this.selectTickets}
      />
    ))

    const hasSelectedTickets = !(
      _.sumBy(selectedTickets, ticket => ticket.quantity) > 0
    )

    let step = null

    const noCheckout = checkoutObj === null
    if (noCheckout) {
      // Step 1: Select Tickets
      step = (

          {renderTickets}
          <Button
            label="Continue"
            handleClick={this.createCheckout}
            disabled={hasSelectedTickets}
          />

      )
    } else if (!formSubmitted) {
      // Step 2: Update personal information
      step = (
        <TicketForm
          updateCheckoutObj={this.updateCheckoutObj}
          handleSubmit={this.updateCheckout}
        />
      )
    } else if (status !== 'completed') {
      // Step 3: Input credit card information
      step = (
        <StripeCheckout
          checkoutPayment={this.checkoutPayment}
          checkoutObj={checkoutObj}
          stripeKey={stripeKey}
        />
      )
    } else {
      // Step 4: Checkout complete
      step = (

          Congratulations on your purchase!

      )
    }

    return (

              {event.attributes.title}

          {step}

    )
  }
}

export default App
<commit_msg>Removed api from initial state<commit_after>import React, { Component } from 'react'
import update from 'immutability-helper'
import _ from 'lodash'
import './App.css'

import Button from './components/Button'
import Tickets from './components/Tickets'
import TicketForm from './components/TicketForm'
import StripeCheckout from './components/StripeCheckout'

// Production Picatic API host
// const host = 'https://api.picatic.com/v2'

// Picatic API Staging Host
const host = 'https://api-staging.picatic.com/v2'

class App extends Component {
  state = {
    event: null,
    tickets: [],
    checkoutObj: null,
    formSubmitted: false,
    selectedTickets: [],
    checkoutStatus: null
  }

  componentWillMount = () => {
    const paramsId = this.props.match.params.id
    const hasParamsId = paramsId !== undefined

    // TODO: Replace with your event id
    let eventSlug = 74701

    eventSlug = hasParamsId ? paramsId : eventSlug

    this.getEvent(eventSlug)
  }

  /**
   * getEvent() gets information about an event.
   *
   * Example endpoint:
   * https://api.picatic.com/v2/event/74701
   *
   * API Doc Reference:
   * http://developer.picatic.com/v2/api/#methods-event-read
   */
  getEvent = eventSlug => {
    const url = `${host}/event/${eventSlug}`

    fetch(url, { method: 'GET' })
      .then(res => res.json())
      .then(json => {
        const event = json.data

        this.getStripeKey(event.id)
        this.getTickets(event.id)
        this.setState({ event })
      })
      .catch(err => console.log(err))
  }

  getStripeKey = eventId => {
    const url = `${host}/event?filter[id]=${eventId}&page[limit]=10&page[offset]=0&include=event_owner`

    fetch(url, { method: 'GET' })
      .then(res => res.json())
      .then(event =>
        this.setState({
          stripeKey: event.included[0].attributes.stripe_publishable_key
        })
      )
      .catch(err => console.log(err))
  }

  /**
   * getTickets() sets an array of tickets to state.
   * The array of tickets are filtered by a particular event
   *
   * Example endpoint:
   * https://api.picatic.com/v2/ticket_price?filter[event_id]=49366&page[limit]=10&page[offset]=0
   *
   * API Doc Reference:
   * http://developer.picatic.com/v2/api/#methods-ticketprice-find
   */
  getTickets = eventId => {
    const url = `${host}/ticket_price?filter[event_id]=${eventId}&page[limit]=10&page[offset]=0`

    fetch(url, { method: 'GET' })
      .then(res => res.json())
      .then(response => this.setState({ tickets: response.data }))
      .catch(err => console.log(err))
  }

  /**
   * createCheckout() creates a checkout order and reserve tickets for an event.
   * Mandatory body fields: event id and ticket id
   *
   * Example endpoint:
   * https://api.picatic.com/v2/checkout
   *
   * API Doc Reference:
   * http://developer.picatic.com/v2/api/#methods-checkout-create
   */
  createCheckout = ticket => {
    const { event, selectedTickets } = this.state
    const url = `${host}/checkout`

    let tickets = []

    // Create array of selected tickets
    selectedTickets.map(ticket => {
      for (let i = 0; i < ticket.quantity; i++) {
        tickets.push({
          ticket_price: { ticket_price_id: Number(ticket.ticket_id) }
        })
      }
      return tickets
    })

    const body = JSON.stringify({
      data: {
        attributes: {
          event_id: Number(event.id),
          tickets
        },
        type: 'checkout'
      }
    })

    fetch(url, {
      method: 'POST',
      body: body
    })
      .then(res => res.json())
      .then(response => this.setState({ checkoutObj: response.data }))
      .catch(err => console.log(err))
  }

  /**
   * updateCheckout() PATCH checkout object with invoice and tickets information
   *
   * Example endpoint:
   * https://api.picatic.com/v2/checkout/:id
   *
   * API Doc Reference:
   * http://developer.picatic.com/v2/api/#methods-checkout-update
   */
  updateCheckout = form => {
    const { checkoutObj } = this.state

    const url = `${host}/checkout/${checkoutObj.id}`

    fetch(url, {
      method: 'PATCH',
      body: JSON.stringify({ data: checkoutObj })
    })
      .then(res => res.json())
      .then(response => this.setState({ checkoutObj: response.data }))
      .catch(err => console.log(err))

    this.setState({ formSubmitted: true })
  }

  /**
   * checkoutPayment() must pass a Stripe card token and the event id.
   *
   * Example endpoint:
   * https://api.picatic.com/v2/checkout/:id/payment
   *
   * API Doc Reference:
   * http://developer.picatic.com/v2/api/#methods-checkout-update
   */
  checkoutPayment = payload => {
    const cardError = payload.error
    if (cardError) {
      return false
    }

    const { event, checkoutObj } = this.state

    const url = `${host}/checkout/${checkoutObj.id}/payment`

    const body = JSON.stringify({
      data: {
        attributes: {
          event_id: Number(event.id),
          payment: {
            source: {
              card_token: payload.token.id
            }
          }
        },
        id: checkoutObj.id,
        type: 'checkout'
      }
    })

    fetch(url, {
      method: 'POST',
      body: body
    })
      .then(res => res.json())
      .then(response => this.confirmCheckout())
      .catch(err => console.log(err))
  }

  /**
   * confirmCheckout() confirm validates and completes a registration/purchase
   * of a checkout.
   * Unconfirmed checkouts expire after 20 minutes
   *
   * Example endpoint:
   * https://api.picatic.com/v2/checkout/:id/confirm
   *
   * API Doc Reference:
   * http://developer.picatic.com/v2/api/#methods-checkout-confirm
   */
  confirmCheckout = () => {
    const { checkoutObj } = this.state

    const url = `${host}/checkout/${checkoutObj.id}/confirm`

    fetch(url, {
      method: 'POST'
    })
      .then(res => res.json())
      .then(response =>
        this.setState({ status: response.data.attributes.status })
      )
      .catch(err => console.log(err))
  }

  updateCheckoutObj = (name, value) => {
    const { checkoutObj } = this.state
    const { invoice, tickets } = checkoutObj.attributes

    const updatedInvoice = update(invoice, {
      $merge: {
        [name]: value
      }
    })

    let updatedTickets = tickets
    tickets.map((ticket, index) => {
      updatedTickets = update(updatedTickets, {
        [index]: {
          $merge: {
            [name]: value
          }
        }
      })
      return tickets
    })

    // Input new invoice and tickets into checkout object
    const newCheckoutObj = update(checkoutObj, {
      attributes: {
        invoice: { $set: updatedInvoice },
        tickets: { $set: updatedTickets }
      }
    })

    this.setState({ checkoutObj: newCheckoutObj })
  }

  selectTickets = (id, quantity) => {
    const { selectedTickets } = this.state

    // Check if ticket has been selected
    const index = _.findIndex(
      selectedTickets,
      selected => selected.ticket_id === id
    )

    const ticketIndex = index === -1 ? selectedTickets.length : index

    // Update quantity of ticket selection
    const updatedSelection = update(selectedTickets, {
      [ticketIndex]: {
        $set: {
          ticket_id: id,
          quantity: quantity
        }
      }
    })

    this.setState({ selectedTickets: updatedSelection })
  }

  render() {
    const {
      event,
      tickets,
      checkoutObj,
      formSubmitted,
      status,
      selectedTickets,
      stripeKey
    } = this.state

    const noEvent = event === null
    if (noEvent) {
      return (

      )
    }

    const cardBackground = {
      background: `linear-gradient(rgba(7,8,38,.28), rgba(7,8,38,.28)), url(${event
        .attributes.cover_image_uri}) no-repeat center center / cover`
    }

    const renderTickets = tickets.map(ticket => (
      <Tickets
        key={ticket.id}
        ticket={ticket}
        selectTickets={this.selectTickets}
      />
    ))

    const hasSelectedTickets = !(
      _.sumBy(selectedTickets, ticket => ticket.quantity) > 0
    )

    let step = null

    const noCheckout = checkoutObj === null
    if (noCheckout) {
      // Step 1: Select Tickets
      step = (

          {renderTickets}
          <Button
            label="Continue"
            handleClick={this.createCheckout}
            disabled={hasSelectedTickets}
          />

      )
    } else if (!formSubmitted) {
      // Step 2: Update personal information
      step = (
        <TicketForm
          updateCheckoutObj={this.updateCheckoutObj}
          handleSubmit={this.updateCheckout}
        />
      )
    } else if (status !== 'completed') {
      // Step 3: Input credit card information
      step = (
        <StripeCheckout
          checkoutPayment={this.checkoutPayment}
          checkoutObj={checkoutObj}
          stripeKey={stripeKey}
        />
      )
    } else {
      // Step 4: Checkout complete
      step = (

          Congratulations on your purchase!

      )
    }

    return (

              {event.attributes.title}

          {step}

    )
  }
}

export default App
<|endoftext|>


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

/**
 * @fileoverview A slider implementation that allows to select a value within a
 * range by dragging a thumb. The selected value is exposed through getValue().
 *
 * To decorate, the slider should be bound to an element with the class name
 * 'goog-slider' containing a child with the class name 'goog-slider-thumb',
 * whose position is set to relative.
 * Note that you won't be able to see these elements unless they are styled.
 *
 * Slider orientation is horizontal by default.
 * Use setOrientation(goog.ui.Slider.Orientation.VERTICAL) for a vertical
 * slider.
 *
 * Decorate Example:
 *

 *

 *

 *
 * JavaScript code:
 *
 *   var slider = new goog.ui.Slider;
 *   slider.decorate(document.getElementById('slider'));
 *
 *
 * @author arv@google.com (Erik Arvidsson)
 * @see ../demos/slider.html
 */

// Implementation note: We implement slider by inheriting from baseslider,
// which allows to select sub-ranges within a range using two thumbs. All we do
// is we co-locate the two thumbs into one.

goog.provide('goog.ui.Slider');
goog.provide('goog.ui.Slider.Orientation');

goog.require('goog.a11y.aria');
goog.require('goog.a11y.aria.Role');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.ui.SliderBase');

/**
 * This creates a slider object.
 * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper.
 * @param {(function(number):?string)=} opt_labelFn An optional function mapping
 *     slider values to a description of the value.
 * @constructor
 * @extends {goog.ui.SliderBase}
 */
goog.ui.Slider = function(opt_domHelper, opt_labelFn) {
  goog.ui.SliderBase.call(this, opt_domHelper, opt_labelFn);
  this.rangeModel.setExtent(0);
};
goog.inherits(goog.ui.Slider, goog.ui.SliderBase);
goog.tagUnsealableClass(goog.ui.Slider);

/**
 * Expose Enum of superclass (representing the orientation of the slider) within
 * Slider namespace.
 *
 * @enum {string}
 */
goog.ui.Slider.Orientation = goog.ui.SliderBase.Orientation;

/**
 * The prefix we use for the CSS class names for the slider and its elements.
 * @type {string}
 */
goog.ui.Slider.CSS_CLASS_PREFIX = goog.getCssName('goog-slider');

/**
 * CSS class name for the single thumb element.
 * @type {string}
 */
goog.ui.Slider.THUMB_CSS_CLASS =
    goog.getCssName(goog.ui.Slider.CSS_CLASS_PREFIX, 'thumb');

/**
 * Returns CSS class applied to the slider element.
 * @param {goog.ui.SliderBase.Orientation} orient Orientation of the slider.
 * @return {string} The CSS class applied to the slider element.
 * @protected
 * @override
 */
goog.ui.Slider.prototype.getCssClass = function(orient) {
  return orient == goog.ui.SliderBase.Orientation.VERTICAL ?
      goog.getCssName(goog.ui.Slider.CSS_CLASS_PREFIX, 'vertical') :
      goog.getCssName(goog.ui.Slider.CSS_CLASS_PREFIX, 'horizontal');
};

/** @override */
goog.ui.Slider.prototype.createThumbs = function() {
  // find thumb
  var element = this.getElement();
  var thumb = goog.dom.getElementsByTagNameAndClass(
      null, goog.ui.Slider.THUMB_CSS_CLASS, element)[0];
  if (!thumb) {
    thumb = this.createThumb_();
    element.appendChild(thumb);
  }
  this.valueThumb = this.extentThumb = /** @type {!HTMLDivElement} */ (thumb);
};

/**
 * Creates the thumb element.
 * @return {!HTMLDivElement} The created thumb element.
 * @private
 */
goog.ui.Slider.prototype.createThumb_ = function() {
  var thumb = this.getDomHelper().createDom(
      goog.dom.TagName.DIV, goog.ui.Slider.THUMB_CSS_CLASS);
  goog.a11y.aria.setRole(thumb, goog.a11y.aria.Role.BUTTON);
  return /** @type {!HTMLDivElement} */ (thumb);
};
<commit_msg>Update the closure slider to have a getThumbCssClass, similar to getCssClass protected method. This allows implementations of this class to have more control over the CSS structure.<commit_after>// Copyright 2006 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview A slider implementation that allows to select a value within a
 * range by dragging a thumb. The selected value is exposed through getValue().
 *
 * To decorate, the slider should be bound to an element with the class name
 * 'goog-slider' containing a child with the class name 'goog-slider-thumb',
 * whose position is set to relative.
 * Note that you won't be able to see these elements unless they are styled.
 *
 * Slider orientation is horizontal by default.
 * Use setOrientation(goog.ui.Slider.Orientation.VERTICAL) for a vertical
 * slider.
 *
 * Decorate Example:
 *

 *

 *

 *
 * JavaScript code:
 *
 *   var slider = new goog.ui.Slider;
 *   slider.decorate(document.getElementById('slider'));
 *
 *
 * @author arv@google.com (Erik Arvidsson)
 * @see ../demos/slider.html
 */

// Implementation note: We implement slider by inheriting from baseslider,
// which allows to select sub-ranges within a range using two thumbs. All we do
// is we co-locate the two thumbs into one.

goog.provide('goog.ui.Slider');
goog.provide('goog.ui.Slider.Orientation');

goog.require('goog.a11y.aria');
goog.require('goog.a11y.aria.Role');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.ui.SliderBase');

/**
 * This creates a slider object.
 * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper.
 * @param {(function(number):?string)=} opt_labelFn An optional function mapping
 *     slider values to a description of the value.
 * @constructor
 * @extends {goog.ui.SliderBase}
 */
goog.ui.Slider = function(opt_domHelper, opt_labelFn) {
  goog.ui.SliderBase.call(this, opt_domHelper, opt_labelFn);
  this.rangeModel.setExtent(0);
};
goog.inherits(goog.ui.Slider, goog.ui.SliderBase);
goog.tagUnsealableClass(goog.ui.Slider);

/**
 * Expose Enum of superclass (representing the orientation of the slider) within
 * Slider namespace.
 *
 * @enum {string}
 */
goog.ui.Slider.Orientation = goog.ui.SliderBase.Orientation;

/**
 * The prefix we use for the CSS class names for the slider and its elements.
 * @type {string}
 */
goog.ui.Slider.CSS_CLASS_PREFIX = goog.getCssName('goog-slider');

/**
 * CSS class name for the single thumb element.
 * @type {string}
 */
goog.ui.Slider.THUMB_CSS_CLASS =
    goog.getCssName(goog.ui.Slider.CSS_CLASS_PREFIX, 'thumb');

/**
 * Returns CSS class applied to the slider element.
 * @param {goog.ui.SliderBase.Orientation} orient Orientation of the slider.
 * @return {string} The CSS class applied to the slider element.
 * @protected
 * @override
 */
goog.ui.Slider.prototype.getCssClass = function(orient) {
  return orient == goog.ui.SliderBase.Orientation.VERTICAL ?
      goog.getCssName(goog.ui.Slider.CSS_CLASS_PREFIX, 'vertical') :
      goog.getCssName(goog.ui.Slider.CSS_CLASS_PREFIX, 'horizontal');
};

/**
 * Returns CSS class applied to the slider's thumb element.
 * @return {string} The CSS class applied to the slider's thumb element.
 * @protected
 */
goog.ui.Slider.prototype.getThumbCssClass = function() {
  return goog.ui.Slider.THUMB_CSS_CLASS;
};

/** @override */
goog.ui.Slider.prototype.createThumbs = function() {
  // find thumb
  var element = this.getElement();
  var thumb = goog.dom.getElementsByTagNameAndClass(
      null, this.getThumbCssClass(), element)[0];
  if (!thumb) {
    thumb = this.createThumb_();
    element.appendChild(thumb);
  }
  this.valueThumb = this.extentThumb = /** @type {!HTMLDivElement} */ (thumb);
};

/**
 * Creates the thumb element.
 * @return {!HTMLDivElement} The created thumb element.
 * @private
 */
goog.ui.Slider.prototype.createThumb_ = function() {
  var thumb = this.getDomHelper().createDom(
      goog.dom.TagName.DIV, this.getThumbCssClass());
  goog.a11y.aria.setRole(thumb, goog.a11y.aria.Role.BUTTON);
  return /** @type {!HTMLDivElement} */ (thumb);
};
<|endoftext|>


<commit_before>(function () {
    var Ext = window.Ext4 || window.Ext;

    Ext.define('Rally.apps.roadmapplanningboard.PlanningGridBoard', {
        extend: 'Rally.ui.gridboard.GridBoard',
        alias: 'widget.roadmapplanninggridboard',
        requires: [
            'Rally.ui.gridboard.plugin.GridBoardAddNew',
            'Rally.ui.gridboard.plugin.GridBoardFilterControl',
            'Rally.ui.gridboard.plugin.GridBoardFeedback',
            'Rally.apps.roadmapplanningboard.plugin.RoadmapScrollable',
            'Rally.ui.gridboard.plugin.GridBoardFieldPicker',
            'Rally.apps.roadmapplanningboard.PlanningBoard'
        ],

        cls: 'roadmap-board',

        toggleState: 'board',
        stateId: 'roadmapgridboard',

        config: {
            /**
             * @cfg {Rally.data.Model} The roadmap to use
             */
            roadmap: null,

            /**
             * @cfg {Rally.data.Model} The timeline to use
             */
            timeline: null,

            /**
             * @cfg {Object} A Rally context
             */
            context: null,

            /**
             * @cfg {Object} Object containing Names and TypePaths of the lowest level portfolio item (eg: 'Feature') and optionally its parent (eg: 'Initiative')
             */
            typeNames: {},

            /**
             * @cfg {Boolean} If the user is an admin
             */
            isAdmin: false,

            cardboardPlugins: []
        },

        initComponent: function () {
            if(!this.typeNames.child || !this.typeNames.child.name) {
                throw 'typeNames must have a child property with a name';
            }

            this.addNewPluginConfig = {
                listeners: {
                    beforecreate: this._onBeforeCreate,
                    beforeeditorshow: this._onBeforeCreate
                },
                style: {
                    'float': 'left'
                },
                fieldLabel: 'New ' + this.typeNames.child.name
            };
            this.plugins = [
                'rallygridboardaddnew',
                {
                    ptype: 'rallygridboardfieldpicker',
                    showInBoardMode: true,
                    headerPosition: 'left',
                    alwaysSelectedValues: ['FormattedID', 'Name'],
                    boardFieldDefaults: ['PreliminaryEstimate', 'Discussions', 'UserStories'],
                    stateful: true,
                    stateId: this.getContext().getScopedStateId('fields')
                },
                {
                    ptype: 'rallygridboardfeedback',
                    feedbackDialogConfig: {
                        title: 'Feedback on Roadmap Planning Board',
                        subject: 'Roadmap Planning Board',
                        feedbackId: 'roadmapplanningboard'
                    }
                }
            ];

            this.cardBoardConfig = {
                xtype: 'roadmapplanningboard',
                context: this.context,
                roadmap: this.roadmap,
                timeline: this.timeline,
                isAdmin: this.isAdmin,
                types: this.modelNames,
                typeNames: this.typeNames,
                firstLoad: this.firstLoad,
                attribute: 'Name',
                plugins: [
                    {
                        ptype: 'rallytimeframescrollablecardboard', timeframeColumnCount: 3
                    }
                ].concat(this.cardboardPlugins)
            };

            this.callParent(arguments);
        },

        afterRender: function() {
            this.callParent(arguments);
            var headerHeight = this.getHeader().getHeight();
            var boardHeight  = this.getHeight() - headerHeight;
            if(!boardHeight) {
                boardHeight = this._getOwnerHeight() - headerHeight;
            }
            this.getGridOrBoard().setHeight(boardHeight);
        },

        _getOwnerHeight: function() {
            var owner = this.ownerCt;
            if(!owner && Rally.BrowserTest) {
                return Ext.getBody().down('#testDiv').getHeight();
            }
            return this.ownerCt.getHeight();
        },

        _initialFilter: function (component, filters) {
            component.on('filter', this._onFilter, this);
            this._applyFilter(filters);
            this.config.storeConfig.autoLoad = true;
            this.loadStore();
        },

        _onFilter: function (component, filters) {
            this._applyFilter(filters);
            this.refresh(this.config);
        },

        _applyFilter: function (filters) {
            this.queryFilter = filters[0];

            if (this.queryFilter) {
                this.filterButton.removeCls('secondary');
                this.filterButton.addCls('primary');
            } else {
                this.filterButton.removeCls('primary');
                this.filterButton.addCls('secondary');
            }
        },

        /**
         * This method is fired by AddNew and will run before the artifact is created.
         * Scoping will be the GridBoardAddNew plugin (because of issues with deep merging of the listener config and the scope)
         * @private
         */
        _onBeforeCreate: function (addNew, record, params) {
            // the order of arguments is different between beforecreate and beforeeditorshow
            if (!record.isModel) {
                params = record;
            }
            var rankRecord = this.gridboard.getGridOrBoard().getFirstRecord();
            if (rankRecord) {
                params.rankAbove = rankRecord.getUri();
            }
        }
    });

})();
<commit_msg>Added 'Name' as a RPB Board Field default<commit_after>(function () {
    var Ext = window.Ext4 || window.Ext;

    Ext.define('Rally.apps.roadmapplanningboard.PlanningGridBoard', {
        extend: 'Rally.ui.gridboard.GridBoard',
        alias: 'widget.roadmapplanninggridboard',
        requires: [
            'Rally.ui.gridboard.plugin.GridBoardAddNew',
            'Rally.ui.gridboard.plugin.GridBoardFilterControl',
            'Rally.ui.gridboard.plugin.GridBoardFeedback',
            'Rally.apps.roadmapplanningboard.plugin.RoadmapScrollable',
            'Rally.ui.gridboard.plugin.GridBoardFieldPicker',
            'Rally.apps.roadmapplanningboard.PlanningBoard'
        ],

        cls: 'roadmap-board',

        toggleState: 'board',
        stateId: 'roadmapgridboard',

        config: {
            /**
             * @cfg {Rally.data.Model} The roadmap to use
             */
            roadmap: null,

            /**
             * @cfg {Rally.data.Model} The timeline to use
             */
            timeline: null,

            /**
             * @cfg {Object} A Rally context
             */
            context: null,

            /**
             * @cfg {Object} Object containing Names and TypePaths of the lowest level portfolio item (eg: 'Feature') and optionally its parent (eg: 'Initiative')
             */
            typeNames: {},

            /**
             * @cfg {Boolean} If the user is an admin
             */
            isAdmin: false,

            cardboardPlugins: []
        },

        initComponent: function () {
            if(!this.typeNames.child || !this.typeNames.child.name) {
                throw 'typeNames must have a child property with a name';
            }

            this.addNewPluginConfig = {
                listeners: {
                    beforecreate: this._onBeforeCreate,
                    beforeeditorshow: this._onBeforeCreate
                },
                style: {
                    'float': 'left'
                },
                fieldLabel: 'New ' + this.typeNames.child.name
            };
            this.plugins = [
                'rallygridboardaddnew',
                {
                    ptype: 'rallygridboardfieldpicker',
                    showInBoardMode: true,
                    headerPosition: 'left',
                    alwaysSelectedValues: ['FormattedID', 'Name'],
                    boardFieldDefaults: ['PreliminaryEstimate', 'Discussions', 'UserStories', 'Name'],
                    stateful: true,
                    stateId: this.getContext().getScopedStateId('fields')
                },
                {
                    ptype: 'rallygridboardfeedback',
                    feedbackDialogConfig: {
                        title: 'Feedback on Roadmap Planning Board',
                        subject: 'Roadmap Planning Board',
                        feedbackId: 'roadmapplanningboard'
                    }
                }
            ];

            this.cardBoardConfig = {
                xtype: 'roadmapplanningboard',
                context: this.context,
                roadmap: this.roadmap,
                timeline: this.timeline,
                isAdmin: this.isAdmin,
                types: this.modelNames,
                typeNames: this.typeNames,
                firstLoad: this.firstLoad,
                attribute: 'Name',
                plugins: [
                    {
                        ptype: 'rallytimeframescrollablecardboard', timeframeColumnCount: 3
                    }
                ].concat(this.cardboardPlugins)
            };

            this.callParent(arguments);
        },

        afterRender: function() {
            this.callParent(arguments);
            var headerHeight = this.getHeader().getHeight();
            var boardHeight  = this.getHeight() - headerHeight;
            if(!boardHeight) {
                boardHeight = this._getOwnerHeight() - headerHeight;
            }
            this.getGridOrBoard().setHeight(boardHeight);
        },

        _getOwnerHeight: function() {
            var owner = this.ownerCt;
            if(!owner && Rally.BrowserTest) {
                return Ext.getBody().down('#testDiv').getHeight();
            }
            return this.ownerCt.getHeight();
        },

        _initialFilter: function (component, filters) {
            component.on('filter', this._onFilter, this);
            this._applyFilter(filters);
            this.config.storeConfig.autoLoad = true;
            this.loadStore();
        },

        _onFilter: function (component, filters) {
            this._applyFilter(filters);
            this.refresh(this.config);
        },

        _applyFilter: function (filters) {
            this.queryFilter = filters[0];

            if (this.queryFilter) {
                this.filterButton.removeCls('secondary');
                this.filterButton.addCls('primary');
            } else {
                this.filterButton.removeCls('primary');
                this.filterButton.addCls('secondary');
            }
        },

        /**
         * This method is fired by AddNew and will run before the artifact is created.
         * Scoping will be the GridBoardAddNew plugin (because of issues with deep merging of the listener config and the scope)
         * @private
         */
        _onBeforeCreate: function (addNew, record, params) {
            // the order of arguments is different between beforecreate and beforeeditorshow
            if (!record.isModel) {
                params = record;
            }
            var rankRecord = this.gridboard.getGridOrBoard().getFirstRecord();
            if (rankRecord) {
                params.rankAbove = rankRecord.getUri();
            }
        }
    });

})();
<|endoftext|>


<commit_before>(function(){
    'use strict';

    var DIR         = __dirname     + '/',
        main        = require(DIR   + 'lib/server/main'),

        LIBDIR      = main.LIBDIR,
        SRVDIR      = main.SRVDIR,
        CLIENTDIR   = LIBDIR + 'client',
        HTMLDIR     = main.HTMLDIR,

        path        = main.path,
        fs          = main.fs,
        CloudFunc   = main.cloudfunc,
        AppCache    = main.appcache,
        Util        = main.util,
        update      = main.update,

        server      = main.librequire('server'),
        Minify      = main.minify,
        Config      = main.config,

        REQUEST     = 'request',
        RESPONSE    = 'response',
        INDEX       = HTMLDIR + 'index.html',
        FS          = CloudFunc.FS,
        NO_JS       = CloudFunc.NO_JS;

        /* reinit main dir os if we on
         * Win32 should be backslashes */
        DIR         = main.DIR;

    readConfig();
    server.start(Config, {
        appcache    : appCacheProcessing,
        minimize    : minimize,
        rest        : rest,
        route       : route
    });

    if(update)
        update.get();

    /**
     * additional processing of index file
     */
    function indexProcessing(pData){
        var lReplace_s,
            lData       = pData.data,
            lAdditional = pData.additional;

        /*
         * если выбрана опция минимизировать скрипты
         * меняем в index.html обычные css на
         * минифицированый
         */
        if(Minify.allowed.css){
            var lPath = '/' + Minify.MinFolder.replace(DIR, '');
            lReplace_s = '<link rel=stylesheet href="/css/reset.css">';
            lData = Util.removeStr(lData, lReplace_s)
                    .replace('/css/style.css', lPath + 'all.min.css');
        }

        /* меняем title */
        lReplace_s = '
';
        lData = lData.replace(lReplace_s, lReplace_s + lAdditional)
                .replace('<title>Cloud Commander</title>',
                    '<title>' + CloudFunc.getTitle() + '</title>');

        if(!Config.appcache)
            lData = Util.removeStr(lData, ' manifest="/cloudcmd.appcache"');

        if(!Config.show_keys_panel){
            var lKeysPanel = '<div id=keyspanel';
            lData = lData.replace(lKeysPanel, lKeysPanel +' class=hidden');
        }

        return lData;

    }

    /**
     * init and process of appcache if it allowed in config
     */
    function appCacheProcessing(){
        var lFiles = [
                {'//themes.googleusercontent.com/static/fonts/droidsansmono/v4/ns-m2xQYezAtqh7ai59hJUYuTAAIFFn5GTWtryCmBQ4.woff' : './font/DroidSansMono.woff'},
                {'//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js' : './lib/client/jquery.js'}];

        if(Config.minification.css)
            lFiles.push('node_modules/minify/min/all.min.css');

        AppCache.addFiles(lFiles);
        AppCache.createManifest();
    }

    /**
     * Функция минимизирует css/js/html
     * если установлены параметры минимизации
     */
    function minimize(pAllowed){
        var lOptimizeParams = [],
            lStyleCSS   = DIR + 'css/style.css',
            lResetCSS   = DIR + 'css/reset.css',

            lCSSOptions = {
                img     : pAllowed.img,
                merge   : true
            };

        if (pAllowed.js)
            lOptimizeParams.push(LIBDIR + 'client.js');

        if (pAllowed.html)
            lOptimizeParams.push(INDEX);

        if (pAllowed.css) {
            var lStyles = [{}, {}];
            lStyles[0][lStyleCSS]   = lCSSOptions;
            lStyles[1][lResetCSS]   = lCSSOptions;

            lOptimizeParams.push(lStyles[0]);
            lOptimizeParams.push(lStyles[1]);
        }

        if (lOptimizeParams.length)
            Minify.optimize(lOptimizeParams, {
                force: true
            });
    }

    /**
     * rest interface
     * @pConnectionData {request, responce}
     */
    function rest(pConnectionData){
        return Util.exec(main.rest, pConnectionData);
    }

    function readConfig(){

        /* Determining server.js directory
         * and chang current process directory
         * (usually /) to it.
         * argv[1] - is always script name
         */
        var lServerDir = path.dirname(process.argv[1]) + '/';

        if( DIR !== lServerDir ){
            Util.log('current dir: ' + DIR);
            process.chdir(lServerDir);
        }
        Util.log('server dir:  ' + lServerDir);
        Util.log('reading configuretion file config.json...');

        if(Config){
            Util.log('config.json readed');

            /* if command line parameter testing resolved
             * setting config to testing, so server
             * not created, just init and
             * all logs writed to screen
             */
            var lArg = process.argv;
                lArg = lArg[lArg.length - 1];
            if ( lArg === 'test' ||  lArg === 'test\r') {
                Util.log(process.argv);
                Config.server  =
                Config.logs    = false;
            }

            if (Config.logs) {
                Util.log('log param setted up in config.json\n' +
                    'from now all logs will be writed to log.txt');
                writeLogsToFile();
            }
        }
    }

    /**
     * routing of server queries
     */
    function route(pParams){
        var lRet,
            lName = pParams.name;

        if( Util.strCmp(lName, ['/auth', '/auth/github']) ){
            Util.log('* Routing' +
                '-> ' + lName);
            pParams.name = main.HTMLDIR + lName + '.html';
            lRet = main.sendFile(pParams);
        }
        else if( Util.isContainStr(lName, [FS, NO_JS]) ||
                 Util.strCmp( lName, ['/', 'json']) ){

                        lRet = main.commander.sendContent({
                            request     : pParams[REQUEST],
                            response    : pParams[RESPONSE],
                            processing  : indexProcessing,
                            index       : Minify.allowed.html ? Minify.getName(INDEX) : INDEX
                        });
        }

        return lRet;
    }

    /* function sets stdout to file log.txt */
    function writeLogsToFile(){
        var stdo = fs.createWriteStream('./log.txt');

        process.stdout.write = (function(write) {
            return function(string, encoding, fd) {
                    stdo.write(string);
            };
        })(process.stdout.write);
    }
})();<commit_msg>minor changes<commit_after>(function(){
    'use strict';

    var DIR         = __dirname     + '/',
        main        = require(DIR   + 'lib/server/main'),

        LIBDIR      = main.LIBDIR,
        SRVDIR      = main.SRVDIR,
        CLIENTDIR   = LIBDIR + 'client',
        HTMLDIR     = main.HTMLDIR,

        path        = main.path,
        fs          = main.fs,
        CloudFunc   = main.cloudfunc,
        AppCache    = main.appcache,
        Util        = main.util,
        update      = main.update,

        server      = main.librequire('server'),
        Minify      = main.minify,
        Config      = main.config,

        REQUEST     = 'request',
        RESPONSE    = 'response',
        INDEX       = HTMLDIR + 'index.html',
        FS          = CloudFunc.FS;

        /* reinit main dir os if we on
         * Win32 should be backslashes */
        DIR         = main.DIR;

    readConfig();
    server.start(Config, {
        appcache    : appCacheProcessing,
        minimize    : minimize,
        rest        : rest,
        route       : route
    });

    if(update)
        update.get();

    /**
     * additional processing of index file
     */
    function indexProcessing(pData){
        var lReplace_s,
            lData       = pData.data,
            lAdditional = pData.additional;

        /*
         * если выбрана опция минимизировать скрипты
         * меняем в index.html обычные css на
         * минифицированый
         */
        if(Minify.allowed.css){
            var lPath = '/' + Minify.MinFolder.replace(DIR, '');
            lReplace_s = '<link rel=stylesheet href="/css/reset.css">';
            lData = Util.removeStr(lData, lReplace_s)
                    .replace('/css/style.css', lPath + 'all.min.css');
        }

        /* меняем title */
        lReplace_s = '
';
        lData = lData.replace(lReplace_s, lReplace_s + lAdditional)
                .replace('<title>Cloud Commander</title>',
                    '<title>' + CloudFunc.getTitle() + '</title>');

        if(!Config.appcache)
            lData = Util.removeStr(lData, ' manifest="/cloudcmd.appcache"');

        if(!Config.show_keys_panel){
            var lKeysPanel = '<div id=keyspanel';
            lData = lData.replace(lKeysPanel, lKeysPanel +' class=hidden');
        }

        return lData;

    }

    /**
     * init and process of appcache if it allowed in config
     */
    function appCacheProcessing(){
        var lFiles = [
                {'//themes.googleusercontent.com/static/fonts/droidsansmono/v4/ns-m2xQYezAtqh7ai59hJUYuTAAIFFn5GTWtryCmBQ4.woff' : './font/DroidSansMono.woff'},
                {'//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js' : './lib/client/jquery.js'}];

        if(Config.minification.css)
            lFiles.push('node_modules/minify/min/all.min.css');

        AppCache.addFiles(lFiles);
        AppCache.createManifest();
    }

    /**
     * Функция минимизирует css/js/html
     * если установлены параметры минимизации
     */
    function minimize(pAllowed){
        var lOptimizeParams = [],
            lStyleCSS   = DIR + 'css/style.css',
            lResetCSS   = DIR + 'css/reset.css',

            lCSSOptions = {
                img     : pAllowed.img,
                merge   : true
            };

        if (pAllowed.js)
            lOptimizeParams.push(LIBDIR + 'client.js');

        if (pAllowed.html)
            lOptimizeParams.push(INDEX);

        if (pAllowed.css) {
            var lStyles = [{}, {}];
            lStyles[0][lStyleCSS]   = lCSSOptions;
            lStyles[1][lResetCSS]   = lCSSOptions;

            lOptimizeParams.push(lStyles[0]);
            lOptimizeParams.push(lStyles[1]);
        }

        if (lOptimizeParams.length)
            Minify.optimize(lOptimizeParams, {
                force: true
            });
    }

    /**
     * rest interface
     * @pConnectionData {request, responce}
     */
    function rest(pConnectionData){
        return Util.exec(main.rest, pConnectionData);
    }

    function readConfig(){

        /* Determining server.js directory
         * and chang current process directory
         * (usually /) to it.
         * argv[1] - is always script name
         */
        var lServerDir = path.dirname(process.argv[1]) + '/';

        if( DIR !== lServerDir ){
            Util.log('current dir: ' + DIR);
            process.chdir(lServerDir);
        }
        Util.log('server dir:  ' + lServerDir);
        Util.log('reading configuretion file config.json...');

        if(Config){
            Util.log('config.json readed');

            /* if command line parameter testing resolved
             * setting config to testing, so server
             * not created, just init and
             * all logs writed to screen
             */
            var lArg = process.argv;
                lArg = lArg[lArg.length - 1];
            if ( lArg === 'test' ||  lArg === 'test\r') {
                Util.log(process.argv);
                Config.server  =
                Config.logs    = false;
            }

            if (Config.logs) {
                Util.log('log param setted up in config.json\n' +
                    'from now all logs will be writed to log.txt');
                writeLogsToFile();
            }
        }
    }

    /**
     * routing of server queries
     */
    function route(pParams){
        var lRet,
            lName = pParams.name;

        if( Util.strCmp(lName, ['/auth', '/auth/github']) ){
            Util.log('* Routing' +
                '-> ' + lName);
            pParams.name = main.HTMLDIR + lName + '.html';
            lRet = main.sendFile(pParams);
        }
        else if( Util.isContainStr(lName, FS) ||
                 Util.strCmp( lName, ['/', 'json']) ){

                        lRet = main.commander.sendContent({
                            request     : pParams[REQUEST],
                            response    : pParams[RESPONSE],
                            processing  : indexProcessing,
                            index       : Minify.allowed.html ? Minify.getName(INDEX) : INDEX
                        });
        }

        return lRet;
    }

    /* function sets stdout to file log.txt */
    function writeLogsToFile(){
        var stdo = fs.createWriteStream('./log.txt');

        process.stdout.write = (function(write) {
            return function(string, encoding, fd) {
                    stdo.write(string);
            };
        })(process.stdout.write);
    }
})();<|endoftext|>


<commit_before>import "core-js/stable";
import "regenerator-runtime/runtime";
import parse from "./parse";
import SchemaRenderer from "./render";

const API_ENDPOINT = "http://localhost:8000/dependencies";

// entry-point
main();

function main() {
  const visualizeButton = document.getElementById("myBtn");
  const uriTextBox = document.getElementById("connectionUri");
  const loadingIndicator = document.getElementById("loader");
  const chargeInput = document.getElementById("charge");
  const linkDistanceInput = document.getElementById("distance");

  const renderer = new SchemaRenderer(
    chargeInput.value,
    linkDistanceInput.value
  );

  // hide the loading indicator initially
  loadingIndicator.style.visibility = "hidden";

  // when the "Visualize" button is clicked
  visualizeButton.addEventListener("click", () => {
    loadingIndicator.style.visibility = "visible";
    const connUri = uriTextBox.value;
    const encodedConnUri = encodeURIComponent(connUri);
    fetch(`${API_ENDPOINT}?connection_uri=${encodedConnUri}`)
      .then(response => response.json())
      .then(data => {
        loadingIndicator.style.visibility = "hidden";
        setupAndRender(data.dependencies, renderer);
      })
      .catch(error => {
        loadingIndicator.style.visibility = "hidden";
        // TODO: show nice error message
        // eslint-disable-next-line no-console
        console.log(error);
      });
  });

  // when user presses "Enter" key with focus on the database uri form input
  uriTextBox.addEventListener("keypress", e => {
    if (e.key === "Enter") {
      // we dont want to reload the page, dawg!
      e.preventDefault();
      // but we do want to simulate a button click!
      visualizeButton.click();
    }
  });

  // re-render (but dont re-download) when particle charge is modified
  chargeInput.addEventListener("change", e => {
    renderer.updateCharge(e.target.value);
  });

  // re-render (but dont re-download) when link distance is modified
  linkDistanceInput.addEventListener("change", e => {
    renderer.updateLinkDistance(e.target.value);
  });
}

function setupAndRender(dependencies, renderer) {
  const { nodes, links } = parse(dependencies);
  const tableCountTd = document.getElementById("table_count");
  tableCountTd.textContent = nodes.length;

  const linkCountTd = document.getElementById("link_count");
  linkCountTd.textContent = links.length;

  const schemaSet = new Set(nodes.map(n => n.schema));

  // this will track whether a given schema is selected
  const schemaSelectionMap = new Map();
  schemaSet.forEach(schema => {
    // initially, every schema is selected
    schemaSelectionMap.set(schema, true);
  });

  const schemaCountTd = document.getElementById("schema_count");
  schemaCountTd.textContent = schemaSet.size;

  const schemaListingContainer = document.getElementById("schemas");
  schemaSet.forEach(schema => {
    const para = document.createElement("p");

    const input = constructInput(schema, e => {
      schemaSelectionMap.set(schema, e.target.checked);
      const updatedDependencies = dependencies.filter(dependency =>
        areSchemasSelected(dependency, schemaSelectionMap)
      );
      const updatedSchema = parse(updatedDependencies);
      renderer.updateSchema(updatedSchema);
    });
    const label = constructLabel(schema);

    para.appendChild(input);
    para.appendChild(label);

    schemaListingContainer.appendChild(para);
  });

  // don't forget to do first-time render!
  renderer.updateSchema({ nodes, links });
}

function constructInput(schema, changeListener) {
  const input = document.createElement("input");
  input.setAttribute("type", "checkbox");
  input.setAttribute("id", schema);
  input.setAttribute("name", schema);
  input.setAttribute("value", schema);
  input.setAttribute("checked", true);
  input.addEventListener("change", changeListener);
  return input;
}

function constructLabel(schema) {
  const label = document.createElement("label");
  label.setAttribute("for", schema);
  label.style.fontFamily = "monospace";
  label.textContent = schema;
  return label;
}

// select a dependency only if both its source and target schemas selected
function areSchemasSelected(dependency, schemaSelectionMap) {
  const { sourceSchema, targetSchema } = dependency;
  return (
    schemaSelectionMap.get(sourceSchema) &&
    targetSchema &&
    schemaSelectionMap.get(targetSchema)
  );
}
<commit_msg>no-op refactor to separate UI updates from intermediate computations<commit_after>import "core-js/stable";
import "regenerator-runtime/runtime";
import parse from "./parse";
import SchemaRenderer from "./render";

const API_ENDPOINT = "http://localhost:8000/dependencies";

// entry-point
main();

function main() {
  const visualizeButton = document.getElementById("myBtn");
  const uriTextBox = document.getElementById("connectionUri");
  const loadingIndicator = document.getElementById("loader");
  const chargeInput = document.getElementById("charge");
  const linkDistanceInput = document.getElementById("distance");

  const renderer = new SchemaRenderer(
    chargeInput.value,
    linkDistanceInput.value
  );

  // hide the loading indicator initially
  loadingIndicator.style.visibility = "hidden";

  // when the "Visualize" button is clicked
  visualizeButton.addEventListener("click", () => {
    loadingIndicator.style.visibility = "visible";
    const connUri = uriTextBox.value;
    const encodedConnUri = encodeURIComponent(connUri);
    fetch(`${API_ENDPOINT}?connection_uri=${encodedConnUri}`)
      .then(response => response.json())
      .then(data => {
        loadingIndicator.style.visibility = "hidden";
        setupAndRender(data.dependencies, renderer);
      })
      .catch(error => {
        loadingIndicator.style.visibility = "hidden";
        // TODO: show nice error message
        // eslint-disable-next-line no-console
        console.log(error);
      });
  });

  // when user presses "Enter" key with focus on the database uri form input
  uriTextBox.addEventListener("keypress", e => {
    if (e.key === "Enter") {
      // we dont want to reload the page, dawg!
      e.preventDefault();
      // but we do want to simulate a button click!
      visualizeButton.click();
    }
  });

  // re-render (but dont re-download) when particle charge is modified
  chargeInput.addEventListener("change", e => {
    renderer.updateCharge(e.target.value);
  });

  // re-render (but dont re-download) when link distance is modified
  linkDistanceInput.addEventListener("change", e => {
    renderer.updateLinkDistance(e.target.value);
  });
}

function setupAndRender(dependencies, renderer) {
  const { nodes, links } = parse(dependencies);
  const schemaSet = new Set(nodes.map(n => n.schema));
  // this will track whether a given schema is selected
  const schemaSelectionMap = new Map();
  schemaSet.forEach(schema => {
    // initially, every schema is selected
    schemaSelectionMap.set(schema, true);
  });

  document.getElementById("table_count").textContent = nodes.length;
  document.getElementById("link_count").textContent = links.length;
  document.getElementById("schema_count").textContent = schemaSet.size;

  const recomputeSchema = () => {
    const updatedDependencies = dependencies.filter(dependency =>
      areSchemasSelected(dependency, schemaSelectionMap)
    );
    return parse(updatedDependencies);
  };

  const schemaListingContainer = document.getElementById("schemas");
  schemaSet.forEach(schema => {
    const para = document.createElement("p");

    const input = constructInput(schema, e => {
      schemaSelectionMap.set(schema, e.target.checked);
      renderer.updateSchema(recomputeSchema());
    });
    const label = constructLabel(schema);

    para.appendChild(input);
    para.appendChild(label);

    schemaListingContainer.appendChild(para);
  });

  // don't forget to do first-time render!
  renderer.updateSchema({ nodes, links });
}

function constructInput(schema, changeListener) {
  const input = document.createElement("input");
  input.setAttribute("type", "checkbox");
  input.setAttribute("id", schema);
  input.setAttribute("name", schema);
  input.setAttribute("value", schema);
  input.setAttribute("checked", true);
  input.addEventListener("change", changeListener);
  return input;
}

function constructLabel(schema) {
  const label = document.createElement("label");
  label.setAttribute("for", schema);
  label.style.fontFamily = "monospace";
  label.textContent = schema;
  return label;
}

// select a dependency only if both its source and target schemas selected
function areSchemasSelected(dependency, schemaSelectionMap) {
  const { sourceSchema, targetSchema } = dependency;
  return (
    schemaSelectionMap.get(sourceSchema) &&
    targetSchema &&
    schemaSelectionMap.get(targetSchema)
  );
}
<|endoftext|>


<commit_before>/**
 * @fileOverview 图分析模版
 * @author huangtonger@aliyun.com
 * read only:
 * edge.isTreeEdge
 * read && write:
 * node.rank - node rank the max rank would be the root node
 * edge.weight - edge weight
 */
const G6 = require('@antv/g6');
const maxSpanningForest = require('./maxSpanningForest');
const Layout = require('../layout.forceAtlas2/layout');
const Util = G6.Util;
require('../tool.textDisplay/');
require('../tool.highlightSubgraph/');
require('../tool.fisheye/');
require('../util.extractSubgraph/');
require('../edge.quadraticCurve/');
require('../behaviour.analysis/');
let pre_navi = {};
const node_style = {
  stroke: '#fff',
  lineWidth: 2
};
const edge_style = {
  endArrow: true,
  stroke: '#4F7DAB',
  strokeOpacity: 0.65
};

class Plugin {
  constructor(options) {
    Util.mix(this, {
      layout: {
        auto: 'once', // true false once
        processer: new Layout({
          kr: 120,
          kg: 8.0,
          mode: 'common',
          prev_overlapping: true,
          dissuade_hubs: false,
          max_iteration: 1000,
          barnes_hut: true,
          ks: 0.1,
          ksmax: 10,
          tao: 0.1,
          ...options.layoutCfg
        })
      },
      ...options
    });
  }
  init() {
    const graph = this.graph;
    const highlighter = new G6.Plugins['tool.highlightSubgraph']();
    const fisheye = new G6.Plugins['tool.fisheye']({
      radius: 200
    });
    const textDisplay = new G6.Plugins['tool.textDisplay']();
    graph.addPlugin(highlighter);
    graph.addPlugin(fisheye);
    graph.addPlugin(textDisplay);
    graph.on('beforeinit', () => {
      const layout = graph.get('layout');
      if (!layout) {
        graph.set('layout', this.layout);
      }
      this.graph.activeItem = this.activeItem;
      this.graph.createMenu = this.createMenu;
    });
    graph.on('beforerender', () => {
      const data = graph.getSource();
      let {
        nodes,
        edges
      } = data;
      nodes = nodes.map((node, index) => {
        return {
          ...node,
          index
        };
      });
      edges = edges.map((edge, index) => {
        return {
          ...edge,
          index
        };
      });
      const forest = maxSpanningForest(nodes, edges);
      forest.edges.forEach(edge => {
        const {
          index
        } = edge;
        data.edges[index].isTreeEdge = true;
      });
      graph.addFilter(item => {
        return !item.isEdge || item.getModel().isTreeEdge;
      });

      this.setStyle();
      this.setListener();
    });
  }
  createMenu(detailListener) {
    const hover_color = '#6af';
    const custom_color = '#777';
    const li_style = 'padding: 5px 10px; cursor: pointer;';
    const menuHtml = `<ul id="menu" style = "
      color: ` + custom_color + `;
      list-style: none;
      width: 150px;
      border: 1px solid #ccc;
      position: absolute;
      display: none;
      background-color: #fff">
    <li id="menu_sources" class = "menu_li" style = "` + li_style + `  color: #777;">来源

    <li id="menu_targets" class = "menu_li" style = "` + li_style + `  color: #777;">去向

    <li id="menu_both" class = "menu_li" style = "` + li_style + `  color: #777;">来源去向

    <li id='menu_detail' class = "menu_li" style = "` + li_style + `
      color: #6af;
      border-top: 1px solid #ccc;">查看单页分析详情

`;

    const menu = Util.createDOM(menuHtml);
    const body = document.getElementsByTagName('body')[0];
    body.appendChild(menu);

    const lis = document.getElementsByClassName('menu_li');
    for (let i = 0; i < lis.length - 1; i += 1) {
      lis[i].addEventListener('mouseover', function() {
        this.style.setProperty('color', hover_color);
      });
      lis[i].addEventListener('mouseout', function() {
        this.style.setProperty('color', custom_color);
      });
    }

    if (detailListener !== undefined) {
      const detail_menu = document.getElementById('menu_detail');
      detail_menu.addEventListener('click', detailListener);
    }
  }
  setStyle() {
    const graph = this.graph;
    const data = graph.getSource();
    const {
      edges
    } = data;
    for (let i = 0; i < edges.length; i += 1) {
      const model = edges[i];
      if (!model.isTreeEdge || typeof model.isTreeEdge === 'undefined') model.shape = 'quadraticCurve';
    }

    graph.edge({
      style() {
        return edge_style;
      }
    });
    graph.node({
      label(model) {
        return {
          text: model.id,
          fill: 'black',
          stroke: '#fff',
          lineWidth: 4
        };
      },
      style: node_style
    });
  }
  activeItem(item) {
    if (Util.isString(item)) {
      item = this.find(item);
    }
    let style = {};
    let pre_style = {};
    if (item.type === 'node') {
      style = {
        stroke: '#fff',
        lineWidth: 2,
        shadowColor: '#6a80aa',
        shadowBlur: 20
      };
      pre_style = node_style;
    } else if (item.type === 'edge edge') {
      style = {
        endArrow: true,
        stroke: '#000',
        strokeOpacity: 0.65
      };
      pre_style = edge_style;
    } else return;

    // // unactive the previous navigate node
    if (pre_navi !== {} && pre_navi !== null && pre_navi !== undefined) {
      this.update(pre_navi.item, {
        style: pre_navi.style
      });
    }

    this.update(item, {
      style
    });
    pre_navi = { item, style: pre_style };
  }
  setListener() {
    let clickOnNode = null;
    const graph = this.graph;
    graph.on('mouseenter', item => {
      if (item.item != null) {
        graph.activeItem(item.item);
      }
    });
    graph.on('mouseleave', item => {
      let style = {};
      if (item.item != null) {
        switch (item.item.type) {
          case 'node':
            style = node_style;
            break;
          case 'edge':
            style = edge_style;
            break;
          default:
            break;
        }
      }
      graph.update(item.item, {
        style
      });
    });

    const menu = document.getElementById('menu');
    graph.on('click', ({
      shape,
      item,
      domEvent
    }) => {
      if (shape && item.isNode) {
        menu.style.display = 'block';
        menu.style.left = domEvent.clientX + 'px';
        menu.style.top = domEvent.clientY + 'px';
        clickOnNode = item;
        graph.draw();
      } else {
        menu.style.display = 'none';
        // restore the highlighted graph and hide the edges which are not tree edges.
        graph.restoreGraph();
        const edges = graph.getEdges();
        Util.each(edges, edge => {
          if (edge.isVisible() && !edge.getModel().isTreeEdge) {
            edge.hide();
          }
        });
        graph.draw();
      }

    });

    menu.addEventListener('click', function(ev) {
      let type = 'in';
      switch (ev.target.id) {
        case 'menu_sources':
          type = 'in';
          break;
        case 'menu_targets':
          type = 'out';
          break;
        case 'menu_both':
          type = 'bi';
          break;
        default:
          return;
      }
      const {
        re_nodes,
        re_edges
      } = Util.extract(graph, type, 1, [ clickOnNode ]);
      graph.highlightSubgraph({
        re_nodes,
        re_edges
      });
      // show the hided edge, which is not tree edge and it is in the es
      // and the source and targert of the edge are both visible
      const edges = graph.getEdges();
      Util.each(edges, edge => {
        if (!edge.isVisible() && !edge.getModel().isTreeEdge &&
          edge.getSource().isVisible() && edge.getTarget().isVisible()) {
          Util.each(re_edges, e => {
            if (edge.id === e.id) {
              edge.show();
            }
          });
        }
      });
      menu.style.display = 'none';
    }, false);
  }
}

G6.Plugins['template.maxSpanningForest'] = Plugin;

module.exports = Plugin;
<commit_msg>fix:node and edge mouseenter<commit_after>/**
 * @fileOverview 图分析模版
 * @author huangtonger@aliyun.com
 * read only:
 * edge.isTreeEdge
 * read && write:
 * node.rank - node rank the max rank would be the root node
 * edge.weight - edge weight
 */
const G6 = require('@antv/g6');
const maxSpanningForest = require('./maxSpanningForest');
const Layout = require('../layout.forceAtlas2/layout');
const Util = G6.Util;
require('../tool.textDisplay/');
require('../tool.highlightSubgraph/');
require('../tool.fisheye/');
require('../util.extractSubgraph/');
require('../edge.quadraticCurve/');
require('../behaviour.analysis/');
let pre_navi = {};
const node_style = {
  stroke: '#fff',
  lineWidth: 2
};
const edge_style = {
  endArrow: true,
  stroke: '#4F7DAB',
  strokeOpacity: 0.65
};

class Plugin {
  constructor(options) {
    Util.mix(this, {
      layout: {
        auto: 'once', // true false once
        processer: new Layout({
          kr: 120,
          kg: 8.0,
          mode: 'common',
          prev_overlapping: true,
          dissuade_hubs: false,
          max_iteration: 1000,
          barnes_hut: true,
          ks: 0.1,
          ksmax: 10,
          tao: 0.1,
          ...options.layoutCfg
        })
      },
      ...options
    });
  }
  init() {
    const graph = this.graph;
    const highlighter = new G6.Plugins['tool.highlightSubgraph']();
    const fisheye = new G6.Plugins['tool.fisheye']({
      radius: 200
    });
    const textDisplay = new G6.Plugins['tool.textDisplay']();
    graph.addPlugin(highlighter);
    graph.addPlugin(fisheye);
    graph.addPlugin(textDisplay);
    graph.on('beforeinit', () => {
      const layout = graph.get('layout');
      if (!layout) {
        graph.set('layout', this.layout);
      }
      this.graph.activeItem = this.activeItem;
      this.graph.createMenu = this.createMenu;
    });
    graph.on('beforerender', () => {
      const data = graph.getSource();
      let {
        nodes,
        edges
      } = data;
      nodes = nodes.map((node, index) => {
        return {
          ...node,
          index
        };
      });
      edges = edges.map((edge, index) => {
        return {
          ...edge,
          index
        };
      });
      const forest = maxSpanningForest(nodes, edges);
      forest.edges.forEach(edge => {
        const {
          index
        } = edge;
        data.edges[index].isTreeEdge = true;
      });
      graph.addFilter(item => {
        return !item.isEdge || item.getModel().isTreeEdge;
      });

      this.setStyle();
      this.setListener();
    });
  }
  createMenu(detailListener) {
    const hover_color = '#6af';
    const custom_color = '#777';
    const li_style = 'padding: 5px 10px; cursor: pointer;';
    const menuHtml = `<ul id="menu" style = "
      color: ` + custom_color + `;
      list-style: none;
      width: 150px;
      border: 1px solid #ccc;
      position: absolute;
      display: none;
      background-color: #fff">
    <li id="menu_sources" class = "menu_li" style = "` + li_style + `  color: #777;">来源

    <li id="menu_targets" class = "menu_li" style = "` + li_style + `  color: #777;">去向

    <li id="menu_both" class = "menu_li" style = "` + li_style + `  color: #777;">来源去向

    <li id='menu_detail' class = "menu_li" style = "` + li_style + `
      color: #6af;
      border-top: 1px solid #ccc;">查看单页分析详情

`;

    const menu = Util.createDOM(menuHtml);
    const body = document.getElementsByTagName('body')[0];
    body.appendChild(menu);

    const lis = document.getElementsByClassName('menu_li');
    for (let i = 0; i < lis.length - 1; i += 1) {
      lis[i].addEventListener('mouseover', function() {
        this.style.setProperty('color', hover_color);
      });
      lis[i].addEventListener('mouseout', function() {
        this.style.setProperty('color', custom_color);
      });
    }

    if (detailListener !== undefined) {
      const detail_menu = document.getElementById('menu_detail');
      detail_menu.addEventListener('click', detailListener);
    }
  }
  setStyle() {
    const graph = this.graph;
    const data = graph.getSource();
    const {
      edges
    } = data;
    for (let i = 0; i < edges.length; i += 1) {
      const model = edges[i];
      if (!model.isTreeEdge || typeof model.isTreeEdge === 'undefined') model.shape = 'quadraticCurve';
    }

    graph.edge({
      style() {
        return edge_style;
      }
    });
    graph.node({
      label(model) {
        return {
          text: model.id,
          fill: 'black',
          stroke: '#fff',
          lineWidth: 4
        };
      },
      style: node_style
    });
  }
  activeItem(item) {
    if (Util.isString(item)) {
      item = this.find(item);
    }
    let style = {};
    let pre_style = {};
    if (item.type === 'node') {
      style = {
        stroke: '#fff',
        lineWidth: 2,
        shadowColor: '#6a80aa',
        shadowBlur: 20
      };
      pre_style = node_style;
    } else if (item.type === 'edge edge') {
      style = {
        endArrow: true,
        stroke: '#000',
        strokeOpacity: 0.65
      };
      pre_style = edge_style;
    } else return;

    // // unactive the previous navigate node
    if (pre_navi !== {} && pre_navi !== null && pre_navi !== undefined) {
      this.update(pre_navi.item, {
        style: pre_navi.style
      });
    }

    this.update(item, {
      style
    });
    pre_navi = { item, style: pre_style };
  }
  setListener() {
    let clickOnNode = null;
    const graph = this.graph;
    graph.on('node:mouseenter', item => {
      if (item.item != null) {
        graph.activeItem(item.item);
      }
    });
    graph.on('node:mouseleave', item => {
      graph.update(item.item, {
        style: node_style
      });
    });

    graph.on('edge:mouseenter', item => {
      if (item.item != null) {
        graph.activeItem(item.item);
      }
    });
    graph.on('edge:mouseleave', item => {
      graph.update(item.item, {
        style: edge_style
      });
    });

    const menu = document.getElementById('menu');
    graph.on('click', ({
      shape,
      item,
      domEvent
    }) => {
      if (shape && item.isNode) {
        menu.style.display = 'block';
        menu.style.left = domEvent.clientX + 'px';
        menu.style.top = domEvent.clientY + 'px';
        clickOnNode = item;
        graph.draw();
      } else {
        menu.style.display = 'none';
        // restore the highlighted graph and hide the edges which are not tree edges.
        graph.restoreGraph();
        const edges = graph.getEdges();
        Util.each(edges, edge => {
          if (edge.isVisible() && !edge.getModel().isTreeEdge) {
            edge.hide();
          }
        });
        graph.draw();
      }

    });

    menu.addEventListener('click', function(ev) {
      let type = 'in';
      switch (ev.target.id) {
        case 'menu_sources':
          type = 'in';
          break;
        case 'menu_targets':
          type = 'out';
          break;
        case 'menu_both':
          type = 'bi';
          break;
        default:
          return;
      }
      const {
        re_nodes,
        re_edges
      } = Util.extract(graph, type, 1, [ clickOnNode ]);
      graph.highlightSubgraph({
        re_nodes,
        re_edges
      });
      // show the hided edge, which is not tree edge and it is in the es
      // and the source and targert of the edge are both visible
      const edges = graph.getEdges();
      Util.each(edges, edge => {
        if (!edge.isVisible() && !edge.getModel().isTreeEdge &&
          edge.getSource().isVisible() && edge.getTarget().isVisible()) {
          Util.each(re_edges, e => {
            if (edge.id === e.id) {
              edge.show();
            }
          });
        }
      });
      menu.style.display = 'none';
    }, false);
  }
}

G6.Plugins['template.maxSpanningForest'] = Plugin;

module.exports = Plugin;
<|endoftext|>


<commit_before>var {
  ADD_LESSON,
  ADD_STEP,
  DELETE_LESSON,
  DELETE_STEP,
  IMPORT_LESSONS,
  SELECT_LESSON,
  SELECT_STEP,
  TOGGLE_EDITING,
  UPDATE_LESSON,
  UPDATE_STEP
} = require('../ActionTypes')

function addLesson() {
  return {
    type: ADD_LESSON
  }
}

function addStep() {
  return {
    type: ADD_STEP
  }
}

function deleteLesson() {
  return {
    type: DELETE_LESSON
  }
}

function deleteStep() {
  return {
    type: DELETE_STEP
  }
}

function importLessons(lessons) {
  return {
    type: IMPORT_LESSONS,
    lessons
  }
}

function selectLesson(lessonIndex) {
  return {
    type: SELECT_LESSON,
    lessonIndex
  }
}

function selectStep(stepIndex) {
  return {
    type: SELECT_STEP,
    stepIndex
  }
}

function toggleEditing(editing) {
  return {
    type: TOGGLE_EDITING,
    editing
  }
}

function updateLesson(update) {
  return {
    type: UPDATE_LESSON,
    update
  }
}

function updateStep(update) {
  return {
    type: UPDATE_STEP,
    update
  }
}

module.exports = {
  toggleEditing,
  addLesson, selectLesson, updateLesson, deleteLesson, importLessons,
  addStep, selectStep, updateStep, deleteStep
}
<commit_msg>Use a factory function for simple arg-passing actions<commit_after>var {
  ADD_LESSON,
  ADD_STEP,
  DELETE_LESSON,
  DELETE_STEP,
  IMPORT_LESSONS,
  SELECT_LESSON,
  SELECT_STEP,
  TOGGLE_EDITING,
  UPDATE_LESSON,
  UPDATE_STEP
} = require('../ActionTypes')

var createAction = (type, ...props) =>
  (...args) =>
    props.reduce((action, prop, i) => (action[prop] = args[i], action), {type})

module.exports = {
  addLesson: createAction(ADD_LESSON),
  addStep: createAction(ADD_STEP),
  deleteLesson: createAction(DELETE_LESSON),
  deleteStep: createAction(DELETE_STEP),
  importLessons: createAction(IMPORT_LESSONS, 'lessons'),
  selectLesson: createAction(SELECT_LESSON, 'lessonIndex'),
  selectStep: createAction(SELECT_STEP, 'stepIndex'),
  toggleEditing: createAction(TOGGLE_EDITING, 'editing'),
  updateLesson: createAction(UPDATE_LESSON, 'update'),
  updateStep: createAction(UPDATE_STEP, 'update')
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Reddit Steam Group Comment Reporter
// @namespace    MilkGames
// @version      0.1
// @description  More options to delete comments
// @author       MilkGames -- Royalgamer06 for original script
// @match        *://steamcommunity.com/groups/reddit*
// @grant        none
// ==/UserScript==

(function() {
    var $comments = jQuery("[class*='commentthread_comment_timestamp']");
    if ($comments.length > 0) {
        $comments.after(' Report Comment');
    }

    jQuery(".repcomment").click(function() {
        var reason = prompt("Please enter the reason for reporting this comment.", "");
        if (reason) {
            var $this = jQuery(this);
            var author = $this.parent().find(".commentthread_author_link").attr("data-miniprofile");
            var date = $this.parent().find(".commentthread_comment_timestamp").attr("title");
            // Ugly code pls no to kill
            var datatosend = "comment=Author: " + author + "\n" + date + "\nReason: " + reason + "&count=15&sessionid=" + g_sessionID + "&extended_data=%7B%22topic_permissions%22%3A%7B%22can_view%22%3A1%2C%22can_post%22%3A1%2C%22can_reply%22%3A1%2C%22can_moderate%22%3A1%2C%22can_edit_others_posts%22%3A1%2C%22can_purge_topics%22%3A1%2C%22is_banned%22%3A0%2C%22can_delete%22%3A1%2C%22can_edit%22%3A1%7D%2C%22original_poster%22%3A144601510%2C%22forum_appid%22%3A0%2C%22forum_public%22%3A0%2C%22forum_type%22%3A%22General%22%2C%22forum_gidfeature%22%3A%220%22%7D&feature2=1456202492181247164&oldestfirst=true&include_raw=true";
            var xhr = new XMLHttpRequest();
            xhr.withCredentials = true;
            xhr.open("POST", "http://steamcommunity.com/comment/ForumTopic/post/103582791429796426/864943227215847264/");
            xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
            xhr.send(datatosend);
            ShowAlertDialog('Thank You!', 'Thank you for reporting a comment to the Reddit Group Moderators. \nYou may view your report here.');
            // IT WORKS! ... I hope.
        }
    });
})();
<commit_msg>Change description<commit_after>// ==UserScript==
// @name         Reddit Steam Group Comment Reporter
// @namespace    MilkGames
// @version      0.1
// @description  Report comments on the Reddit Steam group.
// @author       MilkGames -- Royalgamer06 for original script
// @match        *://steamcommunity.com/groups/reddit*
// @grant        none
// ==/UserScript==

(function() {
    var $comments = jQuery("[class*='commentthread_comment_timestamp']");
    if ($comments.length > 0) {
        $comments.after(' Report Comment');
    }

    jQuery(".repcomment").click(function() {
        var reason = prompt("Please enter the reason for reporting this comment.", "");
        if (reason) {
            var $this = jQuery(this);
            var author = $this.parent().find(".commentthread_author_link").attr("data-miniprofile");
            var date = $this.parent().find(".commentthread_comment_timestamp").attr("title");
            // Ugly code pls no to kill
            var datatosend = "comment=Author: " + author + "\n" + date + "\nReason: " + reason + "&count=15&sessionid=" + g_sessionID + "&extended_data=%7B%22topic_permissions%22%3A%7B%22can_view%22%3A1%2C%22can_post%22%3A1%2C%22can_reply%22%3A1%2C%22can_moderate%22%3A1%2C%22can_edit_others_posts%22%3A1%2C%22can_purge_topics%22%3A1%2C%22is_banned%22%3A0%2C%22can_delete%22%3A1%2C%22can_edit%22%3A1%7D%2C%22original_poster%22%3A144601510%2C%22forum_appid%22%3A0%2C%22forum_public%22%3A0%2C%22forum_type%22%3A%22General%22%2C%22forum_gidfeature%22%3A%220%22%7D&feature2=1456202492181247164&oldestfirst=true&include_raw=true";
            var xhr = new XMLHttpRequest();
            xhr.withCredentials = true;
            xhr.open("POST", "http://steamcommunity.com/comment/ForumTopic/post/103582791429796426/864943227215847264/");
            xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
            xhr.send(datatosend);
            ShowAlertDialog('Thank You!', 'Thank you for reporting a comment to the Reddit Group Moderators. \nYou may view your report here.');
            // IT WORKS! ... I hope.
        }
    });
})();
<|endoftext|>


<commit_before>app.controller('fornecedorController', ['$scope', '$rootScope', '$location', '$http', '$mdDialog', '$mdToast', 'FornecedorFactory', function($scope, $rootScope, $location, $http, $mdDialog, $mdToast, FornecedorFactory) {

    $scope.isLoading = true;

    if (!$rootScope.selectedIndex) {
        $rootScope.selectedIndex = 0;
    }

    $scope.setSelectedIndex = function (index) {
        $rootScope.selectedIndex = index;
    }

    $scope.fornecedores = [];
    $scope.fornecedores = FornecedorFactory.listar(
        {},
        function success() {
            $scope.isLoading = false;
        },
        function err() {
            console.log('Erro ao buscar fornecedores!');
        });

    $scope.editarFornecedor = function (fornecedorCNPJ) {
        $location.path('/fornecedores/editar/' + fornecedorCNPJ);
    };

    $scope.novoFornecedor = function () {
        $location.path('/fornecedores/novo');
    };

}]);

app.controller('formFornecedorController', ['$scope', '$routeParams', '$location', '$http', '$mdDialog', '$mdToast', '$document', 'FornecedorFactory', function($scope, $routeParams, $location, $http, $mdDialog, $mdToast, $document, FornecedorFactory) {

    $scope.showToast = function(message) {
        $mdToast.show(
            $mdToast.simple()
                .textContent(message)
                .hideDelay(3000)
                // .parent($document[0].querySelector('md-card'))
                .position('top right left')
                .theme("success-toast")
        );
    };

    $scope.buttonAction = 'Cadastrar';
    $scope.edicao = false;

    if($routeParams.cnpj) {
        $scope.fornecedor = FornecedorFactory.fornecedor(
            {cnpj: $routeParams.cnpj},
            function success() {

                $scope.fornecedor.cnpj = $scope.fornecedor.cnpj.substring(0, 2) + '.' + $scope.fornecedor.cnpj.substring(2, 5) + '.' + $scope.fornecedor.cnpj.substring(5, 8) + '/' + $scope.fornecedor.cnpj.substring(8, 12) + '-' + $scope.fornecedor.cnpj.substring(12, 14);

                $scope.fornecedor.endereco_CEP = $scope.fornecedor.endereco_CEP.substring(0, 2) + '.' + $scope.fornecedor.endereco_CEP.substring(2, 5) + '-' + $scope.fornecedor.endereco_CEP.substring(5, 8);

                $scope.edicao = true;
                $scope.buttonAction = 'Salvar';

            },
            function err() {
                console.log('Erro ao buscar fornecedor!');
            });
    }

    $scope.salvarFornecedor = function () {

        $scope.fornecedor.cnpj = $scope.fornecedor.cnpj.replace(/\D/g,'');
        $scope.fornecedor.endereco_CEP = $scope.fornecedor.endereco_CEP.replace(/\D/g,'');

        if($scope.edicao) {
            FornecedorFactory.editar(
                $scope.fornecedor,
                function success() {
                    $scope.showToast('Fornecedor editado com sucesso!');
                    $location.path('#/fornecedores');
                },
                function err() {
                    console.log('Erro ao editar fornecedor!');
                });
        } else {
            FornecedorFactory.novo(
                $scope.fornecedor,
                function success() {
                    $scope.showToast('Fornecedor cadastrado com sucesso!');
                    $location.path('#/fornecedores');
                },
                function err() {
                    console.log('Erro ao cadastrar fornecedor!');
                });
        }
    }

    // $scope.estados = [{sigla:"AC",nome:"Acre"},{sigla:"AL",nome:"Alagoas"},{sigla:"AP",nome:"Amapá"},{sigla:"AM",nome:"Amazonas"},{sigla:"BA",nome:"Bahia"},{sigla:"CE",nome:"Ceará"},{sigla:"DF",nome:"Distrito Federal"},{sigla:"ES",nome:"Espírito Santo"},{sigla:"GO",nome:"Goiás"},{sigla:"MA",nome:"Maranhão"},{sigla:"MT",nome:"Mato Grosso"},{sigla:"MS",nome:"Mato Grosso do Sul"},{sigla:"MG",nome:"Minas Gerais"},{sigla:"PA",nome:"Pará"},{sigla:"PB",nome:"Paraíba"},{sigla:"PR",nome:"Paraná"},{sigla:"PE",nome:"Pernambuco"},{sigla:"PI",nome:"Piauí"},{sigla:"RJ",nome:"Rio de Janeiro"},{sigla:"RN",nome:"Rio Grande do Norte"},{sigla:"RS",nome:"Rio Grande do Sul"},{sigla:"RO",nome:"Rondônia"},{sigla:"RR",nome:"Roraima"},{sigla:"SC",nome:"Santa Catarina"},{sigla:"SP",nome:"São Paulo"},{sigla:"SE",nome:"Sergipe"},{sigla:"TO",nome:"Tocantins"}];

}]);<commit_msg>Front-end: pequeno ajuste<commit_after>app.controller('fornecedorController', ['$scope', '$rootScope', '$location', '$http', '$mdDialog', '$mdToast', 'FornecedorFactory', function($scope, $rootScope, $location, $http, $mdDialog, $mdToast, FornecedorFactory) {

    $scope.isLoading = true;

    if (!$rootScope.selectedIndex) {
        $rootScope.selectedIndex = 0;
    }

    $scope.setSelectedIndex = function (index) {
        $rootScope.selectedIndex = index;
    }

    $scope.fornecedores = [];
    $scope.fornecedores = FornecedorFactory.listar(
        {},
        function success() {
            $scope.isLoading = false;
        },
        function err() {
            console.log('Erro ao buscar fornecedores!');
        });

    $scope.editarFornecedor = function (fornecedorCNPJ) {
        $location.path('/fornecedores/editar/' + fornecedorCNPJ);
    };

    $scope.novoFornecedor = function () {
        $location.path('/fornecedores/novo');
    };

}]);

app.controller('formFornecedorController', ['$scope', '$routeParams', '$location', '$http', '$mdDialog', '$mdToast', '$document', 'FornecedorFactory', function($scope, $routeParams, $location, $http, $mdDialog, $mdToast, $document, FornecedorFactory) {

    $scope.showToast = function(message) {
        $mdToast.show(
            $mdToast.simple()
                .textContent(message)
                .hideDelay(3000)
                // .parent($document[0].querySelector('md-card'))
                .position('top right left')
                .theme("success-toast")
        );
    };

    $scope.buttonAction = 'Cadastrar';
    $scope.edicao = false;

    if($routeParams.cnpj) {
        $scope.fornecedor = FornecedorFactory.fornecedor(
            {cnpj: $routeParams.cnpj},
            function success() {

                $scope.fornecedor.cnpj = $scope.fornecedor.cnpj.substring(0, 2) + '.' + $scope.fornecedor.cnpj.substring(2, 5) + '.' + $scope.fornecedor.cnpj.substring(5, 8) + '/' + $scope.fornecedor.cnpj.substring(8, 12) + '-' + $scope.fornecedor.cnpj.substring(12, 14);

                $scope.fornecedor.endereco_CEP = $scope.fornecedor.endereco_CEP.substring(0, 2) + '.' + $scope.fornecedor.endereco_CEP.substring(2, 5) + '-' + $scope.fornecedor.endereco_CEP.substring(5, 8);

                $scope.edicao = true;
                $scope.buttonAction = 'Salvar';

            },
            function err() {
                console.log('Erro ao buscar fornecedor!');
            });
    }

    $scope.salvarFornecedor = function () {

        $scope.fornecedor.cnpj = $scope.fornecedor.cnpj.replace(/\D/g,'');
        $scope.fornecedor.endereco_CEP = $scope.fornecedor.endereco_CEP.replace(/\D/g,'');

        if($scope.edicao) {
            FornecedorFactory.editar(
                $scope.fornecedor,
                function success() {
                    $scope.showToast('Fornecedor editado com sucesso!');
                    $location.path('/fornecedores');
                },
                function err() {
                    console.log('Erro ao editar fornecedor!');
                });
        } else {
            FornecedorFactory.novo(
                $scope.fornecedor,
                function success() {
                    $scope.showToast('Fornecedor cadastrado com sucesso!');
                    $location.path('/fornecedores');
                },
                function err() {
                    console.log('Erro ao cadastrar fornecedor!');
                });
        }
    }

    // $scope.estados = [{sigla:"AC",nome:"Acre"},{sigla:"AL",nome:"Alagoas"},{sigla:"AP",nome:"Amapá"},{sigla:"AM",nome:"Amazonas"},{sigla:"BA",nome:"Bahia"},{sigla:"CE",nome:"Ceará"},{sigla:"DF",nome:"Distrito Federal"},{sigla:"ES",nome:"Espírito Santo"},{sigla:"GO",nome:"Goiás"},{sigla:"MA",nome:"Maranhão"},{sigla:"MT",nome:"Mato Grosso"},{sigla:"MS",nome:"Mato Grosso do Sul"},{sigla:"MG",nome:"Minas Gerais"},{sigla:"PA",nome:"Pará"},{sigla:"PB",nome:"Paraíba"},{sigla:"PR",nome:"Paraná"},{sigla:"PE",nome:"Pernambuco"},{sigla:"PI",nome:"Piauí"},{sigla:"RJ",nome:"Rio de Janeiro"},{sigla:"RN",nome:"Rio Grande do Norte"},{sigla:"RS",nome:"Rio Grande do Sul"},{sigla:"RO",nome:"Rondônia"},{sigla:"RR",nome:"Roraima"},{sigla:"SC",nome:"Santa Catarina"},{sigla:"SP",nome:"São Paulo"},{sigla:"SE",nome:"Sergipe"},{sigla:"TO",nome:"Tocantins"}];

}]);<|endoftext|>