<commit_before>const System = require('systemic')
const defaultMiddleware = require('systemic-express').defaultMiddleware
const app = require('systemic-express').app
const server = require('systemic-express').server

module.exports = new System()
    .add('app', app()).dependsOn('config', 'logger')
    .add('middleware.default', defaultMiddleware()).dependsOn('logger', 'app', 'routes')
    .add('server', server()).dependsOn('config', 'app')
<commit_msg>Removing routes<commit_after>const System = require('systemic')
const defaultMiddleware = require('systemic-express').defaultMiddleware
const app = require('systemic-express').app
const server = require('systemic-express').server

module.exports = new System()
    .add('app', app()).dependsOn('config', 'logger')
    .add('middleware.default', defaultMiddleware()).dependsOn('logger', 'app')
    .add('server', server()).dependsOn('config', 'app')
<|endoftext|>


<commit_before>var htmlparser = require("htmlparser2");
var fs = require('fs');
var _ = require('lodash');
var Supplant = require('supplant');
var subs = new Supplant();
var utils = require('../utils');
var Stream = require('stream').Stream;
var through = require('through');
var getThenCache = require('../getThenCache');
var errorTemplate = "
Error: <%= err %>
";

module.exports = HtmlParserProxy;

function HtmlParserProxy(config, cache, eventHandler) {
    if (!(this instanceof HtmlParserProxy)) return new HtmlParserProxy(config, cache, eventHandler);
    this.config = config;
    this.cache = cache;
    this.eventHandler = eventHandler;
    return this;
};

HtmlParserProxy.prototype.middleware = function(req, res, next) {

        var self = this,
            output = [],
            outputIndex = 0,
            fragmentIndex = 0,
            fragmentOutput = [],
            nextTextDefault = false,
            skipClosingTag = false;

        output[outputIndex] = "";
        req.timerStart = Date.now();

        res.transformer = {
            end: function(data) {
                parser.end(data);
            }
        };

        var parser = new htmlparser.Parser({
            onopentag: function(tagname, attribs) {
                if(attribs && attribs['cx-url']) {

                    if(attribs['cx-replace-outer']) {
                        skipClosingTag = true;
                    } else {
                        output[outputIndex] += utils.createTag(tagname, attribs);
                    }
                    outputIndex ++;

                    output[outputIndex] = "_processing_";
                    fragmentOutput[fragmentIndex] = attribs;
                    fragmentOutput[fragmentIndex].outputIndex = outputIndex;
                    fragmentOutput[fragmentIndex].fragmentIndex = fragmentIndex;
                    nextTextDefault = true;

                    getCx(fragmentOutput[fragmentIndex], function(fragment, response) {
                        output[fragment.outputIndex] = response;
                        fragment.done = true;
                    });

                    outputIndex ++;
                    fragmentIndex ++;
                    output[outputIndex] = "";

                } else {
                    output[outputIndex] += utils.createTag(tagname, attribs);
                }
            },
            onprocessinginstruction: function(name, data) {
                output[outputIndex] += "<" + data + ">";
            },
            ontext:function(data) {
                if(nextTextDefault) {
                    // Set Default value - provided it hasn't already been set
                    // When using memory cache it could actually retrieve a value
                    // Faster than the ontext event fired from this library
                    nextTextDefault = false;
                    if(output[outputIndex-1] == "_processing_") output[outputIndex-1] = data;
                } else {
                    output[outputIndex] += data;
                }
            },
            oncomment: function(data) {
                output[outputIndex] += ""
            },
            onclosetag: function(tagname){
                if(nextTextDefault) nextTextDefault = false;
                if(skipClosingTag) {
                    skipClosingTag = false;
                    return;
                }
                output[outputIndex] += "</" + tagname + ">";
            },
            onend: function(){
                 var timeoutStart = Date.now(), timeout = utils.timeToMillis(req.backend.timeout || "5s");
                 function checkDone() {
                    var done = true, outputHTML = "";
                    for (var i = 0, len = fragmentOutput.length; i < len; i++) {
                        done = done && fragmentOutput[i].done;
                    }
                    if(done) {
                        for (var i = 0, len = output.length; i < len; i++) {
                            outputHTML += output[i];
                        }
                        var responseTime = Date.now() - req.timerStart;
                        self.eventHandler.logger('info', "Page composer response completed", {tracer: req.tracer,responseTime: responseTime});
                        self.eventHandler.stats('timing','responseTime',responseTime);
                        res.end(outputHTML);
                    } else {

                        if((Date.now() - timeoutStart) > timeout) {
                            res.writeHead(500, {"Content-Type": "text/html"});
                            var errorMsg = 'Compoxure failed to respond in <%= timeout %>ms. Failed to respond: ';
                            for (var i = 0, len = fragmentOutput.length; i < len; i++) {
                                if(!fragmentOutput[i].done) {
                                    errorMsg += ' ' + subs.text(fragmentOutput[i]['cx-url'], req.templateVars) + '.';
                                }
                            }
                            res.end(_.template(errorMsg)({timeout:timeout}));
                        } else {
                            setTimeout(checkDone,1);
                        }
                    }
                 }
                 checkDone();
            },
            recognizeSelfClosing: true
         });

        function getCx(node, next) {

            var options = {},
                start = Date.now(),
                templateVars = _.clone(req.templateVars);

            options.unparsedUrl = node['cx-url'];
            options.url = subs.text(node['cx-url'], templateVars);
            options.timeout = utils.timeToMillis(node['cx-timeout'] || "1s");
            options.cacheKey = subs.text(node['cx-cache-key'] || node['cx-url'], templateVars);
            options.cacheTTL = utils.timeToMillis(node['cx-cache-ttl'] || "1m");
            options.explicitNoCache = node['cx-no-cache'] === "true";
            options.type = 'fragment';
            options.cache = (options.cacheTTL > 0);
            options.headers = {
                'cx-page-url': templateVars['param:pageUrl']
            };
            options.headers.cookie = req.headers.cookie;
            options.tracer = req.tracer;
            if (self.config.cdn) options.headers['x-cdn-host'] = self.config.cdn.host;
            var responseStream = {
                end: function(data) {
                    next(node, data);
                }
            };

            getThenCache(options, self.config, self.cache, self.eventHandler, responseStream, onErrorHandler);

            function onErrorHandler(err, oldContent) {

                var errorMsg;

                if (err.statusCode === 404) {
                    res.writeHead(404, {"Content-Type": "text/html"});
                    errorMsg = _.template('404 Service <%= url %> cache <%= cacheKey %> returned 404.');
                    res.end(errorMsg(options));
                } else {

                    if(!req.backend.quietFailure) {

                        var msg = _.template(errorTemplate);
                        responseStream.end(msg({ 'err': err.message }));

                    } else {
                        if(oldContent) {
                            responseStream.end(oldContent);
                            errorMsg = _.template('STALE <%= url %> cache <%= cacheKey %> failed but serving stale content.');
                            self.eventHandler.logger('error', errorMsg(options), {tracer:req.tracer});
                        } else {
                            responseStream.end(req.backend.leaveContentOnFail ? output[node.outputIndex] : "" );
                        }
                    }

                    self.eventHandler.stats('increment', options.statsdKey + '.error');
                    var elapsed = Date.now() - req.timerStart, timing = Date.now() - start;
                    errorMsg = _.template('FAIL <%= url %> did not respond in <%= timing%>, elapsed <%= elapsed %>. Reason: ' + err.message);
                    self.eventHandler.logger('error', errorMsg({url: options.url, timing: timing, elapsed: elapsed}), {tracer:req.tracer});

                }

            }

        }

        next();

}
<commit_msg>Fix undefined object error<commit_after>var htmlparser = require("htmlparser2");
var fs = require('fs');
var _ = require('lodash');
var Supplant = require('supplant');
var subs = new Supplant();
var utils = require('../utils');
var Stream = require('stream').Stream;
var through = require('through');
var getThenCache = require('../getThenCache');
var errorTemplate = "
Error: <%= err %>
";

module.exports = HtmlParserProxy;

function HtmlParserProxy(config, cache, eventHandler) {
    if (!(this instanceof HtmlParserProxy)) return new HtmlParserProxy(config, cache, eventHandler);
    this.config = config;
    this.cache = cache;
    this.eventHandler = eventHandler;
    return this;
};

HtmlParserProxy.prototype.middleware = function(req, res, next) {

        var self = this,
            output = [],
            outputIndex = 0,
            fragmentIndex = 0,
            fragmentOutput = [],
            nextTextDefault = false,
            skipClosingTag = false;

        output[outputIndex] = "";
        req.timerStart = Date.now();

        res.transformer = {
            end: function(data) {
                parser.end(data);
            }
        };

        var parser = new htmlparser.Parser({
            onopentag: function(tagname, attribs) {
                if(attribs && attribs['cx-url']) {

                    if(attribs['cx-replace-outer']) {
                        skipClosingTag = true;
                    } else {
                        output[outputIndex] += utils.createTag(tagname, attribs);
                    }
                    outputIndex ++;

                    output[outputIndex] = "_processing_";
                    fragmentOutput[fragmentIndex] = attribs;
                    fragmentOutput[fragmentIndex].outputIndex = outputIndex;
                    fragmentOutput[fragmentIndex].fragmentIndex = fragmentIndex;
                    nextTextDefault = true;

                    getCx(fragmentOutput[fragmentIndex], function(fragment, response) {
                        output[fragment.outputIndex] = response;
                        fragment.done = true;
                    });

                    outputIndex ++;
                    fragmentIndex ++;
                    output[outputIndex] = "";

                } else {
                    output[outputIndex] += utils.createTag(tagname, attribs);
                }
            },
            onprocessinginstruction: function(name, data) {
                output[outputIndex] += "<" + data + ">";
            },
            ontext:function(data) {
                if(nextTextDefault) {
                    // Set Default value - provided it hasn't already been set
                    // When using memory cache it could actually retrieve a value
                    // Faster than the ontext event fired from this library
                    nextTextDefault = false;
                    if(output[outputIndex-1] == "_processing_") output[outputIndex-1] = data;
                } else {
                    output[outputIndex] += data;
                }
            },
            oncomment: function(data) {
                output[outputIndex] += ""
            },
            onclosetag: function(tagname){
                if(nextTextDefault) nextTextDefault = false;
                if(skipClosingTag) {
                    skipClosingTag = false;
                    return;
                }
                output[outputIndex] += "</" + tagname + ">";
            },
            onend: function(){
                 var timeoutStart = Date.now(), timeout = utils.timeToMillis(req.backend.timeout || "5s");
                 function checkDone() {
                    var done = true, outputHTML = "";
                    for (var i = 0, len = fragmentOutput.length; i < len; i++) {
                        done = done && fragmentOutput[i].done;
                    }
                    if(done) {
                        for (var i = 0, len = output.length; i < len; i++) {
                            outputHTML += output[i];
                        }
                        var responseTime = Date.now() - req.timerStart;
                        self.eventHandler.logger('info', "Page composer response completed", {tracer: req.tracer,responseTime: responseTime});
                        self.eventHandler.stats('timing','responseTime',responseTime);
                        res.end(outputHTML);
                    } else {

                        if((Date.now() - timeoutStart) > timeout) {
                            res.writeHead(500, {"Content-Type": "text/html"});
                            var errorMsg = 'Compoxure failed to respond in <%= timeout %>ms. Failed to respond: ';
                            for (var i = 0, len = fragmentOutput.length; i < len; i++) {
                                if(!fragmentOutput[i].done) {
                                    errorMsg += ' ' + subs.text(fragmentOutput[i]['cx-url'], req.templateVars) + '.';
                                }
                            }
                            res.end(_.template(errorMsg)({timeout:timeout}));
                        } else {
                            setTimeout(checkDone,1);
                        }
                    }
                 }
                 checkDone();
            },
            recognizeSelfClosing: true
         });

        function getCx(node, next) {

            var options = {},
                start = Date.now(),
                templateVars = _.clone(req.templateVars);

            options.unparsedUrl = node['cx-url'];
            options.url = subs.text(node['cx-url'], templateVars);
            options.timeout = utils.timeToMillis(node['cx-timeout'] || "1s");
            options.cacheKey = subs.text(node['cx-cache-key'] || node['cx-url'], templateVars);
            options.cacheTTL = utils.timeToMillis(node['cx-cache-ttl'] || "1m");
            options.explicitNoCache = node['cx-no-cache'] === "true";
            options.type = 'fragment';
            options.cache = (options.cacheTTL > 0);
            options.headers = {
                'cx-page-url': templateVars['param:pageUrl']
            };
            options.headers.cookie = req.headers.cookie;
            options.tracer = req.tracer;
            options.statsdKey = 'fragment_' + utils.urlToCacheKey(options.url);

            if (self.config.cdn) options.headers['x-cdn-host'] = self.config.cdn.host;
            var responseStream = {
                end: function(data) {
                    next(node, data);
                }
            };

            getThenCache(options, self.config, self.cache, self.eventHandler, responseStream, onErrorHandler);

            function onErrorHandler(err, oldContent) {

                var errorMsg;

                if (err.statusCode === 404) {
                    res.writeHead(404, {"Content-Type": "text/html"});
                    errorMsg = _.template('404 Service <%= url %> cache <%= cacheKey %> returned 404.');
                    res.end(errorMsg(options));
                } else {

                    if(!req.backend.quietFailure) {

                        var msg = _.template(errorTemplate);
                        responseStream.end(msg({ 'err': err.message }));

                    } else {
                        if(oldContent) {
                            responseStream.end(oldContent);
                            errorMsg = _.template('STALE <%= url %> cache <%= cacheKey %> failed but serving stale content.');
                            self.eventHandler.logger('error', errorMsg(options), {tracer:req.tracer});
                        } else {
                            responseStream.end(req.backend.leaveContentOnFail ? output[node.outputIndex] : "" );
                        }
                    }

                    self.eventHandler.stats('increment', options.statsdKey + '.error');
                    var elapsed = Date.now() - req.timerStart, timing = Date.now() - start;
                    errorMsg = _.template('FAIL <%= url %> did not respond in <%= timing%>, elapsed <%= elapsed %>. Reason: ' + err.message);
                    self.eventHandler.logger('error', errorMsg({url: options.url, timing: timing, elapsed: elapsed}), {tracer:req.tracer});

                }

            }

        }

        next();

}
<|endoftext|>


<commit_before>'use strict';
import {getTrackCSS, getTrackLeft, getTrackAnimateCSS} from './trackHelper';
import helpers from './helpers';
import assign from 'object-assign';
import ReactDOM from 'react-dom';

var EventHandlers = {
  // Event handler for previous and next
  changeSlide: function (options) {
    var indexOffset, previousInt, slideOffset, unevenOffset, targetSlide;
    const {slidesToScroll, slidesToShow} = this.props
    const {slideCount, currentSlide} = this.state
    unevenOffset = (slideCount % slidesToScroll !== 0);
    indexOffset = unevenOffset ? 0 : (slideCount - currentSlide) % slidesToScroll;

    if (options.message === 'previous') {
      slideOffset = (indexOffset === 0) ? slidesToScroll : slidesToShow - indexOffset;
      targetSlide = currentSlide - slideOffset;
      if (this.props.lazyLoad) {
        previousInt = currentSlide - slideOffset;
        targetSlide = previousInt === -1 ? slideCount -1 : previousInt;
      }
    } else if (options.message === 'next') {
      slideOffset = (indexOffset === 0) ? slidesToScroll : indexOffset;
      targetSlide = currentSlide + slideOffset;
      if (this.props.lazyLoad) {
        targetSlide = ((currentSlide + slidesToScroll) % slideCount) + indexOffset;
      }
    } else if (options.message === 'dots' || options.message === 'children') {
      // Click on dots
      targetSlide = options.index * options.slidesToScroll;
      if (targetSlide === options.currentSlide) {
        return;
      }
    } else if (options.message === 'index') {
      targetSlide = parseInt(options.index);
      if (targetSlide === options.currentSlide) {
        return;
      }
    }

    this.slideHandler(targetSlide);
  },

  // Accessiblity handler for previous and next
  keyHandler: function (e) {
    //Dont slide if the cursor is inside the form fields and arrow keys are pressed
    if(!e.target.tagName.match('TEXTAREA|INPUT|SELECT')) {
        if (e.keyCode === 37 && this.props.accessibility === true) {
            this.changeSlide({
              message: this.props.rtl === true ? 'next' :  'previous'
            });
        } else if (e.keyCode === 39 && this.props.accessibility === true) {
            this.changeSlide({
              message: this.props.rtl === true ? 'previous' : 'next'
            });
        }
    }
  },
  // Focus on selecting a slide (click handler on track)
  selectHandler: function (options) {
    this.changeSlide(options)
  },
  swipeStart: function (e) {
    var touches, posX, posY;

    if ((this.props.swipe === false) || ('ontouchend' in document && this.props.swipe === false)) {
      return;
    } else if (this.props.draggable === false && e.type.indexOf('mouse') !== -1) {
      return;
    }
    posX = (e.touches !== undefined) ? e.touches[0].pageX : e.clientX;
    posY = (e.touches !== undefined) ? e.touches[0].pageY : e.clientY;
    this.setState({
      dragging: true,
      touchObject: {
        startX: posX,
        startY: posY,
        curX: posX,
        curY: posY
      }
    });
  },
  swipeMove: function (e) {
    if (!this.state.dragging) {
      e.preventDefault();
      return;
    }
    if (this.state.animating) {
      return;
    }
    if (this.props.vertical && this.props.swipeToSlide && this.props.verticalSwiping) {
      e.preventDefault();
    }
    var swipeLeft;
    var curLeft, positionOffset;
    var touchObject = this.state.touchObject;

    curLeft = getTrackLeft(assign({
      slideIndex: this.state.currentSlide,
      trackRef: this.track
    }, this.props, this.state));
    touchObject.curX = (e.touches) ? e.touches[0].pageX : e.clientX;
    touchObject.curY = (e.touches) ? e.touches[0].pageY : e.clientY;
    touchObject.swipeLength = Math.round(Math.sqrt(Math.pow(touchObject.curX - touchObject.startX, 2)));

    if (this.props.verticalSwiping) {
      touchObject.swipeLength = Math.round(Math.sqrt(Math.pow(touchObject.curY - touchObject.startY, 2)));
    }

    positionOffset = (this.props.rtl === false ? 1 : -1) * (touchObject.curX > touchObject.startX ? 1 : -1);

    if (this.props.verticalSwiping) {
      positionOffset = touchObject.curY > touchObject.startY ? 1 : -1;
    }

    var currentSlide = this.state.currentSlide;
    var dotCount = Math.ceil(this.state.slideCount / this.props.slidesToScroll);
    var swipeDirection = this.swipeDirection(this.state.touchObject);
    var touchSwipeLength = touchObject.swipeLength;

    if (this.props.infinite === false) {
      if ((currentSlide === 0 && swipeDirection === 'right') || (currentSlide + 1 >= dotCount && swipeDirection === 'left')) {
        touchSwipeLength = touchObject.swipeLength * this.props.edgeFriction;

        if (this.state.edgeDragged === false && this.props.edgeEvent) {
          this.props.edgeEvent(swipeDirection);
          this.setState({ edgeDragged: true });
        }
      }
    }

    if (this.state.swiped === false && this.props.swipeEvent) {
      this.props.swipeEvent(swipeDirection);
      this.setState({ swiped: true });
    }

    if (!this.props.vertical) {
      swipeLeft = curLeft + touchSwipeLength * positionOffset;
    } else {
      swipeLeft = curLeft + (touchSwipeLength * (this.state.listHeight / this.state.listWidth)) * positionOffset;
    }

    if (this.props.verticalSwiping) {
      swipeLeft = curLeft + touchSwipeLength * positionOffset;
    }

    this.setState({
      touchObject: touchObject,
      swipeLeft: swipeLeft,
      trackStyle: getTrackCSS(assign({left: swipeLeft}, this.props, this.state))
    });

    if (Math.abs(touchObject.curX - touchObject.startX) < Math.abs(touchObject.curY - touchObject.startY) * 0.8)
      { return; }
    if (touchObject.swipeLength > 4) {
      e.preventDefault();
    }
  },
  getNavigableIndexes() {
    let max;
    let breakPoint = 0;
    let counter = 0;
    let indexes = [];

    if (!this.props.infinite) {
      max = this.state.slideCount;
    } else {
      breakPoint = this.props.slidesToShow * -1;
      counter = this.props.slidesToShow * -1;
      max = this.state.slideCount * 2;
    }

    while (breakPoint < max) {
      indexes.push(breakPoint);
      breakPoint = counter + this.props.slidesToScroll;

      counter += this.props.slidesToScroll <= this.props.slidesToShow ?
        this.props.slidesToScroll : this.props.slidesToShow;
    }

    return indexes;
  },
  checkNavigable(index) {
    const navigables = this.getNavigableIndexes();
    let prevNavigable = 0;

    if (index > navigables[navigables.length - 1]) {
      index = navigables[navigables.length - 1];
    } else {
      for (var n in navigables) {
        if (index < navigables[n]) {
          index = prevNavigable;
          break;
        }

        prevNavigable = navigables[n];
      }
    }

    return index;
  },
  getSlideCount() {
    const centerOffset = this.props.centerMode ? this.state.slideWidth * Math.floor(this.props.slidesToShow / 2) : 0;

    if (this.props.swipeToSlide) {
      let swipedSlide;

      const slickList = ReactDOM.findDOMNode(this.list);

      const slides = slickList.querySelectorAll('.slick-slide');

      Array.from(slides).every((slide) => {
        if (!this.props.vertical) {
          if (slide.offsetLeft - centerOffset + (this.getWidth(slide) / 2) > this.state.swipeLeft * -1) {
            swipedSlide = slide;
            return false;
          }
        } else {
          if (slide.offsetTop + (this.getHeight(slide) / 2) > this.state.swipeLeft * -1) {
            swipedSlide = slide;
            return false;
          }
        }

        return true;
      });

      const slidesTraversed = Math.abs(swipedSlide.dataset.index - this.state.currentSlide) || 1;

      return slidesTraversed;
    } else {
      return this.props.slidesToScroll;
    }
  },
  swipeEnd: function (e) {
    if (!this.state.dragging) {
      if (this.props.swipe) {
        e.preventDefault();
      }
      return;
    }
    var touchObject = this.state.touchObject;
    var minSwipe = this.state.listWidth/this.props.touchThreshold;
    var swipeDirection = this.swipeDirection(touchObject);

    if (this.props.verticalSwiping) {
      minSwipe = this.state.listHeight/this.props.touchThreshold;
    }

    // reset the state of touch related state variables.
    this.setState({
      dragging: false,
      edgeDragged: false,
      swiped: false,
      swipeLeft: null,
      touchObject: {}
    });
    // Fix for #13
    if (!touchObject.swipeLength) {
      return;
    }
    if (touchObject.swipeLength > minSwipe) {
      e.preventDefault();

      let slideCount, newSlide;

      switch (swipeDirection) {

        case 'left':
        case 'down':
          newSlide = this.state.currentSlide + this.getSlideCount();
          slideCount = this.props.swipeToSlide ? this.checkNavigable(newSlide) : newSlide;
          this.state.currentDirection = 0;
          break;

        case 'right':
        case 'up':
          newSlide = this.state.currentSlide - this.getSlideCount();
          slideCount = this.props.swipeToSlide ? this.checkNavigable(newSlide) : newSlide;
          this.state.currentDirection = 1;
          break;

        default:
          slideCount = this.state.currentSlide;

      }

      this.slideHandler(slideCount);
    } else {
      // Adjust the track back to it's original position.
      var currentLeft = getTrackLeft(assign({
        slideIndex: this.state.currentSlide,
        trackRef: this.track
      }, this.props, this.state));

      this.setState({
        trackStyle: getTrackAnimateCSS(assign({left: currentLeft}, this.props, this.state))
      });
    }
  },
  onInnerSliderEnter: function (e) {
    if (this.props.autoplay && this.props.pauseOnHover) {
      this.pause();
    }
  },
  onInnerSliderOver: function (e) {
    if (this.props.autoplay && this.props.pauseOnHover) {
      this.pause();
    }
  },
  onInnerSliderLeave: function (e) {
    if (this.props.autoplay && this.props.pauseOnHover) {
      this.autoPlay();
    }
  }
};

export default EventHandlers;
<commit_msg>Update condition to not use lazy load calculation for infinite<commit_after>'use strict';
import {getTrackCSS, getTrackLeft, getTrackAnimateCSS} from './trackHelper';
import helpers from './helpers';
import assign from 'object-assign';
import ReactDOM from 'react-dom';

var EventHandlers = {
  // Event handler for previous and next
  changeSlide: function (options) {
    var indexOffset, previousInt, slideOffset, unevenOffset, targetSlide;
    const {slidesToScroll, slidesToShow} = this.props
    const {slideCount, currentSlide} = this.state
    unevenOffset = (slideCount % slidesToScroll !== 0);
    indexOffset = unevenOffset ? 0 : (slideCount - currentSlide) % slidesToScroll;

    if (options.message === 'previous') {
      slideOffset = (indexOffset === 0) ? slidesToScroll : slidesToShow - indexOffset;
      targetSlide = currentSlide - slideOffset;
      if (this.props.lazyLoad && !this.props.infinite) {
        previousInt = currentSlide - slideOffset;
        targetSlide = previousInt === -1 ? slideCount -1 : previousInt;
      }
    } else if (options.message === 'next') {
      slideOffset = (indexOffset === 0) ? slidesToScroll : indexOffset;
      targetSlide = currentSlide + slideOffset;
      if (this.props.lazyLoad && !this.props.infinite) {
        targetSlide = ((currentSlide + slidesToScroll) % slideCount) + indexOffset;
      }
    } else if (options.message === 'dots' || options.message === 'children') {
      // Click on dots
      targetSlide = options.index * options.slidesToScroll;
      if (targetSlide === options.currentSlide) {
        return;
      }
    } else if (options.message === 'index') {
      targetSlide = parseInt(options.index);
      if (targetSlide === options.currentSlide) {
        return;
      }
    }

    this.slideHandler(targetSlide);
  },

  // Accessiblity handler for previous and next
  keyHandler: function (e) {
    //Dont slide if the cursor is inside the form fields and arrow keys are pressed
    if(!e.target.tagName.match('TEXTAREA|INPUT|SELECT')) {
        if (e.keyCode === 37 && this.props.accessibility === true) {
            this.changeSlide({
              message: this.props.rtl === true ? 'next' :  'previous'
            });
        } else if (e.keyCode === 39 && this.props.accessibility === true) {
            this.changeSlide({
              message: this.props.rtl === true ? 'previous' : 'next'
            });
        }
    }
  },
  // Focus on selecting a slide (click handler on track)
  selectHandler: function (options) {
    this.changeSlide(options)
  },
  swipeStart: function (e) {
    var touches, posX, posY;

    if ((this.props.swipe === false) || ('ontouchend' in document && this.props.swipe === false)) {
      return;
    } else if (this.props.draggable === false && e.type.indexOf('mouse') !== -1) {
      return;
    }
    posX = (e.touches !== undefined) ? e.touches[0].pageX : e.clientX;
    posY = (e.touches !== undefined) ? e.touches[0].pageY : e.clientY;
    this.setState({
      dragging: true,
      touchObject: {
        startX: posX,
        startY: posY,
        curX: posX,
        curY: posY
      }
    });
  },
  swipeMove: function (e) {
    if (!this.state.dragging) {
      e.preventDefault();
      return;
    }
    if (this.state.animating) {
      return;
    }
    if (this.props.vertical && this.props.swipeToSlide && this.props.verticalSwiping) {
      e.preventDefault();
    }
    var swipeLeft;
    var curLeft, positionOffset;
    var touchObject = this.state.touchObject;

    curLeft = getTrackLeft(assign({
      slideIndex: this.state.currentSlide,
      trackRef: this.track
    }, this.props, this.state));
    touchObject.curX = (e.touches) ? e.touches[0].pageX : e.clientX;
    touchObject.curY = (e.touches) ? e.touches[0].pageY : e.clientY;
    touchObject.swipeLength = Math.round(Math.sqrt(Math.pow(touchObject.curX - touchObject.startX, 2)));

    if (this.props.verticalSwiping) {
      touchObject.swipeLength = Math.round(Math.sqrt(Math.pow(touchObject.curY - touchObject.startY, 2)));
    }

    positionOffset = (this.props.rtl === false ? 1 : -1) * (touchObject.curX > touchObject.startX ? 1 : -1);

    if (this.props.verticalSwiping) {
      positionOffset = touchObject.curY > touchObject.startY ? 1 : -1;
    }

    var currentSlide = this.state.currentSlide;
    var dotCount = Math.ceil(this.state.slideCount / this.props.slidesToScroll);
    var swipeDirection = this.swipeDirection(this.state.touchObject);
    var touchSwipeLength = touchObject.swipeLength;

    if (this.props.infinite === false) {
      if ((currentSlide === 0 && swipeDirection === 'right') || (currentSlide + 1 >= dotCount && swipeDirection === 'left')) {
        touchSwipeLength = touchObject.swipeLength * this.props.edgeFriction;

        if (this.state.edgeDragged === false && this.props.edgeEvent) {
          this.props.edgeEvent(swipeDirection);
          this.setState({ edgeDragged: true });
        }
      }
    }

    if (this.state.swiped === false && this.props.swipeEvent) {
      this.props.swipeEvent(swipeDirection);
      this.setState({ swiped: true });
    }

    if (!this.props.vertical) {
      swipeLeft = curLeft + touchSwipeLength * positionOffset;
    } else {
      swipeLeft = curLeft + (touchSwipeLength * (this.state.listHeight / this.state.listWidth)) * positionOffset;
    }

    if (this.props.verticalSwiping) {
      swipeLeft = curLeft + touchSwipeLength * positionOffset;
    }

    this.setState({
      touchObject: touchObject,
      swipeLeft: swipeLeft,
      trackStyle: getTrackCSS(assign({left: swipeLeft}, this.props, this.state))
    });

    if (Math.abs(touchObject.curX - touchObject.startX) < Math.abs(touchObject.curY - touchObject.startY) * 0.8)
      { return; }
    if (touchObject.swipeLength > 4) {
      e.preventDefault();
    }
  },
  getNavigableIndexes() {
    let max;
    let breakPoint = 0;
    let counter = 0;
    let indexes = [];

    if (!this.props.infinite) {
      max = this.state.slideCount;
    } else {
      breakPoint = this.props.slidesToShow * -1;
      counter = this.props.slidesToShow * -1;
      max = this.state.slideCount * 2;
    }

    while (breakPoint < max) {
      indexes.push(breakPoint);
      breakPoint = counter + this.props.slidesToScroll;

      counter += this.props.slidesToScroll <= this.props.slidesToShow ?
        this.props.slidesToScroll : this.props.slidesToShow;
    }

    return indexes;
  },
  checkNavigable(index) {
    const navigables = this.getNavigableIndexes();
    let prevNavigable = 0;

    if (index > navigables[navigables.length - 1]) {
      index = navigables[navigables.length - 1];
    } else {
      for (var n in navigables) {
        if (index < navigables[n]) {
          index = prevNavigable;
          break;
        }

        prevNavigable = navigables[n];
      }
    }

    return index;
  },
  getSlideCount() {
    const centerOffset = this.props.centerMode ? this.state.slideWidth * Math.floor(this.props.slidesToShow / 2) : 0;

    if (this.props.swipeToSlide) {
      let swipedSlide;

      const slickList = ReactDOM.findDOMNode(this.list);

      const slides = slickList.querySelectorAll('.slick-slide');

      Array.from(slides).every((slide) => {
        if (!this.props.vertical) {
          if (slide.offsetLeft - centerOffset + (this.getWidth(slide) / 2) > this.state.swipeLeft * -1) {
            swipedSlide = slide;
            return false;
          }
        } else {
          if (slide.offsetTop + (this.getHeight(slide) / 2) > this.state.swipeLeft * -1) {
            swipedSlide = slide;
            return false;
          }
        }

        return true;
      });

      const slidesTraversed = Math.abs(swipedSlide.dataset.index - this.state.currentSlide) || 1;

      return slidesTraversed;
    } else {
      return this.props.slidesToScroll;
    }
  },
  swipeEnd: function (e) {
    if (!this.state.dragging) {
      if (this.props.swipe) {
        e.preventDefault();
      }
      return;
    }
    var touchObject = this.state.touchObject;
    var minSwipe = this.state.listWidth/this.props.touchThreshold;
    var swipeDirection = this.swipeDirection(touchObject);

    if (this.props.verticalSwiping) {
      minSwipe = this.state.listHeight/this.props.touchThreshold;
    }

    // reset the state of touch related state variables.
    this.setState({
      dragging: false,
      edgeDragged: false,
      swiped: false,
      swipeLeft: null,
      touchObject: {}
    });
    // Fix for #13
    if (!touchObject.swipeLength) {
      return;
    }
    if (touchObject.swipeLength > minSwipe) {
      e.preventDefault();

      let slideCount, newSlide;

      switch (swipeDirection) {

        case 'left':
        case 'down':
          newSlide = this.state.currentSlide + this.getSlideCount();
          slideCount = this.props.swipeToSlide ? this.checkNavigable(newSlide) : newSlide;
          this.state.currentDirection = 0;
          break;

        case 'right':
        case 'up':
          newSlide = this.state.currentSlide - this.getSlideCount();
          slideCount = this.props.swipeToSlide ? this.checkNavigable(newSlide) : newSlide;
          this.state.currentDirection = 1;
          break;

        default:
          slideCount = this.state.currentSlide;

      }

      this.slideHandler(slideCount);
    } else {
      // Adjust the track back to it's original position.
      var currentLeft = getTrackLeft(assign({
        slideIndex: this.state.currentSlide,
        trackRef: this.track
      }, this.props, this.state));

      this.setState({
        trackStyle: getTrackAnimateCSS(assign({left: currentLeft}, this.props, this.state))
      });
    }
  },
  onInnerSliderEnter: function (e) {
    if (this.props.autoplay && this.props.pauseOnHover) {
      this.pause();
    }
  },
  onInnerSliderOver: function (e) {
    if (this.props.autoplay && this.props.pauseOnHover) {
      this.pause();
    }
  },
  onInnerSliderLeave: function (e) {
    if (this.props.autoplay && this.props.pauseOnHover) {
      this.autoPlay();
    }
  }
};

export default EventHandlers;
<|endoftext|>


<commit_before>"use strict";

var $ = require('jquery'),
    _ = require('lodash'),
    L = require('leaflet'),
    Marionette = require('../../shim/backbone.marionette'),
    turfRandom = require('turf-random'),
    turfBuffer = require('turf-buffer'),
    turfBboxPolygon = require('turf-bbox-polygon'),
    turfDestination = require('turf-destination'),
    router = require('../router').router,
    App = require('../app'),
    utils = require('./utils'),
    toolbarTmpl = require('./templates/toolbar.html'),
    loadingTmpl = require('./templates/loading.html'),
    selectTypeTmpl = require('./templates/selectType.html'),
    drawTmpl = require('./templates/draw.html'),
    resetDrawTmpl = require('./templates/reset.html'),
    streamSliderTmpl = require('./templates/streamSlider.html'),
    placeMarkerTmpl = require('./templates/placeMarker.html'),
    settings = require('../core/settings');

// Responsible for loading and displaying tools for selecting and drawing
// shapes on the map.
var ToolbarView = Marionette.LayoutView.extend({
    template: toolbarTmpl,

    className: 'draw-tools-container',

    regions: {
        selectTypeRegion: '#select-area-region',
        drawRegion: '#draw-region',
        placeMarkerRegion: '#place-marker-region',
        resetRegion: '#reset-draw-region',
        streamRegion: '#stream-slider-region'
    },

    initialize: function() {
        var map = App.getLeafletMap(),
            ofg = L.featureGroup(),
            sfg = L.featureGroup();
        this.model.set('outlineFeatureGroup', ofg);
        this.model.set('streamFeatureGroup', sfg);
        map.addLayer(ofg);
        map.addLayer(sfg);
    },

    onDestroy: function() {
        var map = App.getLeafletMap(),
            ofg = this.model.get('outlineFeatureGroup'),
            sfg = this.model.get('streamFeatureGroup');
        map.removeLayer(ofg);
        map.removeLayer(sfg);
        this.model.set('outlineFeatureGroup', null);
        this.model.set('streamFeatureGroup', null);
    },

    onShow: function() {
        this.selectTypeRegion.show(new SelectAreaView({
            model: this.model
        }));
        this.drawRegion.show(new DrawView({
            model: this.model
        }));
        this.placeMarkerRegion.show(new PlaceMarkerView({
            model: this.model
        }));
        this.resetRegion.show(new ResetDrawView({
            model: this.model
        }));
        this.streamRegion.show(new StreamSliderView({
            model: this.model
        }));
    }
});

var SelectAreaView = Marionette.ItemView.extend({
    $label: $('#boundary-label'),

    ui: {
        'items': '[data-endpoint]',
        'button': '#predefined-shape',
    },

    events: {
        'click @ui.items': 'onItemClicked'
    },

    modelEvents: {
        'change': 'render',
        'change:toolsEnabled': 'removeBoundaryLayer'
    },

    initialize: function() {
        var ofg = this.model.get('outlineFeatureGroup');
        ofg.on('layerremove', _.bind(this.clearLabel, this));
    },

    onItemClicked: function(e) {
        var $el = $(e.target),
            endpoint = $el.data('endpoint'),
            tableId = $el.data('tableid');

        clearAoiLayer();
        this.changeOutlineLayer(endpoint, tableId);
        e.preventDefault();
    },

    getTemplate: function() {
        var types = this.model.get('predefinedShapeTypes');
        return !types ? loadingTmpl : selectTypeTmpl;
    },

    changeOutlineLayer: function(endpoint, tableId) {
        var self = this,
            ofg = self.model.get('outlineFeatureGroup');

        // Go about the business of adding the ouline and UTFgrid layers.
        if (endpoint && tableId !== undefined) {
            var ol = new L.TileLayer(endpoint + '.png'),
                grid = new L.UtfGrid(endpoint + '.grid.json?callback={cb}',
                                     {
                                         resolution: 4,
                                         maxRequests: 8
                                     });
            grid.on('click', function(e) {
                getShapeAndAnalyze(e, self.model, ofg, grid, tableId);
            });

            grid.on('mousemove', function(e) {
                self.updateDisplayLabel(e.latlng, e.data.name);
            });

            clearBoundaryLayer(self.model);
            ofg.addLayer(ol);
            ofg.addLayer(grid);

            ol.bringToFront();
        }
    },

    removeBoundaryLayer: function() {
        clearBoundaryLayer(this.model);
    },

    updateDisplayLabel: function(latLng, text) {
        var pos = App.getLeafletMap().latLngToContainerPoint(latLng),
            bufferDist = 10,
            buffer = function(cursorPos) {
                var newPt = _.clone(cursorPos);
                _.forEach(newPt, function(val, key, pt) {
                    pt[key] = val + bufferDist;
                });

                return newPt;
            },
            placement = buffer(pos);

        this.$label
            .text(text)
            .css({ top: placement.y, left: placement.x})
            .show();
    },

    clearLabel: function() {
        this.$label.hide();
    }
});

var DrawView = Marionette.ItemView.extend({
    template: drawTmpl,

    ui: {
        drawArea: '#custom-shape',
        drawStamp: '#one-km-stamp'
    },

    events: {
        'click @ui.drawArea': 'enableDrawArea',
        'click @ui.drawStamp': 'enableStampTool'
    },

    modelEvents: {
        'change:toolsEnabled': 'render'
    },

    enableDrawArea: function() {
        var self = this,
            map = App.getLeafletMap(),
            revertLayer = clearAoiLayer();

        this.model.disableTools();
        utils.drawPolygon(map).then(function(shape) {
            addLayer(shape);
            navigateToAnalyze();
        }).fail(function() {
            revertLayer();
        }).always(function() {
            self.model.enableTools();
        });
    },

    enableStampTool: function() {
        var self = this,
            map = App.getLeafletMap(),
            revertLayer = clearAoiLayer();

        this.model.disableTools();
        utils.placeMarker(map).then(function(latlng) {
            var point = {
                  "type": "Feature", "properties": {}, "geometry": {
                    "type": "Point",
                    "coordinates": [latlng.lng, latlng.lat]
                  }
                },
                halfKmbufferPoints = _.map([-180, -90, 0, 90], function(bearing) {
                    var p = turfDestination(point, 0.5, bearing, 'kilometers');
                    return L.latLng(p.geometry.coordinates[1], p.geometry.coordinates[0]);
                }),
                // Convert the four points into two SW and NE for the bounding
                // box. Do this by splitting the array into two arrays of two
                // points. Then map each array of two to a single point by
                // taking the lat from one and lng from the other.
                swNe = _.map(_.toArray(_.groupBy(halfKmbufferPoints, function(p, i) {
                    // split the array of four in half.
                    return i < 2;
                })), function(pointGroup) {
                    return L.latLng(pointGroup[0].lat, pointGroup[1].lng);
                }),
                bounds = L.latLngBounds(swNe),
                bbox = [
                    bounds.getSouthWest().lng,
                    bounds.getSouthWest().lat,
                    bounds.getNorthEast().lng,
                    bounds.getNorthEast().lat
                ],
                box = turfBboxPolygon(bbox);

            addLayer(box, '1 Square Km');
            navigateToAnalyze();
        }).fail(function() {
            revertLayer();
        }).always(function() {
            self.model.enableTools();
        });
    }
});

var PlaceMarkerView = Marionette.ItemView.extend({
    template: placeMarkerTmpl,

    ui: {
        'items': '[data-shape-type]',
        'button': '#delineate-shape',
    },

    events: {
        'click @ui.items': 'onItemClicked',
    },

    modelEvents: {
        'change:toolsEnabled': 'render'
    },

    onItemClicked: function(e) {
        var self = this,
            map = App.getLeafletMap(),
            itemName = $(e.target).text(),
            revertLayer = clearAoiLayer();

        this.model.disableTools();
        utils.placeMarker(map).then(function(latlng) {
            // TODO: This is temporary until we have
            // endpoints that can actually delienate
            // watersheds.
            var point = {
                  "type": "Feature", "properties": {}, "geometry": {
                    "type": "Point",
                    "coordinates": [latlng.lng, latlng.lat]
                  }
                },
                buffered = turfBuffer(point, 5000, 'meters'),
                bounds = L.geoJson(buffered).getBounds(),
                shape = turfRandom('polygons', 1, {
                    max_vertcies: 50,
                    bbox: [
                        bounds.getWest(), bounds.getSouth(),
                        bounds.getEast(), bounds.getNorth()
                    ],
                    max_radial_length: 0.25
                });

            addLayer(shape, itemName);
            navigateToAnalyze();
        }).fail(function() {
            revertLayer();
        }).always(function() {
            self.model.enableTools();
        });
    }
});

var ResetDrawView = Marionette.ItemView.extend({
    template: resetDrawTmpl,

    ui: { 'reset': 'button' },

    events: { 'click @ui.reset': 'resetDrawingState' },

    resetDrawingState: function() {
        utils.cancelDrawing(App.getLeafletMap());
        clearAoiLayer();
        clearBoundaryLayer(this.model);
    }
});

var StreamSliderView = Marionette.ItemView.extend({
    template: streamSliderTmpl,

    ui: {
        slider: '#stream-slider',
        displayValue: '#stream-value'
    },

    events: {
        'input @ui.slider': 'onSliderDragged',
        'change @ui.slider': 'onSliderChanged'
    },

    initialize: function() {
        this.streamLayers = settings.get('stream_layers');
    },

    onShow: function() {
        this.onSliderDragged();
    },

    getSliderIndex: function() {
        return parseInt(this.ui.slider.val());
    },

    getSliderDisplay: function() {
        var ind = this.getSliderIndex();
        if (ind === 0) {
            return 'Off';
        } else {
            return this.streamLayers[ind-1].display;
        }
    },

    onSliderDragged: function() {
        // Preview slider value while dragging.
        this.ui.displayValue.text(this.getSliderDisplay());
    },

    onSliderChanged: function() {
        var ind = this.getSliderIndex();
        clearStreamLayer(this.model);
        if (ind > 0) {
            var streamLayer = this.streamLayers[ind-1];
            changeStreamLayer(streamLayer.endpoint, this.model);
        }
    }
});

function clearStreamLayer(model) {
    model.get('streamFeatureGroup').clearLayers();
}

function changeStreamLayer(endpoint, model) {
    var sfg = model.get('streamFeatureGroup'),
        sl = new L.TileLayer(endpoint + '.png');

    sfg.addLayer(sl);
    sl.bringToFront();
}

function getShapeAndAnalyze(e, model, ofg, grid, tableId) {
    // The shapeId might not be available at the time of the click
    // because the UTF Grid layer might not be loaded yet, so
    // we poll for it.
    var pollInterval = 200,
        maxPolls = 5,
        pollCount = 0,
        deferred = $.Deferred(),
        shapeName = e.data && e.data.name ? e.data.name : null,
        shapeId = e.data ? e.data.id : null;

        if (shapeId) {
            _getShapeAndAnalyze();
        } else {
            pollForShapeId();
        }

    function _getShapeAndAnalyze() {
        App.restApi.getPolygon({
            tableId: tableId,
            shapeId: shapeId
        }).done(function(shape) {
            addLayer(shape, shapeName);
            clearBoundaryLayer(model);
            navigateToAnalyze();
            deferred.resolve();
        }).fail(function() {
            console.log('Shape endpoint failed');
            deferred.reject();
        }).always(function() {
            model.enableTools();
        });
    }

    function pollForShapeId() {
        if (pollCount < maxPolls) {
            var shapeData = grid._objectForEvent(e).data;
            if (shapeData && shapeData.id) {
                shapeId = shapeData.id;
                _getShapeAndAnalyze();
            } else {
                window.setTimeout(pollForShapeId, pollInterval);
                pollCount++;
            }
        } else {
            L.popup()
                .setLatLng(e.latlng)
                .setContent('The region was not available. Please try clicking again.')
                .openOn(App.getLeafletMap());
            model.enableTools();
            deferred.reject();
        }
    }

    return deferred;
}

function clearAoiLayer() {
    App.map.set('areaOfInterest', null);
    return function revertLayer() {
        var previousShape = App.map.previous('areaOfInterest');
        App.map.set('areaOfInterest', previousShape);
    };
}

function clearBoundaryLayer(model) {
    var ofg = model.get('outlineFeatureGroup');
    if (ofg) {
        ofg.clearLayers();
    }
}

function addLayer(shape, name) {
    if (!name) {
        name = 'Selected Area';
    }

    App.map.set('areaOfInterest', shape);
    App.map.set('areaOfInterestName', name);
}

function navigateToAnalyze() {
    router.navigate('analyze', { trigger: true });
}

module.exports = {
    ToolbarView: ToolbarView,
    getShapeAndAnalyze: getShapeAndAnalyze
};
<commit_msg>Simplify bounding box creation.<commit_after>"use strict";

var $ = require('jquery'),
    _ = require('lodash'),
    L = require('leaflet'),
    Marionette = require('../../shim/backbone.marionette'),
    turfRandom = require('turf-random'),
    turfBuffer = require('turf-buffer'),
    turfBboxPolygon = require('turf-bbox-polygon'),
    turfDestination = require('turf-destination'),
    router = require('../router').router,
    App = require('../app'),
    utils = require('./utils'),
    toolbarTmpl = require('./templates/toolbar.html'),
    loadingTmpl = require('./templates/loading.html'),
    selectTypeTmpl = require('./templates/selectType.html'),
    drawTmpl = require('./templates/draw.html'),
    resetDrawTmpl = require('./templates/reset.html'),
    streamSliderTmpl = require('./templates/streamSlider.html'),
    placeMarkerTmpl = require('./templates/placeMarker.html'),
    settings = require('../core/settings');

// Responsible for loading and displaying tools for selecting and drawing
// shapes on the map.
var ToolbarView = Marionette.LayoutView.extend({
    template: toolbarTmpl,

    className: 'draw-tools-container',

    regions: {
        selectTypeRegion: '#select-area-region',
        drawRegion: '#draw-region',
        placeMarkerRegion: '#place-marker-region',
        resetRegion: '#reset-draw-region',
        streamRegion: '#stream-slider-region'
    },

    initialize: function() {
        var map = App.getLeafletMap(),
            ofg = L.featureGroup(),
            sfg = L.featureGroup();
        this.model.set('outlineFeatureGroup', ofg);
        this.model.set('streamFeatureGroup', sfg);
        map.addLayer(ofg);
        map.addLayer(sfg);
    },

    onDestroy: function() {
        var map = App.getLeafletMap(),
            ofg = this.model.get('outlineFeatureGroup'),
            sfg = this.model.get('streamFeatureGroup');
        map.removeLayer(ofg);
        map.removeLayer(sfg);
        this.model.set('outlineFeatureGroup', null);
        this.model.set('streamFeatureGroup', null);
    },

    onShow: function() {
        this.selectTypeRegion.show(new SelectAreaView({
            model: this.model
        }));
        this.drawRegion.show(new DrawView({
            model: this.model
        }));
        this.placeMarkerRegion.show(new PlaceMarkerView({
            model: this.model
        }));
        this.resetRegion.show(new ResetDrawView({
            model: this.model
        }));
        this.streamRegion.show(new StreamSliderView({
            model: this.model
        }));
    }
});

var SelectAreaView = Marionette.ItemView.extend({
    $label: $('#boundary-label'),

    ui: {
        'items': '[data-endpoint]',
        'button': '#predefined-shape',
    },

    events: {
        'click @ui.items': 'onItemClicked'
    },

    modelEvents: {
        'change': 'render',
        'change:toolsEnabled': 'removeBoundaryLayer'
    },

    initialize: function() {
        var ofg = this.model.get('outlineFeatureGroup');
        ofg.on('layerremove', _.bind(this.clearLabel, this));
    },

    onItemClicked: function(e) {
        var $el = $(e.target),
            endpoint = $el.data('endpoint'),
            tableId = $el.data('tableid');

        clearAoiLayer();
        this.changeOutlineLayer(endpoint, tableId);
        e.preventDefault();
    },

    getTemplate: function() {
        var types = this.model.get('predefinedShapeTypes');
        return !types ? loadingTmpl : selectTypeTmpl;
    },

    changeOutlineLayer: function(endpoint, tableId) {
        var self = this,
            ofg = self.model.get('outlineFeatureGroup');

        // Go about the business of adding the ouline and UTFgrid layers.
        if (endpoint && tableId !== undefined) {
            var ol = new L.TileLayer(endpoint + '.png'),
                grid = new L.UtfGrid(endpoint + '.grid.json?callback={cb}',
                                     {
                                         resolution: 4,
                                         maxRequests: 8
                                     });
            grid.on('click', function(e) {
                getShapeAndAnalyze(e, self.model, ofg, grid, tableId);
            });

            grid.on('mousemove', function(e) {
                self.updateDisplayLabel(e.latlng, e.data.name);
            });

            clearBoundaryLayer(self.model);
            ofg.addLayer(ol);
            ofg.addLayer(grid);

            ol.bringToFront();
        }
    },

    removeBoundaryLayer: function() {
        clearBoundaryLayer(this.model);
    },

    updateDisplayLabel: function(latLng, text) {
        var pos = App.getLeafletMap().latLngToContainerPoint(latLng),
            bufferDist = 10,
            buffer = function(cursorPos) {
                var newPt = _.clone(cursorPos);
                _.forEach(newPt, function(val, key, pt) {
                    pt[key] = val + bufferDist;
                });

                return newPt;
            },
            placement = buffer(pos);

        this.$label
            .text(text)
            .css({ top: placement.y, left: placement.x})
            .show();
    },

    clearLabel: function() {
        this.$label.hide();
    }
});

var DrawView = Marionette.ItemView.extend({
    template: drawTmpl,

    ui: {
        drawArea: '#custom-shape',
        drawStamp: '#one-km-stamp'
    },

    events: {
        'click @ui.drawArea': 'enableDrawArea',
        'click @ui.drawStamp': 'enableStampTool'
    },

    modelEvents: {
        'change:toolsEnabled': 'render'
    },

    enableDrawArea: function() {
        var self = this,
            map = App.getLeafletMap(),
            revertLayer = clearAoiLayer();

        this.model.disableTools();
        utils.drawPolygon(map).then(function(shape) {
            addLayer(shape);
            navigateToAnalyze();
        }).fail(function() {
            revertLayer();
        }).always(function() {
            self.model.enableTools();
        });
    },

    enableStampTool: function() {
        var self = this,
            map = App.getLeafletMap(),
            revertLayer = clearAoiLayer();

        this.model.disableTools();
        utils.placeMarker(map).then(function(latlng) {
            var point = {
                  "type": "Feature", "properties": {}, "geometry": {
                    "type": "Point",
                    "coordinates": [latlng.lng, latlng.lat]
                  }
                },
                halfKmbufferPoints = _.map([-180, -90, 0, 90], function(bearing) {
                    var p = turfDestination(point, 0.5, bearing, 'kilometers');
                    return L.latLng(p.geometry.coordinates[1], p.geometry.coordinates[0]);
                }),
                // Convert the four points into two SW and NE for the bounding
                // box. Do this by splitting the array into two arrays of two
                // points. Then map each array of two to a single point by
                // taking the lat from one and lng from the other.
                swNe = _.map(_.toArray(_.groupBy(halfKmbufferPoints, function(p, i) {
                    // split the array of four in half.
                    return i < 2;
                })), function(pointGroup) {
                    return L.latLng(pointGroup[0].lat, pointGroup[1].lng);
                }),
                bounds = L.latLngBounds(swNe),
                box = turfBboxPolygon(bounds.toBBoxString().split(','));

            addLayer(box, '1 Square Km');
            navigateToAnalyze();
        }).fail(function() {
            revertLayer();
        }).always(function() {
            self.model.enableTools();
        });
    }
});

var PlaceMarkerView = Marionette.ItemView.extend({
    template: placeMarkerTmpl,

    ui: {
        'items': '[data-shape-type]',
        'button': '#delineate-shape',
    },

    events: {
        'click @ui.items': 'onItemClicked',
    },

    modelEvents: {
        'change:toolsEnabled': 'render'
    },

    onItemClicked: function(e) {
        var self = this,
            map = App.getLeafletMap(),
            itemName = $(e.target).text(),
            revertLayer = clearAoiLayer();

        this.model.disableTools();
        utils.placeMarker(map).then(function(latlng) {
            // TODO: This is temporary until we have
            // endpoints that can actually delienate
            // watersheds.
            var point = {
                  "type": "Feature", "properties": {}, "geometry": {
                    "type": "Point",
                    "coordinates": [latlng.lng, latlng.lat]
                  }
                },
                buffered = turfBuffer(point, 5000, 'meters'),
                bounds = L.geoJson(buffered).getBounds(),
                shape = turfRandom('polygons', 1, {
                    max_vertcies: 50,
                    bbox: [
                        bounds.getWest(), bounds.getSouth(),
                        bounds.getEast(), bounds.getNorth()
                    ],
                    max_radial_length: 0.25
                });

            addLayer(shape, itemName);
            navigateToAnalyze();
        }).fail(function() {
            revertLayer();
        }).always(function() {
            self.model.enableTools();
        });
    }
});

var ResetDrawView = Marionette.ItemView.extend({
    template: resetDrawTmpl,

    ui: { 'reset': 'button' },

    events: { 'click @ui.reset': 'resetDrawingState' },

    resetDrawingState: function() {
        utils.cancelDrawing(App.getLeafletMap());
        clearAoiLayer();
        clearBoundaryLayer(this.model);
    }
});

var StreamSliderView = Marionette.ItemView.extend({
    template: streamSliderTmpl,

    ui: {
        slider: '#stream-slider',
        displayValue: '#stream-value'
    },

    events: {
        'input @ui.slider': 'onSliderDragged',
        'change @ui.slider': 'onSliderChanged'
    },

    initialize: function() {
        this.streamLayers = settings.get('stream_layers');
    },

    onShow: function() {
        this.onSliderDragged();
    },

    getSliderIndex: function() {
        return parseInt(this.ui.slider.val());
    },

    getSliderDisplay: function() {
        var ind = this.getSliderIndex();
        if (ind === 0) {
            return 'Off';
        } else {
            return this.streamLayers[ind-1].display;
        }
    },

    onSliderDragged: function() {
        // Preview slider value while dragging.
        this.ui.displayValue.text(this.getSliderDisplay());
    },

    onSliderChanged: function() {
        var ind = this.getSliderIndex();
        clearStreamLayer(this.model);
        if (ind > 0) {
            var streamLayer = this.streamLayers[ind-1];
            changeStreamLayer(streamLayer.endpoint, this.model);
        }
    }
});

function clearStreamLayer(model) {
    model.get('streamFeatureGroup').clearLayers();
}

function changeStreamLayer(endpoint, model) {
    var sfg = model.get('streamFeatureGroup'),
        sl = new L.TileLayer(endpoint + '.png');

    sfg.addLayer(sl);
    sl.bringToFront();
}

function getShapeAndAnalyze(e, model, ofg, grid, tableId) {
    // The shapeId might not be available at the time of the click
    // because the UTF Grid layer might not be loaded yet, so
    // we poll for it.
    var pollInterval = 200,
        maxPolls = 5,
        pollCount = 0,
        deferred = $.Deferred(),
        shapeName = e.data && e.data.name ? e.data.name : null,
        shapeId = e.data ? e.data.id : null;

        if (shapeId) {
            _getShapeAndAnalyze();
        } else {
            pollForShapeId();
        }

    function _getShapeAndAnalyze() {
        App.restApi.getPolygon({
            tableId: tableId,
            shapeId: shapeId
        }).done(function(shape) {
            addLayer(shape, shapeName);
            clearBoundaryLayer(model);
            navigateToAnalyze();
            deferred.resolve();
        }).fail(function() {
            console.log('Shape endpoint failed');
            deferred.reject();
        }).always(function() {
            model.enableTools();
        });
    }

    function pollForShapeId() {
        if (pollCount < maxPolls) {
            var shapeData = grid._objectForEvent(e).data;
            if (shapeData && shapeData.id) {
                shapeId = shapeData.id;
                _getShapeAndAnalyze();
            } else {
                window.setTimeout(pollForShapeId, pollInterval);
                pollCount++;
            }
        } else {
            L.popup()
                .setLatLng(e.latlng)
                .setContent('The region was not available. Please try clicking again.')
                .openOn(App.getLeafletMap());
            model.enableTools();
            deferred.reject();
        }
    }

    return deferred;
}

function clearAoiLayer() {
    App.map.set('areaOfInterest', null);
    return function revertLayer() {
        var previousShape = App.map.previous('areaOfInterest');
        App.map.set('areaOfInterest', previousShape);
    };
}

function clearBoundaryLayer(model) {
    var ofg = model.get('outlineFeatureGroup');
    if (ofg) {
        ofg.clearLayers();
    }
}

function addLayer(shape, name) {
    if (!name) {
        name = 'Selected Area';
    }

    App.map.set('areaOfInterest', shape);
    App.map.set('areaOfInterestName', name);
}

function navigateToAnalyze() {
    router.navigate('analyze', { trigger: true });
}

module.exports = {
    ToolbarView: ToolbarView,
    getShapeAndAnalyze: getShapeAndAnalyze
};
<|endoftext|>


<commit_before>module.exports = (() => {
  "use strict";

  var fs = require("fs"),
      xml = require("xml2js").parseString;

  class NicoComment {

    constructor() {
      this._comment = [];
      this.options = {
        size: {
          big: NicoComment.defaultSize.big,
          small: NicoComment.defaultSize.small
        }
      };
    }

    get comment() {
      return this._comment;
    }

    readFromFile(path) {
      var deferred = Promise.defer();

      fs.readFile(path, "utf8", ((err, data) => {
        if (err) return deferred.reject(err);
        this.read(data).then(r => deferred.resolve(r));
      }).bind(this), err => {
        deferred.reject(err);
      });

      return deferred.promise;
    }

    read(data) {
      var deferred = Promise.defer();

      this.clearComment();

      xml(data, ((err, result) => {
        if (err) return deferred.reject(err);

        if (result === null ||
            typeof result.packet !== "object" ||
            !("chat" in result.packet)) {
          return deferred.reject("parse error");
        }

        var margin = result.packet.chat.reduce((margin, obj) => {
          if (margin === -1) margin = 100;
          for (; parseInt(obj.$.vpos) % margin !== 0; margin /= 10);
          return margin;
        }, -1);

        this._comment = result.packet.chat.map(obj => {
          return this._parseChat(obj, margin);
        }, this).filter(obj => obj !== null);

        deferred.resolve(this._comment);
      }).bind(this));

      return deferred.promise;
    }

    addChat(chat) {
      this.addComment([chat]);
    }

    addComment(comment) {
      if (!Array.isArray(comment))
        throw new TypeError("comment must be array: " + typeof comment);

      comment.forEach(chat => {
        this._comment.push(chat);
      }, this);
    }

    clearComment() {
      this._comment = [];
    }

    _parseChat(obj, margin) {
      if (!obj._) return null;

      margin = margin || 0;

      // vposm is custom attribute for jikkyo
      var chat = {
        text: obj._,
        vpos: obj.$.vposm ? parseInt(obj.$.vposm) :
        (parseInt(obj.$.vpos) + Math.floor(Math.random() * margin)) * 10
      };

      if ("mail" in obj.$) {
        obj.$.mail.split(" ").forEach(command => {
          if (command in NicoComment.color) {
            chat.color = NicoComment.color[command];
          } else if (command in this.options.size) {
            chat.size = this.options.size[command];
          } else if (NicoComment.position.includes(command)) {
            chat.position = command;
          } else if (/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(command)) {
            chat.color = command;
          }
        }, this);
      }

      return chat;
    }

  }

  NicoComment.color = {
    white:          "#FFFFFF",
    red:            "#FF0000",
    pink:           "#FF8080",
    orange:         "#FFC000",
    yellow:         "#FFFF00",
    green:          "#00FF00",
    cyan:           "#00FFFF",
    blue:           "#0000FF",
    purple:         "#C000FF",
    black:          "#000000",
    white2:         "#CCCC99",
    niconicowhite:  "#CCCC99",
    red2:           "#CC0033",
    truered:        "#CC0033",
    pink2:          "#FF33CC",
    orange2:        "#FF6600",
    passionorange:  "#FF6600",
    yellow2:        "#999900",
    madyellow:      "#999900",
    green2:         "#00CC66",
    elementalgreen: "#00CC66",
    cyan2:          "#00CCCC",
    blue2:          "#3399FF",
    marineblue:     "#3399FF",
    purple2:        "#6633CC",
    nobleviolet:    "#6633CC",
    black2:         "#666666",
  };

  NicoComment.defaultSize = {
    big:    "150%",
    small:  "50%"
  };

  NicoComment.position = ["ue", "shita"];

  return NicoComment;
})();
<commit_msg>Fix NicoComment<commit_after>module.exports = (() => {
  "use strict";

  var fs = require("fs"),
      xml = require("xml2js").parseString;

  class NicoComment {

    constructor() {
      this._comment = [];
      this.options = {
        size: {
          big: NicoComment.defaultSize.big,
          small: NicoComment.defaultSize.small
        }
      };
    }

    get comment() {
      return this._comment;
    }

    readFromFile(path) {
      var deferred = Promise.defer();

      fs.readFile(path, "utf8", ((err, data) => {
        if (err) return deferred.reject(err);
        this.read(data).then(
          r => deferred.resolve(r),
          e => deferred.reject(e)
        );
      }).bind(this));

      return deferred.promise;
    }

    read(data) {
      var deferred = Promise.defer();

      this.clearComment();

      xml(data, ((err, result) => {
        if (err) return deferred.reject(err);

        if (result === null ||
            typeof result.packet !== "object" ||
            !("chat" in result.packet)) {
          return deferred.reject(new Error("parse error"));
        }

        var margin = result.packet.chat.reduce((margin, obj) => {
          if (margin === -1) margin = 100;
          for (; parseInt(obj.$.vpos) % margin !== 0; margin /= 10);
          return margin;
        }, -1);

        this._comment = result.packet.chat.map(obj => {
          return this._parseChat(obj, margin);
        }, this).filter(obj => obj !== null);

        deferred.resolve(this._comment);
      }).bind(this));

      return deferred.promise;
    }

    addChat(chat) {
      this.addComment([chat]);
    }

    addComment(comment) {
      if (!Array.isArray(comment))
        throw new TypeError("comment must be array: " + typeof comment);

      comment.forEach(chat => {
        this._comment.push(chat);
      }, this);
    }

    clearComment() {
      this._comment = [];
    }

    _parseChat(obj, margin) {
      if (!obj._) return null;

      margin = margin || 0;

      // vposm is custom attribute for jikkyo
      var chat = {
        text: obj._,
        vpos: obj.$.vposm ? parseInt(obj.$.vposm) :
        (parseInt(obj.$.vpos) + Math.floor(Math.random() * margin)) * 10
      };

      if ("mail" in obj.$) {
        obj.$.mail.split(" ").forEach(command => {
          if (command in NicoComment.color) {
            chat.color = NicoComment.color[command];
          } else if (command in this.options.size) {
            chat.size = this.options.size[command];
          } else if (NicoComment.position.includes(command)) {
            chat.position = command;
          } else if (/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(command)) {
            chat.color = command;
          }
        }, this);
      }

      return chat;
    }

  }

  NicoComment.color = {
    white:          "#FFFFFF",
    red:            "#FF0000",
    pink:           "#FF8080",
    orange:         "#FFC000",
    yellow:         "#FFFF00",
    green:          "#00FF00",
    cyan:           "#00FFFF",
    blue:           "#0000FF",
    purple:         "#C000FF",
    black:          "#000000",
    white2:         "#CCCC99",
    niconicowhite:  "#CCCC99",
    red2:           "#CC0033",
    truered:        "#CC0033",
    pink2:          "#FF33CC",
    orange2:        "#FF6600",
    passionorange:  "#FF6600",
    yellow2:        "#999900",
    madyellow:      "#999900",
    green2:         "#00CC66",
    elementalgreen: "#00CC66",
    cyan2:          "#00CCCC",
    blue2:          "#3399FF",
    marineblue:     "#3399FF",
    purple2:        "#6633CC",
    nobleviolet:    "#6633CC",
    black2:         "#666666",
  };

  NicoComment.defaultSize = {
    big:    "150%",
    small:  "50%"
  };

  NicoComment.position = ["ue", "shita"];

  return NicoComment;
})();
<|endoftext|>