Add files
This commit is contained in:
parent
146376db15
commit
7aecf139ba
|
@ -0,0 +1,13 @@
|
|||
/* helper css for selectableScroll */
|
||||
.ui-selectable-helper.no-top {
|
||||
border-top: 0;
|
||||
}
|
||||
.ui-selectable-helper.no-right {
|
||||
border-right: 0;
|
||||
}
|
||||
.ui-selectable-helper.no-bottom {
|
||||
border-bottom: 0;
|
||||
}
|
||||
.ui-selectable-helper.no-left {
|
||||
border-left: 0;
|
||||
}
|
|
@ -0,0 +1,376 @@
|
|||
(function ($) {
|
||||
$.widget('ui.selectableScroll', $.ui.selectable, {
|
||||
options: {
|
||||
scrollSnapX: 5, // When the selection is that pixels near to the top/bottom edges, start to scroll
|
||||
scrollSnapY: 5, // When the selection is that pixels near to the side edges, start to scroll
|
||||
scrollAmount: 25, // In pixels
|
||||
scrollIntervalTime: 100 // In milliseconds
|
||||
},
|
||||
|
||||
/**
|
||||
* This is a slightly modified version of the original _create function, we just add the element's relative positions too
|
||||
* @return {null} no return value
|
||||
*/
|
||||
_create: function () {
|
||||
var selectees,
|
||||
that = this;
|
||||
this.element.addClass("ui-selectable");
|
||||
this.dragged = false;
|
||||
// cache selectee children based on filter
|
||||
this.refresh = function() {
|
||||
var elementOffset = this.element.offset();
|
||||
var scrollLeft = this.element.prop('scrollLeft');
|
||||
var scrollTop = this.element.prop('scrollTop');
|
||||
selectees = $(that.options.filter, that.element[0]);
|
||||
selectees.addClass("ui-selectee");
|
||||
selectees.each(function() {
|
||||
var $this = $(this),
|
||||
pos = $this.offset();
|
||||
$.data(this, "selectable-item", {
|
||||
element: this,
|
||||
$element: $this,
|
||||
left: pos.left,
|
||||
top: pos.top,
|
||||
right: pos.left + $this.outerWidth(),
|
||||
bottom: pos.top + $this.outerHeight(),
|
||||
relative: { // Relative positions according to the element's 0.0
|
||||
left: pos.left - elementOffset.left + scrollLeft,
|
||||
top: pos.top - elementOffset.top + scrollTop,
|
||||
right: pos.left - elementOffset.left + scrollLeft + $this.outerWidth(),
|
||||
bottom: pos.top - elementOffset.top + scrollTop + $this.outerHeight()
|
||||
},
|
||||
startselected: false,
|
||||
selected: $this.hasClass("ui-selected"),
|
||||
selecting: $this.hasClass("ui-selecting"),
|
||||
unselecting: $this.hasClass("ui-unselecting")
|
||||
});
|
||||
});
|
||||
};
|
||||
this.refresh();
|
||||
this.selectees = selectees.addClass("ui-selectee");
|
||||
this._mouseInit();
|
||||
this.helper = $("<div class='ui-selectable-helper'></div>");
|
||||
},
|
||||
|
||||
/**
|
||||
* By starting dragging, calculate the element's current scroll states, relative to the elements 0.0 offset
|
||||
* @param {object} event the mousedown event
|
||||
* @return {boolean} The parent's _mouseStart return value
|
||||
*/
|
||||
_mouseStart: function (event) {
|
||||
var retValue = this._super(event);
|
||||
this.lastDragEvent = null;
|
||||
this.scrollInfo = {
|
||||
elementOffset: this.element.offset(), // The element's 0.0 offset related to the document element
|
||||
scrollHeight: this.element.prop('scrollHeight'), // The maximum scrollable height (visible height + scrollTop)
|
||||
scrollWidth: this.element.prop('scrollWidth'), // The maximum scrollable height (visible width + scrollLeft)
|
||||
elementHeight: this.element.height(), // The visible height
|
||||
elementWidth: this.element.width() // The visible width
|
||||
};
|
||||
this.scrollInfo.dragStartXPos = event.pageX - this.scrollInfo.elementOffset.left + this.element.prop('scrollLeft'); // Relative to element's 0
|
||||
this.scrollInfo.dragStartYPos = event.pageY - this.scrollInfo.elementOffset.top + this.element.prop('scrollTop'); // Relative to element's 0
|
||||
this.scrollIntervalId = null;
|
||||
return retValue;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate/redraw the helper lasso, keep the helper within the scrolled element
|
||||
* @param {object} options The object containing the relative positions of the selected rectangle
|
||||
* @return {null} no return value
|
||||
*/
|
||||
_updateHelper: function (options) {
|
||||
var that = this;
|
||||
var x1, y1, x2, y2; // Absolute positions for the lasso helper
|
||||
var lassoClassesArray = [];
|
||||
if (options.x1 - options.scrollLeft < 0) {
|
||||
lassoClassesArray.push('no-left');
|
||||
x1 = this.scrollInfo.elementOffset.left;
|
||||
} else {
|
||||
x1 = this.scrollInfo.elementOffset.left + options.x1 - options.scrollLeft;
|
||||
}
|
||||
if (options.y1 - options.scrollTop < 0) {
|
||||
lassoClassesArray.push('no-top');
|
||||
y1 = this.scrollInfo.elementOffset.top;
|
||||
} else {
|
||||
y1 = this.scrollInfo.elementOffset.top + options.y1 - options.scrollTop;
|
||||
}
|
||||
if (options.x2 - options.scrollLeft > this.scrollInfo.elementWidth) {
|
||||
lassoClassesArray.push('no-right');
|
||||
x2 = this.scrollInfo.elementOffset.left + this.scrollInfo.elementWidth;
|
||||
} else {
|
||||
x2 = this.scrollInfo.elementOffset.left + options.x2 - options.scrollLeft;
|
||||
}
|
||||
if (options.y2 - options.scrollTop > this.scrollInfo.elementHeight) {
|
||||
lassoClassesArray.push('no-bottom');
|
||||
y2 = this.scrollInfo.elementOffset.top + this.scrollInfo.elementHeight;
|
||||
} else {
|
||||
y2 = this.scrollInfo.elementOffset.top + options.y2 - options.scrollTop;
|
||||
}
|
||||
var modifyHelperClass = function (className) {
|
||||
if (lassoClassesArray.indexOf(className) !== -1) {
|
||||
that.helper.addClass(className);
|
||||
} else {
|
||||
that.helper.removeClass(className);
|
||||
}
|
||||
};
|
||||
['no-top', 'no-bottom', 'no-left', 'no-right'].forEach(modifyHelperClass);
|
||||
this.helper.css({
|
||||
left: x1,
|
||||
top: y1,
|
||||
width: x2 - x1,
|
||||
height: y2 - y1
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* If the mouse is near to the edges of the element's area, scroll
|
||||
* @return {object} The new scrollLeft and scrollTop values, and a boolean if the element should keep scrolling
|
||||
*/
|
||||
_scrollIfNeeded: function (options) {
|
||||
var scrollLeft = this.element.prop('scrollLeft');
|
||||
var scrollTop = this.element.prop('scrollTop');
|
||||
var keepScrolling = false;
|
||||
// Scroll if close to edges or over them
|
||||
if (this.lastDragEvent.pageX - this.scrollInfo.elementOffset.left < this.options.scrollSnapX && scrollLeft > 0) {
|
||||
scrollLeft = scrollLeft < this.options.scrollAmount ? 0 : scrollLeft - this.options.scrollAmount;
|
||||
this.element.prop('scrollLeft', scrollLeft);
|
||||
keepScrolling = true;
|
||||
}
|
||||
if (this.lastDragEvent.pageY - this.scrollInfo.elementOffset.top < this.options.scrollSnapY && scrollTop > 0) {
|
||||
scrollTop = scrollTop < this.options.scrollAmount ? 0 : scrollTop - this.options.scrollAmount;
|
||||
this.element.prop('scrollTop', scrollTop);
|
||||
keepScrolling = true;
|
||||
}
|
||||
if (this.lastDragEvent.pageX - this.scrollInfo.elementOffset.left > this.scrollInfo.elementWidth - this.options.scrollSnapX && this.scrollInfo.scrollWidth > scrollLeft + this.scrollInfo.elementWidth) {
|
||||
scrollLeft = scrollLeft + this.options.scrollAmount > this.scrollInfo.scrollWidth - this.scrollInfo.elementWidth ? this.scrollInfo.scrollWidth - this.scrollInfo.elementWidth : scrollLeft + this.options.scrollAmount;
|
||||
this.element.prop('scrollLeft', scrollLeft);
|
||||
keepScrolling = true;
|
||||
}
|
||||
if (this.lastDragEvent.pageY - this.scrollInfo.elementOffset.top > this.scrollInfo.elementHeight - this.options.scrollSnapY && this.scrollInfo.scrollHeight > scrollLeft + this.scrollInfo.elementHeight) {
|
||||
scrollTop = scrollTop + this.options.scrollAmount > this.scrollInfo.scrollHeight - this.scrollInfo.elementHeight ? this.scrollInfo.scrollHeight - this.scrollInfo.elementHeight : scrollTop + this.options.scrollAmount;
|
||||
this.element.prop('scrollTop', scrollTop);
|
||||
keepScrolling = true;
|
||||
}
|
||||
return {
|
||||
scrollLeft: scrollLeft,
|
||||
scrollTop: scrollTop,
|
||||
keepScrolling: keepScrolling
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate a relative position to the element's 0.0 offset, from the original drag event's coordinates
|
||||
* @param {object} options The absolute X and Y positions
|
||||
* @return {object} The relative X and Y positions
|
||||
*/
|
||||
_calcRelativePosition: function (options) {
|
||||
var relXPos = options.x - this.scrollInfo.elementOffset.left + options.scrollLeft;
|
||||
var relYPos = options.y - this.scrollInfo.elementOffset.top + options.scrollTop;
|
||||
return {
|
||||
x: relXPos,
|
||||
y: relYPos
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate relative area positions to offset element
|
||||
* @param {object} options The relative X and Y positions to the 0.0 of the element
|
||||
* @return {object} An object containing the relative area coordinates
|
||||
*/
|
||||
_calcRelativeArea: function (options) {
|
||||
var relX1 = options.xPos < this.scrollInfo.dragStartXPos ? options.xPos : this.scrollInfo.dragStartXPos;
|
||||
var relY1 = options.yPos < this.scrollInfo.dragStartYPos ? options.yPos : this.scrollInfo.dragStartYPos;
|
||||
var relX2 = options.xPos > this.scrollInfo.dragStartXPos ? options.xPos : this.scrollInfo.dragStartXPos;
|
||||
var relY2 = options.yPos > this.scrollInfo.dragStartYPos ? options.yPos : this.scrollInfo.dragStartYPos;
|
||||
return {
|
||||
x1: relX1,
|
||||
y1: relY1,
|
||||
x2: relX2,
|
||||
y2: relY2
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the selected elements
|
||||
* @param {object} options The return value of _calcRelativeArea()
|
||||
* @return {null} No return value
|
||||
*/
|
||||
_updateSelectees: function (options) {
|
||||
var that = this;
|
||||
this.selectees.each(function() {
|
||||
var selectee = $.data(this, "selectable-item"),
|
||||
hit = false;
|
||||
|
||||
//prevent helper from being selected if appendTo: selectable
|
||||
if (!selectee || selectee.element === that.element[0]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (that.options.tolerance === "touch") {
|
||||
hit = ( !(selectee.relative.left > options.x2 || selectee.relative.right < options.x1 || selectee.relative.top > options.y2 || selectee.relative.bottom < options.y1) );
|
||||
} else if (that.options.tolerance === "fit") {
|
||||
hit = (selectee.relative.left > options.x1 && selectee.relative.right < options.x2 && selectee.relative.top > options.y1 && selectee.relative.bottom < options.y2);
|
||||
}
|
||||
|
||||
if (hit) {
|
||||
// SELECT
|
||||
if (selectee.selected) {
|
||||
selectee.$element.removeClass("ui-selected");
|
||||
selectee.selected = false;
|
||||
}
|
||||
if (selectee.unselecting) {
|
||||
selectee.$element.removeClass("ui-unselecting");
|
||||
selectee.unselecting = false;
|
||||
}
|
||||
if (!selectee.selecting) {
|
||||
selectee.$element.addClass("ui-selecting");
|
||||
selectee.selecting = true;
|
||||
// selectable SELECTING callback
|
||||
that._trigger("selecting", that.lastDragEvent, {
|
||||
selecting: selectee.element
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// UNSELECT
|
||||
if (selectee.selecting) {
|
||||
if ((that.lastDragEvent.metaKey || that.lastDragEvent.ctrlKey) && selectee.startselected) {
|
||||
selectee.$element.removeClass("ui-selecting");
|
||||
selectee.selecting = false;
|
||||
selectee.$element.addClass("ui-selected");
|
||||
selectee.selected = true;
|
||||
} else {
|
||||
selectee.$element.removeClass("ui-selecting");
|
||||
selectee.selecting = false;
|
||||
if (selectee.startselected) {
|
||||
selectee.$element.addClass("ui-unselecting");
|
||||
selectee.unselecting = true;
|
||||
}
|
||||
// selectable UNSELECTING callback
|
||||
that._trigger("unselecting", that.lastDragEvent, {
|
||||
unselecting: selectee.element
|
||||
});
|
||||
}
|
||||
}
|
||||
if (selectee.selected) {
|
||||
if (!that.lastDragEvent.metaKey && !that.lastDragEvent.ctrlKey && !selectee.startselected) {
|
||||
selectee.$element.removeClass("ui-selected");
|
||||
selectee.selected = false;
|
||||
|
||||
selectee.$element.addClass("ui-unselecting");
|
||||
selectee.unselecting = true;
|
||||
// selectable UNSELECTING callback
|
||||
that._trigger("unselecting", that.lastDragEvent, {
|
||||
unselecting: selectee.element
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* The original _mouseDrag function overvritten by our one
|
||||
* @param {object} event The original mousemove event
|
||||
* @return {boolean} Returning false, as the parent returns too
|
||||
*/
|
||||
_mouseDrag: function (event) {
|
||||
this.dragged = true;
|
||||
if (this.options.disabled) {
|
||||
return;
|
||||
}
|
||||
this.lastDragEvent = event;
|
||||
|
||||
var scrollObj = this._scrollIfNeeded();
|
||||
|
||||
var that = this;
|
||||
|
||||
this._updateIntervals({
|
||||
keepScrolling: scrollObj.keepScrolling
|
||||
});
|
||||
this._updateUi({
|
||||
doUpdateHelper: true
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Do the actual calculating/updating of the positions/elements
|
||||
* @param {object} options Options containing if the function should update the helper lasso
|
||||
* @return {null} No return value
|
||||
*/
|
||||
_updateUi: function (options) {
|
||||
var scrollObj = this._scrollIfNeeded({
|
||||
pageX: this.lastDragEvent.pageX,
|
||||
pageY: this.lastDragEvent.pageY
|
||||
});
|
||||
var relativePos = this._calcRelativePosition({
|
||||
x: this.lastDragEvent.pageX,
|
||||
y: this.lastDragEvent.pageY,
|
||||
scrollLeft: scrollObj.scrollLeft,
|
||||
scrollTop: scrollObj.scrollTop
|
||||
});
|
||||
var relativeArea = this._calcRelativeArea({
|
||||
xPos: relativePos.x,
|
||||
yPos: relativePos.y
|
||||
});
|
||||
if (options.doUpdateHelper) {
|
||||
this._updateHelper({
|
||||
scrollLeft: scrollObj.scrollLeft,
|
||||
scrollTop: scrollObj.scrollTop,
|
||||
x1: relativeArea.x1,
|
||||
y1: relativeArea.y1,
|
||||
x2: relativeArea.x2,
|
||||
y2: relativeArea.y2
|
||||
});
|
||||
}
|
||||
this._updateSelectees({
|
||||
x1: relativeArea.x1,
|
||||
y1: relativeArea.y1,
|
||||
x2: relativeArea.x2,
|
||||
y2: relativeArea.y2
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Start the automatic scrolling if needed
|
||||
* @param {object} options Options containing if the function should start the interval
|
||||
* @return {null} No return value
|
||||
*/
|
||||
_updateIntervals: function (options) {
|
||||
var that = this;
|
||||
if (options.keepScrolling && !this.scrollIntervalId) {
|
||||
this.scrollIntervalId = setInterval(function () {
|
||||
that._updateUi({
|
||||
doUpdateHelper: false
|
||||
});
|
||||
}, this.options.scrollIntervalTime);
|
||||
}
|
||||
if (!options.keepScrolling && this.scrollIntervalId)
|
||||
this._clearIntervals();
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear the autoscroll interval
|
||||
* @return {null} No return value
|
||||
*/
|
||||
_clearIntervals: function () {
|
||||
// Stop scrolling
|
||||
this.lastDragEvent = null;
|
||||
if (this.scrollIntervalId)
|
||||
clearInterval(this.scrollIntervalId);
|
||||
this.scrollIntervalId = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* The original _mouseStop event extended with the interval clearer
|
||||
* @param {object} event The original mousestop event
|
||||
* @return {boolean} The parent's return value
|
||||
*/
|
||||
_mouseStop: function (event) {
|
||||
this._clearIntervals();
|
||||
var retValue = this._super(event);
|
||||
return retValue;
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "ui-selectableScroll",
|
||||
"version": "0.1.0",
|
||||
"title": "An extended jQuery-ui selectable with scroll capabilities",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "GPLv3",
|
||||
"url": "http://opensource.org/licenses/GPL-3.0"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": ">=1.8",
|
||||
"jquery-ui": ">=1.10"
|
||||
},
|
||||
"description": "This is an extension of the original jQuery ui selectable plugin. It has capabilities to scroll vertical and horizontal as well.",
|
||||
"keywords": [
|
||||
"jquery",
|
||||
"jqueryui",
|
||||
"selectable",
|
||||
"scroll",
|
||||
"plugin"
|
||||
],
|
||||
"homepage": "https://github.com/karolyi/ui-selectableScroll",
|
||||
"docs": "https://github.com/karolyi/ui-selectableScroll",
|
||||
"download": "https://github.com/karolyi/ui-selectableScroll",
|
||||
"author": {
|
||||
"name": "László Károlyi",
|
||||
"email": "laszlo@karolyi.hu",
|
||||
"url": "https://www.linkedin.com/in/karolyi"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue