<commit_before>/**
 * [square] live reload bootstrap code.
 *
 * @see https://github.com/observing/square
 */

(function loader () {
  "use strict";

  // find out the path of the reload service
  var scripts = document.getElementsByTagName('script')
    , i = scripts.length
    , base;

  while (i--) {
    if (scripts[i].src && ~scripts[i].src.indexOf('/live/reload.js')) {
      base = document.createElement('a');
      base.href = scripts[i].src;

      // compile a base path from the found result
      base = [
          base.protocol + '//'
        , base.hostname
        , base.port ? ':' + base.port : ''
      ].join('');

      break;
    }
  }

  // bailout if we can't find the server
  if (!base) throw new Error('Can\'t find the [square] reload service');

  var script = document.createElement('script');
  script.async = true;

  document.body.appendChild(script);
  script.src = base + '/live/socket.io.js';

  setTimeout(function has () {
    if (!('io' in window)) return setTimeout(has, 250);

    var socket = window.io.connect(base, {
        'resource': 'live'
    });

    socket.on('refresh', function changes (files) {
      // @TODO smarter reloading, so we only reload the files that are updated
      // @TODO filter out files that are not on the page
      window.location.reload();
    });
  }, 250);
}());
<commit_msg>Started work for the live reload without page refreshing.<commit_after>/**
 * [square] live reload bootstrap code.
 *
 * @see https://github.com/observing/square
 */

(function loader () {
  "use strict";

  /**
   * Generate a cache buster querystring for the given url, if it already has
   * a generated cache buster url we are going to replace it with a new one.
   *
   * @param {String} url
   * @returns {String}
   * @api public
   */

  loader.bust = function buster (url) {
    var now = + new Date()
      , prefix = '__square__'
      , token = prefix + now + '=' + now;

    // remove the old token from the url if it exists
    url = url.replace(/[&|?]__square__\d+=\d+/g, '');

    // add it to the url
    return ~url.indexOf('&')
      ? url + '&' + token
      : url + '?' + token;
  };

  /**
   * Array#indexOf polyfill.
   *
   * @see bit.ly/a5Dxa2
   * @param {Array} arr array to search in
   * @param {Mixed} o item to search
   * @param {Number} i optional start index
   * @api public
   */

  loader.indexOf = function indexOf (arr, o, i) {
    var j = arr.length;
    i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0;

    // iterate all the things
    for (; i < j && arr[i] !== o; i++) {}

    return j <= i
      ? -1
      : i;
  };

  /**
   * Generate a array of allowed images for hot reloading.
   *
   * @type {Array}
   * @api private
   */

  loader.images = (function images () {
    var defaults = ['gif', 'jpg', 'jpeg', 'png']
      , navigator = window.navigator;

    if (!('mimeTypes' in navigator)) return defaults;

    // generate a list of accepted extensions based on the mimeTypes that are
    // stored in the browser.
    var mimeTypes = Array.prototype.slice.call(navigator.mimeTypes, 0)
      , i = mimeTypes.length;

    while (i--) {
      var type = mimeTypes[i]
        , extensions = type.split(',')
        , j = extensions.length;

      // we only want image types
      if (type.type && type.type.indexOf('image') === -1) continue;

      // add the extensions to the defaults array if they don't exit there
      // already
      while (j--) {
        if (loader.indexOf(defaults, extensions[j]) === -1) {
          defaults.push(extensions[j]);
        }
      }
    }

    return defaults;
  }());

  /**
   * Reload the data without refreshing the page if we can.
   *
   * @param {String} type extension
   * @api public
   */

  loader.reload = function reload (type) {
    switch (type) {
      case 'js':
        // make sure we reload the page with a `true` to load it again from the
        // server.
        window.location.reload(true);
        break;

      case 'css':
        loader.reload.styles();
        break;

      default:
        loader.reload.images();
    }
  };

  loader.reload.styles = function styles () {};
  loader.reload.images = function images () {};

  // Now for the big tricky part, we are going to load in all the dependencies
  // of our livereload plugin so we can establish a real time connection with
  // the started [square] service.
  var scripts = document.getElementsByTagName('script')
    , i = scripts.length
    , base;

  while (i--) {
    if (scripts[i].src && ~scripts[i].src.indexOf('/live/reload.js')) {
      base = document.createElement('a');
      base.href = scripts[i].src;

      // compile a base path from the found result
      base = [
          base.protocol + '//'
        , base.hostname
        , base.port ? ':' + base.port : ''
      ].join('');

      break;
    }
  }

  // bailout if we can't find the server
  if (!base) throw new Error('Can\'t find the [square] reload service');

  var script = document.createElement('script');
  script.async = true;

  document.body.appendChild(script);
  script.src = base + '/live/socket.io.js';

  // a poorman's script onready checker
  setTimeout(function has () {
    if (!('io' in window)) return setTimeout(has, 250);

    var socket = window.io.connect(base, {
        'resource': 'live'
    });

    socket.on('refresh', function changes (files) {
      // @TODO smarter reloading, so we only reload the files that are updated
      // @TODO filter out files that are not on the page
      window.location.reload();
    });
  }, 250);
}());
<|endoftext|>


<commit_before>const React = require('react');
const Radium = require('radium');
const StyleConstants = require('../constants/Style');

class ToggleSwitch extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      activePosition: 'left'
    };
  }

  componentWillMount () {
    this.setState({
      activePosition: this.props.defaultPosition
    });
  }

  _handleLeftLabelClick () {
    const activePosition = 'left';

    this.setState({
      activePosition
    });

    this.props.onToggle(activePosition);
  }

  _handleRightLabelClick () {
    const activePosition = 'right';

    this.setState({
      activePosition
    });

    this.props.onToggle(activePosition);
  }

  _handleToggle () {
    const activePosition = this.state.activePosition === 'left' ? 'right' : 'left';

    this.setState({
      activePosition
    });

    this.props.onToggle(activePosition);
  }

  _renderLeftLabel (styles) {
    if (this.props.showLabels) {
      return (
        {this.props.leftLabel}
      );
    }
  }

  _renderRightLabel (styles) {
    if (this.props.showLabels) {
      return (
        {this.props.rightLabel}
      );
    }
  }

  render () {
    const styles = {
      activeLabel: {
        color: this.props.activeColor
      },
      component: {
        display: 'inline-block',
        fontFamily: StyleConstants.FontFamily,
        fontSize: '12px',
        height: this.props.height + 'px',
        position: 'relative'
      },
      inactiveLabel: {
        color: this.props.inactiveColor
      },
      label: {
        cursor: 'pointer',
        fontWeight: 'bold'
      },
      left: {
        left: this.props.togglePadding,
        top: this.props.togglePadding,
        transition: 'all .1s'
      },
      right: {
        left: this.props.width - this.props.toggleSize - this.props.togglePadding,
        top: this.props.togglePadding,
        transition: 'all .1s'
      },
      toggle: {
        background: StyleConstants.Colors.INVERSE_PRIMARY,
        borderRadius: '100%',
        height: (this.props.toggleSize) + 'px',
        position: 'absolute',
        width: (this.props.toggleSize) + 'px'
      },
      track: {
        backgroundColor: StyleConstants.Colors.LIGHT_FONT,
        borderRadius: this.props.height + 'px',
        cursor: 'pointer',
        display: 'inline-block',
        height: this.props.height + 'px',
        margin: '0 10px',
        position: 'relative',
        verticalAlign: 'middle',
        width: this.props.width + 'px'
      }
    };

    return (

        {this._renderLeftLabel(styles)}

          {this.props.children}

        {this._renderRightLabel(styles)}

    );
  }
}

ToggleSwitch.propTypes = {
  activeColor: React.PropTypes.string,
  children: React.PropTypes.node,
  componentStyle: React.PropTypes.oneOfType([
    React.PropTypes.array,
    React.PropTypes.object
  ]),
  defaultPosition: React.PropTypes.oneOf(['left', 'right']),
  height: React.PropTypes.number,
  inactiveColor: React.PropTypes.string,
  labelStyle: React.PropTypes.oneOfType([
    React.PropTypes.array,
    React.PropTypes.object
  ]),
  leftLabel: React.PropTypes.string,
  onToggle: React.PropTypes.func,
  rightLabel: React.PropTypes.string,
  showLabels: React.PropTypes.bool,
  togglePadding: React.PropTypes.number,
  toggleSize: React.PropTypes.number,
  toggleStyle: React.PropTypes.oneOfType([
    React.PropTypes.array,
    React.PropTypes.object
  ]),
  trackStyle: React.PropTypes.oneOfType([
    React.PropTypes.array,
    React.PropTypes.object
  ]),
  width: React.PropTypes.number
};

ToggleSwitch.defaultProps = {
  activeColor: StyleConstants.Colors.PRIMARY,
  defaultPosition: 'left',
  height: 20,
  inactiveColor: StyleConstants.Colors.LIGHT_FONT,
  leftLabel: 'On',
  onToggle () {},
  rightLabel: 'Off',
  showLabels: true,
  togglePadding: 2,
  toggleSize: 16,
  width: 38
};

module.exports = Radium(ToggleSwitch);<commit_msg>change toggleSize to toggleHeight and toggleWidth to accomodate for rectangular switches<commit_after>const React = require('react');
const Radium = require('radium');
const StyleConstants = require('../constants/Style');

class ToggleSwitch extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      activePosition: 'left'
    };
  }

  componentWillMount () {
    this.setState({
      activePosition: this.props.defaultPosition
    });
  }

  _handleLeftLabelClick () {
    const activePosition = 'left';

    this.setState({
      activePosition
    });

    this.props.onToggle(activePosition);
  }

  _handleRightLabelClick () {
    const activePosition = 'right';

    this.setState({
      activePosition
    });

    this.props.onToggle(activePosition);
  }

  _handleToggle () {
    const activePosition = this.state.activePosition === 'left' ? 'right' : 'left';

    this.setState({
      activePosition
    });

    this.props.onToggle(activePosition);
  }

  _renderLeftLabel (styles) {
    if (this.props.showLabels) {
      return (
        {this.props.leftLabel}
      );
    }
  }

  _renderRightLabel (styles) {
    if (this.props.showLabels) {
      return (
        {this.props.rightLabel}
      );
    }
  }

  render () {
    const styles = {
      activeLabel: {
        color: this.props.activeColor
      },
      component: {
        display: 'inline-block',
        fontFamily: StyleConstants.FontFamily,
        fontSize: '12px',
        height: this.props.height + 'px',
        position: 'relative'
      },
      inactiveLabel: {
        color: this.props.inactiveColor
      },
      label: {
        cursor: 'pointer',
        fontWeight: 'bold'
      },
      left: {
        left: this.props.togglePadding,
        top: this.props.togglePadding,
        transition: 'all .1s'
      },
      right: {
        left: this.props.width - this.props.toggleWidth - this.props.togglePadding,
        top: this.props.togglePadding,
        transition: 'all .1s'
      },
      toggle: {
        background: StyleConstants.Colors.INVERSE_PRIMARY,
        borderRadius: '100%',
        height: (this.props.toggleHeight) + 'px',
        position: 'absolute',
        width: (this.props.toggleWidth) + 'px'
      },
      track: {
        backgroundColor: StyleConstants.Colors.LIGHT_FONT,
        borderRadius: this.props.height + 'px',
        cursor: 'pointer',
        display: 'inline-block',
        height: this.props.height + 'px',
        margin: '0 10px',
        position: 'relative',
        verticalAlign: 'middle',
        width: this.props.width + 'px'
      }
    };

    return (

        {this._renderLeftLabel(styles)}

          {this.props.children}

        {this._renderRightLabel(styles)}

    );
  }
}

ToggleSwitch.propTypes = {
  activeColor: React.PropTypes.string,
  children: React.PropTypes.node,
  componentStyle: React.PropTypes.oneOfType([
    React.PropTypes.array,
    React.PropTypes.object
  ]),
  defaultPosition: React.PropTypes.oneOf(['left', 'right']),
  height: React.PropTypes.number,
  inactiveColor: React.PropTypes.string,
  labelStyle: React.PropTypes.oneOfType([
    React.PropTypes.array,
    React.PropTypes.object
  ]),
  leftLabel: React.PropTypes.string,
  onToggle: React.PropTypes.func,
  rightLabel: React.PropTypes.string,
  showLabels: React.PropTypes.bool,
  togglePadding: React.PropTypes.number,
  toggleHeight: React.PropTypes.number,
  toggleStyle: React.PropTypes.oneOfType([
    React.PropTypes.array,
    React.PropTypes.object
  ]),
  toggleWidth: React.PropTypes.number,
  trackStyle: React.PropTypes.oneOfType([
    React.PropTypes.array,
    React.PropTypes.object
  ]),
  width: React.PropTypes.number
};

ToggleSwitch.defaultProps = {
  activeColor: StyleConstants.Colors.PRIMARY,
  defaultPosition: 'left',
  height: 20,
  inactiveColor: StyleConstants.Colors.LIGHT_FONT,
  leftLabel: 'On',
  onToggle () {},
  rightLabel: 'Off',
  showLabels: true,
  togglePadding: 2,
  toggleHeight: 16,
  toggleWidth: 16,
  width: 38
};

module.exports = Radium(ToggleSwitch);<|endoftext|>


<commit_before>$(function() {
  $('.component-demos .icon-all').on('click', function() {
    if ($(this).hasClass('expand')) {
      $(this).removeClass('expand');
      $('.code-box').find('.highlight').slideUp();
    } else {
      $(this).addClass('expand');
      $('.code-box').find('.highlight').slideDown();
    }
  });

  $('.code-box').each(function(i, item) {
    item = $(item);
    item.find('.highlight').appendTo(item);
  });

  $('.code-boxes').on('click', '.collapse', function() {
    slideToggleCode($(this).parent().parent());
  });

  function slideToggleCode(item) {
    $(item).find('.highlight').animate({
      height: 'toggle',
      opacity: 'toggle'
    }, 150);
  }

  /*$('.aside-container li h4').click(function() {
    $(this).next().animate({
      height: 'toggle',
      opacity: 'toggle'
    }, 150);
  });*/

  var navFunc={
    navStrArr: [],
    init:function (){
      var self=this;
      self.navBox = $(".nav");
      self.navBar = self.navBox.find(".bar");
      self.navList = self.navBox.find("ul li");
      self.navNum=$(".current").index();
      self.search($(".search"));
      self.navBarAnim();
      self.navResize(null);
      $(window).bind("resize", self.navResize);
    },
    navResize: function (e) {
      var self = navFunc;
      self.navBar.css("left", self.navList.width() * self.navNum);

      self.navList.eq(self.navNum).find("a").addClass("hover");
    },
    search: function (c) {
      var self = this;
      self.searchBox = c;
      self.searchInput = self.searchBox.find("input[type='text']");
      self.searchBtn = self.searchBox.find("button");
      self.searchInput.focus(function (e) {
        $(this).addClass("focus");
        self.searchBtn.css("left", self.searchBox.width() + 13);
      });
      self.searchInput.blur(function (e) {
        if (!self.searchInput.val()) {
          self.searchBtn.attr("style", "");
          $(this).removeClass("focus");
        }
      });
      self.searchBtn.click(function (e) {
        self.searchBox.find("form").submit();
      });
    },
    navBarAnim: function () {
      var self = this,delay;
      function startBarAnim(num) {
        self.navBar.css("left", self.navList.width() * num);
        self.navList.eq(num).find("a").addClass("hover");
      }
      self.navList.bind("mouseenter", function (e) {
        clearTimeout(delay);
        var m = e.currentTarget;
        self.navList.find("a").removeClass("hover");
        self.navBar.addClass("barAnim").css("left", $(m).width() * $(m).index());
      });
      self.navList.bind("mouseleave", function (e) {
        delay = setTimeout(function () {
          startBarAnim(self.navNum);
        }, 500);
      });
    }
  };
  navFunc.init();
    var listFunc={
        num:0,
        cnum:0,
        init:function (){
            var self=this;
            self.listBox=$(".aside-container>ul");
            if(!self.listBox.length){
                return
            }
            self.getUrlNum();
            self.listBox.children().eq(self.num).attr("open",true).find("ul").css("display","block");
            //添加标题事件；
            self.addTitleEvent()
        },
        getUrlNum:function (){
            var self=this,url=location.href,str="";
            //console.log(self.listBox.find("a"))
            for(var i=0;i<self.listBox.find("a").length;i++){
                var m=self.listBox.find("a").eq(i);
                if(m.attr("href")=="./"||url.indexOf(m.attr("href"))>=0){
                    self.num=m.parent().parent().parent().index();
                    self.cnum=m.parent().index();
                }
            }
        },
        addTitleEvent:function (){
            var self=this;
            var title=self.listBox.find("h4");
            title.bind("click",function (e){
                var parent=$(this).parent();
                if(parent.attr("open")){
                    parent.removeAttr("open");
                    if(parent.index()==self.num){
                        $(this).addClass("current")
                    }
                }else{
                    parent.attr("open",true);
                    if(parent.index()==self.num){
                        $(this).removeClass("current")
                    }
                }
                parent.find("ul").slideToggle(300);
            })
        }
    };
    listFunc.init();
});
<commit_msg>remove unused code<commit_after>$(function() {
  $('.component-demos .icon-all').on('click', function() {
    if ($(this).hasClass('expand')) {
      $(this).removeClass('expand');
      $('.code-box').find('.highlight').slideUp();
    } else {
      $(this).addClass('expand');
      $('.code-box').find('.highlight').slideDown();
    }
  });

  $('.code-box').each(function(i, item) {
    item = $(item);
    item.find('.highlight').appendTo(item);
  });

  $('.code-boxes').on('click', '.collapse', function() {
    slideToggleCode($(this).parent().parent());
  });

  function slideToggleCode(item) {
    $(item).find('.highlight').animate({
      height: 'toggle',
      opacity: 'toggle'
    }, 150);
  }

  var navFunc={
    navStrArr: [],
    init:function (){
      var self=this;
      self.navBox = $(".nav");
      self.navBar = self.navBox.find(".bar");
      self.navList = self.navBox.find("ul li");
      self.navNum=$(".current").index();
      self.search($(".search"));
      self.navBarAnim();
      self.navResize(null);
      $(window).bind("resize", self.navResize);
    },
    navResize: function (e) {
      var self = navFunc;
      self.navBar.css("left", self.navList.width() * self.navNum);

      self.navList.eq(self.navNum).find("a").addClass("hover");
    },
    search: function (c) {
      var self = this;
      self.searchBox = c;
      self.searchInput = self.searchBox.find("input[type='text']");
      self.searchBtn = self.searchBox.find("button");
      self.searchInput.focus(function (e) {
        $(this).addClass("focus");
        self.searchBtn.css("left", self.searchBox.width() + 13);
      });
      self.searchInput.blur(function (e) {
        if (!self.searchInput.val()) {
          self.searchBtn.attr("style", "");
          $(this).removeClass("focus");
        }
      });
      self.searchBtn.click(function (e) {
        self.searchBox.find("form").submit();
      });
    },
    navBarAnim: function () {
      var self = this,delay;
      function startBarAnim(num) {
        self.navBar.css("left", self.navList.width() * num);
        self.navList.eq(num).find("a").addClass("hover");
      }
      self.navList.bind("mouseenter", function (e) {
        clearTimeout(delay);
        var m = e.currentTarget;
        self.navList.find("a").removeClass("hover");
        self.navBar.addClass("barAnim").css("left", $(m).width() * $(m).index());
      });
      self.navList.bind("mouseleave", function (e) {
        delay = setTimeout(function () {
          startBarAnim(self.navNum);
        }, 500);
      });
    }
  };
  navFunc.init();
    var listFunc={
        num:0,
        cnum:0,
        init:function (){
            var self=this;
            self.listBox=$(".aside-container>ul");
            if(!self.listBox.length){
                return
            }
            self.getUrlNum();
            self.listBox.children().eq(self.num).attr("open",true).find("ul").css("display","block");
            //添加标题事件；
            self.addTitleEvent()
        },
        getUrlNum:function (){
            var self=this,url=location.href,str="";
            //console.log(self.listBox.find("a"))
            for(var i=0;i<self.listBox.find("a").length;i++){
                var m=self.listBox.find("a").eq(i);
                if(m.attr("href")=="./"||url.indexOf(m.attr("href"))>=0){
                    self.num=m.parent().parent().parent().index();
                    self.cnum=m.parent().index();
                }
            }
        },
        addTitleEvent:function (){
            var self=this;
            var title=self.listBox.find("h4");
            title.bind("click",function (e){
                var parent=$(this).parent();
                if(parent.attr("open")){
                    parent.removeAttr("open");
                    if(parent.index()==self.num){
                        $(this).addClass("current")
                    }
                }else{
                    parent.attr("open",true);
                    if(parent.index()==self.num){
                        $(this).removeClass("current")
                    }
                }
                parent.find("ul").slideToggle(300);
            })
        }
    };
    listFunc.init();
});
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var es = require("event-stream")
var $ = require('gulp-load-plugins')({
  pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del']
});
// TODO require gulp plugins normally instead of using gulp-load-plugins - makes the code easier to understand

var connect = require('gulp-connect');

function handleError(err) {
  console.error(err.toString());
  this.emit('end');
}

gulp.task('styles', ['wiredep'],  function () {
  return gulp.src([
    'src/{app,components}/**/*.less',
    '!src/{app,components}/**/_*.less'
  ])
    .pipe($.less({
      paths: [
        'src/bower_components',
        'src/app',
        'src/components'
      ]
    }))
    .on('error', handleError)
    .pipe($.autoprefixer('last 1 version'))
    .pipe(gulp.dest('.tmp'))
    .pipe($.size());
});

gulp.task('scripts', function () {
  return gulp.src('src/{app,components}/**/*.js')
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'))
    .pipe($.size());
});

gulp.task('partials', function () {
  return gulp.src('src/{app,components}/**/*.html')
    .pipe($.minifyHtml({
      empty: true,
      spare: true,
      quotes: true
    }))
    .pipe($.ngHtml2js({
      moduleName: 'civicClient'
    }))
    .pipe(gulp.dest('.tmp'))
    .pipe($.size());
});

gulp.task('html', ['styles', 'scripts', 'partials'], function () {
  var htmlFilter = $.filter('*.html');
  var jsFilter = $.filter('**/*.js');
  var cssFilter = $.filter('**/*.css');
  var assets;

  return gulp.src('src/*.html')
    .pipe($.inject(
      gulp.src('.tmp/{app,components}/**/*.js'),
      {
        starttag: '<!-- inject:partials -->',
        addRootSlash: false,
        addPrefix: '../'
      }))
    .pipe(assets = $.useref.assets()) // remove links to individual dev files from index.html
    .pipe($.rev()) // append revision hash to static files
    .pipe(jsFilter) // handle scripts
    .pipe($.sourcemaps.init()) // initialize sourcemap generation
    .pipe($.ngAnnotate()) // add angular dependency injection to protect from minification
    .pipe($.uglify({ // minify js
        preserveComments: $.uglifySaveLicense,
        mangle: true,
        compress: {
          drop_console: true,
          unused: true
        }
      }
    ))
    .pipe($.sourcemaps.write('.')) // write sourcemaps
    .pipe(jsFilter.restore())
    .pipe(cssFilter) // handle CSS
    .pipe($.replace('/bower_components/bootstrap/fonts','/assets/fonts')) // rewrite bootstrap font urls
    .pipe($.replace(/url\('ui-grid\.(.*?)'\)/g,'url(\'/assets/fonts/ui-grid.$1\')')) // rewrite ui-grid font urls
    .pipe($.replace(/url\('\.\.\/fonts\/fontawesome-webfont\.(.*?)'\)/g,'url(\'/assets/fonts/fontawesome-webfont.$1\')')) // rewrite font-awesome fonts
    .pipe($.csso()) // minify CSS
    .pipe(cssFilter.restore())
    .pipe(assets.restore())
    .pipe($.useref())
    .pipe($.revReplace()) // substitute new filenames in index.html
    .pipe(htmlFilter) // handle HTML
    .pipe($.minifyHtml({ // minify HTML
      empty: true,
      spare: true,
      quotes: true
    }))
    .pipe(htmlFilter.restore())
    .pipe(gulp.dest('dist'))
    .pipe($.size());
});

gulp.task('images', function () {
  return gulp.src('src/assets/images/**/*')
    .pipe($.cache($.imagemin({
      optimizationLevel: 3,
      progressive: true,
      interlaced: true
    })))
    .pipe(gulp.dest('dist/assets/images'))
    .pipe($.size());
});

gulp.task('fonts', function () {
  return es.concat(
    gulp.src($.mainBowerFiles()),
    gulp.src('src/assets/fonts/**/*')
  )
    .pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}'))
    .pipe($.flatten())
    .pipe(gulp.dest('dist/assets/fonts'))
    .pipe($.size());
});

gulp.task('misc', function () {
  return gulp.src('src/**/*.ico')
    .pipe(gulp.dest('dist'))
    .pipe($.size());
});

gulp.task('clear-cache', function() {
  $.cache.clearAll();
});

gulp.task('clean', function (done) {
  $.del(['.tmp', 'dist'], done);
});

gulp.task('build', ['html', 'images', 'fonts', 'misc']);
<commit_msg>added some helpful comments to gulp HTML build task<commit_after>'use strict';

var gulp = require('gulp');
var es = require("event-stream")
var $ = require('gulp-load-plugins')({
  pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del']
});
// TODO require gulp plugins normally instead of using gulp-load-plugins - makes the code easier to understand

var connect = require('gulp-connect');

function handleError(err) {
  console.error(err.toString());
  this.emit('end');
}

gulp.task('styles', ['wiredep'],  function () {
  return gulp.src([
    'src/{app,components}/**/*.less',
    '!src/{app,components}/**/_*.less'
  ])
    .pipe($.less({
      paths: [
        'src/bower_components',
        'src/app',
        'src/components'
      ]
    }))
    .on('error', handleError)
    .pipe($.autoprefixer('last 1 version'))
    .pipe(gulp.dest('.tmp'))
    .pipe($.size());
});

gulp.task('scripts', function () {
  return gulp.src('src/{app,components}/**/*.js')
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'))
    .pipe($.size());
});

gulp.task('partials', function () {
  return gulp.src('src/{app,components}/**/*.html')
    .pipe($.minifyHtml({
      empty: true,
      spare: true,
      quotes: true
    }))
    .pipe($.ngHtml2js({
      moduleName: 'civicClient'
    }))
    .pipe(gulp.dest('.tmp'))
    .pipe($.size());
});

gulp.task('html', ['styles', 'scripts', 'partials'], function () {
  var htmlFilter = $.filter('*.html');
  var jsFilter = $.filter('**/*.js');
  var cssFilter = $.filter('**/*.css');
  var assets;

  return gulp.src('src/*.html')
    .pipe($.inject(
      // stream JS files in app/component directories
      gulp.src('.tmp/{app,components}/**/*.js'),
      {
        starttag: '<!-- inject:partials -->',
        addRootSlash: false,
        addPrefix: '../'
      }))

    // parse index.html for links to asset (scripts, html, css), group, concatenate, add to stream
    .pipe(assets = $.useref.assets())

    // init asset revisioning with gulp-rev on each block
    .pipe($.rev())

    // pluck javascript block, store everything else
    .pipe(jsFilter)
    .pipe($.sourcemaps.init()) // initialize sourcemap generation
    .pipe($.ngAnnotate()) // add angular dependency injection to protect from minification
    .pipe($.uglify({ // minify js
        preserveComments: $.uglifySaveLicense,
        mangle: true,
        compress: {
          drop_console: true,
          unused: true
        }
      }
    ))
    .pipe($.sourcemaps.write('.')) // write sourcemaps
    .pipe(jsFilter.restore())
    // restore non-js files to stream

    // pluck CSS, store non-css files
    .pipe(cssFilter)
    .pipe($.replace('/bower_components/bootstrap/fonts','/assets/fonts')) // rewrite bootstrap font urls
    .pipe($.replace(/url\('ui-grid\.(.*?)'\)/g,'url(\'/assets/fonts/ui-grid.$1\')')) // rewrite ui-grid font urls
    .pipe($.replace(/url\('\.\.\/fonts\/fontawesome-webfont\.(.*?)'\)/g,'url(\'/assets/fonts/fontawesome-webfont.$1\')')) // rewrite font-awesome fonts
    .pipe($.csso()) // minify CSS
    .pipe(cssFilter.restore())
    // restore non-css files to stream

    // strip asset links from index.html, insert links to concatenated, minified assets
    .pipe(assets.restore())
    .pipe($.useref())

    // apply revisions to concatenated assets
    .pipe($.revReplace())

    // pluck HTML, store everything else
    .pipe(htmlFilter)
    .pipe($.minifyHtml({ // minify HTML
      empty: true,
      spare: true,
      quotes: true
    }))
    .pipe(htmlFilter.restore())
    // restore non-HTML files to stream

    // save files
    .pipe(gulp.dest('dist'))

    // generate size report
    .pipe($.size());
});

gulp.task('images', function () {
  return gulp.src('src/assets/images/**/*')
    .pipe($.cache($.imagemin({
      optimizationLevel: 3,
      progressive: true,
      interlaced: true
    })))
    .pipe(gulp.dest('dist/assets/images'))
    .pipe($.size());
});

gulp.task('fonts', function () {
  return es.concat(
    gulp.src($.mainBowerFiles()),
    gulp.src('src/assets/fonts/**/*')
  )
    .pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}'))
    .pipe($.flatten())
    .pipe(gulp.dest('dist/assets/fonts'))
    .pipe($.size());
});

gulp.task('misc', function () {
  return gulp.src('src/**/*.ico')
    .pipe(gulp.dest('dist'))
    .pipe($.size());
});

gulp.task('clear-cache', function() {
  $.cache.clearAll();
});

gulp.task('clean', function (done) {
  $.del(['.tmp', 'dist'], done);
});

gulp.task('build', ['html', 'images', 'fonts', 'misc']);
<|endoftext|>


<commit_before>import chai from 'chai';
import { div, select, Selection } from 'utils/selection';
import logger from 'utils/logger';

import installFakeTimers from 'test/utils/fake-time';
import emit from 'test/utils/fake-event';

import { tooltip } from 'components/tooltip';
import { config as dropdownConfig } from 'components/dropdown';

export default () => {
  describe('tooltip', () => {
    let clock;
    const chaiSandbox = chai.spy.sandbox();
    const fixture = div('hx-test-tooltip');
    const origAttachToSelector = dropdownConfig.attachToSelector;

    before(() => {
      select('body').add(fixture);
      dropdownConfig.attachToSelector = fixture;
    });

    beforeEach(() => {
      clock = installFakeTimers();
      fixture.clear();
      chaiSandbox.on(logger, 'warn');
    });

    afterEach(() => {
      clock.restore();
      chaiSandbox.restore();
    });

    after(() => {
      dropdownConfig.attachToSelector = origAttachToSelector;
      fixture.remove();
    });

    describe('when given an icon and text', () => {
      let thisTooltip;
      const icon = 'fab fa-angellist';
      let thisIcon;
      beforeEach(() => {
        thisTooltip = tooltip({ icon, text: 'hello' });
        fixture.add(thisTooltip);
        thisIcon = thisTooltip.select('i');
      });

      it('adds the icon element on the span', () => {
        thisIcon.empty().should.equal(false);
      });

      it('sets the icon class correctly', () => {
        thisIcon.class().should.equal(icon);
      });
    });

    describe('when given a label and text', () => {
      let thisTooltip;
      const label = 'hello';
      beforeEach(() => {
        thisTooltip = tooltip({ label, text: 'hello' });
        fixture.add(thisTooltip);

      });

      it('sets the text on the span', () => {
        thisTooltip.text().should.equal(label);
      });
    });

    describe('when given just text', () => {
      let thisTooltip;
      const tooltipText = 'This is a sensible amount of text';
      beforeEach(() => {
        thisTooltip = tooltip({ text: tooltipText });
        fixture.add(thisTooltip);
      });

      it('does not log any warnings', () => {
        logger.warn.should.not.have.been.called();
      });

      it('returns a selection', () => {
        thisTooltip.should.be.an.instanceOf(Selection)
      });

      it('does not set text on the selection', () => {
        thisTooltip.text().should.equal('');
      });

      it('returns a span', () => {
        thisTooltip.node().nodeName.should.equal('SPAN');
      });

      describe('and hovering over selection', () => {
        let thisDropdown;

        beforeEach(() => {
          emit(thisTooltip.node(), 'mouseover');
          clock.tick(200);
          thisDropdown = fixture.select('.hx-dropdown');
        });

        it('opens the dropdown', () => {
          thisDropdown.empty().should.equal(false);
        });

        it('sets the dropdown text', () => {
          thisDropdown.text().should.equal(tooltipText);
        });

        describe('then hovering outside selection', () => {
          beforeEach(() => {
            emit(thisTooltip.node(), 'mouseout');
            thisDropdown = fixture.select('.hx-dropdown');
          });

          it('closes the dropdown', () => {
            thisDropdown.empty().should.equal(true);
          });
        });
      });
    });

    describe('when given an icon and label', () => {
      it('throws an error', () => {
        function fn() {
          tooltip({ icon: 'something', label: 'label', text: 'tooltip text' })
        }
        fn.should.throw('tooltip: You can only use an icon or a label when creating a tooltip');
      });
    });

    describe('when given nothing', () => {
      it('throws an error', () => {
        function fn() {
          tooltip();
        }
        fn.should.throw('tooltip: No text provided for the tooltip');
      });

      it('throws an error', () => {
        function fn() {
          tooltip({});
        }
        fn.should.throw('tooltip: No text provided for the tooltip');
      });
    });

  });
};
<commit_msg>chore: Fix lint<commit_after>import chai from 'chai';
import { div, select, Selection } from 'utils/selection';
import logger from 'utils/logger';

import installFakeTimers from 'test/utils/fake-time';
import emit from 'test/utils/fake-event';

import { tooltip } from 'components/tooltip';
import { config as dropdownConfig } from 'components/dropdown';

export default () => {
  describe('tooltip', () => {
    let clock;
    const chaiSandbox = chai.spy.sandbox();
    const fixture = div('hx-test-tooltip');
    const origAttachToSelector = dropdownConfig.attachToSelector;

    before(() => {
      select('body').add(fixture);
      dropdownConfig.attachToSelector = fixture;
    });

    beforeEach(() => {
      clock = installFakeTimers();
      fixture.clear();
      chaiSandbox.on(logger, 'warn');
    });

    afterEach(() => {
      clock.restore();
      chaiSandbox.restore();
    });

    after(() => {
      dropdownConfig.attachToSelector = origAttachToSelector;
      fixture.remove();
    });

    describe('when given an icon and text', () => {
      let thisTooltip;
      const icon = 'fab fa-angellist';
      let thisIcon;
      beforeEach(() => {
        thisTooltip = tooltip({ icon, text: 'hello' });
        fixture.add(thisTooltip);
        thisIcon = thisTooltip.select('i');
      });

      it('adds the icon element on the span', () => {
        thisIcon.empty().should.equal(false);
      });

      it('sets the icon class correctly', () => {
        thisIcon.class().should.equal(icon);
      });
    });

    describe('when given a label and text', () => {
      let thisTooltip;
      const label = 'hello';
      beforeEach(() => {
        thisTooltip = tooltip({ label, text: 'hello' });
        fixture.add(thisTooltip);
      });

      it('sets the text on the span', () => {
        thisTooltip.text().should.equal(label);
      });
    });

    describe('when given just text', () => {
      let thisTooltip;
      const tooltipText = 'This is a sensible amount of text';
      beforeEach(() => {
        thisTooltip = tooltip({ text: tooltipText });
        fixture.add(thisTooltip);
      });

      it('does not log any warnings', () => {
        logger.warn.should.not.have.been.called();
      });

      it('returns a selection', () => {
        thisTooltip.should.be.an.instanceOf(Selection);
      });

      it('does not set text on the selection', () => {
        thisTooltip.text().should.equal('');
      });

      it('returns a span', () => {
        thisTooltip.node().nodeName.should.equal('SPAN');
      });

      describe('and hovering over selection', () => {
        let thisDropdown;

        beforeEach(() => {
          emit(thisTooltip.node(), 'mouseover');
          clock.tick(200);
          thisDropdown = fixture.select('.hx-dropdown');
        });

        it('opens the dropdown', () => {
          thisDropdown.empty().should.equal(false);
        });

        it('sets the dropdown text', () => {
          thisDropdown.text().should.equal(tooltipText);
        });

        describe('then hovering outside selection', () => {
          beforeEach(() => {
            emit(thisTooltip.node(), 'mouseout');
            thisDropdown = fixture.select('.hx-dropdown');
          });

          it('closes the dropdown', () => {
            thisDropdown.empty().should.equal(true);
          });
        });
      });
    });

    describe('when given an icon and label', () => {
      it('throws an error', () => {
        function fn() {
          tooltip({ icon: 'something', label: 'label', text: 'tooltip text' });
        }
        fn.should.throw('tooltip: You can only use an icon or a label when creating a tooltip');
      });
    });

    describe('when given nothing', () => {
      it('throws an error', () => {
        function fn() {
          tooltip();
        }
        fn.should.throw('tooltip: No text provided for the tooltip');
      });

      it('throws an error', () => {
        function fn() {
          tooltip({});
        }
        fn.should.throw('tooltip: No text provided for the tooltip');
      });
    });
  });
};
<|endoftext|>


<commit_before>import React, { PropTypes, PureComponent } from 'react'
import { connect } from 'react-redux'
import classNames from 'classnames'
import { selectIsLoggedIn } from '../selectors/authentication'
import { trackEvent, trackInitialPage } from '../actions/analytics'
import { getCategories, getPagePromotionals } from '../actions/discover'
import { setSignupModalLaunched } from '../actions/gui'
import { openModal } from '../actions/modals'
import { loadAnnouncements, loadNotifications } from '../actions/notifications'
import { loadProfile } from '../actions/profile'
import { fetchAuthenticationPromos } from '../actions/promotions'
import RegistrationRequestDialog from '../components/dialogs/RegistrationRequestDialog'
import DevTools from '../components/devtools/DevTools'
import { addGlobalDrag, removeGlobalDrag } from '../components/viewport/GlobalDragComponent'
import AnalyticsContainer from '../containers/AnalyticsContainer'
import FooterContainer from '../containers/FooterContainer'
import HeroContainer from '../containers/HeroContainer'
import InputContainer from '../containers/InputContainer'
import KeyboardContainer from '../containers/KeyboardContainer'
import MetaContainer from '../containers/MetaContainer'
import ModalContainer from '../containers/ModalContainer'
import NavbarContainer from '../containers/NavbarContainer'
import OmnibarContainer from '../containers/OmnibarContainer'
import ViewportContainer from '../containers/ViewportContainer'
import {
  selectCategoryData,
  selectIsCategoryPromotion,
  selectIsPagePromotion,
  selectRandomAuthPromotion,
} from '../selectors/promotions'
import { selectViewNameFromRoute } from '../selectors/routing'
import { scrollTo } from '../lib/jello'

function mapStateToProps(state) {
  const viewName = selectViewNameFromRoute(state)
  return {
    authPromo: selectRandomAuthPromotion(state),
    categoryData: selectCategoryData(state),
    isAuthenticationLayout: viewName === 'authentication',
    isCategoryPromotion: selectIsCategoryPromotion(state),
    isLoggedIn: selectIsLoggedIn(state),
    isPagePromotion: selectIsPagePromotion(state),
  }
}

class AppContainer extends PureComponent {

  static propTypes = {
    authPromo: PropTypes.object,
    categoryData: PropTypes.object,
    children: PropTypes.node.isRequired,
    dispatch: PropTypes.func.isRequired,
    isAuthenticationLayout: PropTypes.bool,
    isCategoryPromotion: PropTypes.bool,
    isLoggedIn: PropTypes.bool.isRequired,
    isPagePromotion: PropTypes.bool,
    params: PropTypes.object.isRequired,
  }

  static preRender = (store) => {
    const state = store.getState()
    if (state.authentication.get('isLoggedIn')) {
      return Promise.all([
        store.dispatch(loadProfile()),
        store.dispatch(getCategories()),
        store.dispatch(getPagePromotionals()),
      ])
    }
    return Promise.all([
      store.dispatch(getCategories()),
      store.dispatch(getPagePromotionals()),
    ])
  }

  static childContextTypes = {
    onClickOpenRegistrationRequestDialog: PropTypes.func,
    onClickScrollToContent: PropTypes.func,
    onClickTrackCredits: PropTypes.func,
    onClickTrackCTA: PropTypes.func,
  }

  getChildContext() {
    return {
      onClickOpenRegistrationRequestDialog: this.onClickOpenRegistrationRequestDialog,
      onClickScrollToContent: this.onClickScrollToContent,
      onClickTrackCredits: this.onClickTrackCredits,
      onClickTrackCTA: this.onClickTrackCTA,
    }
  }

  componentDidMount() {
    addGlobalDrag()
    const { dispatch, isLoggedIn } = this.props
    dispatch(trackInitialPage())
    if (isLoggedIn) {
      dispatch(loadProfile())
      dispatch(loadNotifications({ category: 'all' }))
      dispatch(loadAnnouncements())
    } else {
      dispatch(fetchAuthenticationPromos())
    }
    dispatch(getCategories())
    dispatch(getPagePromotionals())
  }

  componentWillReceiveProps(nextProps) {
    const { dispatch } = nextProps
    if (!this.props.isLoggedIn && nextProps.isLoggedIn) {
      dispatch(loadProfile())
      dispatch(getCategories())
      dispatch(getPagePromotionals())
      dispatch(loadAnnouncements())
    } else if (this.props.isLoggedIn && !nextProps.isLoggedIn) {
      dispatch(fetchAuthenticationPromos())
      dispatch(getCategories())
      dispatch(getPagePromotionals())
    }
  }

  componentWillUnmount() {
    removeGlobalDrag()
  }

  onClickOpenRegistrationRequestDialog = (trackPostfix = 'modal') => {
    const { authPromo, dispatch, isAuthenticationLayout } = this.props
    if (isAuthenticationLayout) { return }
    dispatch(openModal(
      <RegistrationRequestDialog promotional={authPromo} />,
      'asDecapitated',
      'RegistrationRequestDialog',
    ))
    dispatch(trackEvent(`open-registration-request-${trackPostfix}`))
    dispatch(setSignupModalLaunched())
  }

  onClickScrollToContent = () => {
    scrollTo(0, document.querySelector('.Hero').offsetHeight)
  }

  onClickTrackCredits = () => {
    const { dispatch, categoryData, isCategoryPromotion, isPagePromotion } = this.props
    let label = ''
    if (isCategoryPromotion && categoryData) {
      label = categoryData.category.get('slug')
    } else if (isPagePromotion) {
      label = 'general'
    } else {
      label = 'auth'
    }
    dispatch(trackEvent('promoByline_clicked', { name: label }))
  }

  onClickTrackCTA = () => {
    const { dispatch, categoryData } = this.props
    dispatch(trackEvent('promoCTA_clicked', { name: categoryData.category.get('slug', 'general') }))
  }

  render() {
    const { children, isLoggedIn, params } = this.props
    const appClasses = classNames(
      'AppContainer',
      { isLoggedIn },
      { isLoggedOut: !isLoggedIn },
    )
    return (

        <MetaContainer params={params} />
        <ViewportContainer params={params} />
        {isLoggedIn ? <OmnibarContainer /> : null}
        <HeroContainer params={params} />
        {children}
        <NavbarContainer params={params} />
        <FooterContainer params={params} />
        {isLoggedIn ? <InputContainer /> : null}
        <ModalContainer />
        <DevTools />
        <KeyboardContainer />
        <AnalyticsContainer />

    )
  }
}

export default connect(mapStateToProps)(AppContainer)

<commit_msg>Add required or default props to AppContainer<commit_after>import React, { PropTypes, PureComponent } from 'react'
import { connect } from 'react-redux'
import classNames from 'classnames'
import { selectIsLoggedIn } from '../selectors/authentication'
import { trackEvent, trackInitialPage } from '../actions/analytics'
import { getCategories, getPagePromotionals } from '../actions/discover'
import { setSignupModalLaunched } from '../actions/gui'
import { openModal } from '../actions/modals'
import { loadAnnouncements, loadNotifications } from '../actions/notifications'
import { loadProfile } from '../actions/profile'
import { fetchAuthenticationPromos } from '../actions/promotions'
import RegistrationRequestDialog from '../components/dialogs/RegistrationRequestDialog'
import DevTools from '../components/devtools/DevTools'
import { addGlobalDrag, removeGlobalDrag } from '../components/viewport/GlobalDragComponent'
import AnalyticsContainer from '../containers/AnalyticsContainer'
import FooterContainer from '../containers/FooterContainer'
import HeroContainer from '../containers/HeroContainer'
import InputContainer from '../containers/InputContainer'
import KeyboardContainer from '../containers/KeyboardContainer'
import MetaContainer from '../containers/MetaContainer'
import ModalContainer from '../containers/ModalContainer'
import NavbarContainer from '../containers/NavbarContainer'
import OmnibarContainer from '../containers/OmnibarContainer'
import ViewportContainer from '../containers/ViewportContainer'
import {
  selectCategoryData,
  selectIsCategoryPromotion,
  selectIsPagePromotion,
  selectRandomAuthPromotion,
} from '../selectors/promotions'
import { selectViewNameFromRoute } from '../selectors/routing'
import { scrollTo } from '../lib/jello'

function mapStateToProps(state) {
  const viewName = selectViewNameFromRoute(state)
  return {
    authPromo: selectRandomAuthPromotion(state),
    categoryData: selectCategoryData(state),
    isAuthenticationLayout: viewName === 'authentication',
    isCategoryPromotion: selectIsCategoryPromotion(state),
    isLoggedIn: selectIsLoggedIn(state),
    isPagePromotion: selectIsPagePromotion(state),
  }
}

class AppContainer extends PureComponent {

  static propTypes = {
    authPromo: PropTypes.object,
    categoryData: PropTypes.object.isRequired,
    children: PropTypes.node.isRequired,
    dispatch: PropTypes.func.isRequired,
    isAuthenticationLayout: PropTypes.bool.isRequired,
    isCategoryPromotion: PropTypes.bool.isRequired,
    isLoggedIn: PropTypes.bool.isRequired,
    isPagePromotion: PropTypes.bool.isRequired,
    params: PropTypes.object.isRequired,
  }

  static defaultProps = {
    authPromo: null,
  }

  static preRender = (store) => {
    const state = store.getState()
    if (state.authentication.get('isLoggedIn')) {
      return Promise.all([
        store.dispatch(loadProfile()),
        store.dispatch(getCategories()),
        store.dispatch(getPagePromotionals()),
      ])
    }
    return Promise.all([
      store.dispatch(getCategories()),
      store.dispatch(getPagePromotionals()),
    ])
  }

  static childContextTypes = {
    onClickOpenRegistrationRequestDialog: PropTypes.func,
    onClickScrollToContent: PropTypes.func,
    onClickTrackCredits: PropTypes.func,
    onClickTrackCTA: PropTypes.func,
  }

  getChildContext() {
    return {
      onClickOpenRegistrationRequestDialog: this.onClickOpenRegistrationRequestDialog,
      onClickScrollToContent: this.onClickScrollToContent,
      onClickTrackCredits: this.onClickTrackCredits,
      onClickTrackCTA: this.onClickTrackCTA,
    }
  }

  componentDidMount() {
    addGlobalDrag()
    const { dispatch, isLoggedIn } = this.props
    dispatch(trackInitialPage())
    if (isLoggedIn) {
      dispatch(loadProfile())
      dispatch(loadNotifications({ category: 'all' }))
      dispatch(loadAnnouncements())
    } else {
      dispatch(fetchAuthenticationPromos())
    }
    dispatch(getCategories())
    dispatch(getPagePromotionals())
  }

  componentWillReceiveProps(nextProps) {
    const { dispatch } = nextProps
    if (!this.props.isLoggedIn && nextProps.isLoggedIn) {
      dispatch(loadProfile())
      dispatch(getCategories())
      dispatch(getPagePromotionals())
      dispatch(loadAnnouncements())
    } else if (this.props.isLoggedIn && !nextProps.isLoggedIn) {
      dispatch(fetchAuthenticationPromos())
      dispatch(getCategories())
      dispatch(getPagePromotionals())
    }
  }

  componentWillUnmount() {
    removeGlobalDrag()
  }

  onClickOpenRegistrationRequestDialog = (trackPostfix = 'modal') => {
    const { authPromo, dispatch, isAuthenticationLayout } = this.props
    if (isAuthenticationLayout) { return }
    dispatch(openModal(
      <RegistrationRequestDialog promotional={authPromo} />,
      'asDecapitated',
      'RegistrationRequestDialog',
    ))
    dispatch(trackEvent(`open-registration-request-${trackPostfix}`))
    dispatch(setSignupModalLaunched())
  }

  onClickScrollToContent = () => {
    scrollTo(0, document.querySelector('.Hero').offsetHeight)
  }

  onClickTrackCredits = () => {
    const { dispatch, categoryData, isCategoryPromotion, isPagePromotion } = this.props
    let label = ''
    if (isCategoryPromotion && categoryData) {
      label = categoryData.category.get('slug')
    } else if (isPagePromotion) {
      label = 'general'
    } else {
      label = 'auth'
    }
    dispatch(trackEvent('promoByline_clicked', { name: label }))
  }

  onClickTrackCTA = () => {
    const { dispatch, categoryData } = this.props
    dispatch(trackEvent('promoCTA_clicked', { name: categoryData.category.get('slug', 'general') }))
  }

  render() {
    const { children, isLoggedIn, params } = this.props
    const appClasses = classNames(
      'AppContainer',
      { isLoggedIn },
      { isLoggedOut: !isLoggedIn },
    )
    return (

        <MetaContainer params={params} />
        <ViewportContainer params={params} />
        {isLoggedIn ? <OmnibarContainer /> : null}
        <HeroContainer params={params} />
        {children}
        <NavbarContainer params={params} />
        <FooterContainer params={params} />
        {isLoggedIn ? <InputContainer /> : null}
        <ModalContainer />
        <DevTools />
        <KeyboardContainer />
        <AnalyticsContainer />

    )
  }
}

export default connect(mapStateToProps)(AppContainer)

<|endoftext|>


<commit_before>/**
 * The Tooltip Component
 *
 * @module aui-tooltip
 */

var Lang = A.Lang,

    getClassName = A.getClassName,

    CSS_TOOLTIP_ARROW = getClassName('tooltip-arrow'),
    CSS_TOOLTIP_INNER = getClassName('tooltip-inner');

/**
 * A base class for Tooltip.
 *
 * Check the [live demo](http://alloyui.com/examples/tooltip/).
 *
 * @class A.Tooltip
 * @extends Widget
 * @uses A.WidgetCssClass, A.WidgetPosition, A.WidgetStdMod, A.WidgetToggle,
 *     A.WidgetAutohide, A.WidgetToolbars, A.WidgetPositionAlign,
 *     A.WidgetPositionAlignSuggestion, A.WidgetPositionConstrain, A.WidgetStack
 * @param {Object} config Object literal specifying widget configuration
 *     properties.
 * @constructor
 * @include http://alloyui.com/examples/tooltip/basic-markup.html
 * @include http://alloyui.com/examples/tooltip/basic.js
 */
A.Tooltip = A.Base.create('tooltip', A.Widget, [
    A.WidgetCssClass,
    A.WidgetPosition,
    A.WidgetStdMod,
    A.WidgetToggle,
    A.WidgetAutohide,
    A.WidgetPositionAlign,
    A.WidgetPositionAlignSuggestion,
    A.WidgetPositionConstrain,
    A.WidgetStack,
    A.WidgetTransition,
    A.WidgetTrigger
], {

    /**
     * Construction logic executed during Tooltip instantiation. Lifecycle.
     *
     * @method initializer
     * @protected
     */
    initializer: function() {
        var instance = this;

        instance._eventHandles = [
            A.after(instance._afterUiSetTrigger, instance, '_uiSetTrigger'),
            A.on('scroll', A.debounce(instance._onScroll, 100, instance)),
            A.on('windowresize', A.bind(instance._onResize, instance))
        ];
    },

    /**
     * Destructor lifecycle implementation for the `Tooltip` class.
     *
     * @method destructor
     * @protected
     */
    destructor: function() {
        (new A.EventHandle(this._eventHandles)).detach();
    },

    /**
     * Render the Tooltip component instance. Lifecycle.
     *
     * @method renderUI
     * @protected
     */
    renderUI: function() {
        var instance = this,
            boundingBox = instance.get('boundingBox'),
            contentBox = instance.get('contentBox');

        contentBox.addClass(CSS_TOOLTIP_INNER);
        boundingBox.append(A.Tooltip.TEMPLATES.arrow);
    },

    /**
     * Binds the events on the `Tooltip` UI. Lifecycle.
     *
     * @method bindUI
     * @protected
     */
    bindUI: function() {
        var instance = this,
            trigger = instance.get('trigger');

        // Do not bind the synthetic hover event to the widget dom events
        // wrapper api. Hover bind method has a different method signature which
        // is not handled by widget yet. Bind to the `boundingBox` instead.
        if (trigger) {
            trigger.on(
                'hover',
                A.bind(instance._onBoundingBoxMouseenter, instance),
                A.bind(instance._onBoundingBoxMouseleave, instance));
        }

        instance.get('boundingBox').on(
            'hover',
            A.bind(instance._onBoundingBoxMouseenter, instance),
            A.bind(instance._onBoundingBoxMouseleave, instance));
    },

    /**
     * Fire after `boundingBox` style changes.
     *
     * @method _afterUiSetVisible
     * @param val
     * @protected
     */
    _uiSetVisible: function(val) {
        var instance = this,
            boundingBox = instance.get('boundingBox');

        instance._widgetUiSetVisible(val);

        boundingBox.setStyle('opacity', val ? instance.get('opacity') : 0);

        if (val) {
            instance._loadTooltipContentFromTitle();
        }
    },

    /**
     * Fire after `trigger` changes.
     *
     * @method _afterUiSetTrigger
     * @param val
     * @protected
     */
    _afterUiSetTrigger: function(val) {
        this.suggestAlignment(val);
    },

    /**
     * If the HTML title attribute exists, copy its contents to data-title
     * and remove it to prevent the browser's native tooltip.
     *
     * @method _borrowTitleAttribute
     * @private
     */
    _borrowTitleAttribute: function() {
        var trigger = this.get('trigger'),
            title = trigger.getAttribute('title');

        if (title) {
            trigger.setAttribute('data-title', title).removeAttribute('title');
        }
    },

    /**
     * Set tooltip section attribute.
     *
     * @method _setStdModSection
     * @param {String | Node} val
     * @protected
     */
    _setStdModSection: function(val) {
        var formatter = this.get('formatter');

        if (Lang.isString(val)) {
            if (formatter) {
                val = formatter.call(this, val);
            }

            if (!this.get('html')) {
                val = A.Escape.html(val);
            }
        }

        return val;
    },

    /**
     * Load tooltip content from trigger title attribute.
     *
     * @method _loadTooltipContentFromTitle
     * @protected
     */
    _loadTooltipContentFromTitle: function() {
        var trigger = this.get('trigger'),
            title;

        if (!trigger) {
            return;
        }

        this._borrowTitleAttribute();

        title = trigger.getAttribute('data-title');
        if (title) {
            this.setStdModContent(A.WidgetStdMod.BODY, title);
        }
    },

    /**
     * Handles `boundingBox` `mouseenter` events.
     *
     * @method _onBoundingBoxMouseenter
     * @param {EventFacade} event
     * @protected
     */
    _onBoundingBoxMouseenter: function() {
        this.show();
    },

    /**
     * Handles `boundingBox` `mouseleave` events.
     *
     * @method _onBoundingBoxMouseleave
     * @param {EventFacade} event
     * @protected
     */
    _onBoundingBoxMouseleave: function() {
        this.hide();
    },

    /**
     * Fired after the window is resized.
     *
     * @method _onResize
     * @protected
     */
    _onResize: function() {
        this.suggestAlignment(this.get('trigger'));
    },

    /**
     * Scroll event listener function.
     *
     * @method _onScroll
     * @protected
     */
    _onScroll: function() {
        this.suggestAlignment(this.get('trigger'));
    },

    _widgetUiSetVisible: A.Widget.prototype._uiSetVisible
}, {

    /**
     * Static property provides a string to identify the CSS prefix.
     *
     * @property CSS_PREFIX
     * @type String
     * @static
     */
    CSS_PREFIX: getClassName('tooltip'),

    /**
     * Static property used to define the default attribute
     * configuration for the Tooltip.
     *
     * @property ATTRS
     * @type Object
     * @static
     */
    ATTRS: {
        /**
         * Determine if the transitions will animate or not.
         *
         * @attribute animated
         * @default true
         * @type Boolean
         * @writeOnce
         */
        animated: {
            value: true
        },

        /**
         * @attribute bodyContent
         * @type {String | Node}
         */
        bodyContent: {
            setter: '_setStdModSection'
        },

        /**
         * Determine the tooltip constrain node.
         *
         * @attribute constrain
         * @default true
         * @type {Boolean|Node}
         */
        constrain: {
            value: true
        },

        /**
         * @attribute footerContent
         * @type {String | Node}
         */
        footerContent: {
            setter: '_setStdModSection'
        },

        /**
         * Format the title attribute before set the content of the tooltip.
         *
         * @attribute formatter
         * @type function
         */
        formatter: {
            validator: A.Lang.isFunction
        },

        /**
         * @attribute headerContent
         * @type {String | Node}
         */
        headerContent: {
            setter: '_setStdModSection'
        },

        /**
         * Determines if the tooltip allows arbitary HTML or is plain text.
         *
         * @attribute html
         * @default false
         * @type Boolean
         */
        html: {
            value: false,
            validator: Lang.isBoolean
        },

        /**
         * Determine the opacity.
         *
         * @attribute opacity
         * @default 0.8
         * @type {Number}
         */
        opacity: {
            value: 0.8
        },

        /**
         * DOM event to show the tooltip.
         *
         * @attribute triggerShowEvent
         * @default mouseenter
         * @type String
         */
        triggerShowEvent: {
            validator: Lang.isString,
            value: 'mouseenter'
        },

        /**
         * The z-index to apply to the Widgets boundingBox. Non-numerical values for
         * zIndex will be converted to 0
         *
         * @attribute zIndex
         * @default 1030
         * @type Number
         */
        zIndex: {
            value: 1030
        }
    },

    /**
     * Static property provides a set of reusable templates.
     *
     * @property TEMPLATES
     * @type Object
     * @static
     */
    TEMPLATES: {
        arrow: '

'
    }
});
<commit_msg>LPS-64993 AUI tooltip misaligned when hovering over subsequent help icons add loadTooltipContentFromTitle to _afterUiSetTrigger to prevent tooltip from displaying incorrect text.<commit_after>/**
 * The Tooltip Component
 *
 * @module aui-tooltip
 */

var Lang = A.Lang,

    getClassName = A.getClassName,

    CSS_TOOLTIP_ARROW = getClassName('tooltip-arrow'),
    CSS_TOOLTIP_INNER = getClassName('tooltip-inner');

/**
 * A base class for Tooltip.
 *
 * Check the [live demo](http://alloyui.com/examples/tooltip/).
 *
 * @class A.Tooltip
 * @extends Widget
 * @uses A.WidgetCssClass, A.WidgetPosition, A.WidgetStdMod, A.WidgetToggle,
 *     A.WidgetAutohide, A.WidgetToolbars, A.WidgetPositionAlign,
 *     A.WidgetPositionAlignSuggestion, A.WidgetPositionConstrain, A.WidgetStack
 * @param {Object} config Object literal specifying widget configuration
 *     properties.
 * @constructor
 * @include http://alloyui.com/examples/tooltip/basic-markup.html
 * @include http://alloyui.com/examples/tooltip/basic.js
 */
A.Tooltip = A.Base.create('tooltip', A.Widget, [
    A.WidgetCssClass,
    A.WidgetPosition,
    A.WidgetStdMod,
    A.WidgetToggle,
    A.WidgetAutohide,
    A.WidgetPositionAlign,
    A.WidgetPositionAlignSuggestion,
    A.WidgetPositionConstrain,
    A.WidgetStack,
    A.WidgetTransition,
    A.WidgetTrigger
], {

    /**
     * Construction logic executed during Tooltip instantiation. Lifecycle.
     *
     * @method initializer
     * @protected
     */
    initializer: function() {
        var instance = this;

        instance._eventHandles = [
            A.after(instance._afterUiSetTrigger, instance, '_uiSetTrigger'),
            A.on('scroll', A.debounce(instance._onScroll, 100, instance)),
            A.on('windowresize', A.bind(instance._onResize, instance))
        ];
    },

    /**
     * Destructor lifecycle implementation for the `Tooltip` class.
     *
     * @method destructor
     * @protected
     */
    destructor: function() {
        (new A.EventHandle(this._eventHandles)).detach();
    },

    /**
     * Render the Tooltip component instance. Lifecycle.
     *
     * @method renderUI
     * @protected
     */
    renderUI: function() {
        var instance = this,
            boundingBox = instance.get('boundingBox'),
            contentBox = instance.get('contentBox');

        contentBox.addClass(CSS_TOOLTIP_INNER);
        boundingBox.append(A.Tooltip.TEMPLATES.arrow);
    },

    /**
     * Binds the events on the `Tooltip` UI. Lifecycle.
     *
     * @method bindUI
     * @protected
     */
    bindUI: function() {
        var instance = this,
            trigger = instance.get('trigger');

        // Do not bind the synthetic hover event to the widget dom events
        // wrapper api. Hover bind method has a different method signature which
        // is not handled by widget yet. Bind to the `boundingBox` instead.
        if (trigger) {
            trigger.on(
                'hover',
                A.bind(instance._onBoundingBoxMouseenter, instance),
                A.bind(instance._onBoundingBoxMouseleave, instance));
        }

        instance.get('boundingBox').on(
            'hover',
            A.bind(instance._onBoundingBoxMouseenter, instance),
            A.bind(instance._onBoundingBoxMouseleave, instance));
    },

    /**
     * Fire after `boundingBox` style changes.
     *
     * @method _afterUiSetVisible
     * @param val
     * @protected
     */
    _uiSetVisible: function(val) {
        var instance = this,
            boundingBox = instance.get('boundingBox');

        instance._widgetUiSetVisible(val);

        boundingBox.setStyle('opacity', val ? instance.get('opacity') : 0);

        if (val) {
            instance._loadTooltipContentFromTitle();
        }
    },

    /**
     * Fire after `trigger` changes.
     *
     * @method _afterUiSetTrigger
     * @param val
     * @protected
     */
    _afterUiSetTrigger: function(val) {
        this._loadTooltipContentFromTitle();
        this.suggestAlignment(val);
    },

    /**
     * If the HTML title attribute exists, copy its contents to data-title
     * and remove it to prevent the browser's native tooltip.
     *
     * @method _borrowTitleAttribute
     * @private
     */
    _borrowTitleAttribute: function() {
        var trigger = this.get('trigger'),
            title = trigger.getAttribute('title');

        if (title) {
            trigger.setAttribute('data-title', title).removeAttribute('title');
        }
    },

    /**
     * Set tooltip section attribute.
     *
     * @method _setStdModSection
     * @param {String | Node} val
     * @protected
     */
    _setStdModSection: function(val) {
        var formatter = this.get('formatter');

        if (Lang.isString(val)) {
            if (formatter) {
                val = formatter.call(this, val);
            }

            if (!this.get('html')) {
                val = A.Escape.html(val);
            }
        }

        return val;
    },

    /**
     * Load tooltip content from trigger title attribute.
     *
     * @method _loadTooltipContentFromTitle
     * @protected
     */
    _loadTooltipContentFromTitle: function() {
        var trigger = this.get('trigger'),
            title;

        if (!trigger) {
            return;
        }

        this._borrowTitleAttribute();

        title = trigger.getAttribute('data-title');
        if (title) {
            this.setStdModContent(A.WidgetStdMod.BODY, title);
        }
    },

    /**
     * Handles `boundingBox` `mouseenter` events.
     *
     * @method _onBoundingBoxMouseenter
     * @param {EventFacade} event
     * @protected
     */
    _onBoundingBoxMouseenter: function() {
        this.show();
    },

    /**
     * Handles `boundingBox` `mouseleave` events.
     *
     * @method _onBoundingBoxMouseleave
     * @param {EventFacade} event
     * @protected
     */
    _onBoundingBoxMouseleave: function() {
        this.hide();
    },

    /**
     * Fired after the window is resized.
     *
     * @method _onResize
     * @protected
     */
    _onResize: function() {
        this.suggestAlignment(this.get('trigger'));
    },

    /**
     * Scroll event listener function.
     *
     * @method _onScroll
     * @protected
     */
    _onScroll: function() {
        this.suggestAlignment(this.get('trigger'));
    },

    _widgetUiSetVisible: A.Widget.prototype._uiSetVisible
}, {

    /**
     * Static property provides a string to identify the CSS prefix.
     *
     * @property CSS_PREFIX
     * @type String
     * @static
     */
    CSS_PREFIX: getClassName('tooltip'),

    /**
     * Static property used to define the default attribute
     * configuration for the Tooltip.
     *
     * @property ATTRS
     * @type Object
     * @static
     */
    ATTRS: {
        /**
         * Determine if the transitions will animate or not.
         *
         * @attribute animated
         * @default true
         * @type Boolean
         * @writeOnce
         */
        animated: {
            value: true
        },

        /**
         * @attribute bodyContent
         * @type {String | Node}
         */
        bodyContent: {
            setter: '_setStdModSection'
        },

        /**
         * Determine the tooltip constrain node.
         *
         * @attribute constrain
         * @default true
         * @type {Boolean|Node}
         */
        constrain: {
            value: true
        },

        /**
         * @attribute footerContent
         * @type {String | Node}
         */
        footerContent: {
            setter: '_setStdModSection'
        },

        /**
         * Format the title attribute before set the content of the tooltip.
         *
         * @attribute formatter
         * @type function
         */
        formatter: {
            validator: A.Lang.isFunction
        },

        /**
         * @attribute headerContent
         * @type {String | Node}
         */
        headerContent: {
            setter: '_setStdModSection'
        },

        /**
         * Determines if the tooltip allows arbitary HTML or is plain text.
         *
         * @attribute html
         * @default false
         * @type Boolean
         */
        html: {
            value: false,
            validator: Lang.isBoolean
        },

        /**
         * Determine the opacity.
         *
         * @attribute opacity
         * @default 0.8
         * @type {Number}
         */
        opacity: {
            value: 0.8
        },

        /**
         * DOM event to show the tooltip.
         *
         * @attribute triggerShowEvent
         * @default mouseenter
         * @type String
         */
        triggerShowEvent: {
            validator: Lang.isString,
            value: 'mouseenter'
        },

        /**
         * The z-index to apply to the Widgets boundingBox. Non-numerical values for
         * zIndex will be converted to 0
         *
         * @attribute zIndex
         * @default 1030
         * @type Number
         */
        zIndex: {
            value: 1030
        }
    },

    /**
     * Static property provides a set of reusable templates.
     *
     * @property TEMPLATES
     * @type Object
     * @static
     */
    TEMPLATES: {
        arrow: '

'
    }
});
<|endoftext|>


<commit_before>import React from 'react';
import { connect } from 'react-redux';
import { throttle } from 'lodash';
import Autocomplete from 'components/Autocomplete';
import {
  typeaheadSearch,
  clearSuggestions,
  updateSuggestionInputValue
} from 'actions/AutocompleteActions';

const QUERY_THROTTLE_TIME = 700;

const AutocompleteContainer = (props) => {
  return <Autocomplete {...props} />;
};

AutocompleteContainer.propTypes = {
  suggestions: React.PropTypes.array,
  value: React.PropTypes.string
};

export const mapStateToProps = ({ autocomplete }) => ({
  suggestions: autocomplete.suggestions,
  value: autocomplete.value
});

export const mapDispatchToProps = (dispatch) => {
  return {
    typeaheadSearch: throttle((endpoint, query) => (
      dispatch(typeaheadSearch(endpoint, query))
    ), QUERY_THROTTLE_TIME),
    clearSuggestions: () => (
      dispatch(clearSuggestions())
    ),
    updateSuggestionInputValue: (newValue) => (
      dispatch(updateSuggestionInputValue(newValue))
    )
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(AutocompleteContainer);
<commit_msg>Added more propTypes to autocomplete container<commit_after>import React from 'react';
import { connect } from 'react-redux';
import { throttle } from 'lodash';
import Autocomplete from 'components/Autocomplete';
import {
  typeaheadSearch,
  clearSuggestions,
  updateSuggestionInputValue
} from 'actions/AutocompleteActions';

const QUERY_THROTTLE_TIME = 700;

const AutocompleteContainer = (props) => {
  return <Autocomplete {...props} />;
};

AutocompleteContainer.propTypes = {
  endpoint: React.PropTypes.string.isRequired,
  suggestionFormatter: React.PropTypes.func.isRequired,
  typeaheadSearch: React.PropTypes.func.isRequired,
  clearSuggestions: React.PropTypes.func.isRequired,
  updateSuggestionInputValue: React.PropTypes.func.isRequired,
  suggestions: React.PropTypes.array,
  value: React.PropTypes.string,
  helper: React.PropTypes.object.isRequired,
  name: React.PropTypes.string,
  html: React.PropTypes.object
};

export const mapStateToProps = ({ autocomplete }) => ({
  suggestions: autocomplete.suggestions,
  value: autocomplete.value
});

export const mapDispatchToProps = (dispatch) => {
  return {
    typeaheadSearch: throttle((endpoint, query) => (
      dispatch(typeaheadSearch(endpoint, query))
    ), QUERY_THROTTLE_TIME),
    clearSuggestions: () => (
      dispatch(clearSuggestions())
    ),
    updateSuggestionInputValue: (newValue) => (
      dispatch(updateSuggestionInputValue(newValue))
    )
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(AutocompleteContainer);
<|endoftext|>


<commit_before>YUI.add('aui-tooltip-tests', function(Y) {

    //--------------------------------------------------------------------------
    // AUI Tooltip Unit Tests
    //--------------------------------------------------------------------------

    var suite = new Y.Test.Suite('aui-tooltip');

    suite.add(new Y.Test.Case({
        name: 'Tooltips',
        '#1: Tooltip constructor should work without a config object.': function() {
            var tooltip = new Y.Tooltip();

            Y.Assert.isInstanceOf(
                Y.Tooltip,
                tooltip,
                'tooltip is not an instance of Y.Tooltip.');
        },

        '#2: #triggerTop button should have tooltip on top.': function() {
            new Y.Tooltip({
                position: 'top',
                trigger: '#triggerTop'
            }).render();

            Y.Assert.isTrue(
                Y.one('.tooltip').hasClass('top'),
                '.tooltip does not have class top.');
        },

        '#3: #triggerRight button should have tooltip on right': function() {
            new Y.Tooltip({
                position: 'right',
                trigger: '#triggerRight'
            }).render();

            Y.Assert.isTrue(
                Y.one('.tooltip').hasClass('right'),
                '.tooltip does not have class right.');
        },

        '#4: #triggerBottom button should have tooltip on bottom': function() {
            new Y.Tooltip({
                position: 'bottom',
                trigger: '#triggerBottom'
            }).render();

            Y.Assert.isTrue(
                Y.one('.tooltip').hasClass('bottom'),
                '.tooltip does not have class bottom.');
        },

        '#5: #triggerLeft button should have tooltip on left': function() {
            new Y.Tooltip({
                position: 'left',
                trigger: '#triggerLeft'
            }).render();

            Y.Assert.isTrue(
                Y.one('.tooltip').hasClass('left'),
                '.tooltip does not have class left.');
        },

        '#6: #triggerTooltipHelp button should display tooltip with class tooltip-help': function() {
            new Y.Tooltip({
                cssClass: 'tooltip-help',
                position: 'right',
                stickDuration: 25,
                trigger: '#triggerTooltipHelp'
            }).render();

            Y.Assert.isTrue(
                Y.one('.tooltip').hasClass('tooltip-help'),
                '.tooltip does not have class tooltip-help.');
        },

        '#7: .tooltip should be hidden when mouseout on #triggerTooltipHelp.': function() {
            var test = this,
                tooltip = Y.one('.tooltip'),
                triggerTooltipHelp = Y.one('#triggerTooltipHelp');

            triggerTooltipHelp.once('mouseout', function() {
                setTimeout(function() {
                    test.resume(function() {
                        Y.Assert.isFalse(
                            Y.one('.tooltip').getStyle('opacity') > 0,
                            '.tooltip is not hidden.');

                        Y.Assert.isTrue(
                            Y.one('.tooltip').hasClass('tooltip-hidden'),
                            '.tooltip does not have class tooltip-hidden');
                    });
                }, 800);
            });

            setTimeout(function() {
                triggerTooltipHelp.simulate('mouseover');
                triggerTooltipHelp.simulate('mouseout');
            }, 0);

            test.wait(1000);
        },

        '#8: .tooltip should be visible when mouseover on #triggerTooltipHelp.': function() {
            var test = this,
                tooltip = Y.one('.tooltip'),
                triggerTooltipHelp = Y.one('#triggerTooltipHelp');

            triggerTooltipHelp.once('mouseover', function(e) {
                setTimeout(function() {
                    test.resume(function() {
                        Y.Assert.isTrue(
                            Y.one('.tooltip').getStyle('opacity') > 0,
                            '.tooltip is hidden.');

                        Y.Assert.isFalse(
                            Y.one('.tooltip').hasClass('tooltip-hidden'),
                            '.tooltip should not have class tooltip-hidden');
                    });
                }, 800);
            });

            setTimeout(function() {
                triggerTooltipHelp.simulate('mouseover');
            }, 0);

            test.wait(1000);
        },

        '#9: .tooltip should be visible when mouse moves from #triggerTooltipHelp to .tooltip': function() {
            var test = this,
                tooltip = Y.one('.tooltip'),
                triggerTooltipHelp = Y.one('#triggerTooltipHelp');

            tooltip.once('mouseover', function() {
                setTimeout(function() {
                    test.resume(function() {
                        Y.Assert.isTrue(
                            Y.one('.tooltip').getStyle('opacity') > 0,
                            '.tooltip is visible.');

                        Y.Assert.isFalse(
                            Y.one('.tooltip').hasClass('tooltip-hidden'),
                            '.tooltip should not have class tooltip-hidden');
                    });
                }, 800);
            });

            setTimeout(function() {
                triggerTooltipHelp.simulate('mouseout');
                tooltip.simulate('mouseover');
            }, 0);

            test.wait(1000);
        },

        '#10: .tooltip should be hidden when mouseout of .tooltip.': function() {
            var test = this,
                tooltip = Y.one('.tooltip'),
                triggerTooltipHelp = Y.one('#triggerTooltipHelp');

            tooltip.once('mouseout', function(e) {
                setTimeout(function() {
                    test.resume(function() {
                        Y.Assert.isFalse(
                            Y.one('.tooltip').getStyle('opacity') > 0,
                            '.tooltip is visible.');

                        Y.Assert.isTrue(
                            Y.one('.tooltip').hasClass('tooltip-hidden'),
                            '.tooltip does not have class tooltip-hidden');
                    });
                }, 800);
            });

            setTimeout(function() {
                tooltip.simulate('mouseout');
            }, 0);

            test.wait(1000);
        },

        '#11: .tooltip should remain visible when mouse moves from .tooltip to #triggerTooltipHelp': function() {
            var test = this,
                tooltip = Y.one('.tooltip'),
                triggerTooltipHelp = Y.one('#triggerTooltipHelp');

            tooltip.once('mouseout', function() {
                setTimeout(function() {
                    test.resume(function() {
                        Y.Assert.isTrue(
                            Y.one('.tooltip').getStyle('opacity') > 0,
                            '.tooltip is hidden.');

                        Y.Assert.isFalse(
                            Y.one('.tooltip').hasClass('tooltip-hidden'),
                            '.tooltip should not have class tooltip-hidden');
                    });
                }, 800);
            });

            setTimeout(function() {
                triggerTooltipHelp.simulate('mouseover');
                triggerTooltipHelp.simulate('mouseout');
                tooltip.simulate('mouseover');
                tooltip.simulate('mouseout');
                triggerTooltipHelp.simulate('mouseover');
            }, 0);

            test.wait(1000);
        },

        // Tests: AUI-1092
        '#12 #triggerLeft\'s tooltip should not cover button #triggerBottom': function() {
            var test = this,
                tooltipLeft = Y.one('.tooltip.left'),
                triggerTooltipHelp = Y.one('#triggerTooltipHelp');

            tooltipLeft.once('mouseout', function() {
                setTimeout(function() {
                    test.resume(function() {
                        condition = (tooltipLeft === null ||
                            tooltipLeft.getStyle('zIndex') < 0 || tooltipLeft.getComputedStyle(
                                'zIndex') < 0);

                        Y.Assert.isTrue(
                            condition,
                            '.tooltip.left does not have a z-index less than 0');
                    });
                }, 800);
            });

            setTimeout(function() {
                triggerTooltipHelp.simulate('mouseout');
                tooltipLeft.simulate('mouseover');
                tooltipLeft.simulate('mouseout');
            });

            test.wait(1000);
        }
    }));
    Y.Test.Runner.add(suite);

}, '', {
    requires: ['aui-tooltip', 'node-event-simulate', 'test']
});
<commit_msg>AUI-1174 Validate source code with JSHint (implicit global)<commit_after>YUI.add('aui-tooltip-tests', function(Y) {

    //--------------------------------------------------------------------------
    // AUI Tooltip Unit Tests
    //--------------------------------------------------------------------------

    var suite = new Y.Test.Suite('aui-tooltip');

    suite.add(new Y.Test.Case({
        name: 'Tooltips',
        '#1: Tooltip constructor should work without a config object.': function() {
            var tooltip = new Y.Tooltip();

            Y.Assert.isInstanceOf(
                Y.Tooltip,
                tooltip,
                'tooltip is not an instance of Y.Tooltip.');
        },

        '#2: #triggerTop button should have tooltip on top.': function() {
            new Y.Tooltip({
                position: 'top',
                trigger: '#triggerTop'
            }).render();

            Y.Assert.isTrue(
                Y.one('.tooltip').hasClass('top'),
                '.tooltip does not have class top.');
        },

        '#3: #triggerRight button should have tooltip on right': function() {
            new Y.Tooltip({
                position: 'right',
                trigger: '#triggerRight'
            }).render();

            Y.Assert.isTrue(
                Y.one('.tooltip').hasClass('right'),
                '.tooltip does not have class right.');
        },

        '#4: #triggerBottom button should have tooltip on bottom': function() {
            new Y.Tooltip({
                position: 'bottom',
                trigger: '#triggerBottom'
            }).render();

            Y.Assert.isTrue(
                Y.one('.tooltip').hasClass('bottom'),
                '.tooltip does not have class bottom.');
        },

        '#5: #triggerLeft button should have tooltip on left': function() {
            new Y.Tooltip({
                position: 'left',
                trigger: '#triggerLeft'
            }).render();

            Y.Assert.isTrue(
                Y.one('.tooltip').hasClass('left'),
                '.tooltip does not have class left.');
        },

        '#6: #triggerTooltipHelp button should display tooltip with class tooltip-help': function() {
            new Y.Tooltip({
                cssClass: 'tooltip-help',
                position: 'right',
                stickDuration: 25,
                trigger: '#triggerTooltipHelp'
            }).render();

            Y.Assert.isTrue(
                Y.one('.tooltip').hasClass('tooltip-help'),
                '.tooltip does not have class tooltip-help.');
        },

        '#7: .tooltip should be hidden when mouseout on #triggerTooltipHelp.': function() {
            var test = this,
                tooltip = Y.one('.tooltip'),
                triggerTooltipHelp = Y.one('#triggerTooltipHelp');

            triggerTooltipHelp.once('mouseout', function() {
                setTimeout(function() {
                    test.resume(function() {
                        Y.Assert.isFalse(
                            Y.one('.tooltip').getStyle('opacity') > 0,
                            '.tooltip is not hidden.');

                        Y.Assert.isTrue(
                            Y.one('.tooltip').hasClass('tooltip-hidden'),
                            '.tooltip does not have class tooltip-hidden');
                    });
                }, 800);
            });

            setTimeout(function() {
                triggerTooltipHelp.simulate('mouseover');
                triggerTooltipHelp.simulate('mouseout');
            }, 0);

            test.wait(1000);
        },

        '#8: .tooltip should be visible when mouseover on #triggerTooltipHelp.': function() {
            var test = this,
                tooltip = Y.one('.tooltip'),
                triggerTooltipHelp = Y.one('#triggerTooltipHelp');

            triggerTooltipHelp.once('mouseover', function(e) {
                setTimeout(function() {
                    test.resume(function() {
                        Y.Assert.isTrue(
                            Y.one('.tooltip').getStyle('opacity') > 0,
                            '.tooltip is hidden.');

                        Y.Assert.isFalse(
                            Y.one('.tooltip').hasClass('tooltip-hidden'),
                            '.tooltip should not have class tooltip-hidden');
                    });
                }, 800);
            });

            setTimeout(function() {
                triggerTooltipHelp.simulate('mouseover');
            }, 0);

            test.wait(1000);
        },

        '#9: .tooltip should be visible when mouse moves from #triggerTooltipHelp to .tooltip': function() {
            var test = this,
                tooltip = Y.one('.tooltip'),
                triggerTooltipHelp = Y.one('#triggerTooltipHelp');

            tooltip.once('mouseover', function() {
                setTimeout(function() {
                    test.resume(function() {
                        Y.Assert.isTrue(
                            Y.one('.tooltip').getStyle('opacity') > 0,
                            '.tooltip is visible.');

                        Y.Assert.isFalse(
                            Y.one('.tooltip').hasClass('tooltip-hidden'),
                            '.tooltip should not have class tooltip-hidden');
                    });
                }, 800);
            });

            setTimeout(function() {
                triggerTooltipHelp.simulate('mouseout');
                tooltip.simulate('mouseover');
            }, 0);

            test.wait(1000);
        },

        '#10: .tooltip should be hidden when mouseout of .tooltip.': function() {
            var test = this,
                tooltip = Y.one('.tooltip'),
                triggerTooltipHelp = Y.one('#triggerTooltipHelp');

            tooltip.once('mouseout', function(e) {
                setTimeout(function() {
                    test.resume(function() {
                        Y.Assert.isFalse(
                            Y.one('.tooltip').getStyle('opacity') > 0,
                            '.tooltip is visible.');

                        Y.Assert.isTrue(
                            Y.one('.tooltip').hasClass('tooltip-hidden'),
                            '.tooltip does not have class tooltip-hidden');
                    });
                }, 800);
            });

            setTimeout(function() {
                tooltip.simulate('mouseout');
            }, 0);

            test.wait(1000);
        },

        '#11: .tooltip should remain visible when mouse moves from .tooltip to #triggerTooltipHelp': function() {
            var test = this,
                tooltip = Y.one('.tooltip'),
                triggerTooltipHelp = Y.one('#triggerTooltipHelp');

            tooltip.once('mouseout', function() {
                setTimeout(function() {
                    test.resume(function() {
                        Y.Assert.isTrue(
                            Y.one('.tooltip').getStyle('opacity') > 0,
                            '.tooltip is hidden.');

                        Y.Assert.isFalse(
                            Y.one('.tooltip').hasClass('tooltip-hidden'),
                            '.tooltip should not have class tooltip-hidden');
                    });
                }, 800);
            });

            setTimeout(function() {
                triggerTooltipHelp.simulate('mouseover');
                triggerTooltipHelp.simulate('mouseout');
                tooltip.simulate('mouseover');
                tooltip.simulate('mouseout');
                triggerTooltipHelp.simulate('mouseover');
            }, 0);

            test.wait(1000);
        },

        // Tests: AUI-1092
        '#12 #triggerLeft\'s tooltip should not cover button #triggerBottom': function() {
            var test = this,
                tooltipLeft = Y.one('.tooltip.left'),
                triggerTooltipHelp = Y.one('#triggerTooltipHelp');

            tooltipLeft.once('mouseout', function() {
                setTimeout(function() {
                    test.resume(function() {
                        var condition = (tooltipLeft === null ||
                            tooltipLeft.getStyle('zIndex') < 0 || tooltipLeft.getComputedStyle(
                                'zIndex') < 0);

                        Y.Assert.isTrue(
                            condition,
                            '.tooltip.left does not have a z-index less than 0');
                    });
                }, 800);
            });

            setTimeout(function() {
                triggerTooltipHelp.simulate('mouseout');
                tooltipLeft.simulate('mouseover');
                tooltipLeft.simulate('mouseout');
            });

            test.wait(1000);
        }
    }));
    Y.Test.Runner.add(suite);

}, '', {
    requires: ['aui-tooltip', 'node-event-simulate', 'test']
});
<|endoftext|>