Opened 14 years ago
Last modified 10 years ago
#4377 open bug
Selectable: Wrong offset when using appendTo
Reported by: | arikshtiv | Owned by: | |
---|---|---|---|
Priority: | major | Milestone: | 2.0.0 |
Component: | ui.selectable | Version: | 1.7.1 |
Keywords: | Cc: | ||
Blocked by: | Blocking: |
Description
When using appendTo on an element which is not body the offset is still calculated in a relation to the body and not to the appendTo.
Attachments (3)
Change History (15)
Changed 14 years ago by
comment:1 Changed 14 years ago by
Here is a better Description:
If the parent of the helper(lasso) has an offset from the page the offset of the helper(lasso) is positioned as if it's parent didn't have an offset.
Also I attached a file that shows the problem.
I made a fix for that problem, to fix it you reduce the offset of the append to from the helper(lasso) offset.
so you change:
// position helper (lasso) this.helper.css({ "z-index": 100, "position": "absolute", "left": event.clientX, "top": event.clientY, "width": 0, "height": 0 });
To:
// position helper (lasso) this.helper.css({ "z-index": 100, "position": "absolute", "left": event.clientX-$(options.appendTo).offset().left, "top": event.clientY-$(options.appendTo).offset().top, "width": 0, "height": 0 });
And:
this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
To:
this.helper.css({left: x1-$(options.appendTo).offset().left, top: y1-$(options.appendTo).offset().top, width: x2-x1, height: y2-y1});
comment:2 Changed 14 years ago by
Owner: | set to andrew_ |
---|---|
Status: | new → assigned |
comment:3 Changed 14 years ago by
I haven't tested this, but the proposed patch seems to only work if the appendTo element is the element with an offset. The patch really needs to grab the offset from the offset parent. I believe draggable has some code to do this, but this should be handled by the positionTo plugin that is currently being designed.
comment:4 Changed 14 years ago by
If you mean that there is a bug if only the appendTo element's parent has a offset so no, it works fine with only the parent having and offset.
comment:5 Changed 14 years ago by
I've attached a file showing why we need to find the offset parent.
Changed 14 years ago by
Attachment: | 4377-offsetparent.patch added |
---|
comment:6 Changed 14 years ago by
Milestone: | TBD → 1.8 |
---|
Attached a patch that uses the offsetParent's offset, based on arikshtiv's patch.
comment:7 Changed 14 years ago by
Hello Scott,
I tested your changes, but it did not work for me. I created a testcase (but not with your patched js, did not know how to upload). http://jsbin.com/uwizo
Thanks & Regards
comment:8 Changed 12 years ago by
Hello, I've created a solution for better selectable table rows with auto scrolling. Testet with Firefox 3.6.
Here's my code:
/** * jQuery UI Selectable 1.8.5 * * modified by mk.keck 9.Aug. 2010 * * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Selectables * * Depends: * jquery.ui.core.js * jquery.ui.mouse.js * jquery.ui.widget.js */ (function( $, undefined ) { $.widget('ui.selectable', $.ui.mouse, { options: { appendTo: 'body', autoRefresh: true, distance: 0, filter: '*', tolerance: 'touch' }, _create: function() { var self = this; this.element.addClass('ui-selectable'); this.dragged = false; // Get Scrollbar-Size var w1 = 0, w2 = 0, old = ''; var div = $('<div style="' + 'width:50px;height:50px;overflow:hidden;' + 'position:absolute;top:-200px;left:-200px;' + '"><div style="height:100px;"></div>'); $('body').append(div); w1 = $('div', div).innerWidth(); div.css('overflow-y', 'scroll'); w2 = $('div', div).innerWidth(); $(div).remove(); this.options.scrollbarwidth = (parseInt(w1, 10) - parseInt(w2, 10)) + 2; // Get Object-Position, where to append the Selectable // See Ticket: http://dev.jqueryui.com/ticket/4377 this.options.fixPosX = 0; this.options.fixPosY = 0; if (this.options.appendTo && this.options.appendTo !== 'body') { this.options.fixPosX = $(this.options.appendTo).offset().left; this.options.fixPosY = $(this.options.appendTo).offset().top; } // cache selectee children based on filter var selectees; this.refresh = function() { selectees = $(self.options.filter, self.element[0]); selectees.each(function() { var $this = $(this); var 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(), 'startselected': false, 'selected': $this.hasClass('ui-selected'), 'selecting': $this.hasClass('ui-selecting'), 'unselecting': $this.hasClass('ui-unselecting') }); }); // Get Scrolled Positions self.options.scrollX = $(self.options.appendTo).scrollLeft(); self.options.scrollY = $(self.options.appendTo).scrollTop(); }; this.refresh(); this.selectees = selectees.addClass('ui-selectee'); this._mouseInit(); this.helper = $('<div class="ui-selectable-helper"></div>'); }, destroy: function() { this.selectees .removeClass('ui-selectee') .removeData('selectable-item'); this.element .removeClass('ui-selectable ui-selectable-disabled') .removeData('selectable') .unbind('.selectable'); this._mouseDestroy(); return this; }, _mouseStart: function(event) { var self = this; this.opos = [event.pageX, event.pageY]; if (this.options.disabled) { return; } // Get Scrolled Positions this.options.scrollX = $(this.options.appendTo).scrollLeft(); this.options.scrollY = $(this.options.appendTo).scrollTop(); var options = this.options; this.selectees = $(options.filter, this.element[0]); this._trigger('start', event); $(options.appendTo).append(this.helper); // See Ticket: http://dev.jqueryui.com/ticket/4377 this.helper.css({ 'left': event.clientX + options.fixPosX + options.scrollX, 'top': event.clientY + options.fixPosY + options.scrollY, 'width': 0, 'height': 0 }); if (options.autoRefresh) { this.refresh(); } this.selectees.filter('.ui-selected').each(function() { var selectee = $.data(this, 'selectable-item'); selectee.startselected = true; if (!event.metaKey) { selectee.$element.removeClass('ui-selected'); selectee.selected = false; selectee.$element.addClass('ui-unselecting'); selectee.unselecting = true; // selectable UNSELECTING callback self._trigger('unselecting', event, { unselecting: selectee.element }); } }); $(event.target).parents().andSelf().each(function() { var selectee = $.data(this, 'selectable-item'); if (selectee) { var doSelect = !event.metaKey || !selectee.$element.hasClass('ui-selected'); selectee.$element .removeClass(doSelect ? 'ui-unselecting' : 'ui-selected') .addClass(doSelect ? 'ui-selecting' : 'ui-unselecting'); selectee.unselecting = !doSelect; selectee.selecting = doSelect; selectee.selected = doSelect; // selectable (UN)SELECTING callback if (doSelect) { self._trigger('selecting', event, { selecting: selectee.element }); } else { self._trigger('unselecting', event, { unselecting: selectee.element }); } return false; } }); }, _mouseDrag: function(event) { var self = this; this.dragged = true; if (this.options.disabled) { return; } var options = this.options; var x1 = this.opos[0], x2 = event.pageX, x3 = 0; var y1 = this.opos[1], y2 = event.pageY, y3 = 0, var px = x2, py = y2, sx = 0, sy = 0, fx = 0, fy = 0; if (x1 > x2) { x3 = x2; x2 = x1; x1 = x3; } if (y1 > y2) { y3 = y2; y2 = y1; y1 = y3; } // See Ticket: http://dev.jqueryui.com/ticket/4377 this.helper.css({ 'left': (x1 - options.fixPosX) + options.scrollX, 'top': (y1 - options.fixPosY) + options.scrollY, 'width': (x2 - x1), 'height': (y2 - y1) }); // Scroll to the Position, if required fx = ($(options.appendTo).width() - options.scrollbarwidth); fy = ($(options.appendTo).height() - options.scrollbarwidth); sx = (((px - options.fixPosX) + options.scrollX) - fx) + ( (x3 > 0) ? options.scrollX : 0 ); sy = (((py - options.fixPosY) + options.scrollY) - fy) + ( (y3 > 0) ? options.scrollY : 0 ); if (sy > 0) { $(options.appendTo).scrollTop(sy); } else { $(options.appendTo).scrollTop(0); } if (sx > 0) { $(options.appendTo).scrollLeft(sx); } else { $(options.appendTo).scrollLeft(0); } this.selectees.each(function() { var hit = false, selectee = $.data(this, 'selectable-item'); // prevent helper from being selected if appendTo: selectable if (!selectee || selectee.element == self.element[0]) { return; } if (options.tolerance == 'touch') { hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); } else if (options.tolerance == 'fit') { hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < 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 self._trigger('selecting', event, { selecting: selectee.element }); } } else { // UNSELECT if (selectee.selecting) { if (event.metaKey && 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 self._trigger('unselecting', event, { unselecting: selectee.element }); } } if (selectee.selected) { if (!event.metaKey && !selectee.startselected) { selectee.$element.removeClass('ui-selected'); selectee.selected = false; selectee.$element.addClass('ui-unselecting'); selectee.unselecting = true; // selectable UNSELECTING callback self._trigger('unselecting', event, { unselecting: selectee.element }); } } } }); return false; }, _mouseStop: function(event) { var self = this; this.dragged = false; var options = this.options; $('.ui-unselecting', this.element[0]).each(function() { var selectee = $.data(this, 'selectable-item'); selectee.$element.removeClass('ui-unselecting'); selectee.unselecting = false; selectee.startselected = false; self._trigger('unselected', event, { unselected: selectee.element }); }); $('.ui-selecting', this.element[0]).each(function() { var selectee = $.data(this, 'selectable-item'); selectee.$element.removeClass('ui-selecting').addClass('ui-selected'); selectee.selecting = false; selectee.selected = true; selectee.startselected = true; self._trigger('selected', event, { selected: selectee.element }); }); this._trigger('stop', event); this.helper.remove(); return false; } }); $.extend($.ui.selectable, { version: '1.8.5' }); })(jQuery);
comment:9 Changed 10 years ago by
Milestone: | 1.9.0 → 2.0.0 |
---|
comment:10 Changed 10 years ago by
Owner: | andrew_ deleted |
---|---|
Status: | assigned → open |
comment:11 Changed 10 years ago by
Summary: | Wrong offset when using appendTo → Selectable: Wrong offset when using appendTo |
---|
A simple file that shows a situation where it exists.