html table selection with colspan or rowspan - javascript

I have a table which user can select rows and columns with mouse and then merge the selected area into one cell, it works just like ms word table's behaviors.
However, when the table have rowSpan or colSpan, the selected area are not regular rectangle, so I'd like to extend the selection to an regular rectangle for the later mergence.
here is the example with rowspan and colspan, when the selection does not include the td has rowspan, it works fine, otherwise, the selection is wrong.
$('td').mousedown(function () {
$(this).closest('table').find('td').removeClass('selected');
var start = {
x: this.cellIndex,
y: this.parentNode.rowIndex
}
$(this).closest('table').find('td').mouseover(function () {
var x1 = Math.min(start.x, this.cellIndex);
var y1 = Math.min(start.y, this.parentNode.rowIndex);
var x2 = Math.max(start.x, this.cellIndex);
var y2 = Math.max(start.y, this.parentNode.rowIndex);
$(this).closest('table').find('td').each(function () {
var x = this.cellIndex;
var y = this.parentNode.rowIndex;
if (x >= x1 && x <= x2 && y >= y1 && y <= y2) {
$(this).addClass('selected');
} else {
$(this).removeClass('selected');
}
});
});
var self = this;
$(document).mouseup(function () {
$(self).closest('table').find('td').unbind('mouseover');
$(document).unbind('mouseup');
});
});
http://jsfiddle.net/uRd87/3/

Selection goes wrong when you have a cell with colspan > 1 because the cellIndex value of the cells after that cell change to adjust for the colspan taken by the previous cell. See the the image below.
This is what your cell selection logic does when you press the mouse down at top left corner of the cell with colspan=2 and drag mouse down to 3rd row (indicated by the red line):
Mouse down on top left corner of cell with colspan=2. Take the cellIndex and rowIndex value of the cell where selection started. Begin cellIndex=2 and rowIndex=0.
Drag the mouse down to 3rd row (indicated by the red line). Ending cellIndex=2 and rowIndex=2
Select cells between and including begin [cellIndex,rowIndex] and end [cellIndex,rowIndex]. In this case select cells [2,0],[2,1],[2,2]. That is where the problem is! Cell [2,1] has moved to the next column to adjust for the previous cell with colspan=2. Though that cell's cellIndex value is 2, you should treat it as if its cellIndex value is 3 and exclude it from selection.

I have found the reason and now I used a jquery plugin named cellPos to solve the cellIndex problem.
However, there still a problem, the selection area can be non-regular rectangle. see the image below.
the first image show the selection area, the arrow indicated the mouse direction.
the second image show what I really what.

Related

Scroll table row into view (and to top) even if it is the last row

I have a table with dynamic content.
When it loads I want a certain row (it differs which one) to be at the top.
This is doable in cases where the table has enough rows below the one I want to scroll into view.
But when I want for instance the 12th row at the top and the table only has 14 rows. It will not scroll down far enough because there is nothing to fill up the remaining space.
I'm guessing I need something to fill the left over space. But something that should shrink to 0 if the table is in a scrollposition that it already fills its container.
I could get an element to fill up that space. But when the user scrolls up it should reduce in height (as the table contents move down) and not grow after that. Meaning the user can scroll up to the top just once.
Someone asked: "Did you try to write something yourself?"
Well, I've come up with this. It almost works on page load, then when you navigate from that to a different anchor, the spacer becomes way too large. For some reason much larger than on the first page load.
Scrollreference is the element that the table scrolls within.
var createSpacer = function (row, height) {
// add element with height equal to distance
spacer = document.createElement('div');
var container = getClosestBySelector(row, tableContainerSelector);
container.appendChild(spacer);
spacer.className = spacerClass;
spacer.style.height = height + 'px';
return spacer;
};
var getInitialSpacerHeight = function (row) {
var scrollreference = getClosestBySelector(row, scrollReferenceSelector);
// get scrollreference that has this row
// return distance from top of table
var sizeAboveRow = row.getBoundingClientRect().top - scrollreference.getBoundingClientRect().top - window.scrollY;
return sizeAboveRow;
};
var navigationHandler = function (e) {
// set anchored row to top even if table doesn't have enough rows to put it there
var rowID = e.detail.newLocation.substring(e.detail.newLocation.indexOf("#") + 1);
// only if the new location has an anchor
if (rowID !== "") {
var row = document.querySelector('#' + rowID);
var spacerHeight = getInitialSpacerHeight(row);
if (spacerHeight === 0) {
// if spacer height = 0 we don't need to act
// remove listener and/or spacer here?
return;
} else {
createSpacer(row, spacerHeight);
var scrollreference = getClosestBySelector(row, scrollReferenceSelector);
scrollreference.scrollTop = scrollreference.scrollHeight;
}
}
}

How to find exact draggable grid line position in rulerguides.js?

I am currently working in rulerguides.js. And i customized into particular div for rulers and grid line.REFER THIS FIDDLE. Rulers are working fine for me but drag-gable create div (GRID LINES) calculated from body element only , that means top of window and left edges of window.Here In my code i can send particular div for rulers
var evt = new Event(),
dragdrop = new Dragdrop(evt),
rg = new RulersGuides(evt, dragdrop,document.getElementById('workarea'));
I need to start from particular div
(For example : ruler h unselectable class will create horizontal grid line and ruler v unselectable class will create vertical grid line in my working area.)
How to get draggable starting element ? And i need to start in particular div just like image
.
I am struggle for more than 2 days.How to solve this issues?
Actually RulersGuides.js is not intended to be used in containers other than document body, so I would think about placing it in an iframe.
If you really need to have it a in a div, here are some adjustments needed:
Update getWindowSize, getScrollPos and getScrollSize functions to calculate container dimensions.
Instead of using vBound and hBound in mousedown handler you need to introduce vLowBound, vHighBound, etc., where container's left and top offsets will be taken in account, like this:
if (vLowBound === 0) {
vLowBound = container.offsetLeft;
vHighBound = vRuler.offsetWidth + vLowBound;
hLowBound = container.offsetTop;
hHighBound = hRuler.offsetHeight + hLowBound;
}
with appropriate checks
if (
(
(x > vLowBound && x < vHighBound) ||
(y > hLowBound && y < hHighBound)
) && rulerStatus === 1
)
and then
if (y > hLowBound && y < hHighBound) {
and
} else if (x > vLowBound && x < vHighBound) {
accordingly
Update removeInboundGuide accordingly in the same way.
Other than that, I think there'll be needed some changes in dom dimensions calculations, dialogs etc.
Please refer to the following jsfiddle for the details.

How to snap jQuery UI draggable back to grid correctly after moving freely with no snapping

Using jQuery UI, I have some draggable DIVs. The DIVs snap to a 32x32 grid using the corresponding option grid: [32, 32].
The user can move around the DIVs in the grid but he can also hold down the Alt key to move them freely without snapping to the grid. When the Alt key is held down, I simply change the grid option to [1, 1] for that DIV.
Problem is that the next time that DIV is going to be moved, it will be aligned to a [32,32] grid but there will be an offset.
So what I need to do is:
DIV is dragged around on a 32,32 grid
User presses Alt and now instance is moved freely in a 1,1 grid
User places the DIV somewhere in an uneven coordinate like (103, 67)
Next time the DIV is dragged, first snap it correctly on the 32,32
grid and then start dragging (unless of course the user is pressing
Alt)
http://jsfiddle.net/SwHpa/2/ (ALT key doesn't work quite fluidly in this fiddle, you have to click on the empty space while holding ALT then drag the DIV to test free dragging)
$(document).ready(function(){
$(".draggable").draggable({
grid: [32, 32]
});
});
$(window).on('keydown', function(event){
if (event.keyCode == 18) {
$(".draggable").draggable({
grid: [2, 2]
});
}
});
$(window).on('keyup', function(event){
if (event.keyCode == 18) {
$(".draggable").draggable({
grid: [32, 32]
});
}
});
I'm new to stack overflow, first time ever commenting but maybe something like this would help: http://jsfiddle.net/SwHpa/4/
var myTop = jQuery(".draggable").css("top");
var myLeft = jQuery(".draggable").css("left");
var myNewTop = 0;
var myNewLeft = 0;
myNewTop = Math.floor(myTop / 32) * 32;
myNewLeft = Math.floor(myLeft / 32) * 32;
jQuery(".draggable").css({"top" : myNewTop, "left" : myNewLeft});
After you let go of the alt key, you'll need to re-calculate to the nearest "32" increment. I figured if you take your current top/left and divide it by 32, then Math.floor it to the nearest whole number and finally multiply it against 32 you'll be right back into the square boxes.

How to center the selection in Ace Editor

I am trying to make it so that when the cursor or the selection (either or both) is moved either left of right in an ace-editor session, the scroll bar scrolls to keep the cursor or selected region in the center of the textarea.
There is a function called centerSelection()
this.centerSelection = function() {
var range = this.getSelectionRange();
var pos = {
row: Math.floor(range.start.row + (range.end.row - range.start.row) / 2),
column: Math.floor(range.start.column + (range.end.column - range.start.column) / 2)
}
this.renderer.alignCursor(pos, 0.5); };
which "Attempts to center the current selection on the screen."
which sounds like what i want but it doesn't seem to be doing anything.
there is also a keybinding for a command called "centerselection"
{
name: "centerselection",
bindKey: bindKey(null, "Ctrl-L"),
exec: function(editor) { editor.centerSelection(); },
readOnly: true}
but it has no Key input for windows, just says null. I don't have a mac so I can't try out Ctrl-L and I'm curious as to why it doesn't have a key input for windows aswell.
after playing with it some more i realise it is working it is just centering the selection row and not the selection column. So is there a way to get the selection to be in the center column as well as the center row?
I think it is because the alignCursor function only aligns the cursor row and not column
this.alignCursor = function(cursor, alignment) {
if (typeof cursor == "number")
cursor = {row: cursor, column: 0};
var pos = this.$cursorLayer.getPixelPosition(cursor);
var h = this.$size.scrollerHeight - this.lineHeight;
var offset = pos.top - h * (alignment || 0);
this.session.setScrollTop(offset);
return offset;
};
Well I think I figured it out, this code below works fine. :)
var cursorLeft = editor.renderer.$cursorLayer.getPixelPosition(0).left;
//gets distance between cursor and left side of textarea in pixels
var scrollerWidth = editor.renderer.$size.scrollerWidth;
//gets the width of the text area (that can be seen)
editor.renderer.scrollToX(cursorLeft - scrollerWidth/2);
//moves the scroller so that the left side i at the same point as the cursor minus half the width of the area that can be seen

How to align td text to the top of visible part of cell?

My table consists of two column: name of object and object. Name is just one word. Object can occupy several screens. I want to hold name on top of visible part of its cell. In this case when user scrolls page down he can see name of the object until the object is hidden. How can I do this? Are there plugins to do so?
It's only a couple lines of jQuery. http://jsfiddle.net/VuRvs/
Attach a handler to the window scroll event, find your "sticky" heading, position them based on the current scroll position make sure they stay inside of their parent element (the TD).
$(window).on("scroll", function() {
var y = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
$(".sticky").each(function() {
var elm = $(this);
var td = elm.parent("td");
var tdTop = td.offset().top;
var tdBot = tdTop + td.height() - elm.outerHeight();
if(y <= tdBot && y >= tdTop) {
// set a placeholder
if(td.children().length == 1)
td.append(elm.clone().removeClass("sticky").css("visibility", "hidden"));
elm.css("position", "absolute");
elm.css("top", y + "px");
}
});
});
What you are describing, is a persistant header, or a freeze pane like Excel.
Check this link, it's nicelly explained.

Categories

Resources