<commit_before>/** Usage:
*
* Add Infowindow model:
*
* var infowindowModel = new cdb.geo.ui.InfowindowModel({
*   template_name: 'templates/map/infowindow',
*   latlng: [72, -45],
*   offset: [100, 10]
* });
*
* var infowindow = new cdb.geo.ui.Infowindow({
*   model: infowindowModel,
*   mapView: mapView
* });
*
* Show the infowindow:
* infowindow.showInfowindow();
*
*/

cdb.geo.ui.InfowindowModel = Backbone.Model.extend({

  defaults: {
    template_name: 'geo/infowindow',
    latlng: [0, 0],
    offset: [28, 0], // offset of the tip calculated from the bottom left corner
    autoPan: true,
    content: "",
    visibility: false,
    fields: null // contains the fields displayed in the infowindow
  },

  clearFields: function() {
    this.set({fields: []});
  },

  _cloneFields: function() {
    return _(this.get('fields')).map(function(v) {
      return _.clone(v);
    });
  },

  _setFields: function(f) {
    f.sort(function(a, b) { return a.position -  b.position; });
    this.set({'fields': f});
  },

  addField: function(fieldName, at) {
    if(!this.containsField(fieldName)) {
      var fields = this._cloneFields() || [];
      at = at === undefined ? fields.length: at;
      fields.push({name: fieldName, title: true, position: at});
      //sort fields
      this._setFields(fields);
    }
    return this;
  },

  getFieldProperty: function(fieldName, k) {
    if(this.containsField(fieldName)) {
      var fields = this.get('fields') || [];
      var idx = _.indexOf(_(fields).pluck('name'), fieldName);
      return fields[idx][k];
    }
    return null;
  },

  setFieldProperty: function(fieldName, k, v) {
    if(this.containsField(fieldName)) {
      var fields = this._cloneFields() || [];
      var idx = _.indexOf(_(fields).pluck('name'), fieldName);
      fields[idx][k] = v;
      this._setFields(fields);
    }
    return this;
  },

  getFieldPos: function(fieldName) {
    var p = this.getFieldProperty(fieldName, 'position');
    if(p == undefined) {
      return Number.MAX_VALUE;
    }
    return p;
  },

  containsField: function(fieldName) {
    var fields = this.get('fields') || [];
    return _.contains(_(fields).pluck('name'), fieldName);
  },

  removeField: function(fieldName) {
    if(this.containsField(fieldName)) {
      var fields = this._cloneFields() || [];
      var idx = _.indexOf(_(fields).pluck('name'), fieldName);
      if(idx >= 0) {
        fields.splice(idx, 1);
      }
      this._setFields(fields);
    }
    return this;
  }

});

cdb.geo.ui.Infowindow = cdb.core.View.extend({
  className: "infowindow",

  events: {
    "click .close":   "_closeInfowindow",
    "dragstart":      "_checkOrigin",
    "mousedown":      "_checkOrigin",
    "mousewheel":     "_stopPropagation",
    "DOMMouseScroll": "_stopPropagation",
    "dbclick":        "_stopPropagation",
    "click":          "_stopPropagation"
  },

  initialize: function(){

    _.bindAll(this, "render", "setLatLng", "changeTemplate", "_updatePosition", "_update", "toggle", "show", "hide");

    this.mapView = this.options.mapView;

    this.template = this.options.template ? this.options.template : cdb.templates.getTemplate(this.model.get("template_name"));

    this.add_related_model(this.model);

    this.model.bind('change:content',       this.render, this);
    this.model.bind('change:template_name', this.changeTemplate, this);
    this.model.bind('change:latlng',        this._update, this);
    this.model.bind('change:visibility',    this.toggle, this);
    this.model.bind('change:template',      this._compileTemplate, this);

    this.mapView.map.bind('change',         this._updatePosition, this);
    //this.map.on('viewreset', this._updatePosition, this);
    this.mapView.bind('drag',               this._updatePosition, this);

    var that = this;
    this.mapView.bind('zoomstart', function(){
      that.hide(true);
    });
    this.mapView.bind('zoomend', function() {
      that.show(true);
    });

    // Set min height to show the scroll
    this.minHeightToScroll = 180;

    this.render();
    this.$el.hide();

  },

  changeTemplate: function(template_name) {
    this.template = cdb.templates.getTemplate(this.model.get("template_name"));
    this.render();
  },

  _compileTemplate: function() {
    this.template = new cdb.core.Template({
       template: this.model.get('template'),
       type: this.model.get('template_type') || 'mustache'
    }).asFunction()
    this.render();
  },

  _checkOrigin: function(ev) {
    // If the mouse down come from jspVerticalBar
    // dont stop the propagation
    var come_from_scroll = ($(ev.target).closest(".jspVerticalBar").length > 0 );

    if (!come_from_scroll) {
      ev.stopPropagation();
    }
  },

  render: function() {
    if(this.template) {

      // If there is content, destroy the jscrollpane first, then remove the content.
      var $jscrollpane = this.$el.find(".cartodb-popup-content");
      if ($jscrollpane.length > 0 && $jscrollpane.data() != null) {
        $jscrollpane.data().jsp && $jscrollpane.data().jsp.destroy();
      }

      this.$el.html($(this.template(_.clone(this.model.attributes))));

      // Hello jscrollpane hacks!
      // It needs some time to initialize, if not it doesn't render properly the fields
      // Check the height of the content + the header if exists
      var that = this;
      setTimeout(function() {
        var actual_height = that.$el.find(".cartodb-popup-content").outerHeight() + that.$el.find(".cartodb-popup-header").outerHeight();
        if (that.minHeightToScroll <= actual_height)
          that.$el.find(".cartodb-popup-content").jScrollPane({
            maintainPosition:       false,
            verticalDragMinHeight:  20
          });
      },1)
    }
    return this;
  },

  toggle: function() {
    this.model.get("visibility") ? this.show() : this.hide();
  },

  _stopPropagation: function(ev) {
    ev.stopPropagation();
  },

  _closeInfowindow: function(ev) {
    if (ev) {
      ev.preventDefault()
      ev.stopPropagation();
    }

    this.model.set("visibility",false);
  },

  /**
  * Set the correct position for the popup
  * @params {latlng} A new Leaflet LatLng object
  */
  setLatLng: function (latlng) {
    this.model.set("latlng", latlng);
    return this;
  },

  showInfowindow: function() {
    this.model.set("visibility", true);
  },

  show: function (no_pan) {
    var that = this;

    if (this.model.get("visibility")) {
      that.$el.css({ left: -5000 });
      that._update(no_pan);
    }
  },

  isHidden: function () {
    return !this.model.get("visibility");
  },

  hide: function (force) {
    if (force || !this.model.get("visibility")) this._animateOut();
  },

  _update: function (no_pan) {

    if(!this.isHidden()) {
      var delay = 0;

      if (!no_pan) {
        var delay = this._adjustPan();
      }

      this._updatePosition();
      this._animateIn(delay);
    }
  },

  _animateIn: function(delay) {
    if (!$.browser.msie || ($.browser.msie && $.browser.version.search("9.") != -1)) {
      this.$el.css({
        'marginBottom':'-10px',
        'display':'block',
        opacity:0
      });

      this.$el
        .delay(delay)
        .animate({
          opacity: 1,
          marginBottom: 0
        },300);
    } else {
      this.$el.show();
    }
  },

  _animateOut: function() {

    if (!$.browser.msie || ($.browser.msie && $.browser.version.search("9.") != -1)) {
      var that = this;
      this.$el.animate({
        marginBottom: "-10px",
        opacity:      "0",
        display:      "block"
      }, 180, function() {
        that.$el.css({display: "none"});
      });
    } else {
      this.$el.hide();
    }

  },

  /**
  * Update the position (private)
  */
  _updatePosition: function () {
    var
    offset          = this.model.get("offset")
    pos             = this.mapView.latLonToPixel(this.model.get("latlng")),
    x               = this.$el.position().left,
    y               = this.$el.position().top,
    containerHeight = this.$el.outerHeight(true),
    containerWidth  = this.$el.width(),
    left            = pos.x - offset[0],
    size            = this.mapView.getSize(),
    bottom          = -1*(pos.y - offset[1] - size.y);

    this.$el.css({ bottom: bottom, left: left });
  },

  _adjustPan: function (callback) {

    var offset = this.model.get("offset");

    if (!this.model.get("autoPan")) { return; }

    var
      x               = this.$el.position().left,
      y               = this.$el.position().top,
      containerHeight = this.$el.outerHeight(true) + 15, // Adding some more space
      containerWidth  = this.$el.width(),
      pos             = this.mapView.latLonToPixel(this.model.get("latlng")),
      adjustOffset    = {x: 0, y: 0};
      size            = this.mapView.getSize()
      wait_callback   = 0;

    if (pos.x - offset[0] < 0) {
      adjustOffset.x = pos.x - offset[0] - 10;
    }

    if (pos.x - offset[0] + containerWidth > size.x) {
      adjustOffset.x = pos.x + containerWidth - size.x - offset[0] + 10;
    }

    if (pos.y - containerHeight < 0) {
      adjustOffset.y = pos.y - containerHeight - 10;
    }

    if (pos.y - containerHeight > size.y) {
      adjustOffset.y = pos.y + containerHeight - size.y;
    }

    if (adjustOffset.x || adjustOffset.y) {
      this.mapView.panBy(adjustOffset);
      wait_callback = 300;
    }

    return wait_callback;
  }

});
<commit_msg>infowindow bug with touch events fixed<commit_after>/** Usage:
*
* Add Infowindow model:
*
* var infowindowModel = new cdb.geo.ui.InfowindowModel({
*   template_name: 'templates/map/infowindow',
*   latlng: [72, -45],
*   offset: [100, 10]
* });
*
* var infowindow = new cdb.geo.ui.Infowindow({
*   model: infowindowModel,
*   mapView: mapView
* });
*
* Show the infowindow:
* infowindow.showInfowindow();
*
*/

cdb.geo.ui.InfowindowModel = Backbone.Model.extend({

  defaults: {
    template_name: 'geo/infowindow',
    latlng: [0, 0],
    offset: [28, 0], // offset of the tip calculated from the bottom left corner
    autoPan: true,
    content: "",
    visibility: false,
    fields: null // contains the fields displayed in the infowindow
  },

  clearFields: function() {
    this.set({fields: []});
  },

  _cloneFields: function() {
    return _(this.get('fields')).map(function(v) {
      return _.clone(v);
    });
  },

  _setFields: function(f) {
    f.sort(function(a, b) { return a.position -  b.position; });
    this.set({'fields': f});
  },

  addField: function(fieldName, at) {
    if(!this.containsField(fieldName)) {
      var fields = this._cloneFields() || [];
      at = at === undefined ? fields.length: at;
      fields.push({name: fieldName, title: true, position: at});
      //sort fields
      this._setFields(fields);
    }
    return this;
  },

  getFieldProperty: function(fieldName, k) {
    if(this.containsField(fieldName)) {
      var fields = this.get('fields') || [];
      var idx = _.indexOf(_(fields).pluck('name'), fieldName);
      return fields[idx][k];
    }
    return null;
  },

  setFieldProperty: function(fieldName, k, v) {
    if(this.containsField(fieldName)) {
      var fields = this._cloneFields() || [];
      var idx = _.indexOf(_(fields).pluck('name'), fieldName);
      fields[idx][k] = v;
      this._setFields(fields);
    }
    return this;
  },

  getFieldPos: function(fieldName) {
    var p = this.getFieldProperty(fieldName, 'position');
    if(p == undefined) {
      return Number.MAX_VALUE;
    }
    return p;
  },

  containsField: function(fieldName) {
    var fields = this.get('fields') || [];
    return _.contains(_(fields).pluck('name'), fieldName);
  },

  removeField: function(fieldName) {
    if(this.containsField(fieldName)) {
      var fields = this._cloneFields() || [];
      var idx = _.indexOf(_(fields).pluck('name'), fieldName);
      if(idx >= 0) {
        fields.splice(idx, 1);
      }
      this._setFields(fields);
    }
    return this;
  }

});

cdb.geo.ui.Infowindow = cdb.core.View.extend({
  className: "infowindow",

  events: {
    // Close bindings
    "click .close":       "_closeInfowindow",
    "touchstart .close":  "_closeInfowindow",
    // Rest infowindow bindings
    "dragstart":          "_checkOrigin",
    "mousedown":          "_checkOrigin",
    "touchstart":         "_checkOrigin",
    "mousewheel":         "_stopPropagation",
    "DOMMouseScroll":     "_stopPropagation",
    "dbclick":            "_stopPropagation",
    "click":              "_stopPropagation"
  },

  initialize: function(){

    _.bindAll(this, "render", "setLatLng", "changeTemplate", "_updatePosition", "_update", "toggle", "show", "hide");

    this.mapView = this.options.mapView;

    this.template = this.options.template ? this.options.template : cdb.templates.getTemplate(this.model.get("template_name"));

    this.add_related_model(this.model);

    this.model.bind('change:content',       this.render, this);
    this.model.bind('change:template_name', this.changeTemplate, this);
    this.model.bind('change:latlng',        this._update, this);
    this.model.bind('change:visibility',    this.toggle, this);
    this.model.bind('change:template',      this._compileTemplate, this);

    this.mapView.map.bind('change',         this._updatePosition, this);
    //this.map.on('viewreset', this._updatePosition, this);
    this.mapView.bind('drag',               this._updatePosition, this);

    var that = this;
    this.mapView.bind('zoomstart', function(){
      that.hide(true);
    });
    this.mapView.bind('zoomend', function() {
      that.show(true);
    });

    // Set min height to show the scroll
    this.minHeightToScroll = 180;

    this.render();
    this.$el.hide();

  },

  changeTemplate: function(template_name) {
    this.template = cdb.templates.getTemplate(this.model.get("template_name"));
    this.render();
  },

  _compileTemplate: function() {
    this.template = new cdb.core.Template({
       template: this.model.get('template'),
       type: this.model.get('template_type') || 'mustache'
    }).asFunction()
    this.render();
  },

  _checkOrigin: function(ev) {
    // If the mouse down come from jspVerticalBar
    // dont stop the propagation, but if the event
    // is a touchstart, stop the propagation
    var come_from_scroll = (($(ev.target).closest(".jspVerticalBar").length > 0) && (ev.type != "touchstart"));

    if (!come_from_scroll) {
      ev.stopPropagation();
    }
  },

  render: function() {
    if(this.template) {

      // If there is content, destroy the jscrollpane first, then remove the content.
      var $jscrollpane = this.$el.find(".cartodb-popup-content");
      if ($jscrollpane.length > 0 && $jscrollpane.data() != null) {
        $jscrollpane.data().jsp && $jscrollpane.data().jsp.destroy();
      }

      this.$el.html($(this.template(_.clone(this.model.attributes))));

      // Hello jscrollpane hacks!
      // It needs some time to initialize, if not it doesn't render properly the fields
      // Check the height of the content + the header if exists
      var that = this;
      setTimeout(function() {
        var actual_height = that.$el.find(".cartodb-popup-content").outerHeight() + that.$el.find(".cartodb-popup-header").outerHeight();
        if (that.minHeightToScroll <= actual_height)
          that.$el.find(".cartodb-popup-content").jScrollPane({
            maintainPosition:       false,
            verticalDragMinHeight:  20
          });
      },1)
    }
    return this;
  },

  toggle: function() {
    this.model.get("visibility") ? this.show() : this.hide();
  },

  _stopPropagation: function(ev) {
    ev.stopPropagation();
  },

  _closeInfowindow: function(ev) {
    if (ev) {
      ev.preventDefault()
      ev.stopPropagation();
    }

    this.model.set("visibility",false);
  },

  /**
  * Set the correct position for the popup
  * @params {latlng} A new Leaflet LatLng object
  */
  setLatLng: function (latlng) {
    this.model.set("latlng", latlng);
    return this;
  },

  showInfowindow: function() {
    this.model.set("visibility", true);
  },

  show: function (no_pan) {
    var that = this;

    if (this.model.get("visibility")) {
      that.$el.css({ left: -5000 });
      that._update(no_pan);
    }
  },

  isHidden: function () {
    return !this.model.get("visibility");
  },

  hide: function (force) {
    if (force || !this.model.get("visibility")) this._animateOut();
  },

  _update: function (no_pan) {

    if(!this.isHidden()) {
      var delay = 0;

      if (!no_pan) {
        var delay = this._adjustPan();
      }

      this._updatePosition();
      this._animateIn(delay);
    }
  },

  _animateIn: function(delay) {
    if (!$.browser.msie || ($.browser.msie && $.browser.version.search("9.") != -1)) {
      this.$el.css({
        'marginBottom':'-10px',
        'display':'block',
        opacity:0
      });

      this.$el
        .delay(delay)
        .animate({
          opacity: 1,
          marginBottom: 0
        },300);
    } else {
      this.$el.show();
    }
  },

  _animateOut: function() {

    if (!$.browser.msie || ($.browser.msie && $.browser.version.search("9.") != -1)) {
      var that = this;
      this.$el.animate({
        marginBottom: "-10px",
        opacity:      "0",
        display:      "block"
      }, 180, function() {
        that.$el.css({display: "none"});
      });
    } else {
      this.$el.hide();
    }

  },

  /**
  * Update the position (private)
  */
  _updatePosition: function () {
    var
    offset          = this.model.get("offset")
    pos             = this.mapView.latLonToPixel(this.model.get("latlng")),
    x               = this.$el.position().left,
    y               = this.$el.position().top,
    containerHeight = this.$el.outerHeight(true),
    containerWidth  = this.$el.width(),
    left            = pos.x - offset[0],
    size            = this.mapView.getSize(),
    bottom          = -1*(pos.y - offset[1] - size.y);

    this.$el.css({ bottom: bottom, left: left });
  },

  _adjustPan: function (callback) {

    var offset = this.model.get("offset");

    if (!this.model.get("autoPan")) { return; }

    var
      x               = this.$el.position().left,
      y               = this.$el.position().top,
      containerHeight = this.$el.outerHeight(true) + 15, // Adding some more space
      containerWidth  = this.$el.width(),
      pos             = this.mapView.latLonToPixel(this.model.get("latlng")),
      adjustOffset    = {x: 0, y: 0};
      size            = this.mapView.getSize()
      wait_callback   = 0;

    if (pos.x - offset[0] < 0) {
      adjustOffset.x = pos.x - offset[0] - 10;
    }

    if (pos.x - offset[0] + containerWidth > size.x) {
      adjustOffset.x = pos.x + containerWidth - size.x - offset[0] + 10;
    }

    if (pos.y - containerHeight < 0) {
      adjustOffset.y = pos.y - containerHeight - 10;
    }

    if (pos.y - containerHeight > size.y) {
      adjustOffset.y = pos.y + containerHeight - size.y;
    }

    if (adjustOffset.x || adjustOffset.y) {
      this.mapView.panBy(adjustOffset);
      wait_callback = 300;
    }

    return wait_callback;
  }

});
<|endoftext|>


<commit_before>/**
 * @desc Placeholder shim for lte IE9
 * @author yongxiang.li@qunar.com
 * @date 2014.11.13
 *
 * Todo
 * 支持密码input的placeholder
 *
 * @usage
 * html: <input type="text" id="demo" placeholder="I am a placeholder" >
 * js: $('#demo').placeholder();
 */

var _VERSION = "0.0.2";

var _createElement = (function() {
	if (typeof document.createElement !== 'function') {
	  	// This is the case in IE7, where the type of createElement is "object".
	  	// For this reason, we cannot call apply() as Object is not a Function.
	  	return function(){
	  		return document.createElement(arguments[0]);
	  	}
	} else {
		return function(){
			return document.createElement.apply(document, arguments);
		}
	}
})();

function _supportPlaceholder(){
	var inp = _createElement('input');
	//return typeof inp.placeholder !== 'undefined';
	//return ('placeholder' in inp);
	return inp.placeholder !== undefined;
	//return false;
}

var Placeholder = function(elem, msg, ocolor,isPsw){

	//element
	this.$elem = $(elem);

	//placeholder 文字
	this.msg = msg;

	//原始颜色
	this.ocolor = ocolor;

	//是否是密码框
	this.isPsw = isPsw || false;

	//初始化状态
	this._inited = false;
}

Placeholder.prototype = {
	constructor: Placeholder,

	init: function(){

		var $elem = this.$elem,
			msg = this.msg;

		//为了兼容之前的placeholder，以及jvalidate校验
		if($elem.data('placeholder') !== msg){
			$elem.data('placeholder', msg);
		}

		//对于支持placeholder的直接返回，不需初始化
		if(_supportPlaceholder()){
			return false;
		}

		this.bindEvents();

		this.onShow();

		//缓存到元素上，方便再次调用
		$elem.data('yoplaceholder', this);

		this._inited = true;

		return this;
	},

	//如果元素已经初始化过，再调用的时候只改变值，不重新绑定事件
	reset: function(msg, ocolor, isPsw){
		this._inited = false;
		this.msg = msg;
		this.ocolor = ocolor; //原始颜色
		this.isPsw = isPsw || false;

		var $elem = this.$elem;

		//为了兼容之前的placeholder，以及jvalidate校验
		if($elem.data('placeholder') !== msg){
			$elem.data('placeholder', msg);
		}

		//对于支持placeholder的直接返回，不需初始化
		if(_supportPlaceholder()){
			return false;
		}

		this.onShow();

		//缓存到元素上，方便再次调用
		$elem.data('yoplaceholder', this);

		this._inited = true;

		return this;
	},

	//展示placeholder
	showPH: function(){
		this.$elem.val(this.msg)
			.css('color', '#AAA');
	},

	//触发展示
	onShow: function(){
		if( this._shouldPlace() ){
			this.showPH();
		}
	},

	//触发隐藏
	onHide: function(){
		if( this._shoulClean() ){
			this.hidePH();
		}
	},

	//隐藏placeholder
	hidePH: function(){
		this.$elem.val('')
			.css('color', this.ocolor);
	},

	bindEvents: function(){
		var self = this,
			$elem = self.$elem;

		$elem.on('focus', function(){
			self.onHide();
		});

		$elem.on('blur', function(){
			self.onShow();
		});
	},

	//是否应该展示placeholder
	_shouldPlace: function(){
		return !this._inited || !this.$elem.val().length;
	},

	//是否应该清空内容
	_shoulClean: function(){
		return this.$elem.attr('placeholder') === this.$elem.val();
	}
};

$.fn.placeholder = function(){
	var elems = this;

	$.each(elems, function(i, elem){
		var $elem = $(elem),
			msg = $elem.attr('placeholder') || $elem.data('placeholder') || '',
			ocolor = $elem.css('color') || '#000',
			isPsw = ($elem.attr('type') === 'password'),
			ph;

		//是否已经初始化过
		if( $elem.data('yoplaceholder') ){
			ph = $elem.data('yoplaceholder');
			ph.reset(msg, ocolor, isPsw);

		} else {
			ph = new Placeholder($elem, msg, ocolor, isPsw);
			ph.init();
		}

	});
};<commit_msg>placeholder for qunar<commit_after>/**
 * @desc Placeholder shim for lte IE9
 * @author yongxiang.li@qunar.com
 * @date 2014.11.13
 *
 * Todo
 * 支持密码input的placeholder
 *
 * @usage
 * html: <input type="text" id="demo" placeholder="I am a placeholder" >
 * js: $('#demo').placeholder();
 */

!function($){

    var _VERSION = "0.0.2";

    var _createElement = (function() {
        if (typeof document.createElement !== 'function') {
            // This is the case in IE7, where the type of createElement is "object".
            // For this reason, we cannot call apply() as Object is not a Function.
            return function(){
                return document.createElement(arguments[0]);
            }
        } else {
            return function(){
                return document.createElement.apply(document, arguments);
            }
        }
    })();

    /**
     * [_supportPlaceholder determain if the brower support placeholder]
     * @return {[type]} [description]
     */
    function _supportPlaceholder(){
        var inp = _createElement('input');
        //return typeof inp.placeholder !== 'undefined';
        //return ('placeholder' in inp);
        return inp.placeholder !== undefined;
    }

    var Placeholder = function(elem, msg, ocolor,isPsw){

        //element
        this.$elem = $(elem);

        //placeholder 文字
        this.msg = msg;

        //原始颜色
        this.ocolor = ocolor;

        //是否是密码框
        this.isPsw = isPsw || false;

        //初始化状态
        this._inited = false;
    }

    Placeholder.prototype = {
        constructor: Placeholder,

        init: function(){

            var $elem = this.$elem,
                msg = this.msg;

            //为了兼容之前的placeholder，以及jvalidate校验
            if($elem.data('placeholder') !== msg){
                $elem.data('placeholder', msg);
            }

            //对于支持placeholder的直接返回，不需初始化
            if(_supportPlaceholder()){
                return false;
            }

            this.bindEvents();

            this.onShow();

            //缓存到元素上，方便再次调用
            $elem.data('yoplaceholder', this);

            this._inited = true;

            return this;
        },

        //如果元素已经初始化过，再调用的时候只改变值，不重新绑定事件
        reset: function(msg, ocolor, isPsw){
            this._inited = false;
            this.msg = msg;
            this.ocolor = ocolor; //原始颜色
            this.isPsw = isPsw || false;

            var $elem = this.$elem;

            //为了兼容之前的placeholder，以及jvalidate校验
            if($elem.data('placeholder') !== msg){
                $elem.data('placeholder', msg);
            }

            //对于支持placeholder的直接返回，不需初始化
            if(_supportPlaceholder()){
                return false;
            }

            this.onShow();

            //缓存到元素上，方便再次调用
            $elem.data('yoplaceholder', this);

            this._inited = true;

            return this;
        },

        //展示placeholder
        showPH: function(){
            this.$elem.val(this.msg)
                .css('color', '#AAA');
        },

        //触发展示
        onShow: function(){
            if( this._shouldPlace() ){
                this.showPH();
            }
        },

        //触发隐藏
        onHide: function(){
            if( this._shoulClean() ){
                this.hidePH();
            }
        },

        //隐藏placeholder
        hidePH: function(){
            this.$elem.val('')
                .css('color', this.ocolor);
        },

        bindEvents: function(){
            var self = this,
                $elem = self.$elem;

            $elem.on('focus', function(){
                self.onHide();
            });

            $elem.on('blur', function(){
                self.onShow();
            });
        },

        //判断输入框内容是否为空
        isPlaceHolderEmpty: function(){
            var self = this,
                $elem = self.$elem;

            return $.trim($elem.val()) === "" || $elem.val() === self.msg;
        },

        //是否应该展示placeholder
        _shouldPlace: function(){
            return !this._inited || !this.$elem.val().length;
        },

        //是否应该清空内容
        _shoulClean: function(){
            return this.$elem.attr('placeholder') === this.$elem.val();
        }
    };

    $.fn.placeholder = function(){
        var elems = this;

        $.each(elems, function(i, elem){
            var $elem = $(elem),
                msg = $elem.attr('placeholder') || $elem.data('placeholder') || '',
                ocolor = $elem.css('color') || '#000',
                isPsw = ($elem.attr('type') === 'password'),
                ph;

            //是否已经初始化过
            if( $elem.data('yoplaceholder') ){
                ph = $elem.data('yoplaceholder');
                ph.reset(msg, ocolor, isPsw);

            } else {
                ph = new Placeholder($elem, msg, ocolor, isPsw);
                ph.init();
            }

            var _isDef = function(){
                return $.trim( $elem.val() ) == "" || $elem.val() == msg;
            }

            $elem[0].isPlaceHolderEmpty = _isDef;

        });
    };

}(jQuery);<|endoftext|>


<commit_before>/* eslint indent: ["off"] */
import $ from 'dom7';
import Utils from '../../utils/utils';
import Modal from '../modal/modal-class';

class Actions extends Modal {
  constructor(app, params) {
    const extendedParams = Utils.extend(
      { on: {} },
      app.params.actions,
      params
    );

    // Extends with open/close Modal methods;
    super(app, extendedParams);

    const actions = this;

    actions.params = extendedParams;

    // Buttons
    let groups;
    if (actions.params.buttons) {
      groups = actions.params.buttons;
      if (!Array.isArray(groups[0])) groups = [groups];
    }
    actions.groups = groups;

    // Find Element
    let $el;
    if (actions.params.el) {
      $el = $(actions.params.el);
    } else if (actions.params.content) {
      $el = $(actions.params.content);
    } else if (actions.params.buttons) {
      if (actions.params.convertToPopover) {
        actions.popoverHtml = actions.renderPopover();
      }
      actions.actionsHtml = actions.render();
    }

    if ($el && $el.length > 0 && $el[0].f7Modal) {
      return $el[0].f7Modal;
    }

    if ($el && $el.length === 0 && !(actions.actionsHtml || actions.popoverHtml)) {
      return actions.destroy();
    }

    // Backdrop
    let $backdropEl;
    if (actions.params.backdrop && actions.params.backdropEl) {
      $backdropEl = $(actions.params.backdropEl);
    } else if (actions.params.backdrop) {
      $backdropEl = app.root.children('.actions-backdrop');
      if ($backdropEl.length === 0) {
        $backdropEl = $('

');
        app.root.append($backdropEl);
      }
    }

    const originalOpen = actions.open;
    const originalClose = actions.close;

    let popover;
    function buttonOnClick(e) {
      const buttonEl = this;
      let buttonIndex;
      let groupIndex;
      if ($(buttonEl).hasClass('list-button')) {
        buttonIndex = $(buttonEl).parents('li').index();
        groupIndex = $(buttonEl).parents('.list').index();
      } else {
        buttonIndex = $(buttonEl).index();
        groupIndex = $(buttonEl).parents('.actions-group').index();
      }
      if (typeof groups !== 'undefined') {
        const button = groups[groupIndex][buttonIndex];
        if (button.onClick) button.onClick(actions, e);
        if (actions.params.onClick) actions.params.onClick(actions, e);
        if (button.close !== false) actions.close();
      }
    }
    actions.open = function open(animate) {
      let convertToPopover = false;
      const { targetEl, targetX, targetY, targetWidth, targetHeight } = actions.params;
      if (actions.params.convertToPopover && (targetEl || (targetX !== undefined && targetY !== undefined))) {
        // Popover
        if (
          actions.params.forceToPopover
          || (app.device.ios && app.device.ipad)
          || app.width >= 768
          || (app.device.desktop && app.theme === 'aurora')
        ) {
          convertToPopover = true;
        }
      }
      if (convertToPopover && actions.popoverHtml) {
        popover = app.popover.create({
          content: actions.popoverHtml,
          backdrop: actions.params.backdrop,
          targetEl,
          targetX,
          targetY,
          targetWidth,
          targetHeight,
        });
        popover.open(animate);
        popover.once('popoverOpened', () => {
          popover.$el.find('.list-button').each((groupIndex, buttonEl) => {
            $(buttonEl).on('click', buttonOnClick);
          });
        });
        popover.once('popoverClosed', () => {
          popover.$el.find('.list-button').each((groupIndex, buttonEl) => {
            $(buttonEl).off('click', buttonOnClick);
          });
          Utils.nextTick(() => {
            popover.destroy();
            popover = undefined;
          });
        });
      } else {
        actions.$el = actions.actionsHtml ? $(actions.actionsHtml) : actions.$el;
        actions.$el[0].f7Modal = actions;
        if (actions.groups) {
          actions.$el.find('.actions-button').each((groupIndex, buttonEl) => {
            $(buttonEl).on('click', buttonOnClick);
          });
          actions.once('actionsClosed', () => {
            actions.$el.find('.actions-button').each((groupIndex, buttonEl) => {
              $(buttonEl).off('click', buttonOnClick);
            });
          });
        }
        actions.el = actions.$el[0];
        originalOpen.call(actions, animate);
      }
      return actions;
    };

    actions.close = function close(animate) {
      if (popover) {
        popover.close(animate);
      } else {
        originalClose.call(actions, animate);
      }
      return actions;
    };

    Utils.extend(actions, {
      app,
      $el,
      el: $el ? $el[0] : undefined,
      $backdropEl,
      backdropEl: $backdropEl && $backdropEl[0],
      type: 'actions',
    });

    function handleClick(e) {
      const target = e.target;
      const $target = $(target);
      const keyboardOpened = !app.device.desktop && app.device.cordova && ((window.Keyboard && window.Keyboard.isVisible) || (window.cordova.plugins && window.cordova.plugins.Keyboard && window.cordova.plugins.Keyboard.isVisible));
      if (keyboardOpened) return;
      if ($target.closest(actions.el).length === 0) {
        if (
          actions.params.closeByBackdropClick
          && actions.params.backdrop
          && actions.backdropEl
          && actions.backdropEl === target
        ) {
          actions.close();
        } else if (actions.params.closeByOutsideClick) {
          actions.close();
        }
      }
    }

    function onKeyDown(e) {
      const keyCode = e.keyCode;
      if (keyCode === 27 && actions.params.closeOnEscape) {
        actions.close();
      }
    }

    if (actions.params.closeOnEscape) {
      actions.on('open', () => {
        $(document).on('keydown', onKeyDown);
      });
      actions.on('close', () => {
        $(document).off('keydown', onKeyDown);
      });
    }

    actions.on('opened', () => {
      if (actions.params.closeByBackdropClick || actions.params.closeByOutsideClick) {
        app.on('click', handleClick);
      }
    });
    actions.on('close', () => {
      if (actions.params.closeByBackdropClick || actions.params.closeByOutsideClick) {
        app.off('click', handleClick);
      }
    });

    if ($el) {
      $el[0].f7Modal = actions;
    }

    return actions;
  }

  render() {
    const actions = this;
    if (actions.params.render) return actions.params.render.call(actions, actions);
    const { groups } = actions;
    return `

        ${groups.map(group => `

            ${group.map((button) => {
              const buttonClasses = [`actions-${button.label ? 'label' : 'button'}`];
              const { color, bg, bold, disabled, label, text, icon } = button;
              if (color) buttonClasses.push(`color-${color}`);
              if (bg) buttonClasses.push(`bg-color-${bg}`);
              if (bold) buttonClasses.push('actions-button-bold');
              if (disabled) buttonClasses.push('disabled');
              if (label) {
                return `<div class="${buttonClasses.join(' ')}">${text}</div>`;
              }
              return `

                  ${icon ? `<div class="actions-button-media">${icon}</div>` : ''}

${text}

`.trim();
            }).join('')}

`).join('')}

    `.trim();
  }

  renderPopover() {
    const actions = this;
    if (actions.params.renderPopover) return actions.params.renderPopover.call(actions, actions);
    const { groups } = actions;
    return `

          ${groups.map(group => `

                ${group.map((button) => {
                  const itemClasses = [];
                  const { color, bg, bold, disabled, label, text, icon } = button;
                  if (color) itemClasses.push(`color-${color}`);
                  if (bg) itemClasses.push(`bg-color-${bg}`);
                  if (bold) itemClasses.push('popover-from-actions-bold');
                  if (disabled) itemClasses.push('disabled');
                  if (label) {
                    itemClasses.push('popover-from-actions-label');
                    return `<li class="${itemClasses.join(' ')}">${text}</li>`;
                  }
                  if (icon) {
                    itemClasses.push('item-link item-content');
                    return `

                            ${icon}

                              ${text}

                    `;
                  }
                  itemClasses.push('list-button');
                  return `

                      ${text}

                  `;
                }).join('')}

          `).join('')}

    `.trim();
  }
}

export default Actions;
<commit_msg>Core: Actions - fix icon button click handler<commit_after>/* eslint indent: ["off"] */
import $ from 'dom7';
import Utils from '../../utils/utils';
import Modal from '../modal/modal-class';

class Actions extends Modal {
  constructor(app, params) {
    const extendedParams = Utils.extend(
      { on: {} },
      app.params.actions,
      params
    );

    // Extends with open/close Modal methods;
    super(app, extendedParams);

    const actions = this;

    actions.params = extendedParams;

    // Buttons
    let groups;
    if (actions.params.buttons) {
      groups = actions.params.buttons;
      if (!Array.isArray(groups[0])) groups = [groups];
    }
    actions.groups = groups;

    // Find Element
    let $el;
    if (actions.params.el) {
      $el = $(actions.params.el);
    } else if (actions.params.content) {
      $el = $(actions.params.content);
    } else if (actions.params.buttons) {
      if (actions.params.convertToPopover) {
        actions.popoverHtml = actions.renderPopover();
      }
      actions.actionsHtml = actions.render();
    }

    if ($el && $el.length > 0 && $el[0].f7Modal) {
      return $el[0].f7Modal;
    }

    if ($el && $el.length === 0 && !(actions.actionsHtml || actions.popoverHtml)) {
      return actions.destroy();
    }

    // Backdrop
    let $backdropEl;
    if (actions.params.backdrop && actions.params.backdropEl) {
      $backdropEl = $(actions.params.backdropEl);
    } else if (actions.params.backdrop) {
      $backdropEl = app.root.children('.actions-backdrop');
      if ($backdropEl.length === 0) {
        $backdropEl = $('

');
        app.root.append($backdropEl);
      }
    }

    const originalOpen = actions.open;
    const originalClose = actions.close;

    let popover;
    function buttonOnClick(e) {
      const $buttonEl = $(this);
      let buttonIndex;
      let groupIndex;
      if ($buttonEl.hasClass('list-button') || $buttonEl.hasClass('item-link')) {
        buttonIndex = $buttonEl.parents('li').index();
        groupIndex = $buttonEl.parents('.list').index();
      } else {
        buttonIndex = $buttonEl.index();
        groupIndex = $buttonEl.parents('.actions-group').index();
      }
      if (typeof groups !== 'undefined') {
        const button = groups[groupIndex][buttonIndex];
        if (button.onClick) button.onClick(actions, e);
        if (actions.params.onClick) actions.params.onClick(actions, e);
        if (button.close !== false) actions.close();
      }
    }
    actions.open = function open(animate) {
      let convertToPopover = false;
      const { targetEl, targetX, targetY, targetWidth, targetHeight } = actions.params;
      if (actions.params.convertToPopover && (targetEl || (targetX !== undefined && targetY !== undefined))) {
        // Popover
        if (
          actions.params.forceToPopover
          || (app.device.ios && app.device.ipad)
          || app.width >= 768
          || (app.device.desktop && app.theme === 'aurora')
        ) {
          convertToPopover = true;
        }
      }
      if (convertToPopover && actions.popoverHtml) {
        popover = app.popover.create({
          content: actions.popoverHtml,
          backdrop: actions.params.backdrop,
          targetEl,
          targetX,
          targetY,
          targetWidth,
          targetHeight,
        });
        popover.open(animate);
        popover.once('popoverOpened', () => {
          popover.$el.find('.list-button, .item-link').each((groupIndex, buttonEl) => {
            $(buttonEl).on('click', buttonOnClick);
          });
        });
        popover.once('popoverClosed', () => {
          popover.$el.find('.list-button, .item-link').each((groupIndex, buttonEl) => {
            $(buttonEl).off('click', buttonOnClick);
          });
          Utils.nextTick(() => {
            popover.destroy();
            popover = undefined;
          });
        });
      } else {
        actions.$el = actions.actionsHtml ? $(actions.actionsHtml) : actions.$el;
        actions.$el[0].f7Modal = actions;
        if (actions.groups) {
          actions.$el.find('.actions-button').each((groupIndex, buttonEl) => {
            $(buttonEl).on('click', buttonOnClick);
          });
          actions.once('actionsClosed', () => {
            actions.$el.find('.actions-button').each((groupIndex, buttonEl) => {
              $(buttonEl).off('click', buttonOnClick);
            });
          });
        }
        actions.el = actions.$el[0];
        originalOpen.call(actions, animate);
      }
      return actions;
    };

    actions.close = function close(animate) {
      if (popover) {
        popover.close(animate);
      } else {
        originalClose.call(actions, animate);
      }
      return actions;
    };

    Utils.extend(actions, {
      app,
      $el,
      el: $el ? $el[0] : undefined,
      $backdropEl,
      backdropEl: $backdropEl && $backdropEl[0],
      type: 'actions',
    });

    function handleClick(e) {
      const target = e.target;
      const $target = $(target);
      const keyboardOpened = !app.device.desktop && app.device.cordova && ((window.Keyboard && window.Keyboard.isVisible) || (window.cordova.plugins && window.cordova.plugins.Keyboard && window.cordova.plugins.Keyboard.isVisible));
      if (keyboardOpened) return;
      if ($target.closest(actions.el).length === 0) {
        if (
          actions.params.closeByBackdropClick
          && actions.params.backdrop
          && actions.backdropEl
          && actions.backdropEl === target
        ) {
          actions.close();
        } else if (actions.params.closeByOutsideClick) {
          actions.close();
        }
      }
    }

    function onKeyDown(e) {
      const keyCode = e.keyCode;
      if (keyCode === 27 && actions.params.closeOnEscape) {
        actions.close();
      }
    }

    if (actions.params.closeOnEscape) {
      actions.on('open', () => {
        $(document).on('keydown', onKeyDown);
      });
      actions.on('close', () => {
        $(document).off('keydown', onKeyDown);
      });
    }

    actions.on('opened', () => {
      if (actions.params.closeByBackdropClick || actions.params.closeByOutsideClick) {
        app.on('click', handleClick);
      }
    });
    actions.on('close', () => {
      if (actions.params.closeByBackdropClick || actions.params.closeByOutsideClick) {
        app.off('click', handleClick);
      }
    });

    if ($el) {
      $el[0].f7Modal = actions;
    }

    return actions;
  }

  render() {
    const actions = this;
    if (actions.params.render) return actions.params.render.call(actions, actions);
    const { groups } = actions;
    return `

        ${groups.map(group => `

            ${group.map((button) => {
              const buttonClasses = [`actions-${button.label ? 'label' : 'button'}`];
              const { color, bg, bold, disabled, label, text, icon } = button;
              if (color) buttonClasses.push(`color-${color}`);
              if (bg) buttonClasses.push(`bg-color-${bg}`);
              if (bold) buttonClasses.push('actions-button-bold');
              if (disabled) buttonClasses.push('disabled');
              if (label) {
                return `<div class="${buttonClasses.join(' ')}">${text}</div>`;
              }
              return `

                  ${icon ? `<div class="actions-button-media">${icon}</div>` : ''}

${text}

`.trim();
            }).join('')}

`).join('')}

    `.trim();
  }

  renderPopover() {
    const actions = this;
    if (actions.params.renderPopover) return actions.params.renderPopover.call(actions, actions);
    const { groups } = actions;
    return `

          ${groups.map(group => `

                ${group.map((button) => {
                  const itemClasses = [];
                  const { color, bg, bold, disabled, label, text, icon } = button;
                  if (color) itemClasses.push(`color-${color}`);
                  if (bg) itemClasses.push(`bg-color-${bg}`);
                  if (bold) itemClasses.push('popover-from-actions-bold');
                  if (disabled) itemClasses.push('disabled');
                  if (label) {
                    itemClasses.push('popover-from-actions-label');
                    return `<li class="${itemClasses.join(' ')}">${text}</li>`;
                  }
                  if (icon) {
                    itemClasses.push('item-link item-content');
                    return `

                            ${icon}

                              ${text}

                    `;
                  }
                  itemClasses.push('list-button');
                  return `

                      ${text}

                  `;
                }).join('')}

          `).join('')}

    `.trim();
  }
}

export default Actions;
<|endoftext|>


<commit_before>var updateFilterTimer;
var resultCache;
var validSet;
var sortBy;
var nominateScatterChart = dc.scatterPlot("#scatter-chart");
var baseTip = d3.select("body").append("div").attr("class", "d3-tip").style("visibility","hidden").attr("id","mapTooltip");
var eW;

// From stackoverflow response, who borrowed it from Shopify--simple ordinal suffix.
function getGetOrdinal(n) {
    var s=["th","st","nd","rd"],
    v=n%100;
    return n+(s[(v-20)%10]||s[v]||s[0]);
 }

$(document).ready(function()
{
	congressNum = $("#congSelector").val();
	$.ajax({
		dataType: "JSON",
		url: "/api/getmembersbycongress?congress="+congressNum+"&chamber="+chamber_param+"&api=Web_Congress",
		success: function(data, status, xhr)
		{
			$('#content').fadeIn();
			$('#loading-container').slideUp();
			resultCache = data;
			writeBioTable();
			nomPlot();
			compositionBar();
		}
	});

	$("#congSelector").change(reloadBios);
});

function nomPlot()
{
	console.log('ok');
	var ndx = crossfilter(resultCache["results"]);
	var all = ndx.groupAll();
	var xDimension = ndx.dimension(
		function(d)
		{
			if(d.nominate!=undefined)
			{
				var x = d.nominate.dim1;
				var y = d.nominate.dim2;
			}
			else
			{
				var x = 999;
				var y = 999;
			}
			return [x,y];
		}
	);
	var xGroup = xDimension.group().reduce(
		function(p, d)
		{
			p.members.push(d);
			return p;
		},

		function(p, d)
		{
			var index = p.members.indexOf(d);
			if(index > -1) { p.members.splice(index, 1); }
			return p;
		},

		function() { return {members: []} ; }
	);

	nominateScatterChart
	.width(890)
	.height(432)
	.margins({top:25,right:25,bottom:75,left:75})
	.dimension(xDimension)
	.mouseZoomable(false)
	.group(xGroup)
	.data(function(group) { return group.all().filter(function(d) { return d.key!=[999,999]; });})
	.symbolSize(7)
	.colorCalculator(function(d) {
		var color = "#CCC";
		try {
			if(d.value.members.length > 0){
				color = blendColors(d.value.members);
			}
		}catch(e){
			console.log(e);
		}
		return color;
	})
	.highlightedSize(10)
	.x(d3.scale.linear().domain([-1.0,1.0]))
	.y(d3.scale.linear().domain([-1.2,1.2]));

	nominateScatterChart.on("filtered", function()
	{
		if(updateFilterTimer) { clearTimeout(updateFilterTimer); }
		updateFilterTimer = setTimeout(function()
		{
			var filterSelect= xDimension.top(Infinity);
			validSet = [];
			for(var i in filterSelect)
			{
				validSet.push(filterSelect[i].icpsr);
			}
			hasFilter=1;
			hideMembersUnselected();
		}, 300);
	});

	dc.filterAll();
	dc.renderAll();
	decorateNominate(nominateScatterChart, resultCache);
}

function rechamber()
{
	if(chamber_param=="house") { chamber_param="senate"; $("#memberLabel").html("Senators"); }
	else { chamber_param="house"; $("#memberLabel").html("Representatives"); }
	reloadBios();
}

function reloadBios()
{
	congressNum = $("#congSelector").val();
	$.ajax({
		dataType: "JSON",
		url: "/api/getmembersbycongress?congress="+congressNum+"&chamber="+chamber_param+"&api=Web_Congress",
		success: function(data, status, xhr)
		{
			validSet = [];
			resultCache = data;
			$("#sortChamber").unbind('click')
			$("#sortChamber").click(function() { resort('elected_'+chamber_param); return false; });
			writeBioTable();
			nomPlot();
			compositionBar();
		}
	});
}

function getVPP(congress)
{
	// This is a hack; we just list thresholds at which the VP/ President of the Senate switches
	var VPParty = {	"115": "Republican", "111": "Democrat", "107": "Republican", "103": "Democrat",
			"97": "Republican", "95": "Democrat", "91": "Republican", "87": "Democrat",
			"83": "Republican", "81": "Democrat", "80": "Vacant", "73": "Democrat",
			"67": "Republican", "63": "Democrat", "59": "Republican", "58": "Vacant",
			"55": "Republican", "53": "Democrat", "51": "Republican", "50": "Vacant",
			"49": "Democrat", "48": "Vacant", "41": "Republican", "40": "Vacant",
			"39": "Democrat", "37": "Republican", "35": "Democrat", "34": "Vacant",
			"33": "Democrat", "32": "Vacant", "31": "Whig", "29": "Democrat",
			"28": "Vacant", "27": "Whig", "25": "Democrat", "20": "Jackson",
			"15": "Democrat-Republican", "14": "Vacant", "5": "Democrat-Republican",
			"4": "Federalist", "1": "Pro-Administration"};

	// Sort the dict keys and reverse them so the short-circuit in the loop below works
	var keys = Object.keys(VPParty);
	keys.reverse();

	// Iterate through keys until we find the bucket we're in
	for(var i=0;i!=keys.length;i++)
	{
		// We just return party name.
		if(parseInt(keys[i])<=parseInt(congress)) { return VPParty[keys[i]]; }
	}
}

function compositionBar()
{
	var partyCount={}
	$.each(resultCache["results"], function(i, d) {
		if(partyCount[d.party_short_name]==undefined) { partyCount[d.party_short_name]=1; }
		else { partyCount[d.party_short_name]++; }
	});

	$("#partyComposition").html("");
	var svgBucket = d3.select("#partyComposition").append("svg").attr("width",300).attr("height",21);
	var x=0;
	var sorted_parties = Object.keys(partyCount).sort();

	var baseTipT = "Party Composition of "+getGetOrdinal(congressNum)+" "+chamber_param.substr(0,1).toUpperCase()+chamber_param.substr(1)+"
";
	var maxN = 0; var maxP = 0; var sumSet=0;
	for(pNi in sorted_parties)
	{
		pN = sorted_parties[pNi];
		if(partyCount[pN]>maxN || (partyCount[pN]==maxN && pN==getVPP(congressNum) && chamber_param=="senate")) { maxN=partyCount[pN]; maxP = pN; }
		var wid = Math.round(300*(partyCount[pN]/resultCache["results"].length));
		try {var voteCol = colorSchemes[partyColorMap[partyNameSimplify(pN)]][0]; } catch(e) { var voteCol = '#000000'; }
		var rect = svgBucket.append("rect")
				.attr("x",x).attr("y",3).attr("width",wid).attr("height",15)
				.attr('class',partyColorMap[partyNameSimplify(pN)])
				//.attr("fill",voteCol)
				.attr("stroke","#000000").attr("stroke-width",1);
		x=x+wid;
		baseTipT += '
'+pN+': '+partyCount[pN];
		if(chamber_param=="senate" && pN==getVPP(congressNum)) { baseTipT += " (+ Vice President)"; }
	}
	baseTipT+= "

Note: Counts include members elected through special elections after resignations, deaths, or vacancies.";
	svgBucket.on('mouseover',function(d) {
		baseTip.html(baseTipT);
		$('#mapTooltip').removeClass().addClass('d3-tip')
				.addClass(partyColorMap[partyNameSimplify(maxP)]);
		eW = baseTip.style('width');
		baseTip.style('visibility','visible');
	}).on('mousemove',function(d) {
		baseTip.style("top",(event.pageY+20)+"px").style("left", (event.pageX-(parseInt(eW.substr(0,eW.length-2))/2))+"px");
	}).on('mouseout',function(d) { baseTip.style('visibility','hidden'); });
}

function hideMembersUnselected()
{
	$("#memberList > li.memberResultBox").each(function(i, d) {
		if(validSet.indexOf(parseInt($(d).attr("id")))!=-1 || validSet.length==0) { $(d).show(); }
		else { $(d).hide(); }
	});
}

<commit_msg>Hack to keep few members in fewer columns #110<commit_after>var updateFilterTimer;
var resultCache;
var validSet;
var sortBy;
var nominateScatterChart = dc.scatterPlot("#scatter-chart");
var baseTip = d3.select("body").append("div").attr("class", "d3-tip").style("visibility","hidden").attr("id","mapTooltip");
var eW;

// From stackoverflow response, who borrowed it from Shopify--simple ordinal suffix.
function getGetOrdinal(n) {
    var s=["th","st","nd","rd"],
    v=n%100;
    return n+(s[(v-20)%10]||s[v]||s[0]);
 }

$(document).ready(function()
{
	congressNum = $("#congSelector").val();
	$.ajax({
		dataType: "JSON",
		url: "/api/getmembersbycongress?congress="+congressNum+"&chamber="+chamber_param+"&api=Web_Congress",
		success: function(data, status, xhr)
		{
			$('#content').fadeIn();
			$('#loading-container').slideUp();
			resultCache = data;
			writeBioTable();
			nomPlot();
			compositionBar();
		}
	});

	$("#congSelector").change(reloadBios);
});

function nomPlot()
{
	console.log('ok');
	var ndx = crossfilter(resultCache["results"]);
	var all = ndx.groupAll();
	var xDimension = ndx.dimension(
		function(d)
		{
			if(d.nominate!=undefined)
			{
				var x = d.nominate.dim1;
				var y = d.nominate.dim2;
			}
			else
			{
				var x = 999;
				var y = 999;
			}
			return [x,y];
		}
	);
	var xGroup = xDimension.group().reduce(
		function(p, d)
		{
			p.members.push(d);
			return p;
		},

		function(p, d)
		{
			var index = p.members.indexOf(d);
			if(index > -1) { p.members.splice(index, 1); }
			return p;
		},

		function() { return {members: []} ; }
	);

	nominateScatterChart
	.width(890)
	.height(432)
	.margins({top:25,right:25,bottom:75,left:75})
	.dimension(xDimension)
	.mouseZoomable(false)
	.group(xGroup)
	.data(function(group) { return group.all().filter(function(d) { return d.key!=[999,999]; });})
	.symbolSize(7)
	.colorCalculator(function(d) {
		var color = "#CCC";
		try {
			if(d.value.members.length > 0){
				color = blendColors(d.value.members);
			}
		}catch(e){
			console.log(e);
		}
		return color;
	})
	.highlightedSize(10)
	.x(d3.scale.linear().domain([-1.0,1.0]))
	.y(d3.scale.linear().domain([-1.2,1.2]));

	nominateScatterChart.on("filtered", function()
	{
		if(updateFilterTimer) { clearTimeout(updateFilterTimer); }
		updateFilterTimer = setTimeout(function()
		{
			var filterSelect= xDimension.top(Infinity);
			validSet = [];
			for(var i in filterSelect)
			{
				validSet.push(filterSelect[i].icpsr);
			}
			hasFilter=1;
			hideMembersUnselected();
		}, 300);
	});

	dc.filterAll();
	dc.renderAll();
	decorateNominate(nominateScatterChart, resultCache);
}

function rechamber()
{
	if(chamber_param=="house") { chamber_param="senate"; $("#memberLabel").html("Senators"); }
	else { chamber_param="house"; $("#memberLabel").html("Representatives"); }
	reloadBios();
}

function reloadBios()
{
	congressNum = $("#congSelector").val();
	$.ajax({
		dataType: "JSON",
		url: "/api/getmembersbycongress?congress="+congressNum+"&chamber="+chamber_param+"&api=Web_Congress",
		success: function(data, status, xhr)
		{
			validSet = [];
			resultCache = data;
			$("#sortChamber").unbind('click')
			$("#sortChamber").click(function() { resort('elected_'+chamber_param); return false; });
			writeBioTable();
			nomPlot();
			compositionBar();
		}
	});
}

function getVPP(congress)
{
	// This is a hack; we just list thresholds at which the VP/ President of the Senate switches
	var VPParty = {	"115": "Republican", "111": "Democrat", "107": "Republican", "103": "Democrat",
			"97": "Republican", "95": "Democrat", "91": "Republican", "87": "Democrat",
			"83": "Republican", "81": "Democrat", "80": "Vacant", "73": "Democrat",
			"67": "Republican", "63": "Democrat", "59": "Republican", "58": "Vacant",
			"55": "Republican", "53": "Democrat", "51": "Republican", "50": "Vacant",
			"49": "Democrat", "48": "Vacant", "41": "Republican", "40": "Vacant",
			"39": "Democrat", "37": "Republican", "35": "Democrat", "34": "Vacant",
			"33": "Democrat", "32": "Vacant", "31": "Whig", "29": "Democrat",
			"28": "Vacant", "27": "Whig", "25": "Democrat", "20": "Jackson",
			"15": "Democrat-Republican", "14": "Vacant", "5": "Democrat-Republican",
			"4": "Federalist", "1": "Pro-Administration"};

	// Sort the dict keys and reverse them so the short-circuit in the loop below works
	var keys = Object.keys(VPParty);
	keys.reverse();

	// Iterate through keys until we find the bucket we're in
	for(var i=0;i!=keys.length;i++)
	{
		// We just return party name.
		if(parseInt(keys[i])<=parseInt(congress)) { return VPParty[keys[i]]; }
	}
}

function compositionBar()
{
	var partyCount={}
	$.each(resultCache["results"], function(i, d) {
		if(partyCount[d.party_short_name]==undefined) { partyCount[d.party_short_name]=1; }
		else { partyCount[d.party_short_name]++; }
	});

	$("#partyComposition").html("");
	var svgBucket = d3.select("#partyComposition").append("svg").attr("width",300).attr("height",21);
	var x=0;
	var sorted_parties = Object.keys(partyCount).sort();

	var baseTipT = "Party Composition of "+getGetOrdinal(congressNum)+" "+chamber_param.substr(0,1).toUpperCase()+chamber_param.substr(1)+"
";
	var maxN = 0; var maxP = 0; var sumSet=0;
	for(pNi in sorted_parties)
	{
		pN = sorted_parties[pNi];
		if(partyCount[pN]>maxN || (partyCount[pN]==maxN && pN==getVPP(congressNum) && chamber_param=="senate")) { maxN=partyCount[pN]; maxP = pN; }
		var wid = Math.round(300*(partyCount[pN]/resultCache["results"].length));
		try {var voteCol = colorSchemes[partyColorMap[partyNameSimplify(pN)]][0]; } catch(e) { var voteCol = '#000000'; }
		var rect = svgBucket.append("rect")
				.attr("x",x).attr("y",3).attr("width",wid).attr("height",15)
				.attr('class',partyColorMap[partyNameSimplify(pN)])
				//.attr("fill",voteCol)
				.attr("stroke","#000000").attr("stroke-width",1);
		x=x+wid;
		baseTipT += '
'+pN+': '+partyCount[pN];
		if(chamber_param=="senate" && pN==getVPP(congressNum)) { baseTipT += " (+ Vice President)"; }
	}
	baseTipT+= "

Note: Counts include members elected through special elections after resignations, deaths, or vacancies.";
	svgBucket.on('mouseover',function(d) {
		baseTip.html(baseTipT);
		$('#mapTooltip').removeClass().addClass('d3-tip')
				.addClass(partyColorMap[partyNameSimplify(maxP)]);
		eW = baseTip.style('width');
		baseTip.style('visibility','visible');
	}).on('mousemove',function(d) {
		baseTip.style("top",(event.pageY+20)+"px").style("left", (event.pageX-(parseInt(eW.substr(0,eW.length-2))/2))+"px");
	}).on('mouseout',function(d) { baseTip.style('visibility','hidden'); });
}

function hideMembersUnselected()
{

	$("#memberList > li.memberResultBox").each(function(i, d) {
		if(validSet.indexOf(parseInt($(d).attr("id")))!=-1 || validSet.length==0) { $(d).show(); }
		else { $(d).hide(); }
	});

        // Set number of columns by number of selected members
        if(validSet.length < 5){
	        $("#memberList").css("columns","1").css("width","25%");
	} else if (validSet.length < 9)
	{
	        $("#memberList").css("columns","2").css("width","50%")
	} else if (validSet.length < 13)
	{
	        $("#memberList").css("columns","3").css("width","75%")
	} else
	{
	        $("#memberList").css("columns","4").css("width","100%")
	}

}

<|endoftext|>


<commit_before>// search all links (into definitions) linking to elements in the current page (href starts with #)
// To set the title of the link to the definition it points to
document.querySelectorAll("[id^=\"def-\"]").forEach(function(def){
	const id = def.id;
	let title = def.parentNode.textContent;
	if ( title.match(/\.\s/) ) {
		// We take everything until the last period. (Everything after are links such as "Wikipedia"
		title = title.match(/^.*\.\s/)[0];
	}
	document.querySelectorAll(".definition>a[href^=\"#"+id+"\"]").forEach(function(a){
		a.title = title;
	});
});

// search for invalid links
/*eslint no-console: ["error", { allow: ["error"] }] */
document.querySelectorAll(".definition>a[href^=\"#\"]").forEach(function(a){
	if ( a.title ) return;
	let href = a.href;
	let id = href.substring(href.indexOf("#")+1);
	if ( ! id ) return;
	let el = document.getElementById(id);
	if ( ! el ) {
		console.error("Invalid link to:"+id);
		return;
	}
});<commit_msg>Fix #1037 (#1068)<commit_after>// search all links (into definitions) linking to elements in the current page (href starts with #)
// To set the title of the link to the definition it points to
document.querySelectorAll("[id^=\"def-\"]").forEach(function(def){
	const id = def.id;
	let title = def.closest(".definition").textContent;
	if ( title.match(/\.\s/) ) {
		// We take everything until the last period. (Everything after are links such as "Wikipedia"
		title = title.match(/^[\s\S]*\.\s/)[0];
		title = title.replace(/\n/g," ");
		title = title.replace(/\s\s+/g," ");
	}
	document.querySelectorAll(".definition>a[href^=\"#"+id+"\"]").forEach(function(a){
		a.title = title;
	});
});

// search for invalid links
/*eslint no-console: ["error", { allow: ["error"] }] */
document.querySelectorAll(".definition>a[href^=\"#\"]").forEach(function(a){
	if ( a.title ) return;
	let href = a.href;
	let id = href.substring(href.indexOf("#")+1);
	if ( ! id ) return;
	let el = document.getElementById(id);
	if ( ! el ) {
		console.error("Invalid link to:"+id);
		return;
	}
});<|endoftext|>


<commit_before>$(document).ready(function() {
    var ctx = document.getElementById("tests-chart").getContext("2d");
    var data = {
        labels: ["January", "February", "March", "April", "May", "June", "July"],
        datasets: [
            {
                label: "My First dataset",
                fillColor: "rgba(220,220,220,0.2)",
                strokeColor: "rgba(220,220,220,1)",
                pointColor: "rgba(220,220,220,1)",
                pointStrokeColor: "#fff",
                pointHighlightFill: "#fff",
                pointHighlightStroke: "rgba(220,220,220,1)",
                data: [65, 59, 80, 81, 56, 55, 40]
            },
            {
                label: "My Second dataset",
                fillColor: "rgba(151,187,205,0.2)",
                strokeColor: "rgba(151,187,205,1)",
                pointColor: "rgba(151,187,205,1)",
                pointStrokeColor: "#fff",
                pointHighlightFill: "#fff",
                pointHighlightStroke: "rgba(151,187,205,1)",
                data: [28, 48, 40, 19, 86, 27, 90]
            }
        ]
    };
    var options = {};

    var myLineChart = new Chart(ctx).Line(data, options);
});<commit_msg>Dynamically load data for the graph<commit_after>$(document).ready(function() {
    var ctx = document.getElementById("tests-chart").getContext("2d");
    $.getJSON('/api/stats', function(data) {
        var options = {};
        console.log(data);
        var myLineChart = new Chart(ctx).Line(data, options);
    });
});<|endoftext|>


<commit_before>// func(a, idx), to customize the <a> element inside pagination
function createPagination(parent, current, total, func){
    ul = document.createElement("ul");
    ul.classList.add("pagination");

    if(current>0) {
        li = document.createElement("li")
        li.classList.add("previous")
        a = document.createElement("a")
        a.innerHTML = "← Prev"
        li.append(a)
        if( func ) {
            func(a, current-1)
        }
        ul.append(li)
    }

    for(var i=0; i<total; i++) {
        li = document.createElement("li")

        if(i == current) {
            li.classList.add("active")
        }
        a = document.createElement("a")
        a.innerHTML = i+1
        if( func ) {
            func(a, i);
        }
        li.append(a)
        ul.append(li)
    }

    if((current+1)<total) {
        li = document.createElement("li")
        li.classList.add("next")
        a = document.createElement("a")
        a.innerHTML = "→ Next"
        li.append(a)
        if( func ) {
            func(a, current+1)
        }
        ul.append(li)
    }
    parent.append(ul);
}
<commit_msg>Minor fix: not create pagination for only 1 page<commit_after>// func(a, idx), to customize the <a> element inside pagination
function createPagination(parent, current, total, func){
    if(total < 2) {
        return
    }

    ul = document.createElement("ul");
    ul.classList.add("pagination");

    if(current>0) {
        li = document.createElement("li")
        li.classList.add("previous")
        a = document.createElement("a")
        a.innerHTML = "← Prev"
        li.append(a)
        if( func ) {
            func(a, current-1)
        }
        ul.append(li)
    }

    for(var i=0; i<total; i++) {
        li = document.createElement("li")

        if(i == current) {
            li.classList.add("active")
        }
        a = document.createElement("a")
        a.innerHTML = i+1
        if( func ) {
            func(a, i);
        }
        li.append(a)
        ul.append(li)
    }

    if((current+1)<total) {
        li = document.createElement("li")
        li.classList.add("next")
        a = document.createElement("a")
        a.innerHTML = "→ Next"
        li.append(a)
        if( func ) {
            func(a, current+1)
        }
        ul.append(li)
    }
    parent.append(ul);
}
<|endoftext|>


<commit_before>var tooltips = {};

tooltips.init = function() {

  tooltips.limit = 200;
  tooltips.loadingPreviews = {};
  tooltips.loadedContent = {};
  tooltips.quoteReference = {};
  tooltips.knownPosts = {};
  tooltips.knownData = {};

  var posts = document.getElementsByClassName('postCell');

  for (var i = 0; i < posts.length; i++) {
    tooltips.addToKnownPostsForBackLinks(posts[i])
  }

  var threads = document.getElementsByClassName('opCell');

  for (i = 0; i < threads.length; i++) {
    tooltips.addToKnownPostsForBackLinks(threads[i])
  }

  tooltips.cacheExistingHTML('innerOP');
  tooltips.cacheExistingHTML('innerPost');

  var quotes = document.getElementsByClassName('quoteLink');

  for (i = 0; i < quotes.length; i++) {
    tooltips.processQuote(quotes[i]);
  }

};

tooltips.cacheExistingHTML = function(className) {

  var innerContent = document.getElementsByClassName(className);

  for (var i = 0; i < innerContent.length; i++) {

    var inner = innerContent[i];

    var temp = document.createElement('div');
    temp.className = 'innerPost';
    temp.innerHTML = inner.innerHTML;

    var deletionCheckBox = temp.getElementsByClassName('deletionCheckBox')[0];

    if (deletionCheckBox) {
      deletionCheckBox.remove();
    }

    var quoteLink = temp.getElementsByClassName('linkSelf')[0];
    tooltips.loadedContent[quoteLink.href] = temp.outerHTML;
  }

};

tooltips.addToKnownPostsForBackLinks = function(posting) {

  var postBoard = posting.dataset.boarduri;

  var list = tooltips.knownPosts[postBoard] || {};
  tooltips.knownPosts[postBoard] = list;

  list[posting.id] = {
    added : [],
    container : posting.getElementsByClassName('panelBacklinks')[0]
  };

};

tooltips.addBackLink = function(quoteUrl, quote) {

  var matches = quoteUrl.match(/\/(\w+)\/res\/(\d+)\.html\#(\d+)/);

  var board = matches[1];
  var thread = matches[2];
  var post = matches[3];

  var knownBoard = tooltips.knownPosts[board];

  if (knownBoard) {

    var knownBackLink = knownBoard[post];

    if (knownBackLink) {

      var containerPost = quote.parentNode.parentNode;

      if (containerPost.className !== 'opCell') {
        containerPost = containerPost.parentNode;
      }

      var sourceBoard = containerPost.dataset.boarduri;
      var sourcePost = containerPost.id;

      var sourceId = sourceBoard + '_' + sourcePost;

      if (knownBackLink.added.indexOf(sourceId) > -1) {
        return;
      } else {
        knownBackLink.added.push(sourceId);
      }

      var innerHTML = '>>';

      if (sourceBoard != board) {
        innerHTML += '/' + containerPost.dataset.boarduri + '/';
      }

      innerHTML += sourcePost;

      var backLink = document.createElement('a');
      backLink.innerHTML = innerHTML;

      var backLinkUrl = '/' + sourceBoard + '/res/' + thread + '.html#'
          + sourcePost;

      backLink.href = backLinkUrl;

      knownBackLink.container.appendChild(backLink);

      tooltips.processQuote(backLink, true);

    }

  }

};

tooltips.processQuote = function(quote, backLink) {

  var tooltip;

  var quoteUrl = quote.href;

  if (!backLink) {
    tooltips.addBackLink(quoteUrl, quote);
  }

  quote.onmouseenter = function() {

    tooltip = document.createElement('div');
    tooltip.className = 'quoteTooltip';

    document.body.appendChild(tooltip);

    if (tooltips.loadedContent[quoteUrl]) {
      tooltip.innerHTML = tooltips.loadedContent[quoteUrl];
    } else {
      tooltip.innerHTML = 'Loading';
    }

    var rect = quote.getBoundingClientRect();

    var previewOrigin = {
      x : rect.right + 10 + window.scrollX,
      y : rect.top + window.scrollY
    };

    var windowHeight = document.documentElement.clientHeight;

    if (previewOrigin.y + tooltips.limit > windowHeight) {
      previewOrigin.y = windowHeight - tooltips.limit;
    }

    tooltip.style.left = previewOrigin.x + 'px';
    tooltip.style.top = previewOrigin.y + 'px';
    tooltip.style.display = 'inline';

    if (!tooltips.loadedContent[quoteUrl]
        && !tooltips.loadingPreviews[quoteUrl]) {
      tooltips.loadQuote(tooltip, quoteUrl);
    }

    if (!api.isBoard) {
      var matches = quote.href.match(/\#(\d+)/);

      quote.onclick = function() {
        thread.markPost(matches[1]);
      };
    }

  };

  quote.onmouseout = function() {
    if (tooltip) {
      tooltip.remove();
      tooltip = null;
    }
  };

};

tooltips.generateHTMLFromData = function(postingData, tooltip, quoteUrl) {

  if (!postingData) {
    tooltip.innerHTML = 'Not found';
    return;
  }

  var tempDiv = posting.addPost(postingData, postingData.boardUri,
      postingData.threadId, true).getElementsByClassName('innerPost')[0];

  tempDiv.getElementsByClassName('deletionCheckBox')[0].remove();

  tooltip.innerHTML = tempDiv.outerHTML;

  tooltips.loadedContent[quoteUrl] = tempDiv.outerHTML;

};

tooltips.cacheData = function(threadData) {

  for (var i = 0; i < threadData.posts.length; i++) {
    var postData = threadData.posts[i];
    tooltips.knownData[threadData.boardUri + '/' + postData.postId] = postData;
  }

  tooltips.knownData[threadData.boardUri + '/' + threadData.threadId] = threadData;

};

tooltips.loadQuote = function(tooltip, quoteUrl) {

  var matches = quoteUrl.match(/\/(\w+)\/res\/(\d+)\.html\#(\d+)/);

  var board = matches[1];
  var thread = +matches[2];
  var post = +matches[3];

  var postingData = tooltips.knownData[board + '/' + post];

  if (postingData) {
    tooltips.generateHTMLFromData(postingData, tooltip, quoteUrl);
    return;
  }

  var threadUrl = '/' + board + '/res/' + thread + '.json';

  tooltips.loadingPreviews[quoteUrl] = true;

  api.localRequest(threadUrl, function receivedData(error, data) {

    delete tooltips.loadingPreviews[quoteUrl];

    if (error) {
      tooltip.innerHTML = 'Not found';
      return;
    }

    tooltips.cacheData(JSON.parse(data));

    tooltips.generateHTMLFromData(tooltips.knownData[board + '/' + post],
        tooltip, quoteUrl);

  });

};

tooltips.init();<commit_msg>Fixed tooltips not showing on the proper place outside thread pages.<commit_after>var tooltips = {};

tooltips.init = function() {

  tooltips.limit = 200;
  tooltips.loadingPreviews = {};
  tooltips.loadedContent = {};
  tooltips.quoteReference = {};
  tooltips.knownPosts = {};
  tooltips.knownData = {};

  var posts = document.getElementsByClassName('postCell');

  for (var i = 0; i < posts.length; i++) {
    tooltips.addToKnownPostsForBackLinks(posts[i])
  }

  var threads = document.getElementsByClassName('opCell');

  for (i = 0; i < threads.length; i++) {
    tooltips.addToKnownPostsForBackLinks(threads[i])
  }

  tooltips.cacheExistingHTML('innerOP');
  tooltips.cacheExistingHTML('innerPost');

  var quotes = document.getElementsByClassName('quoteLink');

  for (i = 0; i < quotes.length; i++) {
    tooltips.processQuote(quotes[i]);
  }

};

tooltips.cacheExistingHTML = function(className) {

  var innerContent = document.getElementsByClassName(className);

  for (var i = 0; i < innerContent.length; i++) {

    var inner = innerContent[i];

    var temp = document.createElement('div');
    temp.className = 'innerPost';
    temp.innerHTML = inner.innerHTML;

    var deletionCheckBox = temp.getElementsByClassName('deletionCheckBox')[0];

    if (deletionCheckBox) {
      deletionCheckBox.remove();
    }

    var quoteLink = temp.getElementsByClassName('linkSelf')[0];
    tooltips.loadedContent[quoteLink.href] = temp.outerHTML;
  }

};

tooltips.addToKnownPostsForBackLinks = function(posting) {

  var postBoard = posting.dataset.boarduri;

  var list = tooltips.knownPosts[postBoard] || {};
  tooltips.knownPosts[postBoard] = list;

  list[posting.id] = {
    added : [],
    container : posting.getElementsByClassName('panelBacklinks')[0]
  };

};

tooltips.addBackLink = function(quoteUrl, quote) {

  var matches = quoteUrl.match(/\/(\w+)\/res\/(\d+)\.html\#(\d+)/);

  var board = matches[1];
  var thread = matches[2];
  var post = matches[3];

  var knownBoard = tooltips.knownPosts[board];

  if (knownBoard) {

    var knownBackLink = knownBoard[post];

    if (knownBackLink) {

      var containerPost = quote.parentNode.parentNode;

      if (containerPost.className !== 'opCell') {
        containerPost = containerPost.parentNode;
      }

      var sourceBoard = containerPost.dataset.boarduri;
      var sourcePost = containerPost.id;

      var sourceId = sourceBoard + '_' + sourcePost;

      if (knownBackLink.added.indexOf(sourceId) > -1) {
        return;
      } else {
        knownBackLink.added.push(sourceId);
      }

      var innerHTML = '>>';

      if (sourceBoard != board) {
        innerHTML += '/' + containerPost.dataset.boarduri + '/';
      }

      innerHTML += sourcePost;

      var backLink = document.createElement('a');
      backLink.innerHTML = innerHTML;

      var backLinkUrl = '/' + sourceBoard + '/res/' + thread + '.html#'
          + sourcePost;

      backLink.href = backLinkUrl;

      knownBackLink.container.appendChild(backLink);

      tooltips.processQuote(backLink, true);

    }

  }

};

tooltips.processQuote = function(quote, backLink) {

  var tooltip;

  var quoteUrl = quote.href;

  if (!backLink) {
    tooltips.addBackLink(quoteUrl, quote);
  }

  quote.onmouseenter = function() {

    tooltip = document.createElement('div');
    tooltip.className = 'quoteTooltip';

    document.body.appendChild(tooltip);

    if (tooltips.loadedContent[quoteUrl]) {
      tooltip.innerHTML = tooltips.loadedContent[quoteUrl];
    } else {
      tooltip.innerHTML = 'Loading';
    }

    var rect = quote.getBoundingClientRect();

    var previewOrigin = {
      x : rect.right + 10 + window.scrollX,
      y : rect.top + window.scrollY
    };

    var windowHeight = document.documentElement.clientHeight + window.scrollY;

    if (previewOrigin.y + tooltips.limit > windowHeight) {
      previewOrigin.y = windowHeight - tooltips.limit;
    }

    tooltip.style.left = previewOrigin.x + 'px';
    tooltip.style.top = previewOrigin.y + 'px';
    tooltip.style.display = 'inline';

    if (!tooltips.loadedContent[quoteUrl]
        && !tooltips.loadingPreviews[quoteUrl]) {
      tooltips.loadQuote(tooltip, quoteUrl);
    }

    if (!api.isBoard) {
      var matches = quote.href.match(/\#(\d+)/);

      quote.onclick = function() {
        thread.markPost(matches[1]);
      };
    }

  };

  quote.onmouseout = function() {
    if (tooltip) {
      tooltip.remove();
      tooltip = null;
    }
  };

};

tooltips.generateHTMLFromData = function(postingData, tooltip, quoteUrl) {

  if (!postingData) {
    tooltip.innerHTML = 'Not found';
    return;
  }

  var tempDiv = posting.addPost(postingData, postingData.boardUri,
      postingData.threadId, true).getElementsByClassName('innerPost')[0];

  tempDiv.getElementsByClassName('deletionCheckBox')[0].remove();

  tooltip.innerHTML = tempDiv.outerHTML;

  tooltips.loadedContent[quoteUrl] = tempDiv.outerHTML;

};

tooltips.cacheData = function(threadData) {

  for (var i = 0; i < threadData.posts.length; i++) {
    var postData = threadData.posts[i];
    tooltips.knownData[threadData.boardUri + '/' + postData.postId] = postData;
  }

  tooltips.knownData[threadData.boardUri + '/' + threadData.threadId] = threadData;

};

tooltips.loadQuote = function(tooltip, quoteUrl) {

  var matches = quoteUrl.match(/\/(\w+)\/res\/(\d+)\.html\#(\d+)/);

  var board = matches[1];
  var thread = +matches[2];
  var post = +matches[3];

  var postingData = tooltips.knownData[board + '/' + post];

  if (postingData) {
    tooltips.generateHTMLFromData(postingData, tooltip, quoteUrl);
    return;
  }

  var threadUrl = '/' + board + '/res/' + thread + '.json';

  tooltips.loadingPreviews[quoteUrl] = true;

  api.localRequest(threadUrl, function receivedData(error, data) {

    delete tooltips.loadingPreviews[quoteUrl];

    if (error) {
      tooltip.innerHTML = 'Not found';
      return;
    }

    tooltips.cacheData(JSON.parse(data));

    tooltips.generateHTMLFromData(tooltips.knownData[board + '/' + post],
        tooltip, quoteUrl);

  });

};

tooltips.init();<|endoftext|>


<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as
 */

THREE.PlaneBufferGeometry = function ( width, height, widthSegments, heightSegments ) {

	THREE.BufferGeometry.call( this );

	this.type = 'PlaneBufferGeometry';

	this.parameters = {
		width: width,
		height: height,
		widthSegments: widthSegments,
		heightSegments: heightSegments
	};

	var width_half = width / 2;
	var height_half = height / 2;

	var gridX = widthSegments || 1;
	var gridY = heightSegments || 1;

	var gridX1 = gridX + 1;
	var gridY1 = gridY + 1;

	var segment_width = width / gridX;
	var segment_height = height / gridY;

	var vertices = new Float32Array( gridX1 * gridY1 * 3 );
	var normals = new Float32Array( gridX1 * gridY1 * 3 );
	var uvs = new Float32Array( gridX1 * gridY1 * 2 );

	var offset = 0;
	var offset2 = 0;

	for ( var iy = 0; iy < gridY1; iy ++ ) {

		var y = iy * segment_height - height_half;

		for ( var ix = 0; ix < gridX1; ix ++ ) {

			var x = ix * segment_width - width_half;

			vertices[ offset     ] = x;
			vertices[ offset + 1 ] = - y;

			normals[ offset + 2 ] = 1;

			uvs[ offset2     ] = ix / gridX;
			uvs[ offset2 + 1 ] = 1 - ( iy / gridY );

			offset += 3;
			offset2 += 2;

		}

	}

	offset = 0;

	var indices = new ( ( vertices.length / 3 ) > 65535 ? Uint32Array : Uint16Array )( gridX * gridY * 6 );

	for ( var iy = 0; iy < gridY; iy ++ ) {

		for ( var ix = 0; ix < gridX; ix ++ ) {

			var a = ix + gridX1 * iy;
			var b = ix + gridX1 * ( iy + 1 );
			var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
			var d = ( ix + 1 ) + gridX1 * iy;

			indices[ offset     ] = a;
			indices[ offset + 1 ] = b;
			indices[ offset + 2 ] = d;

			indices[ offset + 3 ] = b;
			indices[ offset + 4 ] = c;
			indices[ offset + 5 ] = d;

			offset += 6;

		}

	}

	this.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) );
	this.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
	this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
	this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );

};

THREE.PlaneBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
THREE.PlaneBufferGeometry.prototype.constructor = THREE.PlaneBufferGeometry;
<commit_msg>PlaneBufferGeometry: Avoid breakage when using a float for *Segments<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as
 */

THREE.PlaneBufferGeometry = function ( width, height, widthSegments, heightSegments ) {

	THREE.BufferGeometry.call( this );

	this.type = 'PlaneBufferGeometry';

	this.parameters = {
		width: width,
		height: height,
		widthSegments: widthSegments,
		heightSegments: heightSegments
	};

	var width_half = width / 2;
	var height_half = height / 2;

	var gridX = Math.floor( widthSegments ) || 1;
	var gridY = Math.floor( heightSegments ) || 1;

	var gridX1 = gridX + 1;
	var gridY1 = gridY + 1;

	var segment_width = width / gridX;
	var segment_height = height / gridY;

	var vertices = new Float32Array( gridX1 * gridY1 * 3 );
	var normals = new Float32Array( gridX1 * gridY1 * 3 );
	var uvs = new Float32Array( gridX1 * gridY1 * 2 );

	var offset = 0;
	var offset2 = 0;

	for ( var iy = 0; iy < gridY1; iy ++ ) {

		var y = iy * segment_height - height_half;

		for ( var ix = 0; ix < gridX1; ix ++ ) {

			var x = ix * segment_width - width_half;

			vertices[ offset     ] = x;
			vertices[ offset + 1 ] = - y;

			normals[ offset + 2 ] = 1;

			uvs[ offset2     ] = ix / gridX;
			uvs[ offset2 + 1 ] = 1 - ( iy / gridY );

			offset += 3;
			offset2 += 2;

		}

	}

	offset = 0;

	var indices = new ( ( vertices.length / 3 ) > 65535 ? Uint32Array : Uint16Array )( gridX * gridY * 6 );

	for ( var iy = 0; iy < gridY; iy ++ ) {

		for ( var ix = 0; ix < gridX; ix ++ ) {

			var a = ix + gridX1 * iy;
			var b = ix + gridX1 * ( iy + 1 );
			var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
			var d = ( ix + 1 ) + gridX1 * iy;

			indices[ offset     ] = a;
			indices[ offset + 1 ] = b;
			indices[ offset + 2 ] = d;

			indices[ offset + 3 ] = b;
			indices[ offset + 4 ] = c;
			indices[ offset + 5 ] = d;

			offset += 6;

		}

	}

	this.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) );
	this.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
	this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
	this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );

};

THREE.PlaneBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
THREE.PlaneBufferGeometry.prototype.constructor = THREE.PlaneBufferGeometry;
<|endoftext|>


<commit_before>var Content = (function () {
    'use strict';

    var localize = {};

    var populate = function () {

        localize =  {
            textStartTime: text.localize('Start time'),
            textSpot: text.localize('Spot'),
            textBarrier: text.localize('Barrier'),
            textBarrierOffset: text.localize('Barrier offset'),
            textHighBarrier: text.localize('High barrier'),
            textHighBarrierOffset: text.localize('High barrier offset'),
            textLowBarrier: text.localize('Low barrier'),
            textLowBarrierOffset: text.localize('Low barrier offset'),
            textPayout: text.localize('Payout'),
            textStake: text.localize('Stake'),
            textPurchase: text.localize('Purchase'),
            textDuration: text.localize('Duration'),
            textEndTime: text.localize('End Time'),
            textMinDuration: text.localize('min'),
            textMinDurationTooltip: text.localize('minimum available duration'),
            textBarrierOffsetTooltip: text.localize("Enter the barrier in terms of the difference from the spot price. If you enter +0.005, then you will be purchasing a contract with a barrier 0.005 higher than the entry spot. The entry spot will be the next tick after your order has been received"),
            textDurationSeconds: text.localize('seconds'),
            textDurationMinutes: text.localize('minutes'),
            textDurationHours: text.localize('hours'),
            textDurationDays: text.localize('days'),
            textDurationTicks: text.localize('ticks'),
            textNetProfit: text.localize('Net profit'),
            textReturn: text.localize('Return'),
            textNow: text.localize('Now'),
            textContractConfirmationHeading: text.localize('Contract Confirmation'),
            textContractConfirmationReference: text.localize('Your transaction reference is'),
            textContractConfirmationBalance: text.localize('Your current balance is')

        };

        var starTime = document.getElementById('start_time_label');
        if (starTime) {
            starTime.textContent = localize.textStartTime;
        }

        var minDurationTooltip = document.getElementById('duration_tooltip');
        if (minDurationTooltip) {
            minDurationTooltip.textContent = localize.textMinDuration;
            minDurationTooltip.setAttribute('title', localize.textMinDurationTooltip);
        }

        var spotLabel = document.getElementById('spot_label');
        if (spotLabel) {
            spotLabel.textContent = localize.textSpot;
        }

        var barrierTooltip = document.getElementById('barrier_tooltip');
        if (barrierTooltip) {
            barrierTooltip.textContent = localize.textBarrierOffset;
            barrierTooltip.setAttribute('title', localize.textBarrierOffsetTooltip);
        }

        var barrierSpan = document.getElementById('barrier_span');
        if (barrierSpan) {
            barrierSpan.textContent = localize.textBarrier;
        }

        var barrierHighTooltip = document.getElementById('barrier_high_tooltip');
        if (barrierHighTooltip) {
            barrierHighTooltip.textContent = localize.textHighBarrierOffset;
            barrierHighTooltip.setAttribute('title', localize.textBarrierOffsetTooltip);
        }
        var barrierHighSpan = document.getElementById('barrier_high_span');
        if (barrierHighSpan) {
            barrierHighSpan.textContent = localize.textHighBarrier;
        }

        var barrierLowTooltip = document.getElementById('barrier_low_tooltip');
        if (barrierLowTooltip) {
            barrierLowTooltip.textContent = localize.textLowBarrierOffset;
            barrierLowTooltip.setAttribute('title', localize.textBarrierOffsetTooltip);
        }
        var barrierLowSpan = document.getElementById('barrier_low_span');
        if (barrierLowSpan) {
            barrierLowSpan.textContent = localize.textLowBarrier;
        }

        var payoutOption = document.getElementById('payout_option');
        if (payoutOption) {
            payoutOption.textContent = localize.textPayout;
        }

        var stakeOption = document.getElementById('stake_option');
        if (stakeOption) {
            stakeOption.textContent = localize.textStake;
        }

        var purchaseButtonTop = document.getElementById('purchase_button_top');
        if (purchaseButtonTop) {
            purchaseButtonTop.textContent = localize.textPurchase;
        }

        var purchaseButtonBottom = document.getElementById('purchase_button_bottom');
        if (purchaseButtonBottom) {
            purchaseButtonBottom.textContent = localize.textPurchase;
        }
    };

    return {
        localize: function () { return localize; },
        populate: populate
    };

})();
<commit_msg>add contract categories for localization<commit_after>var Content = (function () {
    'use strict';

    var localize = {};

    var populate = function () {

        localize =  {
            textStartTime: text.localize('Start time'),
            textSpot: text.localize('Spot'),
            textBarrier: text.localize('Barrier'),
            textBarrierOffset: text.localize('Barrier offset'),
            textHighBarrier: text.localize('High barrier'),
            textHighBarrierOffset: text.localize('High barrier offset'),
            textLowBarrier: text.localize('Low barrier'),
            textLowBarrierOffset: text.localize('Low barrier offset'),
            textPayout: text.localize('Payout'),
            textStake: text.localize('Stake'),
            textPurchase: text.localize('Purchase'),
            textDuration: text.localize('Duration'),
            textEndTime: text.localize('End Time'),
            textMinDuration: text.localize('min'),
            textMinDurationTooltip: text.localize('minimum available duration'),
            textBarrierOffsetTooltip: text.localize("Enter the barrier in terms of the difference from the spot price. If you enter +0.005, then you will be purchasing a contract with a barrier 0.005 higher than the entry spot. The entry spot will be the next tick after your order has been received"),
            textDurationSeconds: text.localize('seconds'),
            textDurationMinutes: text.localize('minutes'),
            textDurationHours: text.localize('hours'),
            textDurationDays: text.localize('days'),
            textDurationTicks: text.localize('ticks'),
            textNetProfit: text.localize('Net profit'),
            textReturn: text.localize('Return'),
            textNow: text.localize('Now'),
            textContractConfirmationHeading: text.localize('Contract Confirmation'),
            textContractConfirmationReference: text.localize('Your transaction reference is'),
            textContractConfirmationBalance: text.localize('Your current balance is'),
            textFormRiseFall: text.localize('Rise/Fall'),
            textFormHigherLower: text.localize('Higher/Lower')
        };

        var starTime = document.getElementById('start_time_label');
        if (starTime) {
            starTime.textContent = localize.textStartTime;
        }

        var minDurationTooltip = document.getElementById('duration_tooltip');
        if (minDurationTooltip) {
            minDurationTooltip.textContent = localize.textMinDuration;
            minDurationTooltip.setAttribute('title', localize.textMinDurationTooltip);
        }

        var spotLabel = document.getElementById('spot_label');
        if (spotLabel) {
            spotLabel.textContent = localize.textSpot;
        }

        var barrierTooltip = document.getElementById('barrier_tooltip');
        if (barrierTooltip) {
            barrierTooltip.textContent = localize.textBarrierOffset;
            barrierTooltip.setAttribute('title', localize.textBarrierOffsetTooltip);
        }

        var barrierSpan = document.getElementById('barrier_span');
        if (barrierSpan) {
            barrierSpan.textContent = localize.textBarrier;
        }

        var barrierHighTooltip = document.getElementById('barrier_high_tooltip');
        if (barrierHighTooltip) {
            barrierHighTooltip.textContent = localize.textHighBarrierOffset;
            barrierHighTooltip.setAttribute('title', localize.textBarrierOffsetTooltip);
        }
        var barrierHighSpan = document.getElementById('barrier_high_span');
        if (barrierHighSpan) {
            barrierHighSpan.textContent = localize.textHighBarrier;
        }

        var barrierLowTooltip = document.getElementById('barrier_low_tooltip');
        if (barrierLowTooltip) {
            barrierLowTooltip.textContent = localize.textLowBarrierOffset;
            barrierLowTooltip.setAttribute('title', localize.textBarrierOffsetTooltip);
        }
        var barrierLowSpan = document.getElementById('barrier_low_span');
        if (barrierLowSpan) {
            barrierLowSpan.textContent = localize.textLowBarrier;
        }

        var payoutOption = document.getElementById('payout_option');
        if (payoutOption) {
            payoutOption.textContent = localize.textPayout;
        }

        var stakeOption = document.getElementById('stake_option');
        if (stakeOption) {
            stakeOption.textContent = localize.textStake;
        }

        var purchaseButtonTop = document.getElementById('purchase_button_top');
        if (purchaseButtonTop) {
            purchaseButtonTop.textContent = localize.textPurchase;
        }

        var purchaseButtonBottom = document.getElementById('purchase_button_bottom');
        if (purchaseButtonBottom) {
            purchaseButtonBottom.textContent = localize.textPurchase;
        }
    };

    return {
        localize: function () { return localize; },
        populate: populate
    };

})();
<|endoftext|>