<commit_before>'use strict';

import React from 'react';
import EventHandlersMixin from './mixins/event-handlers';
import HelpersMixin from './mixins/helpers';
import initialState from './initial-state';
import defaultProps from './default-props';
import createReactClass from 'create-react-class';
import classnames from 'classnames';
import assign from 'object-assign';

import { Track } from './track';
import { Dots } from './dots';
import { PrevArrow, NextArrow } from './arrows';

export var InnerSlider = createReactClass({
  mixins: [HelpersMixin, EventHandlersMixin],
  list: null, // wraps the track
  track: null, // component that rolls out like a film
  listRefHandler: function (ref) {
    this.list = ref;
  },
  trackRefHandler: function (ref) {
    this.track = ref;
  },
  getInitialState: function () {
    return Object.assign({}, initialState, {
      currentSlide: this.props.initialSlide
    });
  },
  componentWillMount: function () {
    if (this.props.init) {
      this.props.init();
    }
    let lazyLoadedList = [];
    // number of slides shown in the active frame
    const slidesToShow = this.props.slidesToShow;
    const childrenLen = React.Children.count(this.props.children);
    const currentSlide = this.state.currentSlide;
    for (let i = 0; i < childrenLen; i++) {
      // if currentSlide is the lastSlide of current frame and
      // rest of the active slides are on the left of currentSlide
      // then the following might cause a problem
      if (i >= currentSlide && i < currentSlide + slidesToShow) {
        lazyLoadedList.push(i);
      }
    }
    if (this.props.centerMode === true) {
      // add slides to show on the left in case of centerMode with lazyLoad
      let additionalCount = Math.floor(slidesToShow / 2);
      if (parseInt(this.props.centerPadding) > 0) {
        additionalCount += 1;
      }
      let additionalNum = currentSlide;
      while(additionalCount--){
        lazyLoadedList.push((--additionalNum + childrenLen) % childrenLen)
      }
    }

    if (this.props.lazyLoad && this.state.lazyLoadedList.length === 0) {
      this.setState({
        lazyLoadedList: lazyLoadedList
      });
      if (this.props.lazyLoaded && lazyLoadedList.length > 0) {
        this.props.lazyLoaded(lazyLoadedList)
      }
    }
  },
  componentDidMount: function componentDidMount() {
    // Hack for autoplay -- Inspect Later
    this.initialize(this.props);
    this.adaptHeight();

    // To support server-side rendering
    if (!window) {
      return
    }
    if (window.addEventListener) {
      window.addEventListener('resize', this.onWindowResized);
    } else {
      window.attachEvent('onresize', this.onWindowResized);
    }
  },
  componentWillUnmount: function componentWillUnmount() {
    if (this.animationEndCallback) {
      clearTimeout(this.animationEndCallback);
    }
    if (window.addEventListener) {
      window.removeEventListener('resize', this.onWindowResized);
    } else {
      window.detachEvent('onresize', this.onWindowResized);
    }
    if (this.state.autoPlayTimer) {
      clearInterval(this.state.autoPlayTimer);
    }
  },
  componentWillReceiveProps: function (nextProps) {
    if (this.props.slickGoTo != nextProps.slickGoTo) {
      if (process.env.NODE_ENV !== 'production') {
        console.warn('react-slick deprecation warning: slickGoTo prop is deprecated and it will be removed in next release. Use slickGoTo method instead')
      }
      this.changeSlide({
        message: 'index',
        index: nextProps.slickGoTo,
        currentSlide: this.state.currentSlide
      });
    } else if (this.state.currentSlide >= nextProps.children.length) {
      this.update(nextProps);
      this.changeSlide({
        message: 'index',
        index: nextProps.children.length - nextProps.slidesToShow,
        currentSlide: this.state.currentSlide
      });
    } else {
      this.update(nextProps);
    }
  },
  componentDidUpdate: function () {
    if (this.props.reInit) {
      this.props.reInit()
    }
    if(this.props.lazyLoad && this.props.centerMode) {
      let childrenLen = React.Children.count(this.props.children)
      let additionalCount = Math.floor(this.props.slidesToShow / 2)
      if(parseInt(this.props.centerPadding) > 0) additionalCount++;
      let leftMostSlide = (this.state.currentSlide - additionalCount + childrenLen) % childrenLen
      let rightMostSlide = (this.state.currentSlide + additionalCount) % childrenLen
      if(!this.state.lazyLoadedList.includes(leftMostSlide)){
        this.setState({
          lazyLoadedList: this.state.lazyLoadedList + [leftMostSlide]
        })
        if (this.props.lazyLoaded) {
          this.props.lazyLoaded([leftMostSlide])
        }
      }
      if(!this.state.lazyLoadedList.includes(rightMostSlide)){
        this.setState({
          lazyLoadedList: this.state.lazyLoadedList + [rightMostSlide]
        })
        if (this.props.lazyLoaded) {
          this.props.lazyLoaded([leftMostSlide])
        }
      }
    }
    this.adaptHeight();
  },
  onWindowResized: function () {
    this.update(this.props);
    // animating state should be cleared while resizing, otherwise autoplay stops working
    this.setState({
      animating: false
    });
    clearTimeout(this.animationEndCallback);
    delete this.animationEndCallback;
  },
  slickPrev: function () {
    // this and fellow methods are wrapped in setTimeout
    // to make sure initialize setState has happened before
    // any of such methods are called
    setTimeout(() => this.changeSlide({ message: 'previous' }), 0)
  },
  slickNext: function () {
    setTimeout(() => this.changeSlide({ message: 'next' }), 0)
  },
  slickGoTo: function (slide) {
    slide = Number(slide)
    !isNaN(slide) && setTimeout( () => this.changeSlide({
      message: 'index',
      index: slide,
      currentSlide: this.state.currentSlide
    }), 0)
  },
  slickGetOption: function(option) {
    const options = assign({}, this.props, this.state)
    return options[option]
  },
  render: function () {
    var className = classnames('slick-initialized', 'slick-slider', this.props.className, {
      'slick-vertical': this.props.vertical,
    });

    var trackProps = {
      fade: this.props.fade,
      cssEase: this.props.cssEase,
      speed: this.props.speed,
      infinite: this.props.infinite,
      centerMode: this.props.centerMode,
      focusOnSelect: this.props.focusOnSelect ? this.selectHandler : null,
      currentSlide: this.state.currentSlide,
      lazyLoad: this.props.lazyLoad,
      lazyLoadedList: this.state.lazyLoadedList,
      rtl: this.props.rtl,
      slideWidth: this.state.slideWidth,
      slideHeight: this.state.slideHeight,
      listHeight: this.state.listHeight,
      vertical: this.props.vertical,
      slidesToShow: this.props.slidesToShow,
      slidesToScroll: this.props.slidesToScroll,
      slideCount: this.state.slideCount,
      trackStyle: this.state.trackStyle,
      variableWidth: this.props.variableWidth,
      unslick: this.props.unslick
    };

    var dots;

    if (this.props.dots === true && this.state.slideCount >= this.props.slidesToShow) {
      var dotProps = {
        dotsClass: this.props.dotsClass,
        slideCount: this.state.slideCount,
        slidesToShow: this.props.slidesToShow,
        currentSlide: this.state.currentSlide,
        slidesToScroll: this.props.slidesToScroll,
        clickHandler: this.changeSlide,
        children: this.props.children,
        customPaging: this.props.customPaging,
        infinite: this.props.infinite,
        appendDots: this.props.appendDots
      };

      dots = (<Dots {...dotProps} />);
    }

    var prevArrow, nextArrow;

    var arrowProps = {
      infinite: this.props.infinite,
      centerMode: this.props.centerMode,
      currentSlide: this.state.currentSlide,
      slideCount: this.state.slideCount,
      slidesToShow: this.props.slidesToShow,
      prevArrow: this.props.prevArrow,
      nextArrow: this.props.nextArrow,
      clickHandler: this.changeSlide
    };

    if (this.props.arrows) {
      prevArrow = (<PrevArrow {...arrowProps} />);
      nextArrow = (<NextArrow {...arrowProps} />);
    }

    var verticalHeightStyle = null;

    if (this.props.vertical) {
      verticalHeightStyle = {
        height: this.state.listHeight,
      };
    }

    var centerPaddingStyle = null;

    if (this.props.vertical === false) {
      if (this.props.centerMode === true) {
        centerPaddingStyle = {
          padding: ('0px ' + this.props.centerPadding)
        };
      }
    } else {
      if (this.props.centerMode === true) {
        centerPaddingStyle = {
          padding: (this.props.centerPadding + ' 0px')
        };
      }
    }

    const listStyle = assign({}, verticalHeightStyle, centerPaddingStyle);
    let listProps = {
      className: 'slick-list',
      style: listStyle,
      onMouseDown: this.swipeStart,
      onMouseMove: this.state.dragging ? this.swipeMove : null,
      onMouseUp: this.swipeEnd,
      onMouseLeave: this.state.dragging ? this.swipeEnd : null,
      onTouchStart: this.swipeStart,
      onTouchMove: this.state.dragging ? this.swipeMove : null,
      onTouchEnd: this.swipeEnd,
      onTouchCancel: this.state.dragging ? this.swipeEnd : null,
      onKeyDown: this.props.accessibility ? this.keyHandler : null,
    }

    let innerSliderProps = {
      className: className,
      onMouseEnter: this.onInnerSliderEnter,
      onMouseLeave: this.onInnerSliderLeave,
      onMouseOver: this.onInnerSliderOver,
    }

    if (this.props.unslick) {
      listProps = { className: 'slick-list' }
      innerSliderProps = { className }
    }

    return (

        { !this.props.unslick ? prevArrow : '' }

          <Track ref={this.trackRefHandler} {...trackProps}>
            {this.props.children}
          </Track>

        { !this.props.unslick ? nextArrow: '' }
        { !this.props.unslick ? dots : '' }

    );
  }
});
<commit_msg>extracted getLazyLoadedList from componentWillMount method<commit_after>'use strict';

import React from 'react';
import EventHandlersMixin from './mixins/event-handlers';
import HelpersMixin from './mixins/helpers';
import initialState from './initial-state';
import defaultProps from './default-props';
import createReactClass from 'create-react-class';
import classnames from 'classnames';
import assign from 'object-assign';

import { Track } from './track';
import { Dots } from './dots';
import { PrevArrow, NextArrow } from './arrows';

export var InnerSlider = createReactClass({
  mixins: [HelpersMixin, EventHandlersMixin],
  list: null, // wraps the track
  track: null, // component that rolls out like a film
  listRefHandler: function (ref) {
    this.list = ref;
  },
  trackRefHandler: function (ref) {
    this.track = ref;
  },
  getInitialState: function () {
    return Object.assign({}, initialState, {
      currentSlide: this.props.initialSlide
    });
  },
  getLazyLoadedList: function () {
    let toLazyLoad = []
    const slidesToShow = this.props.slidesToShow
    const childrenLen = React.Children.count(this.props.children)
    const currentSlide = this.state.currentSlide
    // two variables below don't care about rtl mode, fix later
    let slidesToLeft = this.props.centerMode
      ? Math.floor(slidesToShow / 2) + (parseInt(this.props.centerPadding) > 0)
      : 0
    let slidesToRight = this.props.centerMode
      ? Math.floor(slidesToShow / 2) + (parseInt(this.props.centerPadding) > 0) + 1 // because of for loop exclusion
      : slidesToShow
    for (let slideIndex = currentSlide - slidesToLeft;
      slideIndex < currentSlide + slidesToRight; slideIndex++) {
      toLazyLoad.push(slideIndex)
    }
    console.log('lazyload:', toLazyLoad)
    return toLazyLoad
  },
  componentWillMount: function () {
    if (this.props.init) {
      this.props.init();
    }
    if (this.props.lazyLoad) {
      const lazyLoadedList = this.getLazyLoadedList()
      this.setState({ lazyLoadedList })
      if (this.props.lazyLoaded && lazyLoadedList.length > 0) {
        this.props.lazyLoaded(lazyLoadedList)
      }
    }
  },
  componentDidMount: function componentDidMount() {
    // Hack for autoplay -- Inspect Later
    this.initialize(this.props);
    this.adaptHeight();

    // To support server-side rendering
    if (!window) {
      return
    }
    if (window.addEventListener) {
      window.addEventListener('resize', this.onWindowResized);
    } else {
      window.attachEvent('onresize', this.onWindowResized);
    }
  },
  componentWillUnmount: function componentWillUnmount() {
    if (this.animationEndCallback) {
      clearTimeout(this.animationEndCallback);
    }
    if (window.addEventListener) {
      window.removeEventListener('resize', this.onWindowResized);
    } else {
      window.detachEvent('onresize', this.onWindowResized);
    }
    if (this.state.autoPlayTimer) {
      clearInterval(this.state.autoPlayTimer);
    }
  },
  componentWillReceiveProps: function (nextProps) {
    if (this.props.slickGoTo != nextProps.slickGoTo) {
      if (process.env.NODE_ENV !== 'production') {
        console.warn('react-slick deprecation warning: slickGoTo prop is deprecated and it will be removed in next release. Use slickGoTo method instead')
      }
      this.changeSlide({
        message: 'index',
        index: nextProps.slickGoTo,
        currentSlide: this.state.currentSlide
      });
    } else if (this.state.currentSlide >= nextProps.children.length) {
      this.update(nextProps);
      this.changeSlide({
        message: 'index',
        index: nextProps.children.length - nextProps.slidesToShow,
        currentSlide: this.state.currentSlide
      });
    } else {
      this.update(nextProps);
    }
  },
  componentDidUpdate: function () {
    if (this.props.reInit) {
      this.props.reInit()
    }
    if(this.props.lazyLoad && this.props.centerMode) {
      let childrenLen = React.Children.count(this.props.children)
      let additionalCount = Math.floor(this.props.slidesToShow / 2)
      if(parseInt(this.props.centerPadding) > 0) additionalCount++;
      let leftMostSlide = (this.state.currentSlide - additionalCount + childrenLen) % childrenLen
      let rightMostSlide = (this.state.currentSlide + additionalCount) % childrenLen
      if(!this.state.lazyLoadedList.includes(leftMostSlide)){
        this.setState({
          lazyLoadedList: this.state.lazyLoadedList.concat(leftMostSlide)
        })
        if (this.props.lazyLoaded) {
          this.props.lazyLoaded([leftMostSlide])
        }
      }
      if(!this.state.lazyLoadedList.includes(rightMostSlide)){
        this.setState({
          lazyLoadedList: this.state.lazyLoadedList.concat(rightMostSlide)
        })
        if (this.props.lazyLoaded) {
          this.props.lazyLoaded([leftMostSlide])
        }
      }
    }
    this.adaptHeight();
  },
  onWindowResized: function () {
    this.update(this.props);
    // animating state should be cleared while resizing, otherwise autoplay stops working
    this.setState({
      animating: false
    });
    clearTimeout(this.animationEndCallback);
    delete this.animationEndCallback;
  },
  slickPrev: function () {
    // this and fellow methods are wrapped in setTimeout
    // to make sure initialize setState has happened before
    // any of such methods are called
    setTimeout(() => this.changeSlide({ message: 'previous' }), 0)
  },
  slickNext: function () {
    setTimeout(() => this.changeSlide({ message: 'next' }), 0)
  },
  slickGoTo: function (slide) {
    slide = Number(slide)
    !isNaN(slide) && setTimeout( () => this.changeSlide({
      message: 'index',
      index: slide,
      currentSlide: this.state.currentSlide
    }), 0)
  },
  slickGetOption: function(option) {
    const options = assign({}, this.props, this.state)
    return options[option]
  },
  render: function () {
    var className = classnames('slick-initialized', 'slick-slider', this.props.className, {
      'slick-vertical': this.props.vertical,
    });

    var trackProps = {
      fade: this.props.fade,
      cssEase: this.props.cssEase,
      speed: this.props.speed,
      infinite: this.props.infinite,
      centerMode: this.props.centerMode,
      focusOnSelect: this.props.focusOnSelect ? this.selectHandler : null,
      currentSlide: this.state.currentSlide,
      lazyLoad: this.props.lazyLoad,
      lazyLoadedList: this.state.lazyLoadedList,
      rtl: this.props.rtl,
      slideWidth: this.state.slideWidth,
      slideHeight: this.state.slideHeight,
      listHeight: this.state.listHeight,
      vertical: this.props.vertical,
      slidesToShow: this.props.slidesToShow,
      slidesToScroll: this.props.slidesToScroll,
      slideCount: this.state.slideCount,
      trackStyle: this.state.trackStyle,
      variableWidth: this.props.variableWidth,
      unslick: this.props.unslick
    };

    var dots;

    if (this.props.dots === true && this.state.slideCount >= this.props.slidesToShow) {
      var dotProps = {
        dotsClass: this.props.dotsClass,
        slideCount: this.state.slideCount,
        slidesToShow: this.props.slidesToShow,
        currentSlide: this.state.currentSlide,
        slidesToScroll: this.props.slidesToScroll,
        clickHandler: this.changeSlide,
        children: this.props.children,
        customPaging: this.props.customPaging,
        infinite: this.props.infinite,
        appendDots: this.props.appendDots
      };

      dots = (<Dots {...dotProps} />);
    }

    var prevArrow, nextArrow;

    var arrowProps = {
      infinite: this.props.infinite,
      centerMode: this.props.centerMode,
      currentSlide: this.state.currentSlide,
      slideCount: this.state.slideCount,
      slidesToShow: this.props.slidesToShow,
      prevArrow: this.props.prevArrow,
      nextArrow: this.props.nextArrow,
      clickHandler: this.changeSlide
    };

    if (this.props.arrows) {
      prevArrow = (<PrevArrow {...arrowProps} />);
      nextArrow = (<NextArrow {...arrowProps} />);
    }

    var verticalHeightStyle = null;

    if (this.props.vertical) {
      verticalHeightStyle = {
        height: this.state.listHeight,
      };
    }

    var centerPaddingStyle = null;

    if (this.props.vertical === false) {
      if (this.props.centerMode === true) {
        centerPaddingStyle = {
          padding: ('0px ' + this.props.centerPadding)
        };
      }
    } else {
      if (this.props.centerMode === true) {
        centerPaddingStyle = {
          padding: (this.props.centerPadding + ' 0px')
        };
      }
    }

    const listStyle = assign({}, verticalHeightStyle, centerPaddingStyle);
    let listProps = {
      className: 'slick-list',
      style: listStyle,
      onMouseDown: this.swipeStart,
      onMouseMove: this.state.dragging ? this.swipeMove : null,
      onMouseUp: this.swipeEnd,
      onMouseLeave: this.state.dragging ? this.swipeEnd : null,
      onTouchStart: this.swipeStart,
      onTouchMove: this.state.dragging ? this.swipeMove : null,
      onTouchEnd: this.swipeEnd,
      onTouchCancel: this.state.dragging ? this.swipeEnd : null,
      onKeyDown: this.props.accessibility ? this.keyHandler : null,
    }

    let innerSliderProps = {
      className: className,
      onMouseEnter: this.onInnerSliderEnter,
      onMouseLeave: this.onInnerSliderLeave,
      onMouseOver: this.onInnerSliderOver,
    }

    if (this.props.unslick) {
      listProps = { className: 'slick-list' }
      innerSliderProps = { className }
    }

    return (

        { !this.props.unslick ? prevArrow : '' }

          <Track ref={this.trackRefHandler} {...trackProps}>
            {this.props.children}
          </Track>

        { !this.props.unslick ? nextArrow: '' }
        { !this.props.unslick ? dots : '' }

    );
  }
});
<|endoftext|>


<commit_before>import core from 'core-js';

export class CSRFInterceptor {

  /**
   * @constructor
   * @param url URL of the sails CSRF getter
   * @param {SailsSocketClient} client Client for getting CSRF from server
   * @param token Optional token - use when you have prefetched token, e.g. rendered in HTML
   */
  constructor(url, client, token) {
    this.url = url;
    this.client = client;
    this.token = token;
  }

  /**
   * Request message interceptor
   *
   * @param message
   * @returns {SocketRequestMessage}
   */
  request(message) {
    if (message.method === 'get' || message.url === this.url) {
      return message;
    }

    if (this.token) {
      this.setCsrfTokenHeader(message);
      return message;
    } else {
      return new Promise((resolve, reject) => {
        this.client.get(this.url).then(response => {
          this.token = response.content._csrf;
          this.setCsrfTokenHeader(message);
          resolve(message);
        }).catch(reject);
      });
    }

  }

  setCsrfTokenHeader(message) {
    message.headers.add('X-Csrf-Token', this.token);
    return message;
  }

}
<commit_msg>feat(LoggerInterceptor): added LoggerInterceptor for debuging messages<commit_after>import core from 'core-js';
import { LogManager } from 'aurelia-framework';

export class CSRFInterceptor {

  /**
   * @constructor
   * @param url URL of the sails CSRF getter
   * @param {SailsSocketClient} client Client for getting CSRF from server
   * @param token Optional token - use when you have prefetched token, e.g. rendered in HTML
   */
  constructor(url, client, token) {
    this.url = url;
    this.client = client;
    this.token = token;
  }

  /**
   * Request message interceptor
   *
   * @param message
   * @returns {SocketRequestMessage}
   */
  request(message) {
    if (message.method === 'get' || message.url === this.url) {
      return message;
    }

    if (this.token) {
      this.setCsrfTokenHeader(message);
      return message;
    } else {
      return new Promise((resolve, reject) => {
        this.client.get(this.url).then(response => {
          this.token = response.content._csrf;
          this.setCsrfTokenHeader(message);
          resolve(message);
        }).catch(reject);
      });
    }

  }

  setCsrfTokenHeader(message) {
    message.headers.add('X-Csrf-Token', this.token);
    return message;
  }

}

var logger = LogManager.getLogger('sails');

export class LoggerInterceptor {

  request(message) {
    logger.debug('Sending message to sails', message);
    return message;
  }

  response(response) {
    logger.debug('Receiving response from sails', response);
    return response;
  }

  responseError(response) {
    logger.error('There was an error during sails request', response);
    throw response;
  }

}
<|endoftext|>


<commit_before>;(function ($, undefined) {
    var slice = Array.prototype.slice;
    $.defer = function ( /*[func] [, delay] [, funcParameters]*/ ) {
        var args = arguments,
            isFunc = $.isFunction(args[0]),
            func = isFunc ? args[0] : $.noop,
            delay = (isFunc ? args[1] : args[0]) || 0,
            funcArgs = isFunc ? slice.call(args, 2) : undefined,
            isCancelled = false,
            cancel = function (reject /* = true */ ) {
                clearTimeout(timerId);
                isCancelled = true;
                if ((!arguments.length || reject) && deferred.state() === "pending") {
                    deferred.rejectWith(null, funcArgs);
                }
            },
            deferred = $.Deferred(),
            timerId = setTimeout(function () {
                deferred.notifyWith(promise, funcArgs);
                if (isCancelled) {
                    return;
                }
                try {
                    var result = func.apply(this, funcArgs);
                    deferred.resolveWith(result, funcArgs);
                } catch (e) {
                    deferred.rejectWith(e, funcArgs);
                }
            }, delay),
            promise = $.extend(deferred.promise(), {
                cancel: cancel
            });
        return promise;
    };
})(jQuery);<commit_msg>arguments to .apply have to be an array for IE8 and older, at least.<commit_after>;(function($) {
    var slice = Array.prototype.slice;
	$.defer = function( /*[func] [, delay] [, funcParameters]*/) {
		var args = arguments,
		    isFunc = $.isFunction(args[0]),
		    func = isFunc ? args[0] : $.noop,
		    delay = (isFunc ? args[1] : args[0]) || 0,
		    funcArgs = isFunc ? slice.call(args, 2) : [],
		    isCancelled = false,
		    cancel = function(reject /* = true */) {
			    clearTimeout(timerId);
			    isCancelled = true;
			    if ((!arguments.length || reject) && deferred.state() === "pending") {
				    deferred.rejectWith(null, funcArgs);
			    }
		    },
		    deferred = $.Deferred(),
		    timerId = setTimeout(function() {
			    deferred.notifyWith(promise, funcArgs);
			    if (isCancelled) {
				    return;
			    }
			    try {
				    var result = func.apply(this, funcArgs);
				    deferred.resolveWith(result, funcArgs);
			    } catch(e) {
			    	deferred.rejectWith(e, funcArgs);
			    }
		    }, delay),
		    promise = $.extend(deferred.promise(), {
			    cancel: cancel
		    });
		return promise;
	};
})(jQuery);
<|endoftext|>


<commit_before>import { isString, isUndefined, toNode } from '../util/index';

var supportsMultiple, supportsForce;

export default function (UIkit) {

    UIkit.prototype.$addClass = function (...args) {
        var el = getEl(args, this.$el);

        if (!args.length) {
            return;
        }

        if (~args[0].indexOf(' ')) {
            args = args[0].split(' ').concat(args.slice(1));
        }

        supportsMultiple
            ? el.classList.add.apply(el.classList, args)
            : args.forEach(cls => args[0].classList.add(cls));
    };

    UIkit.prototype.$removeClass = function (...args) {
        var el = getEl(args, this.$el);

        if (!args.length) {
            return;
        }

        if (~args[0].indexOf(' ')) {
            args = args[0].split(' ').concat(args.slice(1));
        }

        supportsMultiple
            ? el.classList.remove.apply(el.classList, args)
            : args.forEach(cls => el.classList.remove(cls));
    };

    UIkit.prototype.$hasClass = function (...args) {
        var el = getEl(args, this.$el);
        return args.length && el.classList.contains(args[0]);
    };

    UIkit.prototype.$toggleClass = function (...args) {
        var el = getEl(args, this.$el);

        if (!args.length) {
            return;
        }

        supportsForce
            ? el.classList.toggle(args[0], args[1])
            : (el.classList[(!isUndefined(args[1]) ? args[1] : !el.classList.contains(args[0])) ? 'add' : 'remove'](args[0]));
    };

}

function getEl(args, el) {
    return toNode(isString(args[0]) ? el : args.shift());
}

(function() {

    var el = document.createElement('_');
    el.classList.add('c1', 'c2');
    supportsMultiple = el.classList.contains('c2');
    el.classList.toggle('c3', false);
    supportsForce = el.classList.contains('c3')
    el = null;

})();
<commit_msg>cleanup<commit_after>import { isString, isUndefined, toNode } from '../util/index';

var supportsMultiple, supportsForce;

export default function (UIkit) {

    UIkit.prototype.$addClass = function (...args) {
        var el = getEl(args, this.$el);

        if (!args[0]) {
            return;
        }

        if (~args[0].indexOf(' ')) {
            args = args[0].split(' ').concat(args.slice(1));
        }

        supportsMultiple
            ? el.classList.add.apply(el.classList, args)
            : args.forEach(cls => args[0].classList.add(cls));
    };

    UIkit.prototype.$removeClass = function (...args) {
        var el = getEl(args, this.$el);

        if (!args[0]) {
            return;
        }

        if (~args[0].indexOf(' ')) {
            args = args[0].split(' ').concat(args.slice(1));
        }

        supportsMultiple
            ? el.classList.remove.apply(el.classList, args)
            : args.forEach(cls => el.classList.remove(cls));
    };

    UIkit.prototype.$hasClass = function (...args) {
        var el = getEl(args, this.$el);
        return args.length && el.classList.contains(args[0]);
    };

    UIkit.prototype.$toggleClass = function (...args) {
        var el = getEl(args, this.$el);

        args[0] && supportsForce
            ? el.classList.toggle(args[0], args[1])
            : (el.classList[(!isUndefined(args[1]) ? args[1] : !el.classList.contains(args[0])) ? 'add' : 'remove'](args[0]));
    };

}

function getEl(args, el) {
    return toNode(isString(args[0]) ? el : args.shift());
}

(function() {

    var el = document.createElement('_');
    el.classList.add('c1', 'c2');
    supportsMultiple = el.classList.contains('c2');
    el.classList.toggle('c3', false);
    supportsForce = el.classList.contains('c3')
    el = null;

})();
<|endoftext|>


<commit_before>/* global window,Node */

import HeightAnimator from './HeightAnimator';

export function nothing(e) {
  e.preventDefault();
  e.stopPropagation();
  e.stopImmediatePropagation();
  return false;
}

export function setBrowserActionIcon(icon) {
  const iconPaths = {
    default: 'icons/bookmark48.png',
    star: 'icons/star_fav.png',
    star_empty: 'icons/star_fav_empty.png',
  };

  window.chrome.browserAction.setIcon({
    path: iconPaths[icon],
  });
}

export function translateDocument(document) {
  const translatableElements = document.querySelectorAll('[data-i18n-key]');
  translatableElements.forEach((translatableElement) => {
    const key = translatableElement.getAttribute('data-i18n-key');
    const translation = window.chrome.i18n.getMessage(key);
    if (translation !== '') {
      translatableElement.innerHTML = translation;
    }
  });
}

export function hasClass(element, className) {
  const regex = new RegExp(`(^| )${className}( |$)`);
  return regex.test(element.className);
}

export function addClass(element, className) {
  if (element.className === '') {
    element.className = className;
  } else {
    element.className += ` ${className}`;
  }
}

export function removeClass(element, className) {
  const regex = new RegExp(`\\b${className}( |$)`, 'g');
  element.className = element.className.replace(regex, '').trimRight();
}

export function toggleClass(element, className) {
  if (hasClass(element, className)) {
    removeClass(element, className);
  } else {
    addClass(element, className);
  }
}

export function getElementData(element, key) {
  return element.getAttribute(`data-${key}`);
}

export function setElementData(element, key, value) {
  element.setAttribute(`data-${key}`, value);
}

export function getAncestorsWithClass(elem, className) {
  const parents = [];
  if (!elem.parentNode || !elem.parentNode.className) {
    return parents;
  }
  if (hasClass(elem.parentNode, className)) {
    parents.push(elem.parentNode);
  }

  return parents.concat(getAncestorsWithClass(elem.parentNode, className));
}

export function slideUp(element, duration) {
  const animator = new HeightAnimator(element, 0, duration);
  animator.start();
}

export function slideDown(element, duration) {
  const animator = new HeightAnimator(element, 'auto', duration);
  animator.start();
}

export function elementIndex(element) {
  if (!element || typeof element.parentNode === 'undefined') {
    return null;
  }
  const parent = element.parentNode;
  const children = parent.childNodes;
  let i = 0;
  for (let j = 0; j < children.length; j++) {
    if (children[j].nodeType === Node.TEXT_NODE) {
      continue;
    }
    if (element === children[j]) {
      return i;
    }
    i++;
  }
  return -1;
}

export function handleOpenAllBookmarks(bookmark) {
  if (bookmark.url) {
    window.chrome.tabs.create({
      url: bookmark.url,
      active: false,
    });

    return;
  }

  if (bookmark.children) {
    bookmark.children.forEach((child) => {
      handleOpenAllBookmarks(child);
    });
  }
}
<commit_msg>Start with active tab when opening all bookmarks in a folder<commit_after>/* global window,Node */

import HeightAnimator from './HeightAnimator';

export function nothing(e) {
  e.preventDefault();
  e.stopPropagation();
  e.stopImmediatePropagation();
  return false;
}

export function setBrowserActionIcon(icon) {
  const iconPaths = {
    default: 'icons/bookmark48.png',
    star: 'icons/star_fav.png',
    star_empty: 'icons/star_fav_empty.png',
  };

  window.chrome.browserAction.setIcon({
    path: iconPaths[icon],
  });
}

export function translateDocument(document) {
  const translatableElements = document.querySelectorAll('[data-i18n-key]');
  translatableElements.forEach((translatableElement) => {
    const key = translatableElement.getAttribute('data-i18n-key');
    const translation = window.chrome.i18n.getMessage(key);
    if (translation !== '') {
      translatableElement.innerHTML = translation;
    }
  });
}

export function hasClass(element, className) {
  const regex = new RegExp(`(^| )${className}( |$)`);
  return regex.test(element.className);
}

export function addClass(element, className) {
  if (element.className === '') {
    element.className = className;
  } else {
    element.className += ` ${className}`;
  }
}

export function removeClass(element, className) {
  const regex = new RegExp(`\\b${className}( |$)`, 'g');
  element.className = element.className.replace(regex, '').trimRight();
}

export function toggleClass(element, className) {
  if (hasClass(element, className)) {
    removeClass(element, className);
  } else {
    addClass(element, className);
  }
}

export function getElementData(element, key) {
  return element.getAttribute(`data-${key}`);
}

export function setElementData(element, key, value) {
  element.setAttribute(`data-${key}`, value);
}

export function getAncestorsWithClass(elem, className) {
  const parents = [];
  if (!elem.parentNode || !elem.parentNode.className) {
    return parents;
  }
  if (hasClass(elem.parentNode, className)) {
    parents.push(elem.parentNode);
  }

  return parents.concat(getAncestorsWithClass(elem.parentNode, className));
}

export function slideUp(element, duration) {
  const animator = new HeightAnimator(element, 0, duration);
  animator.start();
}

export function slideDown(element, duration) {
  const animator = new HeightAnimator(element, 'auto', duration);
  animator.start();
}

export function elementIndex(element) {
  if (!element || typeof element.parentNode === 'undefined') {
    return null;
  }
  const parent = element.parentNode;
  const children = parent.childNodes;
  let i = 0;
  for (let j = 0; j < children.length; j++) {
    if (children[j].nodeType === Node.TEXT_NODE) {
      continue;
    }
    if (element === children[j]) {
      return i;
    }
    i++;
  }
  return -1;
}

function getAllBookmarksStartingAt(bookmark) {
  let bookmarks = [];
  if (bookmark.url) {
    bookmarks.push(bookmark.url);
  }

  if (bookmark.children) {
    bookmark.children.forEach((child) => {
      bookmarks = bookmarks.concat(getAllBookmarksStartingAt(child));
    });
  }

  return bookmarks;
}

export function handleOpenAllBookmarks(startingBookmark) {
  const bookmarks = getAllBookmarksStartingAt(startingBookmark);

  window.chrome.tabs.query({ active: true }, (tab) => {
    window.chrome.tabs.update(tab.id, { url: bookmarks[0] });
  });

  bookmarks.slice(1).forEach((bookmark) => {
    window.chrome.tabs.create({
      url: bookmark,
      active: false,
    });
  });
}
<|endoftext|>


<commit_before>import './common'
let location = require('./location/locationSelector')
const templating = require('./template-render')
const browser = require('./browser')
const socialShare = require('./social-share')

location
  .getCurrent()
  .then((result) => {
    let theData = {
      isManchester: result.id === 'manchester',
      isLeeds: result.id === 'leeds',
      locations: location.getViewModel(result)
    }
    var callback = function () {
      browser.loaded()
      socialShare.init()
    }

    templating.renderTemplate('js-content-tpl', theData, 'js-template-output', callback)
  })
<commit_msg>Revert "got rid of redundant city selector on home page js"<commit_after>import './common'
let location = require('./location/locationSelector')
const templating = require('./template-render')
const browser = require('./browser')
const socialShare = require('./social-share')

location
  .getCurrent()
  .then((result) => {
    let theData = {
      isManchester: result.id === 'manchester',
      isLeeds: result.id === 'leeds',
      locations: location.getViewModel(result)
    }
    var callback = function () {
      location.handler(() => {
        window.location.reload()
      }, '.js-homepage-promo-location-selector')

      browser.loaded()
      socialShare.init()
    }

    templating.renderTemplate('js-content-tpl', theData, 'js-template-output', callback)
  })
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

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

    var Fluxxor = require("fluxxor");

    var events = require("../events"),
        log = require("js/util/log"),
        math = require("js/util/math");

    /**
     * Panel/column identifiers.
     *
     * @const
     * @type {object}
     */
    var UI_COMPONENTS = Object.freeze({
        LAYERS_LIBRARY_COL: "layersLibrariesVisible",
        PROPERTIES_COL: "propertiesVisible",
        TRANSFORM_PANEL: "transformVisible",
        STYLES_PANEL: "stylesVisible",
        APPEARANCE_PANEL: "appearanceVisible",
        EFFECTS_PANEL: "effectsVisible",
        EXPORT_PANEL: "exportVisible",
        LAYERS_PANEL: "layersVisible",
        LIBRARIES_PANEL: "libraryVisible"
    });

    var UIStore = Fluxxor.createStore({

        /**
         * The current window-to-canvas transform represented as a 2d matrix
         *
         * @private
         * @type {?Array.<number>}
         */
        _transformMatrix: null,

        /**
         * The current canvas-to-window transform represented as a 2d matrix
         *
         * @private
         * @type {?Array.<number>}
         */
        _inverseTransformMatrix: null,

        /**
         * Current zoom factor
         *
         * @private
         * @type {Number}
         */
        _zoom: null,

        /**
         * Flag to tell whether Scrim should draw any of the SVG overlays or not
         *
         * @private
         * @type {boolean}
         */
        _overlaysEnabled: null,

        /**
         * Current root font size, which is used to calculated rem units
         *
         * @private
         * @type {number}
         */
        _rootSize: null,

        /**
         * Flag to tell if the scrim should be drawing a marquee
         *
         * @private
         * @type {boolean}
         */
        _marqueeEnabled: null,

        /**
         * Marquee start location
         *
         * @private
         * @type {{x: number, y: number}}
         */
        _marqueeStart: null,

        /**
         * Panel set width
         *
         * @private
         * @type {number}
         */
        _panelWidth: null,

        /**
         * Icon bar width
         *
         * @private
         * @type {number}
         */
        _iconBarWidth: null,

        /**
         * Document header height
         *
         * @private
         * @type {number}
         */
        _headerHeight: null,

        /**
         * Toolbar width, 0 if it's not pinned
         *
         * @private
         * @type {number}
         */
        _toolbarWidth: null,

        /**
         * Constants used to refer to different panels/columns.
         *
         * @const
         * @type {object}
         */
        components: UI_COMPONENTS,

        /**
         * Reference point for a layer when adjusting W and H
         * Default is "lt" for left, top
         *
         * @private
         * @type {string}
         */
        _referencePoint: null,

        /**
         * The coordinates of the current mouse position if it's being tracked; otherwise null.
         *
         * @private
         * @type {?{currentMouseX: number, currentMouseY: number}}
         */
        _currentMousePosition: null,

        initialize: function () {
            this.bindActions(
                events.RESET, this._handleReset,
                events.ui.TRANSFORM_UPDATED, this._transformUpdated,
                events.ui.PANELS_RESIZED, this._handlePanelResize,
                events.ui.SUPERSELECT_MARQUEE, this._handleMarqueeStart,
                events.ui.TOGGLE_OVERLAYS, this._handleOverlayToggle,
                events.ui.REFERENCE_POINT_CHANGED, this._handleReferencePointChanged,
                events.ui.DISPLAY_CHANGED, this._handleDisplayChanged,
                events.ui.MOUSE_POSITION_CHANGED, this._handleMousePositionChanged,
                events.document.DOCUMENT_UPDATED, this._handleLayersUpdated,
                events.document.history.RESET_LAYERS, this._handleLayersUpdated,
                events.document.history.RESET_BOUNDS, this._handleLayersUpdated
            );

            // HACK: Do not reset panel sizes because they should remain constant.
            this._panelWidth = 0;
            this._columnCount = 0;
            this._iconBarWidth = 0;
            this._headerHeight = 0;
            this._toolbarWidth = 0;

            this._handleReset();
        },

        /**
         * Reset or initialize store state.
         *
         * @private
         */
        _handleReset: function () {
            this._setRootSize();
            this._overlaysEnabled = true;
            this._marqueeEnabled = false;
            this._marqueeStart = null;
            this._zoom = null;
            this._transformMatrix = null;
            this._inverseTransformMatrix = null;
            this._referencePoint = "lt";
            this._currentMousePosition = null;
        },

        /** @ignore */
        getState: function () {
            return {
                transformMatrix: this._transformMatrix,
                inverseTransformMatrix: this._inverseTransformMatrix,
                zoomFactor: this._zoom,
                centerOffsets: this.getCenterOffsets(),
                overlaysEnabled: this._overlaysEnabled,
                marqueeEnabled: this._marqueeEnabled,
                marqueeStart: this._marqueeStart,
                referencePoint: this._referencePoint
            };
        },

        /** @ignore */
        zoomWindowToCanvas: function (x) {
            return x * this._zoom;
        },

        /** @ignore */
        zoomCanvasToWindow: function (x) {
            return x / this._zoom;
        },

        /**
         * Map (x,y) coordinates in window space to canvas space.
         *
         * @private
         * @param {number} x Offset from the left window edge
         * @param {number} y Offset from the top window edge
         * @return {{x: number, y: number}} A point that describes the offset
         *  from the top-left corner of the canvas.
         */
        transformWindowToCanvas: function (x, y) {
            if (!this._transformMatrix) {
                return {
                    x: 0,
                    y: 0
                };
            }
            var transform = this._transformMatrix,
                xx = transform[0],
                yx = transform[1],
                xy = transform[2],
                yy = transform[3],
                x0 = transform[4],
                y0 = transform[5];

            var xt = xx * x + yx * y + x0,
                yt = xy * x + yy * y + y0;

            return {
                x: xt,
                y: yt
            };
        },

        /**
         * Map (x,y) coordinates in canvas space to window space.
         *
         * @private
         * @param {number} x Offset from the left canvas edge
         * @param {number} y Offset from the top canvas edge
         * @return {{x: number, y: number}} A point that describes the offset
         *  from the top-left corner of the window.
         */
        transformCanvasToWindow: function (x, y) {
            if (!this._inverseTransformMatrix) {
                return {
                    x: 0,
                    y: 0
                };
            }
            var transform = this._inverseTransformMatrix,
                xx = transform[0],
                yx = transform[1],
                xy = transform[2],
                yy = transform[3],
                x0 = transform[4],
                y0 = transform[5];

            var xt = xx * x + xy * y + x0,
                yt = yx * x + yy * y + y0;

            return {
                x: xt,
                y: yt
            };
        },

        /**
         * Calculate the overlay offsets, optionally taking into account a
         * (future) number of open columns.
         *
         * @return {{top: number, right: number, bottom: number, left: number}}
         */
        getCenterOffsets: function (columns) {
            var preferences = this.flux.store("preferences").getState(),
                singleColumn = preferences.get("singleColumnModeEnabled", false),
                right = (columns !== undefined && singleColumn) ? 0 :
                    this._iconBarWidth;

            if (singleColumn) {
                right += this._panelWidth;
            } else if (columns === undefined || columns === this._columnCount) {
                right += this._panelWidth;
            } else if (columns > 0) {
                if (columns === 1 && this._columnCount === 2) {
                    right += (this._panelWidth / 2);
                } else if (columns === 2 && this._columnCount === 1) {
                    right += (this._panelWidth * 2);
                } else {
                    log.warn("Unable to infer enter offsets for " + columns +
                        " columns from " + this._columnCount);
                }
            }

            return {
                top: this._headerHeight,
                right: right,
                left: this._toolbarWidth,
                bottom: 0
            };
        },

        /**
         * Get the current cloaking rectangle, which omits the static UI.
         *
         * @return {?{top: number, right: number, left: number, bottom: number}}
         */
        getCloakRect: function () {
            var centerOffsets = this.getCenterOffsets(),
                windowWidth = window.document.body.clientWidth,
                windowHeight = window.document.body.clientHeight;

            return {
                left: centerOffsets.left,
                top: centerOffsets.top,
                bottom: windowHeight - centerOffsets.bottom,
                right: windowWidth - centerOffsets.right
            };
        },

        /**
         * Inverts the given affine transformation matrix
         *
         * @private
         * @param  {Array.<number>} matrix
         * @return {Array.<number>} Inverted matrix
         */
        _inverseOf: function (matrix) {
            var xx = matrix[0],
                xy = matrix[1],
                yx = matrix[2],
                yy = matrix[3],
                x0 = matrix[4],
                y0 = matrix[5],

                det = xx * yy - xy * yx;

            if (!det) {
                log.warn("Window to canvas matrix not invertable.");
                return null;
            }

            det = 1.0 / det;

            return [
                yy * det,
                -yx * det,
                -xy * det,
                xx * det,
                (xy * y0 - yy * x0) * det,
                (yx * x0 - xx * y0) * det
            ];
        },

        /**
         * Set the current transform from a transformation object.
         *
         * @private
         * @param {{xx: number, yx: number, xy: number, yy: number, tx: number, ty: number}} transformObj
         */
        _setTransformObject: function (transformObj) {
            if (transformObj) {
                this._transformMatrix = [
                    transformObj.xx,
                    transformObj.yx,
                    transformObj.xy,
                    transformObj.yy,
                    transformObj.tx,
                    transformObj.ty
                ];
                this._inverseTransformMatrix = this._inverseOf(this._transformMatrix);
            } else {
                this._transformMatrix = null;
                this._inverseTransformMatrix = null;
            }
        },

        /**
        * Get the root font size
        * @return {number}
        */
        getRootSize: function () {
            return this._rootSize;
        },

        /**
         * Converts a rem value to a pixel value based on
         * root font size
         * 16 px is 1 rem, so if our font-size is 62.5% (10px)
         * all our UI should be shrunk to that as well
         *
         * @return {number}
         */
        remToPx: function (rem) {
            return rem * this._rootSize;
        },

        /**
        * Set the root size based on the document root element font size
        *
        * @private
        */
        _setRootSize: function () {
            var computedStyle = window.getComputedStyle(window.document.documentElement);
            this._rootSize = math.pixelDimensionToNumber(computedStyle.fontSize);
        },

        /**
         * Set the current transform from a 2d matrix. The format of this array
         * is described here:
         * http://cairographics.org/manual/cairo-cairo-matrix-t.html
         *
         * @private
         * @param {Array.<number>} transformMatrix
         */
        _setTransformMatrix: function (transformMatrix) {
            this._transformMatrix = transformMatrix;
            this._inverseTransformMatrix = this._inverseOf(transformMatrix);
        },

        /**
         * Reset the current window-to-canvas transform
         *
         * @private
         * @param {{transformMatrx: Array.<number>=, transformObject: object=}} payload
         */
        _transformUpdated: function (payload) {
            if (payload.transformMatrix) {
                this._setTransformMatrix(payload.transformMatrix);
            } else {
                this._setTransformObject(payload.transformObject);
            }

            this._zoom = payload.zoom;
            this._overlaysEnabled = true;

            this.emit("change");
        },

        /**
         * Updates the center offsets when they change.
         *
         * @private
         * @param {{panelWidth: number=, headerHeight: number=, toolbarWidth: number=}} payload
         */
        _handlePanelResize: function (payload) {
            var changed;
            if (payload.hasOwnProperty("panelWidth") && payload.panelWidth !== this._panelWidth) {
                this._panelWidth = payload.panelWidth;
                changed = true;
            }

            if (payload.hasOwnProperty("columnCount") && payload.columnCount !== this._columnCount) {
                this._columnCount = payload.columnCount;
                changed = true;
            }

            if (payload.hasOwnProperty("iconBarWidth") && payload.iconBarWidth !== this._iconBarWidth) {
                this._iconBarWidth = payload.iconBarWidth;
                changed = true;
            }

            if (payload.hasOwnProperty("headerHeight") && payload.headerHeight !== this._headerHeight) {
                this._headerHeight = payload.headerHeight;
                changed = true;
            }

            if (payload.hasOwnProperty("toolbarWidth") && payload.toolbarWidth !== this._toolbarWidth) {
                this._toolbarWidth = payload.toolbarWidth;
                changed = true;
            }

            if (changed) {
                this.emit("change");
            }
        },

        /**
         * Updates the overlays enabled flag
         *
         * @private
         * @param {{enabled: boolean}} payload
         */
        _handleOverlayToggle: function (payload) {
            this._overlaysEnabled = payload.enabled;
            this.emit("change");
        },

        /**
         * Re-enables the overlays once document layers are updated.
         *
         * @private
         */
        _handleLayersUpdated: function () {
            this.waitFor(["document"], function () {
                this._overlaysEnabled = true;
                this.emit("change");
            });
        },

        /**
         * Updates the marquee start location and flag
         *
         * @param {{x: number, y: number, enabled: boolean}} payload
         */
        _handleMarqueeStart: function (payload) {
            this._marqueeEnabled = payload.enabled;
            this._marqueeStart = payload.enabled ? {
                x: payload.x,
                y: payload.y
            } : null;

            this.emit("change");
        },

        /**
         * Set the size-adjustment reference point.
         *
         * @private
         * @param {{referencePoint: string}} payload
         */
        _handleReferencePointChanged: function (payload) {
            this._referencePoint = payload.referencePoint;
            this.emit("change");
        },

        /**
         * Re-set the root font size when the display changes.
         *
         * @private
         */
        _handleDisplayChanged: function () {
            this._setRootSize();
            this.emit("change");
        },

        /**
         * Update the current mouse position.
         *
         * @private
         * @param {?{currentMouseX: number, currentMouseY: number}} payload
         */
        _handleMousePositionChanged: function (payload) {
            this._currentMousePosition = payload;
        },

        /**
         * Get the current mouse position if it's being tracked; otherwise null.
         *
         * @return {?{currentMouseX: number, currentMouseY: number}}
         */
        getCurrentMousePosition: function () {
            return this._currentMousePosition;
        },

        /**
         * Get the current transform matrix if it's being tracked; otherwise null.
         *
         * @return {?{transformMatrix: Array.<number>}}
         */
        getCurrentTransformMatrix: function () {
            return this._transformMatrix;
        }
    });

    module.exports = UIStore;
});
<commit_msg>Refer to transform matrix correctly in JSDoc<commit_after>/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

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

    var Fluxxor = require("fluxxor");

    var events = require("../events"),
        log = require("js/util/log"),
        math = require("js/util/math");

    /**
     * Panel/column identifiers.
     *
     * @const
     * @type {object}
     */
    var UI_COMPONENTS = Object.freeze({
        LAYERS_LIBRARY_COL: "layersLibrariesVisible",
        PROPERTIES_COL: "propertiesVisible",
        TRANSFORM_PANEL: "transformVisible",
        STYLES_PANEL: "stylesVisible",
        APPEARANCE_PANEL: "appearanceVisible",
        EFFECTS_PANEL: "effectsVisible",
        EXPORT_PANEL: "exportVisible",
        LAYERS_PANEL: "layersVisible",
        LIBRARIES_PANEL: "libraryVisible"
    });

    var UIStore = Fluxxor.createStore({

        /**
         * The current window-to-canvas transform represented as a 2d matrix
         *
         * @private
         * @type {?Array.<number>}
         */
        _transformMatrix: null,

        /**
         * The current canvas-to-window transform represented as a 2d matrix
         *
         * @private
         * @type {?Array.<number>}
         */
        _inverseTransformMatrix: null,

        /**
         * Current zoom factor
         *
         * @private
         * @type {Number}
         */
        _zoom: null,

        /**
         * Flag to tell whether Scrim should draw any of the SVG overlays or not
         *
         * @private
         * @type {boolean}
         */
        _overlaysEnabled: null,

        /**
         * Current root font size, which is used to calculated rem units
         *
         * @private
         * @type {number}
         */
        _rootSize: null,

        /**
         * Flag to tell if the scrim should be drawing a marquee
         *
         * @private
         * @type {boolean}
         */
        _marqueeEnabled: null,

        /**
         * Marquee start location
         *
         * @private
         * @type {{x: number, y: number}}
         */
        _marqueeStart: null,

        /**
         * Panel set width
         *
         * @private
         * @type {number}
         */
        _panelWidth: null,

        /**
         * Icon bar width
         *
         * @private
         * @type {number}
         */
        _iconBarWidth: null,

        /**
         * Document header height
         *
         * @private
         * @type {number}
         */
        _headerHeight: null,

        /**
         * Toolbar width, 0 if it's not pinned
         *
         * @private
         * @type {number}
         */
        _toolbarWidth: null,

        /**
         * Constants used to refer to different panels/columns.
         *
         * @const
         * @type {object}
         */
        components: UI_COMPONENTS,

        /**
         * Reference point for a layer when adjusting W and H
         * Default is "lt" for left, top
         *
         * @private
         * @type {string}
         */
        _referencePoint: null,

        /**
         * The coordinates of the current mouse position if it's being tracked; otherwise null.
         *
         * @private
         * @type {?{currentMouseX: number, currentMouseY: number}}
         */
        _currentMousePosition: null,

        initialize: function () {
            this.bindActions(
                events.RESET, this._handleReset,
                events.ui.TRANSFORM_UPDATED, this._transformUpdated,
                events.ui.PANELS_RESIZED, this._handlePanelResize,
                events.ui.SUPERSELECT_MARQUEE, this._handleMarqueeStart,
                events.ui.TOGGLE_OVERLAYS, this._handleOverlayToggle,
                events.ui.REFERENCE_POINT_CHANGED, this._handleReferencePointChanged,
                events.ui.DISPLAY_CHANGED, this._handleDisplayChanged,
                events.ui.MOUSE_POSITION_CHANGED, this._handleMousePositionChanged,
                events.document.DOCUMENT_UPDATED, this._handleLayersUpdated,
                events.document.history.RESET_LAYERS, this._handleLayersUpdated,
                events.document.history.RESET_BOUNDS, this._handleLayersUpdated
            );

            // HACK: Do not reset panel sizes because they should remain constant.
            this._panelWidth = 0;
            this._columnCount = 0;
            this._iconBarWidth = 0;
            this._headerHeight = 0;
            this._toolbarWidth = 0;

            this._handleReset();
        },

        /**
         * Reset or initialize store state.
         *
         * @private
         */
        _handleReset: function () {
            this._setRootSize();
            this._overlaysEnabled = true;
            this._marqueeEnabled = false;
            this._marqueeStart = null;
            this._zoom = null;
            this._transformMatrix = null;
            this._inverseTransformMatrix = null;
            this._referencePoint = "lt";
            this._currentMousePosition = null;
        },

        /** @ignore */
        getState: function () {
            return {
                transformMatrix: this._transformMatrix,
                inverseTransformMatrix: this._inverseTransformMatrix,
                zoomFactor: this._zoom,
                centerOffsets: this.getCenterOffsets(),
                overlaysEnabled: this._overlaysEnabled,
                marqueeEnabled: this._marqueeEnabled,
                marqueeStart: this._marqueeStart,
                referencePoint: this._referencePoint
            };
        },

        /** @ignore */
        zoomWindowToCanvas: function (x) {
            return x * this._zoom;
        },

        /** @ignore */
        zoomCanvasToWindow: function (x) {
            return x / this._zoom;
        },

        /**
         * Map (x,y) coordinates in window space to canvas space.
         *
         * @private
         * @param {number} x Offset from the left window edge
         * @param {number} y Offset from the top window edge
         * @return {{x: number, y: number}} A point that describes the offset
         *  from the top-left corner of the canvas.
         */
        transformWindowToCanvas: function (x, y) {
            if (!this._transformMatrix) {
                return {
                    x: 0,
                    y: 0
                };
            }
            var transform = this._transformMatrix,
                xx = transform[0],
                yx = transform[1],
                xy = transform[2],
                yy = transform[3],
                x0 = transform[4],
                y0 = transform[5];

            var xt = xx * x + yx * y + x0,
                yt = xy * x + yy * y + y0;

            return {
                x: xt,
                y: yt
            };
        },

        /**
         * Map (x,y) coordinates in canvas space to window space.
         *
         * @private
         * @param {number} x Offset from the left canvas edge
         * @param {number} y Offset from the top canvas edge
         * @return {{x: number, y: number}} A point that describes the offset
         *  from the top-left corner of the window.
         */
        transformCanvasToWindow: function (x, y) {
            if (!this._inverseTransformMatrix) {
                return {
                    x: 0,
                    y: 0
                };
            }
            var transform = this._inverseTransformMatrix,
                xx = transform[0],
                yx = transform[1],
                xy = transform[2],
                yy = transform[3],
                x0 = transform[4],
                y0 = transform[5];

            var xt = xx * x + xy * y + x0,
                yt = yx * x + yy * y + y0;

            return {
                x: xt,
                y: yt
            };
        },

        /**
         * Calculate the overlay offsets, optionally taking into account a
         * (future) number of open columns.
         *
         * @return {{top: number, right: number, bottom: number, left: number}}
         */
        getCenterOffsets: function (columns) {
            var preferences = this.flux.store("preferences").getState(),
                singleColumn = preferences.get("singleColumnModeEnabled", false),
                right = (columns !== undefined && singleColumn) ? 0 :
                    this._iconBarWidth;

            if (singleColumn) {
                right += this._panelWidth;
            } else if (columns === undefined || columns === this._columnCount) {
                right += this._panelWidth;
            } else if (columns > 0) {
                if (columns === 1 && this._columnCount === 2) {
                    right += (this._panelWidth / 2);
                } else if (columns === 2 && this._columnCount === 1) {
                    right += (this._panelWidth * 2);
                } else {
                    log.warn("Unable to infer enter offsets for " + columns +
                        " columns from " + this._columnCount);
                }
            }

            return {
                top: this._headerHeight,
                right: right,
                left: this._toolbarWidth,
                bottom: 0
            };
        },

        /**
         * Get the current cloaking rectangle, which omits the static UI.
         *
         * @return {?{top: number, right: number, left: number, bottom: number}}
         */
        getCloakRect: function () {
            var centerOffsets = this.getCenterOffsets(),
                windowWidth = window.document.body.clientWidth,
                windowHeight = window.document.body.clientHeight;

            return {
                left: centerOffsets.left,
                top: centerOffsets.top,
                bottom: windowHeight - centerOffsets.bottom,
                right: windowWidth - centerOffsets.right
            };
        },

        /**
         * Inverts the given affine transformation matrix
         *
         * @private
         * @param  {Array.<number>} matrix
         * @return {Array.<number>} Inverted matrix
         */
        _inverseOf: function (matrix) {
            var xx = matrix[0],
                xy = matrix[1],
                yx = matrix[2],
                yy = matrix[3],
                x0 = matrix[4],
                y0 = matrix[5],

                det = xx * yy - xy * yx;

            if (!det) {
                log.warn("Window to canvas matrix not invertable.");
                return null;
            }

            det = 1.0 / det;

            return [
                yy * det,
                -yx * det,
                -xy * det,
                xx * det,
                (xy * y0 - yy * x0) * det,
                (yx * x0 - xx * y0) * det
            ];
        },

        /**
         * Set the current transform from a transformation object.
         *
         * @private
         * @param {{xx: number, yx: number, xy: number, yy: number, tx: number, ty: number}} transformObj
         */
        _setTransformObject: function (transformObj) {
            if (transformObj) {
                this._transformMatrix = [
                    transformObj.xx,
                    transformObj.yx,
                    transformObj.xy,
                    transformObj.yy,
                    transformObj.tx,
                    transformObj.ty
                ];
                this._inverseTransformMatrix = this._inverseOf(this._transformMatrix);
            } else {
                this._transformMatrix = null;
                this._inverseTransformMatrix = null;
            }
        },

        /**
        * Get the root font size
        * @return {number}
        */
        getRootSize: function () {
            return this._rootSize;
        },

        /**
         * Converts a rem value to a pixel value based on
         * root font size
         * 16 px is 1 rem, so if our font-size is 62.5% (10px)
         * all our UI should be shrunk to that as well
         *
         * @return {number}
         */
        remToPx: function (rem) {
            return rem * this._rootSize;
        },

        /**
        * Set the root size based on the document root element font size
        *
        * @private
        */
        _setRootSize: function () {
            var computedStyle = window.getComputedStyle(window.document.documentElement);
            this._rootSize = math.pixelDimensionToNumber(computedStyle.fontSize);
        },

        /**
         * Set the current transform from a 2d matrix. The format of this array
         * is described here:
         * http://cairographics.org/manual/cairo-cairo-matrix-t.html
         *
         * @private
         * @param {Array.<number>} transformMatrix
         */
        _setTransformMatrix: function (transformMatrix) {
            this._transformMatrix = transformMatrix;
            this._inverseTransformMatrix = this._inverseOf(transformMatrix);
        },

        /**
         * Reset the current window-to-canvas transform
         *
         * @private
         * @param {{transformMatrx: Array.<number>=, transformObject: object=}} payload
         */
        _transformUpdated: function (payload) {
            if (payload.transformMatrix) {
                this._setTransformMatrix(payload.transformMatrix);
            } else {
                this._setTransformObject(payload.transformObject);
            }

            this._zoom = payload.zoom;
            this._overlaysEnabled = true;

            this.emit("change");
        },

        /**
         * Updates the center offsets when they change.
         *
         * @private
         * @param {{panelWidth: number=, headerHeight: number=, toolbarWidth: number=}} payload
         */
        _handlePanelResize: function (payload) {
            var changed;
            if (payload.hasOwnProperty("panelWidth") && payload.panelWidth !== this._panelWidth) {
                this._panelWidth = payload.panelWidth;
                changed = true;
            }

            if (payload.hasOwnProperty("columnCount") && payload.columnCount !== this._columnCount) {
                this._columnCount = payload.columnCount;
                changed = true;
            }

            if (payload.hasOwnProperty("iconBarWidth") && payload.iconBarWidth !== this._iconBarWidth) {
                this._iconBarWidth = payload.iconBarWidth;
                changed = true;
            }

            if (payload.hasOwnProperty("headerHeight") && payload.headerHeight !== this._headerHeight) {
                this._headerHeight = payload.headerHeight;
                changed = true;
            }

            if (payload.hasOwnProperty("toolbarWidth") && payload.toolbarWidth !== this._toolbarWidth) {
                this._toolbarWidth = payload.toolbarWidth;
                changed = true;
            }

            if (changed) {
                this.emit("change");
            }
        },

        /**
         * Updates the overlays enabled flag
         *
         * @private
         * @param {{enabled: boolean}} payload
         */
        _handleOverlayToggle: function (payload) {
            this._overlaysEnabled = payload.enabled;
            this.emit("change");
        },

        /**
         * Re-enables the overlays once document layers are updated.
         *
         * @private
         */
        _handleLayersUpdated: function () {
            this.waitFor(["document"], function () {
                this._overlaysEnabled = true;
                this.emit("change");
            });
        },

        /**
         * Updates the marquee start location and flag
         *
         * @param {{x: number, y: number, enabled: boolean}} payload
         */
        _handleMarqueeStart: function (payload) {
            this._marqueeEnabled = payload.enabled;
            this._marqueeStart = payload.enabled ? {
                x: payload.x,
                y: payload.y
            } : null;

            this.emit("change");
        },

        /**
         * Set the size-adjustment reference point.
         *
         * @private
         * @param {{referencePoint: string}} payload
         */
        _handleReferencePointChanged: function (payload) {
            this._referencePoint = payload.referencePoint;
            this.emit("change");
        },

        /**
         * Re-set the root font size when the display changes.
         *
         * @private
         */
        _handleDisplayChanged: function () {
            this._setRootSize();
            this.emit("change");
        },

        /**
         * Update the current mouse position.
         *
         * @private
         * @param {?{currentMouseX: number, currentMouseY: number}} payload
         */
        _handleMousePositionChanged: function (payload) {
            this._currentMousePosition = payload;
        },

        /**
         * Get the current mouse position if it's being tracked; otherwise null.
         *
         * @return {?{currentMouseX: number, currentMouseY: number}}
         */
        getCurrentMousePosition: function () {
            return this._currentMousePosition;
        },

        /**
         * Get the current transform matrix if it's being tracked; otherwise null.
         *
         * @return {?Array.<number>}
         */
        getCurrentTransformMatrix: function () {
            return this._transformMatrix;
        }
    });

    module.exports = UIStore;
});
<|endoftext|>