All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scout.scrollbar.Scrollbar.js Maven / Gradle / Ivy

There is a newer version: 25.1.0-beta.0
Show newest version
/*******************************************************************************
 * Copyright (c) 2014-2015 BSI Business Systems Integration AG.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     BSI Business Systems Integration AG - initial API and implementation
 ******************************************************************************/
scout.Scrollbar = function() {
  scout.Scrollbar.parent.call(this);

  this._beginDefault = 0;
  this._thumbRange;
  this._scrollSize;
  this._offsetSize;
  this._addEventSupport();

  this._onScrollWheelHandler = this._onScrollWheel.bind(this);
  this._onScrollHandler = this._onScroll.bind(this);
  this._onScrollbarMousedownHandler = this._onScrollbarMousedown.bind(this);
  this._onThumbMousedownHandler = this._onThumbMousedown.bind(this);
  this._onDocumentMousemoveHandler = this._onDocumentMousemove.bind(this);
  this._onDocumentMouseupHandler = this._onDocumentMouseup.bind(this);
  this._fixScrollbarHandler = this._fixScrollbar.bind(this);
  this._unfixScrollbarHandler = this._unfixScrollbar.bind(this);
};
scout.inherits(scout.Scrollbar, scout.Widget);

scout.Scrollbar.prototype._init = function(options) {
  scout.Scrollbar.parent.prototype._init.call(this, options);
  var defaults = {
    axis: 'y',
    borderless: false,
    mouseWheelNeedsShift: false
  };

  $.extend(this, defaults, options);
};

scout.Scrollbar.prototype._render = function($parent) {
  this._begin = 0;
  this.$container = $parent.appendDiv('scrollbar')
    .addClass(this.axis + '-axis');
  this._$thumb = this.$container.appendDiv('scrollbar-thumb')
    .addClass(this.axis + '-axis');
  if (this.borderless) {
    this.$container.addClass('borderless');
  }

  this._dim = this.axis === 'x' ? 'Width' : 'Height';
  this._dir = this.axis === 'x' ? 'left' : 'top';
  this._dirReverse = this.axis === 'x' ? 'right' : 'bottom';
  this._scrollDir = this.axis === 'x' ? 'scrollLeft' : 'scrollTop';

  // Install listeners
  $parent
    .on('DOMMouseScroll mousewheel', this._onScrollWheelHandler)
    .on('scroll', this._onScrollHandler)
    .data('scrollbars').forEach(function(scrollbar) {
      scrollbar.on('scrollstart', this._fixScrollbarHandler);
      scrollbar.on('scrollend', this._unfixScrollbarHandler);
    }.bind(this));
  this.$container.on('mousedown', this._onScrollbarMousedownHandler);
  this._$thumb.on('mousedown', this._onThumbMousedownHandler);
};

scout.Scrollbar.prototype._onScrollWheel = function(event) {
  var w, d;
  if (!this.$container.isVisible()) {
    return true; // ignore scroll wheel event if there is no scroll bar visible
  }
  if (event.ctrlKey) {
    return true; // allow ctrl + mousewheel to zoom the page
  }
  if (this.mouseWheelNeedsShift !== event.shiftKey) {
    // only scroll if shift modifier matches
    return true;
  }
  event = event.originalEvent || this.$container.window(true).event.originalEvent;
  w = event.wheelDelta ? -event.wheelDelta / 2 : event.detail * 20;
  d = this._scrollSize / this._offsetSize;

  this.trigger('scrollstart');
  this.scroll(w / d);
  this.trigger('scrollend');
  return false;
};

scout.Scrollbar.prototype._onScroll = function(event) {
  this.update();
};

scout.Scrollbar.prototype._onScrollbarMousedown = function(event) {
  this.trigger('scrollstart');
  this._scrollTo(event);
  this.trigger('scrollend');
};

scout.Scrollbar.prototype._onThumbMousedown = function(event) {
  this.trigger('scrollstart');
  this._begin = (this.axis === 'x' ? event.pageX : event.pageY) - this._$thumb.offset()[this._dir];
  this._$thumb.addClass('scrollbar-thumb-move');
  this._$thumb.document()
    .on('mousemove', this._onDocumentMousemoveHandler)
    .one('mouseup', this._onDocumentMouseupHandler);
  return false;
};

scout.Scrollbar.prototype._onDocumentMousemove = function(event) {
  if (!this.rendered) {
    // Scrollbar may be removed in the meantime
    return;
  }
  this._scrollTo(event);
};

scout.Scrollbar.prototype._onDocumentMouseup = function(event) {
  var $document = $(event.currentTarget);
  $document.off('mousemove', this._onDocumentMousemoveHandler);
  if (this.rendered) {
    this._$thumb.removeClass('scrollbar-thumb-move');
  }
  this.trigger('scrollend');
  return false;
};

scout.Scrollbar.prototype._scrollTo = function(event) {
  var begin = this._begin === 0 ? this._beginDefault : this._begin;
  var end = (this.axis === 'x' ? event.pageX : event.pageY) - this._$thumb.offset()[this._dir];
  this.scroll(end - begin);
};

scout.Scrollbar.prototype._remove = function() {
  // Uninstall listeners
  this.$parent
    .off('DOMMouseScroll mousewheel', this._onScrollWheelHandler)
    .off('scroll', this._onScrollHandler)
    .data('scrollbars').forEach(function(scrollbar) {
      scrollbar.off('scrollstart', this._fixScrollbarHandler);
      scrollbar.off('scrollend', this._unfixScrollbarHandler);
    }.bind(this));
  this.$container.off('mousedown', this._onScrollbarMousedownHandler);
  this._$thumb.off('mousedown', '', this._onThumbMousedownHandler);

  scout.Scrollbar.parent.prototype._remove.call(this);
};

/**
 * do not use this internal method
 */
scout.Scrollbar.prototype.update = function() {
  var margin = this.$container['cssMargin' + this.axis.toUpperCase()](),
    scrollPos = this.$parent[this._scrollDir](),
    scrollLeft = this.$parent.scrollLeft(),
    scrollTop = this.$parent.scrollTop();

  this.reset();
  this._offsetSize = this.$parent[0]['offset' + this._dim];
  this._scrollSize = this.$parent[0]['scroll' + this._dim];

  // calc size and range of thumb
  var thumbSize = Math.max(this._offsetSize * this._offsetSize / this._scrollSize - margin, 30);
  this._thumbRange = this._offsetSize - thumbSize - margin;

  // set size of thumb
  this._$thumb.css(this._dim.toLowerCase(), thumbSize);
  this._beginDefault = thumbSize / 2;

  // set location of thumb
  var posNew = scrollPos / (this._scrollSize - this._offsetSize) * this._thumbRange;
  this._$thumb.css(this._dir, posNew);

  // show scrollbar
  if (this._offsetSize >= this._scrollSize) {
    this.$container.css('display', 'none');
  } else {
    this.$container.css('display', '');
  }

  // Position the scrollbar(s)
  // Always update both to make sure every scrollbar (x and y) is positioned correctly
  this.$container.cssRight(-1 * scrollLeft);
  this.$container.cssBottom(-1 * scrollTop);
};

/*
 * Resets thumb size and scrollbar position to make sure it does not extend the scrollSize
 */
scout.Scrollbar.prototype.reset = function() {
  this._$thumb.css(this._dim.toLowerCase(), 0);
  this.$container.cssRight(0);
  this.$container.cssBottom(0);
};

scout.Scrollbar.prototype.scroll = function(posDiff) {
  var scrollbarOffset = this.$container.offset(),
    thumbOffset = this._$thumb.offset(),
    posOld = thumbOffset[this._dir] - scrollbarOffset[this._dir],
    posNew = Math.min(this._thumbRange, Math.max(0, posOld + posDiff)),
    scrollPos = (this._scrollSize - this._offsetSize) / this._thumbRange * posNew;

  this.$parent[this._scrollDir](scrollPos);

  // Thumb and scrollbar would be updated by the scroll handler. To make it more fluent it is done here as well
  this._$thumb.css(this._dir, posNew);
  this.$container.css(this._dirReverse, -1 * scrollPos);
};

/**
 * Sets the position to fixed and updates left and top position.
 * This is necessary to prevent flickering in IE.
 */
scout.Scrollbar.prototype._fixScrollbar = function() {
  scout.scrollbars.fix(this.$container);
};

/**
 * Reverts the changes made by fixScrollbar.
 */
scout.Scrollbar.prototype._unfixScrollbar = function() {
  this._unfixTimeoutId = scout.scrollbars.unfix(this.$container, this._unfixTimeoutId);
};

scout.Scrollbar.prototype.notifyBeforeScroll = function() {
  this.trigger('scrollstart');
};

scout.Scrollbar.prototype.notifyAfterScroll = function() {
  this.trigger('scrollend');
};




© 2015 - 2025 Weber Informatics LLC | Privacy Policy