<commit_before>var _ = require('underscore');
var $ = require('jquery');
var Ps = require('perfect-scrollbar');
var cdb = require('cartodb.js');
var CategoryContentView = require('./widgets/category/content-view');
var FormulaContentView = require('./widgets/formula/content-view');
var HistogramContentView = require('./widgets/histogram/content-view');
var WidgetViewFactory = require('./widgets/widget-view-factory');
var template = require('./dashboard-sidebar.tpl');
var matchMedia = window.matchMedia;

module.exports = cdb.core.View.extend({
  className: 'CDB-Widget-canvas',

  initialize: function (options) {
    this._widgetViewFactory = new WidgetViewFactory([
      {
        type: 'formula',
        createContentView: function (widgetModel) {
          return new FormulaContentView({
            model: widgetModel
          });
        }
      }, {
        type: 'histogram',
        createContentView: function (widgetModel) {
          return new HistogramContentView({
            model: widgetModel
          });
        }
      }, {
        type: 'category',
        createContentView: function (widgetModel) {
          return new CategoryContentView({
            model: widgetModel
          });
        }
      }
    ]);

    this._widgets = options.widgets;

    this._widgets.bind('add', this._maybeRenderWidgetView, this);
    this._widgets.bind('reset', this.render, this);
    this._widgets.bind('orderChanged', this.render, this);
    this._widgets.bind('change:collapsed', this._onWidgetUpdate, this);
    this._widgets.bind('add remove reset', this._onWidgetsChange, this); // have to be called _after_ any other add/remove/reset
    this.add_related_model(this._widgets);

    this._resizeHandler = this._onResize.bind(this);
  },

  render: function () {
    this._cleanScroll();
    this._observer && this._observer.disconnect();
    this.clearSubViews();

    this.$el.html(template());
    this.$el.toggleClass('CDB-Widget-canvas--withMenu', this.model.get('renderMenu'));
    this._widgets.each(this._maybeRenderWidgetView, this);
    this._toggleVisiblity();

    this._renderScroll();
    this._renderShadows();
    this._bindScroll();
    this._initResize();

    return this;
  },

  _initResize: function () {
    var breakpoints = ['(max-width: 1600px)', '(max-width: 1280px)', '(max-width: 759px)'];
    breakpoints.forEach(function (breakpoint) {
      var mq = matchMedia(breakpoint);
      mq.addListener(this._resizeHandler);
    }, this);
  },

  _updateScrollCss: function () {
    this._onWidgetUpdate();

    var element = this._container();
    if (!element) return;

    var containerWidth = element.clientWidth;
    var containerHeight = element.clientHeight;
    var contentWidth = element.scrollWidth;
    var contentHeight = element.scrollHeight;
    var xScroll = containerWidth < contentWidth;
    var yScroll = containerHeight < contentHeight;

    this._$container().toggleClass('hasXScroll', xScroll);
    this._$container().toggleClass('hasYScroll', yScroll);
  },

  _$container: function () {
    return $(this._container());
  },

  _container: function () {
    return this.el.querySelector('.js-container');
  },

  _maybeRenderWidgetView: function (widgetModel) {
    var view = this._widgetViewFactory.createWidgetView(widgetModel);
    if (view) {
      this.addView(view);
      this._$container().append(view.render().el);
    }
  },

  _bindScroll: function () {
    this._$container()
      .on('ps-y-reach-start', _.bind(this._onScrollTop, this))
      .on('ps-y-reach-end', _.bind(this._onScrollBottom, this))
      .on('ps-scroll-y', _.bind(this._onScroll, this));
  },

  _renderScroll: function () {
    Ps.initialize(this._container(), {
      wheelSpeed: 1,
      wheelPropagation: false,
      swipePropagation: true,
      stopPropagationOnClick: false,
      minScrollbarLength: 20
    });
  },

  _onWidgetUpdate: function () {
    Ps.update(this._container());
  },

  _renderShadows: function () {
    this.$shadowTop = $('<div>').addClass('CDB-Widget-canvasShadow CDB-Widget-canvasShadow--top');
    this.$shadowBottom = $('<div>').addClass('CDB-Widget-canvasShadow CDB-Widget-canvasShadow--bottom');
    this.$el.append(this.$shadowTop);
    this.$el.append(this.$shadowBottom);
  },

  _onScrollTop: function () {
    this.$shadowTop.removeClass('is-visible');
  },

  _onScroll: function () {
    var $el = this._$container();
    var currentPos = $el.scrollTop();<commit_msg>Use wheel to scroll horizontal widgets<commit_after>var _ = require('underscore');
var $ = require('jquery');
var Ps = require('perfect-scrollbar');
var cdb = require('cartodb.js');
var CategoryContentView = require('./widgets/category/content-view');
var FormulaContentView = require('./widgets/formula/content-view');
var HistogramContentView = require('./widgets/histogram/content-view');
var WidgetViewFactory = require('./widgets/widget-view-factory');
var template = require('./dashboard-sidebar.tpl');
var matchMedia = window.matchMedia;

module.exports = cdb.core.View.extend({
  className: 'CDB-Widget-canvas',

  initialize: function (options) {
    this._widgetViewFactory = new WidgetViewFactory([
      {
        type: 'formula',
        createContentView: function (widgetModel) {
          return new FormulaContentView({
            model: widgetModel
          });
        }
      }, {
        type: 'histogram',
        createContentView: function (widgetModel) {
          return new HistogramContentView({
            model: widgetModel
          });
        }
      }, {
        type: 'category',
        createContentView: function (widgetModel) {
          return new CategoryContentView({
            model: widgetModel
          });
        }
      }
    ]);

    this._widgets = options.widgets;

    this._widgets.bind('add', this._maybeRenderWidgetView, this);
    this._widgets.bind('reset', this.render, this);
    this._widgets.bind('orderChanged', this.render, this);
    this._widgets.bind('change:collapsed', this._onWidgetUpdate, this);
    this._widgets.bind('add remove reset', this._onWidgetsChange, this); // have to be called _after_ any other add/remove/reset
    this.add_related_model(this._widgets);

    this._resizeHandler = this._onResize.bind(this);
  },

  render: function () {
    this._cleanScroll();
    this._observer && this._observer.disconnect();
    this.clearSubViews();

    this.$el.html(template());
    this.$el.toggleClass('CDB-Widget-canvas--withMenu', this.model.get('renderMenu'));
    this._widgets.each(this._maybeRenderWidgetView, this);
    this._toggleVisiblity();

    this._renderScroll();
    this._renderShadows();
    this._bindScroll();
    this._initResize();

    return this;
  },

  _initResize: function () {
    var breakpoints = ['(max-width: 1600px)', '(max-width: 1280px)', '(max-width: 759px)'];
    breakpoints.forEach(function (breakpoint) {
      var mq = matchMedia(breakpoint);
      mq.addListener(this._resizeHandler);
    }, this);
  },

  _updateScrollCss: function () {
    this._onWidgetUpdate();

    var element = this._container();
    if (!element) return;

    var containerWidth = element.clientWidth;
    var containerHeight = element.clientHeight;
    var contentWidth = element.scrollWidth;
    var contentHeight = element.scrollHeight;
    var xScroll = containerWidth < contentWidth;
    var yScroll = containerHeight < contentHeight;

    this._$container().toggleClass('hasXScroll', xScroll);
    this._$container().toggleClass('hasYScroll', yScroll);
  },

  _$container: function () {
    return $(this._container());
  },

  _container: function () {
    return this.el.querySelector('.js-container');
  },

  _maybeRenderWidgetView: function (widgetModel) {
    var view = this._widgetViewFactory.createWidgetView(widgetModel);
    if (view) {
      this.addView(view);
      this._$container().append(view.render().el);
    }
  },

  _bindScroll: function () {
    this._$container()
      .on('ps-y-reach-start', _.bind(this._onScrollTop, this))
      .on('ps-y-reach-end', _.bind(this._onScrollBottom, this))
      .on('ps-scroll-y', _.bind(this._onScroll, this));
  },

  _renderScroll: function () {
    Ps.initialize(this._container(), {
      wheelSpeed: 1,
      wheelPropagation: false,
      swipePropagation: true,
      stopPropagationOnClick: false,
      minScrollbarLength: 20,
      useBothWheelAxes: true
    });
  },

  _onWidgetUpdate: function () {
    Ps.update(this._container());
  },

  _renderShadows: function () {
    this.$shadowTop = $('<div>').addClass('CDB-Widget-canvasShadow CDB-Widget-canvasShadow--top');
    this.$shadowBottom = $('<div>').addClass('CDB-Widget-canvasShadow CDB-Widget-canvasShadow--bottom');
    this.$el.append(this.$shadowTop);
    this.$el.append(this.$shadowBottom);
  },

  _onScrollTop: function () {
    this.$shadowTop.removeClass('is-visible');
  },

  _onScroll: function () {
    var $el = this._$container();
    var currentPos = $el.scrollTop();
{'fraction_non_alphanumeric': 0.14912768085342815, 'fraction_numerical': 0.003111456828536504, 'mean_word_length': 3.3352601156069364, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2860045', 'n_tokens_mistral': 2718, 'n_tokens_neox': 2623, 'n_words': 472}