<commit_before>/*
 * This file is distributed under the MIT license.
 *
 * (c) Jan-Oliver Pantel <info@janpantel.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/*global angular, io */

(function (angular, io) {
    'use strict';
    var ngSailsModule = angular.module('ngSails', []);

    ngSailsModule.service('$sails', ['$rootScope', function ($rootScope) {

        var socket = io.connect(),
            connected = false,
            reconnectAttempt = null;

        socket.on('connect', function () {
            connected = true;
            if (typeof reconnectAttempt === 'function') {
                reconnectAttempt();
                reconnectAttempt = null;
            }
        });
        socket.on('disconnect', function () {
            connected = false;
        });

        return {
            reconnect: function (url, options) {
                var exec = function () {
                    socket.disconnect();
                    if (socket.socket !== undefined) {
                        socket.socket.connect(url, options);
                    }
                };
                //If we are connected, we can execute the reconnect right away.
                //If we are not, we queue it up, to execute it during to connect event occured.
                if (connected === true) {
                    exec();
                } else {
                    reconnectAttempt = exec;
                }

            },
            disconnect: function () {
                socket.disconnect();
            },
            emit: function (event, data) {
                socket.emit(event, data);
            },
            on: function (event, cb) {
                socket.on(event, function () {
                    var args = arguments;
                    $rootScope.$apply(function () {
                        cb.apply(socket, args);
                    });
                });
            },
            get: function (url, data, cb) {
                if (cb === undefined && typeof data === 'function') {
                    cb = data;
                    data = null;
                }
                socket.get(url, data, function () {
                    var args = arguments;
                    $rootScope.$apply(function () {
                        cb.apply(socket, args);
                    });
                });
            },
            post: function (url, data, cb) {
                if (cb === undefined && typeof data === 'function') {
                    cb = data;
                    data = null;
                }
                socket.post(url, data, function () {
                    var args = arguments;
                    $rootScope.$apply(function () {
                        cb.apply(socket, args);
                    });
                });
            },
            put: function (url, data, cb) {
                if (cb === undefined && typeof data === 'function') {
                    cb = data;
                    data = null;
                }
                socket.put(url, data, function () {
                    var args = arguments;
                    $rootScope.$apply(function () {
                        cb.apply(socket, args);
                    });
                });
            },
            'delete': function (url, data, cb) {
                if (cb === undefined && typeof data === 'function') {
                    cb = data;
                    data = null;
                }
                socket['delete'](url, data, function () {
                    var args = arguments;
                    $rootScope.$apply(function () {
                        cb.apply(socket, args);
                    });
                });
            }
        };
    }]);

}(angular, io));
<commit_msg>Add Feature: Promise<commit_after>/*
 * This file is distributed under the MIT license.
 *
 * (c) Jan-Oliver Pantel <info@janpantel.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/*global angular, io */

(function (angular, io) {
    'use strict';
    var ngSailsModule = angular.module('ngSails', []);

    ngSailsModule.service('$sails', ['$q', function ($q) {

        var socket = io.connect(),
            connected = false,
            reconnectAttempt = null;

        socket.on('connect', function () {
            connected = true;
            if (typeof reconnectAttempt === 'function') {
                reconnectAttempt();
                reconnectAttempt = null;
            }
        });
        socket.on('disconnect', function () {
            connected = false;
        });

        function defer() {
            var deferred = $q.defer(),
                promise = deferred.promise;

            promise.success = function (fn) {
                promise.then(function (response) {
                    fn(response);
                });
                return promise;
            };

            // Not sure this could ever happen... sails.io is currently handling errors, and we never reject below.
            promise.error = function (fn) {
                promise.then(null, function (response) {
                    fn(response);
                });
                return promise;
            };

            return deferred;
        }

        return {
            reconnect: function (url, options) {
                var exec = function () {
                    socket.disconnect();
                    if (socket.socket !== undefined) {
                        socket.socket.connect(url, options);
                    }
                };
                //If we are connected, we can execute the reconnect right away.
                //If we are not, we queue it up, to execute it during to connect event occured.
                if (connected === true) {
                    exec();
                } else {
                    reconnectAttempt = exec;
                }

            },
            disconnect: function () {
                socket.disconnect();
            },
            emit: function (event, data) {
                socket.emit(event, data);
            },
            on: function (event, cb) {
                var deferred = defer();
                deferred.promise.then(cb);
                socket.on(event, function () {
                    deferred.resolve.apply(socket, arguments);
                });
                return deferred.promise;
            },
            get: function (url, data, cb) {
                var deferred = defer();
                if (cb === undefined && typeof data === 'function') {
                    cb = data;
                    data = null;
                }
                deferred.promise.then(cb);
                socket.get(url, data, function () {
                    deferred.resolve.apply(socket, arguments);
                });
                return deferred.promise;
            },
            post: function (url, data, cb) {
                var deferred = defer();
                if (cb === undefined && typeof data === 'function') {
                    cb = data;
                    data = null;
                }
                deferred.promise.then(cb);
                socket.post(url, data, function () {
                    deferred.resolve.apply(socket, arguments);
                });
                return deferred.promise;
            },
            put: function (url, data, cb) {
                var deferred = defer();
                if (cb === undefined && typeof data === 'function') {
                    cb = data;
                    data = null;
                }
                deferred.promise.then(cb);
                socket.put(url, data, function () {
                    deferred.resolve.apply(socket, arguments);
                });
                return deferred.promise;
            },
            'delete': function (url, data, cb) {
                var deferred = defer();
                if (cb === undefined && typeof data === 'function') {
                    cb = data;
                    data = null;
                }
                deferred.promise.then(cb);
                socket['delete'](url, data, function () {
                    deferred.resolve.apply(socket, arguments);
                });
                return deferred.promise;
            }
        };

    }]);

}(angular, io));
<|endoftext|>


<commit_before>

export default class Socket {

    constructor(options = {}) {

        const { host, port } = options

        this.dataListener = null

        this.proxy = Ti.Network.Socket.createTCP({
            host: host,
            port: port,

            connected: (v) => {

                Ti.Stream.pump(v.socket, e => {
                    this.dataListener && this.dataListener('' + e.buffer)
                }, 1024, true)
            },

            error: (e) => {
                console.log(e)
            }
        })

        this.proxy.connect()
    }

    onData(fn) {
        if (typeof fn === 'function') {
            this.dataListener = fn
        }
    }

    end() {
        this.proxy.close()
    }
}
<commit_msg>improve socket class<commit_after>

export default class Socket {

    constructor(options = {}) {

        const { host, port } = options

        this.host = host
        this.port = port
        this.dataListener  = null
        this.errorListener = null
        this.proxy = this.createTCPSocket()
    }

    /**
     * connect to TCP server
     */
    connect() {
        this.proxy.connect()
    }

    /**
     * reconnect to TCP server
     */
    reconnect() {
        this.end()
        delete this.proxy
        this.proxy = this.createTCPSocket()
        this.connect()
    }

    /**
     * create socket proxy for TCP connection
     */
    createTCPSocket() {
        return Ti.Network.Socket.createTCP({
            host: this.host,
            port: this.port,

            connected: (v) => {

                Ti.Stream.pump(v.socket, e => {
                    // end signal
                    if (!e.buffer) {
                        return this.closeListener && this.closeListener()
                    }
                    this.dataListener && this.dataListener('' + e.buffer)
                }, 1024, true)
            },

            error: (e) => this.errorListener && this.errorListener(e)
        })
    }

    /**
     * set listener of data event
     * @param {function} fn
     */
    onData(fn) {
        if (typeof fn === 'function') this.dataListener = fn
    }

    /**
     * set listener of close event
     * @param {function} fn
     */
    onClose(fn) {
        if (typeof fn === 'function') this.closeListener = fn
    }

    /**
     * set listener of error event
     * @param {function} fn
     */
    onError(fn) {
        if (typeof fn === 'function') this.errorListener = fn
    }

    /**
     * close socket
     */
    end() {
        try { this.proxy.close() } catch (e) {}
    }
}
<|endoftext|>


<commit_before>// D3

const d3Chart = {}

d3Chart.create = function (el, props, state) {
  // svg canvas
  const svg = d3.select(el).append('svg')
    .attr('class', 'd3')
    .attr('width', props.width)
    .attr('height', props.height)

  // First point
  svg.append('g')
    .attr('class', 'd3-line')
  this.update(el, state)
}

d3Chart._scales = function (el, domain) {
  if (!domain) {
    return null
  }
  const width = el.offsetWidth
  const height = el.offsetHeight

  const x = d3.scaleLinear()
    .range([0, width - 20])
    .domain(domain.x)
  const y = d3.scaleLinear()
    .range([height * 0.89, 10])
    .domain(domain.y)
  return { x, y }
}

d3Chart.update = function (el, state) {

  // remove old line and axes
  d3.select(el).select('.d3-line').select('path').remove()
  d3.select(el).selectAll('.xAxis').remove()
  d3.select(el).selectAll('.yAxis').remove()

  // get canvas
  const svg = d3.select(el).select('svg')

  // axis
  const scales = this._scales(el, state.domain)
  const xAxis = d3.axisBottom().scale(scales.x)
  const yAxis = d3.axisLeft().scale(scales.y)
  svg.append('g')
    .attr('class','xAxis')
    .attr('transform','translate(0,' + svg.attr('height') + ')')
    .call(xAxis)
  svg.append('g')
    .attr('class','yAxis')
    .call(yAxis)

  // lines
  const g = d3.select(el).selectAll('.d3-line')
  const line = d3.line()
    .y(d => scales.y(Math.max( ...state.domain.y) - d.y))
    .x(d => scales.x(d.x))
  g.append('path')
    .datum(state.data)
    .attr('fill', 'none')
    .attr('stroke', 'steelblue')
    .attr('stroke-linejoin', 'round')
    .attr('stroke-width', 2)
    .attr('d', line)
}

const Chart = React.createClass({
  propTypes: {
    data: React.PropTypes.array,
    domain: React.PropTypes.object
  },
  componentDidMount: function () {
    const el = ReactDOM.findDOMNode(this)
    d3Chart.create(el, {
      width: '100%',
      height: 200 // percentage doesn't work well with height
    }, this.getChartState())
  },
  componentDidUpdate: function () {
    const el = ReactDOM.findDOMNode(this)
    d3Chart.update(el, this.getChartState())
  },
  getChartState: function () {
    return {
      data: this.props.data,
      domain: this.props.domain
    }
  },
  componentWillUnmount: function () {
    const el = ReactDOM.findDOMNode(this)
    d3Chart.destroy(el)
  },
  render: function () {
    return (

    )
  }
})

// React

const GraphDashboard = React.createClass({
  getInitialState: function () {
    return {
      data: [{
        id: 9,
        y: 0,
        x: 0 // start from max x axis (far right of the graph)
      }],
      domain: {
        x: [-10, 0],
        y: [0, 9]
      }
    }
  },
  componentWillMount: function () {
    this.ws = new WebSocket("ws://parrot:3000/")
    this.ws.onopen = () => this.ws.send("ok")
  },
  componentDidMount: function () {
    this.ws.onmessage = (event, flags) => {
      let stateData = this.state.data
      let stateDomain = this.state.domain
      stateDomain.x = stateDomain.x.map(e => e + 1)

      if (stateData.length > 10) {
        stateData.shift()
      }

      const newData = parseInt(event.data)
      stateData.push({
        id: stateData[stateData.length - 1].id + 1,
        x: stateData[stateData.length - 1].x + 1,
        y: newData
      })
      this.setState({
        data: stateData,
        domain: stateDomain
      })
    }
  },
  render: function () {
    return (

        <Chart
          data={this.state.data}
          domain={this.state.domain}
        />

    )
  }
})

ReactDOM.render(
  <GraphDashboard />,
  document.getElementById('content')
)
<commit_msg>make it easier to tweak x axis<commit_after>// D3

const XDOMAIN = 50 // how many tick do we want the x axis to have
const d3Chart = {}

d3Chart.create = function (el, props, state) {
  // svg canvas
  const svg = d3.select(el).append('svg')
    .attr('class', 'd3')
    .attr('width', props.width)
    .attr('height', props.height)

  // First point
  svg.append('g')
    .attr('class', 'd3-line')
  this.update(el, state)
}

d3Chart._scales = function (el, domain) {
  if (!domain) {
    return null
  }
  const width = el.offsetWidth
  const height = el.offsetHeight

  const x = d3.scaleLinear()
    .range([0, width - 20])
    .domain(domain.x)
  const y = d3.scaleLinear()
    .range([height * 0.89, 10])
    .domain(domain.y)
  return { x, y }
}

d3Chart.update = function (el, state) {

  // remove old line and axes
  d3.select(el).select('.d3-line').select('path').remove()
  d3.select(el).selectAll('.xAxis').remove()
  d3.select(el).selectAll('.yAxis').remove()

  // get canvas
  const svg = d3.select(el).select('svg')

  // axis
  const scales = this._scales(el, state.domain)
  const xAxis = d3.axisBottom().scale(scales.x)
  const yAxis = d3.axisLeft().scale(scales.y)
  svg.append('g')
    .attr('class','xAxis')
    .attr('transform','translate(0,' + svg.attr('height') + ')')
    .call(xAxis)
  svg.append('g')
    .attr('class','yAxis')
    .call(yAxis)

  // lines
  const g = d3.select(el).selectAll('.d3-line')
  const line = d3.line()
    .y(d => scales.y(Math.max( ...state.domain.y) - d.y))
    .x(d => scales.x(d.x))
  g.append('path')
    .datum(state.data)
    .attr('fill', 'none')
    .attr('stroke', 'steelblue')
    .attr('stroke-linejoin', 'round')
    .attr('stroke-width', 2)
    .attr('d', line)
}

const Chart = React.createClass({
  propTypes: {
    data: React.PropTypes.array,
    domain: React.PropTypes.object
  },
  componentDidMount: function () {
    const el = ReactDOM.findDOMNode(this)
    d3Chart.create(el, {
      width: '100%',
      height: 200 // percentage doesn't work well with height
    }, this.getChartState())
  },
  componentDidUpdate: function () {
    const el = ReactDOM.findDOMNode(this)
    d3Chart.update(el, this.getChartState())
  },
  getChartState: function () {
    return {
      data: this.props.data,
      domain: this.props.domain
    }
  },
  componentWillUnmount: function () {
    const el = ReactDOM.findDOMNode(this)
    d3Chart.destroy(el)
  },
  render: function () {
    return (

    )
  }
})

// React

const GraphDashboard = React.createClass({
  getInitialState: function () {
    return {
      data: [{
        id: 9,
        y: 0,
        x: 0 // start from max x axis (far right of the graph)
      }],
      domain: {
        x: [-XDOMAIN, 0],
        y: [0, 9]
      }
    }
  },
  componentWillMount: function () {
    this.ws = new WebSocket("ws://parrot:3000/")
    this.ws.onopen = () => this.ws.send("ok")
  },
  componentDidMount: function () {
    this.ws.onmessage = (event, flags) => {
      let stateData = this.state.data
      let stateDomain = this.state.domain
      stateDomain.x = stateDomain.x.map(e => e + 1)

      if (stateData.length > XDOMAIN) {
        stateData.shift()
      }

      const newData = parseInt(event.data)
      stateData.push({
        id: stateData[stateData.length - 1].id + 1,
        x: stateData[stateData.length - 1].x + 1,
        y: newData
      })
      this.setState({
        data: stateData,
        domain: stateDomain
      })
    }
  },
  render: function () {
    return (

        <Chart
          data={this.state.data}
          domain={this.state.domain}
        />

    )
  }
})

ReactDOM.render(
  <GraphDashboard />,
  document.getElementById('content')
)
<|endoftext|>


<commit_before>Package.describe({
  name: "babrahams:transactions",
  summary: "Undo/Redo stack based on transactions",
  version: "0.6.9",
  git: "https://github.com/jackadams/meteor-transactions.git"
});

Package.onUse(function (api, where) {

  api.versionsFrom("1.0");

  api.use('jquery', 'client');
  api.use('tracker', 'client');
  api.use('minimongo', 'client');
  api.use('templating', 'client');
  api.use('spacebars', 'client');
  api.use('underscore');
  api.use('mongo');
  api.use('accounts-base');
  api.imply('mongo');
  api.use('dburles:mongo-collection-instances@0.2.6');

  api.add_files('lib/transactions_client.html', 'client');
  api.add_files('lib/transactions_client.js', 'client');
  api.add_files('lib/transactions_client.css', 'client');
  api.add_files('lib/transactions_server.js', 'server');
  api.add_files('lib/transactions_common.js', ['client','server']);

  if (api.export) {
    api.export('tx');
  }

});<commit_msg>Added aldeed:collection2 as a weak dependency<commit_after>Package.describe({
  name: "babrahams:transactions",
  summary: "Undo/Redo stack based on transactions",
  version: "0.6.10",
  git: "https://github.com/jackadams/meteor-transactions.git"
});

Package.onUse(function (api, where) {

  api.versionsFrom("1.0");

  api.use('jquery', 'client');
  api.use('tracker', 'client');
  api.use('minimongo', 'client');
  api.use('templating', 'client');
  api.use('spacebars', 'client');
  api.use('underscore');
  api.use('mongo');
  api.use('accounts-base');
  api.imply('mongo');
  api.use('dburles:mongo-collection-instances@0.2.6');
  api.use('aldeed:collection2', ['client','server'], {weak:true});

  api.add_files('lib/transactions_client.html', 'client');
  api.add_files('lib/transactions_client.js', 'client');
  api.add_files('lib/transactions_client.css', 'client');
  api.add_files('lib/transactions_server.js', 'server');
  api.add_files('lib/transactions_common.js', ['client','server']);

  if (api.export) {
    api.export('tx');
  }

});<|endoftext|>


<commit_before>'use strict';

module.exports = ['$rootScope', function($rootScope) {
  var log = document.getElementById('log');

  return function (text,  mode, mustTranslate) {
    // special modes management
    var before = '', after = '', style = '';
    switch(mode) {
      case 'error':
        before = '[!] ';
        after = ' [!]';
        style = 'error';
        break;
      case 'success':
        style = 'success';
        break;
      case 'step':
        style = 'step';
        break;
      case 'separator':
        before = '
';
        break;
      case undefined:
        break;
      default:
        after = ' ' + mode;
    }
    // update log from scope
    log.innerHTML +=
      '' + before +
      (
        (mustTranslate)
        ? ($rootScope.translate(text) || '')
        : text
      )
      + after + '';
    // scroll to the bottom of the log area
    log.scrollTop = log.scrollHeight;
  };
}];
<commit_msg>Log translation bug fix<commit_after>'use strict';

module.exports = ['$rootScope', function($rootScope) {
  var log = document.getElementById('log');

  return function (text,  mode, mustTranslate) {
    // special modes management
    var before = '', after = '', style = '';
    switch(mode) {
      case 'error':
        before = '[!] ';
        after = ' [!]';
        style = 'error';
        break;
      case 'success':
        style = 'success';
        break;
      case 'step':
        style = 'step';
        break;
      case 'separator':
        before = '
';
        break;
      case undefined:
        break;
      default:
        after = ' ' + mode;
    }
    // update log from scope
    log.innerHTML +=
      '' + before +
      (
        (mustTranslate === undefined || mustTranslate)
        ? ($rootScope.translate(text) || '')
        : text
      )
      + after + '';
    // scroll to the bottom of the log area
    log.scrollTop = log.scrollHeight;
  };
}];
<|endoftext|>


<commit_before>/*
 Import all product specific js
 */
import $ from 'jquery';
import utils from '@bigcommerce/stencil-utils';
import 'foundation-sites/js/foundation/foundation';
import 'foundation-sites/js/foundation/foundation.reveal';
import ImageGallery from '../product/image-gallery';
import modalFactory from '../global/modal';
import _ from 'lodash';

// We want to ensure that the events are bound to a single instance of the product details component
let quantityInput = document.querySelector('.form-input--incrementTotal').value;
quantityInput = parseInt(quantityInput);

let previewModal = null;
let productSingleton = null;

utils.hooks.on('cart-item-add', (event, form) => {
    if (productSingleton) {
        productSingleton.addProductToCart(event, form);
    }
});

utils.hooks.on('product-option-change', (event, changedOption) => {
    if (productSingleton) {
        productSingleton.productOptionsChanged(event, changedOption);
    }
});

export default class Product {
    constructor($scope, context) {
        const productAttributesData = window.BCData.product_attributes || {};

        this.$scope = $scope;
        this.context = context;
        this.imageGallery = new ImageGallery($('[data-image-gallery]', this.$scope));
        this.imageGallery.init();
        this.listenQuantityChange();
        this.initRadioAttributes();

        const $form = $('form[data-cart-item-add]', $scope);
        const $productOptionsElement = $('[data-product-option-change]', $form);
        const hasOptions = $productOptionsElement.html().trim().length;

        // Update product attributes. If we're in quick view and the product has options, then also update the initial view in case items are oos
        if (_.isEmpty(productAttributesData) && hasOptions) {
            const $productId = $('[name="product_id"]', $form).val();

            utils.api.productAttributes.optionChange($productId, $form.serialize(), (err, response) => {
                const attributesData = response.data || {};

                this.updateProductAttributes(attributesData);
                this.updateView(attributesData);
            });
        } else {
            this.updateProductAttributes(productAttributesData);
        }

        $productOptionsElement.show();

        previewModal = modalFactory('#previewModal')[0];
        productSingleton = this;

        let startingPrice = document.querySelector('#productSalePrice').innerText.split('$')[1];
        startingPrice = parseFloat(startingPrice);
        this.updateQualifyForShipping();
    }

    /**
     * Since $productView can be dynamically inserted using render_with,
     * We have to retrieve the respective elements
     *
     * @param $scope
     */
    initQty(price) {
        console.log('changed the quantity: +1');
        console.log(quantityInput);
        this.updateQualifyForShipping();
        console.log($productQuantity.val());
        this.calculatePrice(price, $productQuantity.val);
    }

    getViewModel($scope) {
        return {
            $priceWithTax: $('[data-product-price-with-tax]', $scope),
            $rrpWithTax: $('[data-product-rrp-with-tax]', $scope),
            $priceWithoutTax: $('[data-product-price-without-tax]', $scope),
            $productQuantity: $('[id="#qty[]"]', $scope),
            $rrpWithoutTax: $('[data-product-rrp-without-tax]', $scope),
            $weight: $('.productView-info [data-product-weight]', $scope),
            $increments: $('.form-field--increments :input', $scope),
            $addToCart: $('#form-action-addToCart', $scope),
            $wishlistVariation: $('[data-wishlist-add] [name="variation_id"]', $scope),
            stock: {
                $container: $('.form-field--stock', $scope),
                $input: $('[data-product-stock]', $scope),
            },
            $sku: $('[data-product-sku]'),
            quantity: {
                $text: $('.incrementTotal', $scope),
                $input: $('[name=qty\\[\\]]', $scope),
            },
        };
    }

    /**
     *
     * Handle product options changes
     *
     */
    productOptionsChanged(event, changedOption) {
        const $changedOption = $(changedOption);
        const $form = $changedOption.parents('form');
        const productId = $('[name="product_id"]', $form).val();

        // Do not trigger an ajax request if it's a file or if the browser doesn't support FormData
        if ($changedOption.attr('type') === 'file' || window.FormData === undefined) {
            return;
        }

        utils.api.productAttributes.optionChange(productId, $form.serialize(), (err, response) => {
            const productAttributesData = response.data || {};

            this.updateProductAttributes(productAttributesData);
            this.updateView(productAttributesData);
        });
    }

    showProductImage(image) {
        if (_.isPlainObject(image)) {
            const zoomImageUrl = utils.tools.image.getSrc(
                image.data,
                this.context.themeSettings.zoom_size
            );

            const mainImageUrl = utils.tools.image.getSrc(
                image.data,
                this.context.themeSettings.product_size
            );

            this.imageGallery.setAlternateImage({
                mainImageUrl,
                zoomImageUrl,
            });
        } else {
            this.imageGallery.restoreImage();
        }
    }

    /**
     *
     * Handle action when the shopper clicks on + / - for quantity
     *
     */
    listenQuantityChange() {
        this.$scope.on('click', '[data-quantity-change] button', (event) => {
            event.preventDefault();
            const $target = $(event.currentTarget);
            const viewModel = this.getViewModel(this.$scope);
            const $input = viewModel.quantity.$input;
            const quantityMin = parseInt($input.data('quantity-min'), 10);
            const quantityMax = parseInt($input.data('quantity-max'), 10);

            let qty = parseInt($input.val(), 10);

            // If action is incrementing
            if ($target.data('action') === 'inc') {
                // If quantity max option is set
                if (quantityMax > 0) {
                    // Check quantity does not exceed max
                    if ((qty + 1) <= quantityMax) {
                        qty++;
                    }
                } else {
                    qty++;
                }
            } else if (qty > 1) {
                // If quantity min option is set
                if (quantityMin > 0) {
                    // Check quantity does not fall below min
                    if ((qty - 1) >= quantityMin) {
                        qty--;
                    }
                } else {
                    qty--;
                }
            }

            // update hidden input
            viewModel.quantity.$input.val(qty);
            // update text
            viewModel.quantity.$text.text(qty);
            console.log('changing qty values');
            let currentPrice = document.querySelector('#productSalePrice');
            currentPrice = currentPrice.innerText;
            currentPrice = currentPrice.split('$')[1];
            currentPrice = parseFloat(currentPrice);
            console.log(currentPrice);

            //console.log(this.getViewModel());
            this.updateQualifyForShipping();
            return qty;
        });

    }

    /**
     *
     * Add a product to cart
     *
     */
    addProductToCart(event, form) {
        const $addToCartBtn = $('#form-action-addToCart', $(event.target));
        const originalBtnVal = $addToCartBtn.val();
        const waitMessage = $addToCartBtn.data('waitMessage');

        // Do not do AJAX if browser doesn't support FormData
        if (window.FormData === undefined) {
            return;
        }

        // Prevent default
        event.preventDefault();

        $addToCartBtn
            .val(waitMessage)
            .prop('disabled', true);

        // Add item to cart
        utils.api.cart.itemAdd(new FormData(form), (err, response) => {
            const errorMessage = err || response.data.error;

            $addToCartBtn
                .val(originalBtnVal)
                .prop('disabled', false);

            // Guard statement
            if (errorMessage) {
                // Strip the HTML from the error message
                const tmp = document.createElement('DIV');
                tmp.innerHTML = errorMessage;

                alert(tmp.textContent || tmp.innerText);

                return;
            }

            // Open preview modal and update content
            previewModal.open();

            this.updateCartContent(previewModal, response.data.cart_item.hash);
        });
    }

    /**
     * Get cart contents
     *
     * @param {String} cartItemHash
     * @param {Function} onComplete
     */
    getCartContent(cartItemHash, onComplete) {
        const options = {
            template: 'cart/preview',
            params: {
                suggest: cartItemHash,
            },
            config: {
                cart: {
                    suggestions: {
                        limit: 4,
                    },
                },
            },
        };

        utils.api.cart.getContent(options, onComplete);
    }

    /**
     * Update cart content
     *
     * @param {Modal} modal
     * @param {String} cartItemHash
     * @param {Function} onComplete
     */
    updateCartContent(modal, cartItemHash, onComplete) {
        this.getCartContent(cartItemHash, (err, response) => {
            if (err) {
                return;
            }

            modal.updateContent(response);

            // Update cart counter
            const $body = $('body');
            const $cartQuantity = $('[data-cart-quantity]', modal.$content);
            const $cartCounter = $('.navUser-action .cart-count');
            const quantity = $cartQuantity.data('cart-quantity') || 0;

            $cartCounter.addClass('cart-count--positive');
            $body.trigger('cart-quantity-update', quantity);

            if (onComplete) {
                onComplete(response);
            }
        });
    }

    /**
     * Show an message box if a message is passed
     * Hide the box if the message is empty
     * @param  {String} message
     */
    showMessageBox(message) {
        const $messageBox = $('.productAttributes-message');

        if (message) {
            $('.alertBox-message', $messageBox).text(message);
            $messageBox.show();
        } else {
            $messageBox.hide();
        }
    }

    /**
     * Update the view of price, messages, SKU and stock options when a product option changes
     * @param  {Object} data Product attribute data
     */
    calculatePrice(price, qty, brand) {
        let freeShippingMinAmount = 249;

        //Console Log Tracking - Pre Function
        console.log('Brand: ' + brand);
        console.log('Individual Price: ' + price);
        console.log('Quantity Total: ' + qty);
        console.log('Price Total: ' + (qty*price));

        //
        if (price * qty >= freeShippingMinAmount) {
            if (brand !== 'spod' &&  brand !== 'maximus-3' && brand !== 'warrior products') {
                console.log('you getting free shipping');
            }
        } else {
            console.log('not qualified for free shipping.');
        }
    }

    updateQualifyForShipping() {
        //Scrape for Website Price
        let currentPrice = document.querySelector('#productSalePrice');
        currentPrice = currentPrice.innerText.split('$')[1];
        currentPrice = parseFloat(currentPrice);

        let brandName = document.querySelector('#productBrandName');
        brandName = brandName.innerText.trim('').toLowerCase();

        let quantityInput = document.querySelector('.form-input--incrementTotal').value;
        console.log(quantityInput);

        this.calculatePrice(currentPrice, quantityInput, brandName);
    }

    updatePriceView(viewModel, price) {
        if (price.with_tax) {
            viewModel.$priceWithTax.html(price.with_tax.formatted);
        }

        if (price.without_tax) {
            viewModel.$priceWithoutTax.html(price.without_tax.formatted);
        }

        if (price.rrp_with_tax) {
            viewModel.$rrpWithTax.html(price.rrp_with_tax.formatted);
        }

        if (price.rrp_without_tax) {
            viewModel.$rrpWithoutTax.html(price.rrp_without_tax.formatted);
        }
        console.log('something changed the price');
        this.updateQualifyForShipping();
    }

    /**
     * Update the view of price, messages, SKU and stock options when a product option changes
     * @param  {Object} data Product attribute data
     */
    updateView(data) {
        const viewModel = this.getViewModel(this.$scope);

        this.showMessageBox(data.stock_message || data.purchasing_message);

        if (_.isObject(data.price)) {
            this.updatePriceView(viewModel, data.price);
        }

        if (_.isObject(data.weight)) {
            viewModel.$weight.html(data.weight.formatted);
        }

        // Set variation_id if it exists for adding to wishlist
        if (data.variantId) {
            viewModel.$wishlistVariation.val(data.variantId);
        }

        // If SKU is available
        if (data.sku) {
            viewModel.$sku.text('SKU: ' + data.sku);
        }

        // if stock view is on (CP settings)
        if (viewModel.stock.$container.length && _.isNumber(data.stock)) {
            // if the stock container is hidden, show
            viewModel.stock.$container.removeClass('u-hiddenVisually');

            viewModel.stock.$input.text(data.stock);
        }

        if (!data.purchasable || !data.instock) {
            viewModel.$addToCart.prop('disabled', true);
            viewModel.$increments.prop('disabled', true);
        } else {
            viewModel.$addToCart.prop('disabled', false);
            viewModel.$increments.prop('disabled', false);
        }
    }

    /**
     * Hide or mark as unavailable out of stock attributes if enabled
     * @param  {Object} data Product attribute data
     */
    updateProductAttributes(data) {
        const behavior = data.out_of_stock_behavior;
        const inStockIds = data.in_stock_attributes;
        const outOfStockMessage = ` (${data.out_of_stock_message})`;

        this.showProductImage(data.image);

        if (behavior !== 'hide_option' && behavior !== 'label_option') {
            return;
        }

        $('[data-product-attribute-value]', this.$scope).each((i, attribute) => {
            const $attribute = $(attribute);
            const attrId = parseInt($attribute.data('product-attribute-value'), 10);

            if (inStockIds.indexOf(attrId) !== -1) {
                this.enableAttribute($attribute, behavior, outOfStockMessage);
            } else {
                this.disableAttribute($attribute, behavior, outOfStockMessage);
            }
        });
    }

    disableAttribute($attribute, behavior, outOfStockMessage) {
        if (this.getAttributeType($attribute) === 'set-select') {
            return this.disableSelectOptionAttribute($attribute, behavior, outOfStockMessage);
        }

        if (behavior === 'hide_option') {
            $attribute.hide();
        } else {
            $attribute.addClass('unavailable');
        }
    }

    disableSelectOptionAttribute($attribute, behavior, outOfStockMessage) {
        const $select = $attribute.parent();

        if (behavior === 'hide_option') {
            $attribute.toggleOption(false);
            // If the attribute is the selected option in a select dropdown, select the first option (MERC-639)
            if ($attribute.parent().val() === $attribute.attr('value')) {
                $select[0].selectedIndex = 0;
            }
        } else {
            $attribute.attr('disabled', 'disabled');
            $attribute.html($attribute.html().replace(outOfStockMessage, '') + outOfStockMessage);
        }
    }

    enableAttribute($attribute, behavior, outOfStockMessage) {
        if (this.getAttributeType($attribute) === 'set-select') {
            return this.enableSelectOptionAttribute($attribute, behavior, outOfStockMessage);
        }

        if (behavior === 'hide_option') {
            $attribute.show();
        } else {
            $attribute.removeClass('unavailable');
        }
    }

    enableSelectOptionAttribute($attribute, behavior, outOfStockMessage) {
        if (behavior === 'hide_option') {
            $attribute.toggleOption(true);
        } else {
            $attribute.removeAttr('disabled');
            $attribute.html($attribute.html().replace(outOfStockMessage, ''));
        }
    }

    getAttributeType($attribute) {
        const $parent = $attribute.closest('[data-product-attribute]');

        return $parent ? $parent.data('product-attribute') : null;
    }

    /**
     * Allow radio buttons to get deselected
     */
    initRadioAttributes() {
        $('[data-product-attribute] input[type="radio"]', this.$scope).each((i, radio) => {
            const $radio = $(radio);

            // Only bind to click once
            if ($radio.attr('data-state') !== undefined) {
                $radio.click(() => {
                    if ($radio.data('state') === true) {
                        $radio.prop('checked', false);
                        $radio.data('state', false);

                        $radio.change();
                    } else {
                        $radio.data('state', true);
                    }

                    this.initRadioAttributes();
                });
            }

            $radio.attr('data-state', $radio.prop('checked'));
        });
    }
}
<commit_msg>added placeholder for free shipping notification (line 345)<commit_after>/*
 Import all product specific js
 */
import $ from 'jquery';
import utils from '@bigcommerce/stencil-utils';
import 'foundation-sites/js/foundation/foundation';
import 'foundation-sites/js/foundation/foundation.reveal';
import ImageGallery from '../product/image-gallery';
import modalFactory from '../global/modal';
import _ from 'lodash';

// We want to ensure that the events are bound to a single instance of the product details component
let quantityInput = document.querySelector('.form-input--incrementTotal').value;
quantityInput = parseInt(quantityInput);

let previewModal = null;
let productSingleton = null;

utils.hooks.on('cart-item-add', (event, form) => {
    if (productSingleton) {
        productSingleton.addProductToCart(event, form);
    }
});

utils.hooks.on('product-option-change', (event, changedOption) => {
    if (productSingleton) {
        productSingleton.productOptionsChanged(event, changedOption);
    }
});

export default class Product {
    constructor($scope, context) {
        const productAttributesData = window.BCData.product_attributes || {};

        this.$scope = $scope;
        this.context = context;
        this.imageGallery = new ImageGallery($('[data-image-gallery]', this.$scope));
        this.imageGallery.init();
        this.listenQuantityChange();
        this.initRadioAttributes();

        const $form = $('form[data-cart-item-add]', $scope);
        const $productOptionsElement = $('[data-product-option-change]', $form);
        const hasOptions = $productOptionsElement.html().trim().length;

        // Update product attributes. If we're in quick view and the product has options, then also update the initial view in case items are oos
        if (_.isEmpty(productAttributesData) && hasOptions) {
            const $productId = $('[name="product_id"]', $form).val();

            utils.api.productAttributes.optionChange($productId, $form.serialize(), (err, response) => {
                const attributesData = response.data || {};

                this.updateProductAttributes(attributesData);
                this.updateView(attributesData);
            });
        } else {
            this.updateProductAttributes(productAttributesData);
        }

        $productOptionsElement.show();

        previewModal = modalFactory('#previewModal')[0];
        productSingleton = this;

        let startingPrice = document.querySelector('#productSalePrice').innerText.split('$')[1];
        startingPrice = parseFloat(startingPrice);
        this.updateQualifyForShipping();
    }

    /**
     * Since $productView can be dynamically inserted using render_with,
     * We have to retrieve the respective elements
     *
     * @param $scope
     */
    initQty(price) {
        console.log('changed the quantity: +1');
        console.log(quantityInput);
        this.updateQualifyForShipping();
        console.log($productQuantity.val());
        this.calculatePrice(price, $productQuantity.val);
    }

    getViewModel($scope) {
        return {
            $priceWithTax: $('[data-product-price-with-tax]', $scope),
            $rrpWithTax: $('[data-product-rrp-with-tax]', $scope),
            $priceWithoutTax: $('[data-product-price-without-tax]', $scope),
            $productQuantity: $('[id="#qty[]"]', $scope),
            $rrpWithoutTax: $('[data-product-rrp-without-tax]', $scope),
            $weight: $('.productView-info [data-product-weight]', $scope),
            $increments: $('.form-field--increments :input', $scope),
            $addToCart: $('#form-action-addToCart', $scope),
            $wishlistVariation: $('[data-wishlist-add] [name="variation_id"]', $scope),
            stock: {
                $container: $('.form-field--stock', $scope),
                $input: $('[data-product-stock]', $scope),
            },
            $sku: $('[data-product-sku]'),
            quantity: {
                $text: $('.incrementTotal', $scope),
                $input: $('[name=qty\\[\\]]', $scope),
            },
        };
    }

    /**
     *
     * Handle product options changes
     *
     */
    productOptionsChanged(event, changedOption) {
        const $changedOption = $(changedOption);
        const $form = $changedOption.parents('form');
        const productId = $('[name="product_id"]', $form).val();

        // Do not trigger an ajax request if it's a file or if the browser doesn't support FormData
        if ($changedOption.attr('type') === 'file' || window.FormData === undefined) {
            return;
        }

        utils.api.productAttributes.optionChange(productId, $form.serialize(), (err, response) => {
            const productAttributesData = response.data || {};

            this.updateProductAttributes(productAttributesData);
            this.updateView(productAttributesData);
        });
    }

    showProductImage(image) {
        if (_.isPlainObject(image)) {
            const zoomImageUrl = utils.tools.image.getSrc(
                image.data,
                this.context.themeSettings.zoom_size
            );

            const mainImageUrl = utils.tools.image.getSrc(
                image.data,
                this.context.themeSettings.product_size
            );

            this.imageGallery.setAlternateImage({
                mainImageUrl,
                zoomImageUrl,
            });
        } else {
            this.imageGallery.restoreImage();
        }
    }

    /**
     *
     * Handle action when the shopper clicks on + / - for quantity
     *
     */
    listenQuantityChange() {
        this.$scope.on('click', '[data-quantity-change] button', (event) => {
            event.preventDefault();
            const $target = $(event.currentTarget);
            const viewModel = this.getViewModel(this.$scope);
            const $input = viewModel.quantity.$input;
            const quantityMin = parseInt($input.data('quantity-min'), 10);
            const quantityMax = parseInt($input.data('quantity-max'), 10);

            let qty = parseInt($input.val(), 10);

            // If action is incrementing
            if ($target.data('action') === 'inc') {
                // If quantity max option is set
                if (quantityMax > 0) {
                    // Check quantity does not exceed max
                    if ((qty + 1) <= quantityMax) {
                        qty++;
                    }
                } else {
                    qty++;
                }
            } else if (qty > 1) {
                // If quantity min option is set
                if (quantityMin > 0) {
                    // Check quantity does not fall below min
                    if ((qty - 1) >= quantityMin) {
                        qty--;
                    }
                } else {
                    qty--;
                }
            }

            // update hidden input
            viewModel.quantity.$input.val(qty);
            // update text
            viewModel.quantity.$text.text(qty);
            console.log('changing qty values');
            let currentPrice = document.querySelector('#productSalePrice');
            currentPrice = currentPrice.innerText;
            currentPrice = currentPrice.split('$')[1];
            currentPrice = parseFloat(currentPrice);
            console.log(currentPrice);

            //console.log(this.getViewModel());
            this.updateQualifyForShipping();
            return qty;
        });

    }

    /**
     *
     * Add a product to cart
     *
     */
    addProductToCart(event, form) {
        const $addToCartBtn = $('#form-action-addToCart', $(event.target));
        const originalBtnVal = $addToCartBtn.val();
        const waitMessage = $addToCartBtn.data('waitMessage');

        // Do not do AJAX if browser doesn't support FormData
        if (window.FormData === undefined) {
            return;
        }

        // Prevent default
        event.preventDefault();

        $addToCartBtn
            .val(waitMessage)
            .prop('disabled', true);

        // Add item to cart
        utils.api.cart.itemAdd(new FormData(form), (err, response) => {
            const errorMessage = err || response.data.error;

            $addToCartBtn
                .val(originalBtnVal)
                .prop('disabled', false);

            // Guard statement
            if (errorMessage) {
                // Strip the HTML from the error message
                const tmp = document.createElement('DIV');
                tmp.innerHTML = errorMessage;

                alert(tmp.textContent || tmp.innerText);

                return;
            }

            // Open preview modal and update content
            previewModal.open();

            this.updateCartContent(previewModal, response.data.cart_item.hash);
        });
    }

    /**
     * Get cart contents
     *
     * @param {String} cartItemHash
     * @param {Function} onComplete
     */
    getCartContent(cartItemHash, onComplete) {
        const options = {
            template: 'cart/preview',
            params: {
                suggest: cartItemHash,
            },
            config: {
                cart: {
                    suggestions: {
                        limit: 4,
                    },
                },
            },
        };

        utils.api.cart.getContent(options, onComplete);
    }

    /**
     * Update cart content
     *
     * @param {Modal} modal
     * @param {String} cartItemHash
     * @param {Function} onComplete
     */
    updateCartContent(modal, cartItemHash, onComplete) {
        this.getCartContent(cartItemHash, (err, response) => {
            if (err) {
                return;
            }

            modal.updateContent(response);

            // Update cart counter
            const $body = $('body');
            const $cartQuantity = $('[data-cart-quantity]', modal.$content);
            const $cartCounter = $('.navUser-action .cart-count');
            const quantity = $cartQuantity.data('cart-quantity') || 0;

            $cartCounter.addClass('cart-count--positive');
            $body.trigger('cart-quantity-update', quantity);

            if (onComplete) {
                onComplete(response);
            }
        });
    }

    /**
     * Show an message box if a message is passed
     * Hide the box if the message is empty
     * @param  {String} message
     */
    showMessageBox(message) {
        const $messageBox = $('.productAttributes-message');

        if (message) {
            $('.alertBox-message', $messageBox).text(message);
            $messageBox.show();
        } else {
            $messageBox.hide();
        }
    }

    /**
     * Update the view of price, messages, SKU and stock options when a product option changes
     * @param  {Object} data Product attribute data
     */
    calculatePrice(price, qty, brand) {
        let freeShippingMinAmount = 249;

        //Console Log Tracking - Pre Function
        console.log('Brand: ' + brand);
        console.log('Individual Price: ' + price);
        console.log('Quantity Total: ' + qty);
        console.log('Price Total: ' + (qty*price));

        //
        if (price * qty >= freeShippingMinAmount) {
            if (brand !== 'spod' &&  brand !== 'maximus-3' && brand !== 'warrior products') {
                //Create Free Shipping Notification
                console.log('you getting free shipping');
            }
        } else {
            console.log('not qualified for free shipping.');
        }
    }

    updateQualifyForShipping() {
        //Scrape for Website Price
        let currentPrice = document.querySelector('#productSalePrice');
        currentPrice = currentPrice.innerText.split('$')[1];
        currentPrice = parseFloat(currentPrice);

        let brandName = document.querySelector('#productBrandName');
        brandName = brandName.innerText.trim('').toLowerCase();

        let quantityInput = document.querySelector('.form-input--incrementTotal').value;
        console.log(quantityInput);

        this.calculatePrice(currentPrice, quantityInput, brandName);
    }

    updatePriceView(viewModel, price) {
        if (price.with_tax) {
            viewModel.$priceWithTax.html(price.with_tax.formatted);
        }

        if (price.without_tax) {
            viewModel.$priceWithoutTax.html(price.without_tax.formatted);
        }

        if (price.rrp_with_tax) {
            viewModel.$rrpWithTax.html(price.rrp_with_tax.formatted);
        }

        if (price.rrp_without_tax) {
            viewModel.$rrpWithoutTax.html(price.rrp_without_tax.formatted);
        }
        console.log('something changed the price');
        this.updateQualifyForShipping();
    }

    /**
     * Update the view of price, messages, SKU and stock options when a product option changes
     * @param  {Object} data Product attribute data
     */
    updateView(data) {
        const viewModel = this.getViewModel(this.$scope);

        this.showMessageBox(data.stock_message || data.purchasing_message);

        if (_.isObject(data.price)) {
            this.updatePriceView(viewModel, data.price);
        }

        if (_.isObject(data.weight)) {
            viewModel.$weight.html(data.weight.formatted);
        }

        // Set variation_id if it exists for adding to wishlist
        if (data.variantId) {
            viewModel.$wishlistVariation.val(data.variantId);
        }

        // If SKU is available
        if (data.sku) {
            viewModel.$sku.text('SKU: ' + data.sku);
        }

        // if stock view is on (CP settings)
        if (viewModel.stock.$container.length && _.isNumber(data.stock)) {
            // if the stock container is hidden, show
            viewModel.stock.$container.removeClass('u-hiddenVisually');

            viewModel.stock.$input.text(data.stock);
        }

        if (!data.purchasable || !data.instock) {
            viewModel.$addToCart.prop('disabled', true);
            viewModel.$increments.prop('disabled', true);
        } else {
            viewModel.$addToCart.prop('disabled', false);
            viewModel.$increments.prop('disabled', false);
        }
    }

    /**
     * Hide or mark as unavailable out of stock attributes if enabled
     * @param  {Object} data Product attribute data
     */
    updateProductAttributes(data) {
        const behavior = data.out_of_stock_behavior;
        const inStockIds = data.in_stock_attributes;
        const outOfStockMessage = ` (${data.out_of_stock_message})`;

        this.showProductImage(data.image);

        if (behavior !== 'hide_option' && behavior !== 'label_option') {
            return;
        }

        $('[data-product-attribute-value]', this.$scope).each((i, attribute) => {
            const $attribute = $(attribute);
            const attrId = parseInt($attribute.data('product-attribute-value'), 10);

            if (inStockIds.indexOf(attrId) !== -1) {
                this.enableAttribute($attribute, behavior, outOfStockMessage);
            } else {
                this.disableAttribute($attribute, behavior, outOfStockMessage);
            }
        });
    }

    disableAttribute($attribute, behavior, outOfStockMessage) {
        if (this.getAttributeType($attribute) === 'set-select') {
            return this.disableSelectOptionAttribute($attribute, behavior, outOfStockMessage);
        }

        if (behavior === 'hide_option') {
            $attribute.hide();
        } else {
            $attribute.addClass('unavailable');
        }
    }

    disableSelectOptionAttribute($attribute, behavior, outOfStockMessage) {
        const $select = $attribute.parent();

        if (behavior === 'hide_option') {
            $attribute.toggleOption(false);
            // If the attribute is the selected option in a select dropdown, select the first option (MERC-639)
            if ($attribute.parent().val() === $attribute.attr('value')) {
                $select[0].selectedIndex = 0;
            }
        } else {
            $attribute.attr('disabled', 'disabled');
            $attribute.html($attribute.html().replace(outOfStockMessage, '') + outOfStockMessage);
        }
    }

    enableAttribute($attribute, behavior, outOfStockMessage) {
        if (this.getAttributeType($attribute) === 'set-select') {
            return this.enableSelectOptionAttribute($attribute, behavior, outOfStockMessage);
        }

        if (behavior === 'hide_option') {
            $attribute.show();
        } else {
            $attribute.removeClass('unavailable');
        }
    }

    enableSelectOptionAttribute($attribute, behavior, outOfStockMessage) {
        if (behavior === 'hide_option') {
            $attribute.toggleOption(true);
        } else {
            $attribute.removeAttr('disabled');
            $attribute.html($attribute.html().replace(outOfStockMessage, ''));
        }
    }

    getAttributeType($attribute) {
        const $parent = $attribute.closest('[data-product-attribute]');

        return $parent ? $parent.data('product-attribute') : null;
    }

    /**
     * Allow radio buttons to get deselected
     */
    initRadioAttributes() {
        $('[data-product-attribute] input[type="radio"]', this.$scope).each((i, radio) => {
            const $radio = $(radio);

            // Only bind to click once
            if ($radio.attr('data-state') !== undefined) {
                $radio.click(() => {
                    if ($radio.data('state') === true) {
                        $radio.prop('checked', false);
                        $radio.data('state', false);

                        $radio.change();
                    } else {
                        $radio.data('state', true);
                    }

                    this.initRadioAttributes();
                });
            }

            $radio.attr('data-state', $radio.prop('checked'));
        });
    }
}
<|endoftext|>


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

  angular.module('RkyApp.directives')
    .directive('d3Bars', ['d3', function(d3) {
      return {
        restrict: 'EA',
        scope: {
          data: "=",
          label: "@",
          onClick: "&"
        },
        link: function(scope, iElement, iAttrs) {
          var svg = d3.select(iElement[0])
              .append("svg")
              .attr("width", "100%");

          // on window resize, re-render d3 canvas
          window.onresize = function() {
            return scope.$apply();
          };
          scope.$watch(function(){
              return angular.element(window)[0].innerWidth;
            }, function(){
              return scope.render(scope.data);
            }
          );

          // watch for data changes and re-render
          scope.$watch('data', function(newVals, oldVals) {
            return scope.render(newVals);
          }, true);

          // define render function
          scope.render = function(data){
            // remove all previous items before render
            svg.selectAll("*").remove();

            // setup variables
            var width, height, max;
            width = d3.select(iElement[0])[0][0].offsetWidth - 20;
              // 20 is for margins and can be changed
            height = scope.data.length * 35;
              // 35 = 30(bar height) + 5(margin between bars)
            max = 98;
              // this can also be found dynamically when the data is not static
              // max = Math.max.apply(Math, _.map(data, ((val)-> val.count)))

            // set the height based on the calculations above
            svg.attr('height', height);

            //create the rectangles for the bar chart
            svg.selectAll("rect")
              .data(data)
              .enter()
                .append("rect")
                .on("click", function(d, i){return scope.onClick({item: d});})
                .attr("height", 30) // height of each bar
                .attr("width", 0) // initial width of 0 for transition
                .attr("x", 10) // half of the 20 side margin specified above
                .attr("y", function(d, i){
                  return i * 35;
                }) // height + margin between bars
                .transition()
                  .duration(1000) // time of duration
                  .attr("width", function(d){
                    return d.value/(max/width);
                  }); // width based on scale

            svg.selectAll("text")
              .data(data)
              .enter()
                .append("text")
                .attr("fill", "#fff")
                .attr("y", function(d, i){return i * 35 + 22;})
                .attr("x", 15)
                .text(function(d){return d[scope.label];});

          };
        }
      };
    }]);

}());

// -- by e-Coucou

(function () {
  'use strict';

  angular.module('RkyApp.directives')
    .directive('d3Lines', ['d3', function(d3) {
      return {
        restrict: 'EA',
        scope: {
          data: "=",
          label: "@",
          moyn: "=",
          onClick: "&"
        },
        link: function(scope, iElement, iAttrs) {
        // Dimensions.
		var width = d3.select(iElement[0])[0][0].offsetWidth;
		console.log(width);
        var margin = {top: 20, right: 20, bottom: 30, left: 40},
            width =  width - margin.right -margin.left,
            height = 400 - margin.top - margin.bottom;
        // creation du conteneur
        var svg = d3.select(iElement[0])
              .append("svg")
              .attr("width", "100%")
//              .attr("width", width + margin.left + margin.right)
              .attr("height", height + margin.top + margin.bottom)
//              .attr("height", "100%")
            .append("g")
              .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
console.log(d3.select(iElement[0]).node.offsetWidth);
console.log(d3.select(iElement[0])[0][0].offsetHeight);

          // on window resize, re-render d3 canvas
          window.onresize = function() {
            return scope.$apply();
          };
          scope.$watch(function(){
              return angular.element(window)[0].innerWidth;
            }, function(){
              return scope.render(scope.data);
            }
          );

          // watch for data changes and re-render
          scope.$watch('data', function(newVals, oldVals) {
            return scope.render(newVals);
          }, true);
          // define render function
          scope.render = function(data,moyn){

            // setup variables
            var max,maxi, min,mini;
            var padding = 1;

            // accessor
            function x(d,i) { return i * (width / data.length);}
            function y(d) { return (height - (d.value-min)/((max-min)/height)); }
            function h(d) { return ((d.value-min)/((max-min)/height));}

            // fonction
            function info(d,i) {
              var s_date = d.date.split('/');
              var s_heure = d.heure.split(':');
              var date_text = s_date[1]+'/'+s_date[0]+'\n'+s_heure[0]+':'+s_heure[1];
              label.text(Math.round(d.value*100)/100) ;
              var datac = [ { "x" : x(d,i), "y" : 20 }, { "x" : x(d,i), "y" : height } ];
              d3.selectAll(".curseur").remove();
              d3.selectAll(".date").remove();
              var datadate = [{"x" : x(d,i), "text":d.heure}];
              svg.append("text")
                 .data(datadate)
                 .attr("class", "date label")
                 .attr("text-anchor", "middle")
                 .attr("x",  function(d) {return d.x;} )
                 .attr("y", 0)
                 .text(function(d) {return date_text;});

              svg.append("path")
                .datum(datac)
                .attr("class", "curseur")
                .attr("d", curseur);
              }
            // remove all previous items before render
            svg.selectAll("*").remove();

//            console.log(height,width);
              // 20 is for margins and can be changed
//            width = 1160 ;//scope.data.length * 35;
//            width = 1000;
//            height = 450 ;
            if (data.length > 500 ) { padding = 0; } // no padding si trop de data
            maxi = Math.max.apply(Math, data.map(function(x) {return x.value; }));
            mini = Math.min.apply(Math, data.map(function(x) {return x.value; }));
//            console.log("max: ",maxi,"min: ",mini, "moyenne: ",scope.moyn);

            max = maxi + 0.07 * (maxi-mini);
            min = mini - 0.15 * (maxi-mini);

            // set the height based on the calculations above
            svg.attr('height', height)
               .attr('width',  width);

// Add the year label; the value is set on transition.
var label = svg.append("text")
    .attr("class", "year label")
    .attr("text-anchor", "end")
    .attr("y",  55)
    .attr("x", width)
    .text('VALEUR');

var curseur = d3.svg.line()
    .x(function(d) { return d.x; })
    .y(function(d) { return d.y; });

var repere_min = d3.svg.line()
    .x(function(d) { return d.x; })
    .y(function(d) { return d.y; });

var repere_max = d3.svg.line()
    .x(function(d) { return d.x; })
    .y(function(d) { return d.y; });

var repere_moy = d3.svg.line()
    .x(function(d) { return d.x; })
    .y(function(d) { return d.y; });

// Add a y-axis label.
var yScale = d3.scale.linear().domain([max, min]).range([0,height]),
    yAxis = d3.svg.axis().scale(yScale).orient("left");

svg.append("g")
    .attr("class", "y axis")
    .call(yAxis);

svg.append("text")
    .attr("class", "y label")
    .attr("text-anchor", "end")
    .attr("y", 6)
    .attr("dy", ".75em")
    .attr("transform", "rotate(-90)")
    .text("mesure");

            //create the rectangles for the bar chart
            svg.selectAll("rect")
              .data(data)
              .enter()
                .append("rect")
                .on("click", function(d, i){return scope.onClick({item: d});})
                .on("mouseover",function (d,i) { return info(d,i);})
                .attr("height", 0) // height of each bar
                .attr("width", width / data.length - padding)
                .attr("x", function(d,i) { return x(d, i);})  // height + margin between bars
                .attr("fill","yellow")
                .transition()
                  .duration(3000) // time of duration
                  .attr("stroke-width",0)
                  .attr("fill", function(d) {
                    var val = ((d.value -min)/((max-min)/16));
                    return "rgb(10, 160, " + val*16 + ")";
                    })
                  .attr("height", function (d) { return h(d); }) // half of the 20 side margin specified above
                  .attr("y", function (d) { return y(d);}); // width based on scale

            // position des repères
            var ordonne = height - (mini-min)/((max-min)/height);
            var datac = [ { "x" : 0, "y" : ordonne }, { "x" : width, "y" : ordonne } ];
            d3.selectAll(".repere_min").remove();
            svg.append("path")
              .datum(datac)
              .attr("class", "repere")
              .style("stroke-dasharray", ("10,5,2,5"))
              .attr("d", repere_min);
            ordonne = height - (maxi-min)/((max-min)/height);
            datac = [ { "x" : 0, "y" : ordonne }, { "x" : width, "y" : ordonne } ];
            d3.selectAll(".repere_max").remove();
            svg.append("path")
              .datum(datac)
              .attr("class", "repere")
              .style("stroke-dasharray", ("10,5,2,5"))
              .attr("d", repere_max);
            ordonne = height - (scope.moyn-min)/((max-min)/height);
            datac = [ { "x" : 0, "y" : ordonne }, { "x" : width, "y" : ordonne } ];
            d3.selectAll(".repere_moy").remove();
            svg.append("path")
              .datum(datac)
              .attr("class", "repere")
              .style("stroke-dasharray", ("10,5,2,5"))
              .attr("d", repere_moy);

            svg.selectAll("text")
              .data(data)
              .enter()
                .append("text")
                .attr("fill", "#fff")
                .attr("y", function(d, i){return i * 35 + 22;})
                .attr("x", 15)
                .text(function(d){return d[scope.label];});

          };
        }
      };
    }]);

}());<commit_msg>ielement<commit_after>(function () {
  'use strict';

  angular.module('RkyApp.directives')
    .directive('d3Bars', ['d3', function(d3) {
      return {
        restrict: 'EA',
        scope: {
          data: "=",
          label: "@",
          onClick: "&"
        },
        link: function(scope, iElement, iAttrs) {
          var svg = d3.select(iElement[0])
              .append("svg")
              .attr("width", "100%");

          // on window resize, re-render d3 canvas
          window.onresize = function() {
            return scope.$apply();
          };
          scope.$watch(function(){
              return angular.element(window)[0].innerWidth;
            }, function(){
              return scope.render(scope.data);
            }
          );

          // watch for data changes and re-render
          scope.$watch('data', function(newVals, oldVals) {
            return scope.render(newVals);
          }, true);

          // define render function
          scope.render = function(data){
            // remove all previous items before render
            svg.selectAll("*").remove();

            // setup variables
            var width, height, max;
            width = d3.select(iElement[0])[0][0].offsetWidth - 20;
              // 20 is for margins and can be changed
            height = scope.data.length * 35;
              // 35 = 30(bar height) + 5(margin between bars)
            max = 98;
              // this can also be found dynamically when the data is not static
              // max = Math.max.apply(Math, _.map(data, ((val)-> val.count)))

            // set the height based on the calculations above
            svg.attr('height', height);

            //create the rectangles for the bar chart
            svg.selectAll("rect")
              .data(data)
              .enter()
                .append("rect")
                .on("click", function(d, i){return scope.onClick({item: d});})
                .attr("height", 30) // height of each bar
                .attr("width", 0) // initial width of 0 for transition
                .attr("x", 10) // half of the 20 side margin specified above
                .attr("y", function(d, i){
                  return i * 35;
                }) // height + margin between bars
                .transition()
                  .duration(1000) // time of duration
                  .attr("width", function(d){
                    return d.value/(max/width);
                  }); // width based on scale

            svg.selectAll("text")
              .data(data)
              .enter()
                .append("text")
                .attr("fill", "#fff")
                .attr("y", function(d, i){return i * 35 + 22;})
                .attr("x", 15)
                .text(function(d){return d[scope.label];});

          };
        }
      };
    }]);

}());

// -- by e-Coucou

(function () {
  'use strict';

  angular.module('RkyApp.directives')
    .directive('d3Lines', ['d3', function(d3) {
      return {
        restrict: 'EA',
        scope: {
          data: "=",
          label: "@",
          moyn: "=",
          onClick: "&"
        },
        link: function(scope, iElement, iAttrs) {
        // Dimensions.
		var width = (iElement[0])[0][0].getBoundingClientRect();
		console.log(width);
        var margin = {top: 20, right: 20, bottom: 30, left: 40},
            width =  width - margin.right -margin.left,
            height = 400 - margin.top - margin.bottom;
        // creation du conteneur
        var svg = d3.select(iElement[0])
              .append("svg")
              .attr("width", "100%")
//              .attr("width", width + margin.left + margin.right)
              .attr("height", height + margin.top + margin.bottom)
//              .attr("height", "100%")
            .append("g")
              .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
console.log(d3.select(iElement[0]).node.offsetWidth);
console.log(d3.select(iElement[0])[0][0].offsetHeight);

          // on window resize, re-render d3 canvas
          window.onresize = function() {
            return scope.$apply();
          };
          scope.$watch(function(){
              return angular.element(window)[0].innerWidth;
            }, function(){
              return scope.render(scope.data);
            }
          );

          // watch for data changes and re-render
          scope.$watch('data', function(newVals, oldVals) {
            return scope.render(newVals);
          }, true);
          // define render function
          scope.render = function(data,moyn){

            // setup variables
            var max,maxi, min,mini;
            var padding = 1;

            // accessor
            function x(d,i) { return i * (width / data.length);}
            function y(d) { return (height - (d.value-min)/((max-min)/height)); }
            function h(d) { return ((d.value-min)/((max-min)/height));}

            // fonction
            function info(d,i) {
              var s_date = d.date.split('/');
              var s_heure = d.heure.split(':');
              var date_text = s_date[1]+'/'+s_date[0]+'\n'+s_heure[0]+':'+s_heure[1];
              label.text(Math.round(d.value*100)/100) ;
              var datac = [ { "x" : x(d,i), "y" : 20 }, { "x" : x(d,i), "y" : height } ];
              d3.selectAll(".curseur").remove();
              d3.selectAll(".date").remove();
              var datadate = [{"x" : x(d,i), "text":d.heure}];
              svg.append("text")
                 .data(datadate)
                 .attr("class", "date label")
                 .attr("text-anchor", "middle")
                 .attr("x",  function(d) {return d.x;} )
                 .attr("y", 0)
                 .text(function(d) {return date_text;});

              svg.append("path")
                .datum(datac)
                .attr("class", "curseur")
                .attr("d", curseur);
              }
            // remove all previous items before render
            svg.selectAll("*").remove();

//            console.log(height,width);
              // 20 is for margins and can be changed
//            width = 1160 ;//scope.data.length * 35;
//            width = 1000;
//            height = 450 ;
            if (data.length > 500 ) { padding = 0; } // no padding si trop de data
            maxi = Math.max.apply(Math, data.map(function(x) {return x.value; }));
            mini = Math.min.apply(Math, data.map(function(x) {return x.value; }));
//            console.log("max: ",maxi,"min: ",mini, "moyenne: ",scope.moyn);

            max = maxi + 0.07 * (maxi-mini);
            min = mini - 0.15 * (maxi-mini);

            // set the height based on the calculations above
            svg.attr('height', height)
               .attr('width',  width);

// Add the year label; the value is set on transition.
var label = svg.append("text")
    .attr("class", "year label")
    .attr("text-anchor", "end")
    .attr("y",  55)
    .attr("x", width)
    .text('VALEUR');

var curseur = d3.svg.line()
    .x(function(d) { return d.x; })
    .y(function(d) { return d.y; });

var repere_min = d3.svg.line()
    .x(function(d) { return d.x; })
    .y(function(d) { return d.y; });

var repere_max = d3.svg.line()
    .x(function(d) { return d.x; })
    .y(function(d) { return d.y; });

var repere_moy = d3.svg.line()
    .x(function(d) { return d.x; })
    .y(function(d) { return d.y; });

// Add a y-axis label.
var yScale = d3.scale.linear().domain([max, min]).range([0,height]),
    yAxis = d3.svg.axis().scale(yScale).orient("left");

svg.append("g")
    .attr("class", "y axis")
    .call(yAxis);

svg.append("text")
    .attr("class", "y label")
    .attr("text-anchor", "end")
    .attr("y", 6)
    .attr("dy", ".75em")
    .attr("transform", "rotate(-90)")
    .text("mesure");

            //create the rectangles for the bar chart
            svg.selectAll("rect")
              .data(data)
              .enter()
                .append("rect")
                .on("click", function(d, i){return scope.onClick({item: d});})
                .on("mouseover",function (d,i) { return info(d,i);})
                .attr("height", 0) // height of each bar
                .attr("width", width / data.length - padding)
                .attr("x", function(d,i) { return x(d, i);})  // height + margin between bars
                .attr("fill","yellow")
                .transition()
                  .duration(3000) // time of duration
                  .attr("stroke-width",0)
                  .attr("fill", function(d) {
                    var val = ((d.value -min)/((max-min)/16));
                    return "rgb(10, 160, " + val*16 + ")";
                    })
                  .attr("height", function (d) { return h(d); }) // half of the 20 side margin specified above
                  .attr("y", function (d) { return y(d);}); // width based on scale

            // position des repères
            var ordonne = height - (mini-min)/((max-min)/height);
            var datac = [ { "x" : 0, "y" : ordonne }, { "x" : width, "y" : ordonne } ];
            d3.selectAll(".repere_min").remove();
            svg.append("path")
              .datum(datac)
              .attr("class", "repere")
              .style("stroke-dasharray", ("10,5,2,5"))
              .attr("d", repere_min);
            ordonne = height - (maxi-min)/((max-min)/height);
            datac = [ { "x" : 0, "y" : ordonne }, { "x" : width, "y" : ordonne } ];
            d3.selectAll(".repere_max").remove();
            svg.append("path")
              .datum(datac)
              .attr("class", "repere")
              .style("stroke-dasharray", ("10,5,2,5"))
              .attr("d", repere_max);
            ordonne = height - (scope.moyn-min)/((max-min)/height);
            datac = [ { "x" : 0, "y" : ordonne }, { "x" : width, "y" : ordonne } ];
            d3.selectAll(".repere_moy").remove();
            svg.append("path")
              .datum(datac)
              .attr("class", "repere")
              .style("stroke-dasharray", ("10,5,2,5"))
              .attr("d", repere_moy);

            svg.selectAll("text")
              .data(data)
              .enter()
                .append("text")
                .attr("fill", "#fff")
                .attr("y", function(d, i){return i * 35 + 22;})
                .attr("x", 15)
                .text(function(d){return d[scope.label];});

          };
        }
      };
    }]);

}());<|endoftext|>


<commit_before>import React from 'react'
import { LineChart, Line, CartesianGrid, XAxis, YAxis, Tooltip } from 'recharts'
import SummaryChartIcon from './SummaryChartIcon'
import moment from 'moment'

const SummaryChart = ({ forecastHourly }) => {
  let forecastHourlyFormat = forecastHourly.map(data => {
    return {
      momentId: data.momentId,
      timespan: data.timespan,
      temp: Math.round(data.temp),
      weatherIconCode: data.weatherIconCode,
      rain: data.rain,
      hour: moment.unix(data.timespan).format('hh A')
    }
  })
  return (
    <LineChart width={800} height={500} data={forecastHourlyFormat} margin={{ top: 20, right: 20, bottom: 20, left: 20 }}>
      <Line type='monotone' dataKey='temp' stroke='#8884d8' dot={<SummaryChartIcon />} />
      <CartesianGrid stroke='#ccc' strokeDasharray='5 5' />
      <XAxis dataKey='hour' />
      <YAxis dataKey='temp' />
      <Tooltip />
    </LineChart>
  )
}

// const SummaryChart = ({ forecastHourly }) => (
//   <LineChart width={800} height={500} data={forecastHourly} margin={{ top: 20, right: 20, bottom: 20, left: 20 }}>
//     <Line type='monotone' dataKey='temp' stroke='#8884d8' dot={<SummaryChartIcon />} />
//     <CartesianGrid stroke='#ccc' strokeDasharray='5 5' />
//     <XAxis dataKey='hour' />
//     <Tooltip />
//   </LineChart>
// )

export default SummaryChart
<commit_msg>Add custom tooltip<commit_after>import React from 'react'
import { LineChart, Line, CartesianGrid, XAxis, YAxis, Tooltip } from 'recharts'
import SummaryChartIcon from './SummaryChartIcon'
import moment from 'moment'

const CustomTooltip = React.createClass({
  render () {
    const { payload, active } = this.props
    if (!active) {
      return null
    }
    const data = payload[0].payload
    const hour = data.hour
    const temp = data.temp
    const rain = data.rain ? payload[0].payload.rain.toFixed(1) : 'N/A'
    const day = data.day
    return (

          {day}

            Hour:

            {hour}

          Temp:

            {temp} °

          Rain:

            {rain}

    )
  }
})

const SummaryChart = ({ forecastHourly }) => {
  let forecastHourlyFormat = forecastHourly.map(data => {
    return {
      momentId: data.momentId,
      timespan: data.timespan,
      temp: Math.round(data.temp),
      weatherIconCode: data.weatherIconCode,
      rain: data.rain,
      day: moment.unix(data.timespan).format('ddd, MMM D'),
      hour: moment.unix(data.timespan).format('hh A')
    }
  })
  console.log(forecastHourly)
  return (
    <LineChart width={900} height={450} data={forecastHourlyFormat}>
      <Line type='monotone' dataKey='temp' stroke='#8884d8' dot={<SummaryChartIcon />} />
      <CartesianGrid stroke='#ccc' strokeDasharray='5 5' />
      <XAxis dataKey='hour' />
      <YAxis dataKey='temp' />
      <Tooltip content={<CustomTooltip />} />
    </LineChart>
  )
}

// const SummaryChart = ({ forecastHourly }) => (
//   <LineChart width={800} height={500} data={forecastHourly} margin={{ top: 20, right: 20, bottom: 20, left: 20 }}>
//     <Line type='monotone' dataKey='temp' stroke='#8884d8' dot={<SummaryChartIcon />} />
//     <CartesianGrid stroke='#ccc' strokeDasharray='5 5' />
//     <XAxis dataKey='hour' />
//     <Tooltip />
//   </LineChart>
// )

export default SummaryChart
<|endoftext|>


<commit_before>var exec = require('child_process').exec;
var gitStreaming = require('../util/git-streaming.js');
var gulp = require('gulp');
var highland = require('highland');
var killStream = require('../util/kill-stream.js');
var packageJson = require('../../package.json');
var utils = require('../util/utils.js');

// publish to github repo, github pages and npm.
gulp.task('publish', ['sync-tag-version'], function publish(callback) {
  highland(gitStreaming.push('origin', 'master'))
  .errors(killStream)
  .flatMap(gitStreaming.push('origin', packageJson.version))
  .errors(killStream)
  .flatMap(gitStreaming.checkout('gh-pages'))
  .flatMap(gitStreaming.merge('master'))
  .flatMap(gitStreaming.push('origin', 'gh-pages'))
  .flatMap(gitStreaming.checkout('master'))
  /*
  //* TODO why does this take 1.57 min to complete?
  .flatMap(function() {
    return utils.createExecStream('npm publish');
  })
  .map(function(stdout, stderr) {
    return stdout;
  })
  //*/
  .each(function(data) {
    return callback(null, data);
  });
});
<commit_msg>Try avoiding pushing the tag to gh before npm publish<commit_after>var exec = require('child_process').exec;
var gitStreaming = require('../util/git-streaming.js');
var gulp = require('gulp');
var highland = require('highland');
var killStream = require('../util/kill-stream.js');
var packageJson = require('../../package.json');
var utils = require('../util/utils.js');

// publish to github repo, github pages and npm.
gulp.task('publish', ['sync-tag-version'], function publish(callback) {
  highland(gitStreaming.push('origin', 'master'))
  .errors(killStream)
  //.flatMap(gitStreaming.push('origin', packageJson.version))
  .errors(killStream)
  .flatMap(gitStreaming.checkout('gh-pages'))
  .flatMap(gitStreaming.merge('master'))
  .flatMap(gitStreaming.push('origin', 'gh-pages'))
  .flatMap(gitStreaming.checkout('master'))
  //*
  //* TODO why does this take 1.57 min to complete?
  .flatMap(function() {
    return utils.createExecStream('npm publish');
  })
  .map(function(stdout, stderr) {
    return stdout;
  })
  //*/
  .each(function(data) {
    return callback(null, data);
  });
});
<|endoftext|>


<commit_before>import React from 'react';
import { Component } from 'react';
import { connect } from 'react-redux';
import ChallengeNav from './ChallengeNav';
import ChallengeDetails from './ChallengeDetails';
import ChallengeComments from './ChallengeComments';

class Challenge extends Component {
    componentDidMount() {
        const id = this.props.params.id;
        const dispatch = this.props.dispatch;
        dispatch(getChallenge(id));
        //console.log('did');
    }

    //shouldComponentUpdate(nextProps, nextState) {
    //    console.log(this.props.routeParams.id, nextProps.routeParams.id);
    //    return nextProps.challenge.id !== this.props.challenge.id;
    //}

    render() {
        return (

                <ChallengeNav />
                <ChallengeDetails {...this.props.challenge} />
                <ChallengeComments />

        );
    }
}

const mapStateToProps = ({ challenge }) => ({ challenge });

function getChallenge(id) {
    return function fetchChallenge(dispatch) {
        fetch('http://localhost:9000/api/challenge/' + id)
        //fetch('/api/challenge/' + id)
            .then(response => response.json())
            .then((challenge) => {
                dispatch({
                    type: 'GET_CHALLENGE',
                    challenge
                });
            });
    };
}

Challenge.propTypes = {
    dispatch: React.PropTypes.func
};

Challenge = connect(
    mapStateToProps
)(Challenge);

export default Challenge;
<commit_msg>#19 Challenge details page: FE / BE<commit_after>import React from 'react';
import { Component } from 'react';
import { connect } from 'react-redux';
import ChallengeNav from './ChallengeNav';
import ChallengeDetails from './ChallengeDetails';
import ChallengeComments from './ChallengeComments';

class Challenge extends Component {
    componentDidMount() {
        const id = this.props.params.id;
        const dispatch = this.props.dispatch;
        dispatch(getChallenge(id));
    }

    render() {
        return (

                <ChallengeNav />
                <ChallengeDetails {...this.props.challenge} />
                <ChallengeComments />

        );
    }
}

const mapStateToProps = ({ challenge }) => ({ challenge });

function getChallenge(id) {
    return function fetchChallenge(dispatch) {
        fetch('http://localhost:9000/api/challenge/' + id)
        //fetch('/api/challenge/' + id)
            .then(response => response.json())
            .then((challenge) => {
                dispatch({
                    type: 'GET_CHALLENGE',
                    challenge
                });
            });
    };
}

Challenge.propTypes = {
    dispatch: React.PropTypes.func
};

Challenge = connect(
    mapStateToProps
)(Challenge);

export default Challenge;
<|endoftext|>


<commit_before>Package.describe({
  name: 'zephadias:errors',
  summary: 'A pattern to display application errors to the user',
  version: '1.0.0',
  git: ' /* Fill me in! */ '
});

Package.onUse(function(api) {
  api.versionsFrom('1.0');
  api.use(['minimongo', 'mongo-livedata', 'templating'], 'client');
  api.addFiles(['errors.js', 'errors_list.html', 'errors_list.js'], 'client');

  if (api.export)
    api.export('Errors');

});

Package.onTest(function(api) {
  api.use('zephadias:errors', 'client');
  api.use(['tinytest', 'test-helpers'], 'client');
  api.addFiles('errors_tests.js', 'client');
});
<commit_msg>adding in the github link<commit_after>Package.describe({
  name: 'zephadias:errors',
  summary: 'A pattern to display application errors to the user',
  version: '1.0.0',
  git: 'https://github.com/Zephadias/meteor-errors'
});

Package.onUse(function(api) {
  api.versionsFrom('1.0');
  api.use(['minimongo', 'mongo-livedata', 'templating'], 'client');
  api.addFiles(['errors.js', 'errors_list.html', 'errors_list.js'], 'client');

  if (api.export)
    api.export('Errors');

});

Package.onTest(function(api) {
  api.use('zephadias:errors', 'client');
  api.use(['tinytest', 'test-helpers'], 'client');
  api.addFiles('errors_tests.js', 'client');
});
<|endoftext|>


<commit_before>/*global require, localStorage, screen*/
var gui = require('nw.gui'); // Load native UI library

(function () {
    "use strict";
    var win = gui.Window.get(), // Get the current window
        windowKey = "window",
        windowConf = {
            width: screen.availWidth / 2,
            height: screen.availHeight,
            x: screen.availWidth / 2,
            y: 0
        },
        confStr = localStorage.getItem(windowKey),
        startInTray = false;

    if (confStr) {
        windowConf = JSON.parse(confStr);
    }

    if (windowConf.width > screen.availWidth ||
        windowConf.height > screen.availHeight ||
        windowConf.x > screen.availWidth ||
        windowConf.y > screen.availHeight) {

        windowConf = {
            width: screen.availWidth / 2,
            height: screen.availHeight,
            x: screen.availWidth / 2,
            y: 0
        };
    }

    win.width = windowConf.width;
    win.height = windowConf.height;
    win.x = windowConf.x;
    win.y = windowConf.y;

    localStorage.setItem(windowKey, JSON.stringify(windowConf));

    for (var i = 0; i < gui.App.argv.length; i++) {
        if (gui.App.argv[i] == '--tray') {
            startInTray = true;
        }
    }

    if (!startInTray) {
        win.show();
    }

    var nativeMenuBar = new gui.Menu({
        type: "menubar"
    });
    try {
        nativeMenuBar.createMacBuiltin("Lazymine");
        win.menu = nativeMenuBar;
    } catch (ex) {
        console.log(ex.message);
    }

    win.on('close', function () {
        localStorage.setItem(windowKey, JSON.stringify({
            width: win.width,
            height: win.height,
            x: win.x,
            y: win.y
        }));

        this.hide();
    });

    var resetWindow = function (screen) {
        if (win.width > screen.availWidth ||
            win.height > screen.availHeight ||
            win.x > screen.availWidth ||
            win.y > screen.availHeight) {

            win.width = screen.availWidth / 2;
            win.height = screen.availHeight;
            win.x = screen.availWidth / 2;
            win.y = 0;
        }
    };

    gui.Screen.on('displayBoundsChanged', resetWindow);

    gui.Screen.on('onDisplayRemoved', resetWindow);
}());

var minimizeWindow = function () {
    "use strict";
    var win = gui.Window.get(),
        windowKey = "window";

    localStorage.setItem(windowKey, JSON.stringify({
        width: win.width,
        height: win.height,
        x: win.x,
        y: win.y
    }));

    win.minimize();
};

var closeWindow = function () {
    "use strict";
    var win = gui.Window.get(),
        windowKey = "window";

    localStorage.setItem(windowKey, JSON.stringify({
        width: win.width,
        height: win.height,
        x: win.x,
        y: win.y
    }));

    win.hide();
};

var openExternalUrl = function (url) {
    "use strict";
    gui.Shell.openExternal(url);
};
<commit_msg>Fixed issue in window.js<commit_after>/*global require, localStorage, screen*/
var gui = require('nw.gui'); // Load native UI library

(function () {
    "use strict";
    var win = gui.Window.get(), // Get the current window
        windowKey = "window",
        windowConf = {
            width: screen.availWidth / 2,
            height: screen.availHeight,
            x: screen.availWidth / 2,
            y: 0
        },
        confStr = localStorage.getItem(windowKey),
        startInTray = false;

    // Initialize the Screen object
    gui.Screen.Init();

    if (confStr) {
        windowConf = JSON.parse(confStr);
    }

    if (windowConf.width > screen.availWidth ||
        windowConf.height > screen.availHeight ||
        windowConf.x > screen.availWidth ||
        windowConf.y > screen.availHeight) {

        windowConf = {
            width: screen.availWidth / 2,
            height: screen.availHeight,
            x: screen.availWidth / 2,
            y: 0
        };
    }

    win.width = windowConf.width;
    win.height = windowConf.height;
    win.x = windowConf.x;
    win.y = windowConf.y;

    localStorage.setItem(windowKey, JSON.stringify(windowConf));

    for (var i = 0; i < gui.App.argv.length; i++) {
        if (gui.App.argv[i] == '--tray') {
            startInTray = true;
        }
    }

    if (!startInTray) {
        win.show();
    }

    var nativeMenuBar = new gui.Menu({
        type: "menubar"
    });
    try {
        nativeMenuBar.createMacBuiltin("Lazymine");
        win.menu = nativeMenuBar;
    } catch (ex) {
        console.log(ex.message);
    }

    win.on('close', function () {
        localStorage.setItem(windowKey, JSON.stringify({
            width: win.width,
            height: win.height,
            x: win.x,
            y: win.y
        }));

        this.hide();
    });

    var resetWindow = function (screen) {
        if (win.width > screen.availWidth ||
            win.height > screen.availHeight ||
            win.x > screen.availWidth ||
            win.y > screen.availHeight) {

            win.width = screen.availWidth / 2;
            win.height = screen.availHeight;
            win.x = screen.availWidth / 2;
            win.y = 0;
        }
    };

    gui.Screen.on('displayBoundsChanged', resetWindow);

    gui.Screen.on('displayRemoved', resetWindow);
}());

var minimizeWindow = function () {
    "use strict";
    var win = gui.Window.get(),
        windowKey = "window";

    localStorage.setItem(windowKey, JSON.stringify({
        width: win.width,
        height: win.height,
        x: win.x,
        y: win.y
    }));

    win.minimize();
};

var closeWindow = function () {
    "use strict";
    var win = gui.Window.get(),
        windowKey = "window";

    localStorage.setItem(windowKey, JSON.stringify({
        width: win.width,
        height: win.height,
        x: win.x,
        y: win.y
    }));

    win.hide();
};

var openExternalUrl = function (url) {
    "use strict";
    gui.Shell.openExternal(url);
};
<|endoftext|>